diff --git a/.github/issue_template.md b/.github/issue_template.md
index 24772c3660..1442eaed1d 100644
--- a/.github/issue_template.md
+++ b/.github/issue_template.md
@@ -1,8 +1,8 @@
-The issue tracker is only for reporting bugs or asking for feature requests and bugs.
-If you need technical assistance for running a node please consult the #fullnode channel on discord (https://discord.gg/jrxApWC) or https://forum.helloiota.com/Technology/Help.
-If you have general questions on IOTA you can go to https://iota.stackexchange.com/, or https://helloiota.com/, or browse discord channels (https://discord.gg/C88Wexg).
+The issue tracker is only for reporting bugs or submitting feature requests.
+If you need technical assistance for running a node please consult the #fullnode channel on Discord (https://discord.gg/jrxApWC) or https://forum.helloiota.com/Technology/Help.
+If you have general questions on IOTA you can go to https://iota.stackexchange.com/, https://helloiota.com/, or browse Discord channels (https://discord.gg/C88Wexg).
@@ -20,7 +20,7 @@ On what hardware is the node running on?
### Expected behaviour
What should happen.
-### Actual behavior
+### Actual behaviour
What really happened.
### Errors
diff --git a/.gitignore b/.gitignore
index c22a8502d8..1d9ec7ac4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@
/.settings
/tomcat.*
/.idea
+/bin
+/mainnetdb
+/mainnet.log
/*.iml
.classpath
.project
@@ -14,6 +17,7 @@ target/*
src/main/ixi/
dependency-reduced-pom.xml
+
# Created by https://www.gitignore.io/api/osx,linux,windows
### Linux ###
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..8353850693
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,35 @@
+## How to contribute to IRI
+
+#### **Did you find a bug?**
+
+* **Do not open a GitHub issue if the bug is a security vulnerability
+ in IRI**, and instead, please contact us via [security@iota.org](mailto:security@iota.org).
+
+* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/iotaledger/iri/issues). You can also look up related issues by a label. For example, if your issue is database-related, filter based on the `C-DB` label and look for related issues. If it's API related, use `C-API` and so on. `C` stands for component. Make sure you skim through the labels to find your category.
+
+* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/iotaledger/iri/issues/new). Be sure to include a **title and clear description**, and as much relevant information as possible. Make sure you follow our new issue template. The first part of the issue template is dedicated to reporting bugs, delete the second part. Steps to reproduce are particularly important. Add any relevant log output and screenshots. The easier it will be to reproduce your issue, the more likely it's getting fixed.
+
+#### **Did you write a patch that fixes a bug?**
+
+* [New issues](https://github.com/iotaledger/iri/issues/new) should be used for reporting issues. If you already wrote a patch for an issue that you or someone else reported, make sure you link it to the open issue. You can do this by mentioning the issue number in the comment or description on the PR, for example `#123` to link issue "123".
+
+* Ensure the PR description clearly describes the problem and solution. Very large PRs are difficult to review and test. This makes them less likely to be merged. If possible, split the PR into multiple PRs, each addressing a specific concern or scenario. Only make the code changes necessary to address the actual issue.
+
+#### **Do you intend to add a new feature or change an existing one?**
+
+* Suggest your change as a [new issues](https://github.com/iotaledger/iri/issues/new). Use the second part of the issue template, dedicated to new feature requests and delete the first part. If you plan on implementing the change yourself, start writing the code and submit a PR. Note that the fact that the feature is "code ready" doesn't mean it will get merged. It is advisable to gather feedback for the change first. You are encouraged to start and drive a discussion on [Discord](https://discordapp.com/invite/fNGZXvh). The IRI team also monitors the repo and will provide feedback where relevant.
+
+
+#### **Do you have questions about the functioning of IRI nodes, the network or anything IOTA related?**
+
+* Use our [Discord](https://discordapp.com/invite/fNGZXvh) to join the discussion and ask questions.
+
+#### **Do you want to contribute to the IRI documentation?**
+
+The IOTA documentation is based in the [docs](https://github.com/iotaledger/docs) repo. You are welcome to contribute. Make sure you follow the instructions on adding new docs.
+
+Thanks! :heart: :heart: :heart:
+
+The contribution guidelines are inspired by the Ruby on Rails contribution guidelines.
+
+IRI Team
\ No newline at end of file
diff --git a/DOCKER.md b/DOCKER.md
index c3d27c185a..efc0718290 100644
--- a/DOCKER.md
+++ b/DOCKER.md
@@ -2,13 +2,13 @@
Run the official iotaledger/iri container, passing the mandatory -p option:
-```docker run iotaledger/iri:v1.5.4 -p 14265```
+```docker run iotaledger/iri:v1.5.5 -p 14265```
This will get your a running IRI with its API listening on port 14265, no neighbours and an empty database. The IRI Docker container by default expects data at /iri/data. Use the `-v` option of the `docker run` command to mount volumes so to have persistent data. You can also pass more command line options to the docker run command and those will be passed to IRI.
If you want to use a iri.ini file with the docker container, supposing it's stored under /path/to/conf/iri.ini on your docker host, then pass `-v /path/to/conf:/iri/conf` and add -c /iri/conf/iri.ini as docker run arguments. So for example the `docker run` command above would become:
-```docker run -v /path/to/conf:/iri/conf -v /path/to/data:/iri/data iotaledger/iri:v1.5.4 -p 14265 -c /iri/conf/iri.ini```
+```docker run -v /path/to/conf:/iri/conf -v /path/to/data:/iri/data iotaledger/iri:v1.5.5 -p 14265 -c /iri/conf/iri.ini```
Please refer to the IRI documentation for further command line options and iri.ini options.
@@ -61,7 +61,7 @@ ExecStart=/usr/bin/docker run \
-p 14265:14265 \
-p 15600:15600 \
-p 14600:14600/udp \
-iotaledger/iri:v1.5.4 \
+iotaledger/iri:v1.5.5 \
-p 14265 \
--zmq-enabled \
--testnet
diff --git a/Dockerfile b/Dockerfile
index d901c9a66e..dc2f3b468a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,59 +1,13 @@
-FROM ubuntu:18.04 as local_stage_java
+FROM iotacafe/maven:3.5.4.oracle8u181.1.webupd8.1.1-1 as local_stage_build
MAINTAINER giorgio@iota.org
-# Install Java
-ARG JAVA_VERSION=8u181-1
-RUN \
- apt-get update && \
- apt-get install -y software-properties-common --no-install-recommends && \
- echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
- add-apt-repository -y ppa:webupd8team/java && \
- apt-get update && \
- apt-get install -y oracle-java8-installer=${JAVA_VERSION}~webupd8~1 --no-install-recommends && \
- rm -rf /var/lib/apt/lists/* && \
- rm -rf /var/cache/oracle-jdk8-installer
-
-# Define commonly used JAVA_HOME variable
-ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
-
-# install maven on top of java stage
-FROM local_stage_java as local_stage_build
-ARG MAVEN_VERSION=3.5.3
-ARG USER_HOME_DIR="/root"
-ARG SHA=b52956373fab1dd4277926507ab189fb797b3bc51a2a267a193c931fffad8408
-ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
- curl \
- && rm -rf /var/lib/apt/lists/*
-
-RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
- && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
- && echo "${SHA} /tmp/apache-maven.tar.gz" | sha256sum -c - \
- && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
- && rm -f /tmp/apache-maven.tar.gz \
- && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
-
-ENV MAVEN_HOME /usr/share/maven
-ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"
-
-COPY docker/mvn-entrypoint.sh /usr/local/bin/mvn-entrypoint.sh
-COPY docker/settings-docker.xml /usr/share/maven/ref/
-
-VOLUME "$USER_HOME_DIR/.m2"
-
-# install build dependencies
-RUN apt-get update && apt-get install -y --no-install-recommends \
- git \
- && rm -rf /var/lib/apt/lists/*
-
WORKDIR /iri
COPY . /iri
RUN mvn clean package
# execution image
-FROM local_stage_java
+FROM iotacafe/java:oracle8u181.1.webupd8.1-1
RUN apt-get update && apt-get install -y --no-install-recommends \
jq curl socat \
diff --git a/README.md b/README.md
index 5ec45fa694..fb16e0b625 100644
--- a/README.md
+++ b/README.md
@@ -34,8 +34,12 @@ If you want to get tokens for your testcase, please just ask in one of the commu
## Reporting Issues
-If you notice any bugs, problems or other irregularities with this release,
-please submit an issue on github [[submit new issue]](https://github.com/iotaledger/iri/issues/new).
+If you'd like to contribute to IRI, report bugs, problems or irregularities with this release,
+please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
+
+# Documentation
+
+This page contains basic instructions for setting up an IRI node. You can find the full documentation on our [documentation website](https://docs.iota.org/iri). Also see the [IRI API refernece](https://iota.readme.io/reference).
# Installing
diff --git a/changelog.txt b/changelog.txt
index 572153392f..664f2020f7 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,20 @@
+1.5.5
+ - Javadoc on API command methods (#943)
+ - Parse case insensitive boolean text (#966)
+ - re-enable `--remote` flag - opens API interface to all hosts (#953)
+ - fix generics in RocksDbPersistenceProvider (#956)
+ - Fix milestone start index default value (#941)
+ - Enable batch deletion in rocksDB (#939)
+ - Refactor Configuration (#910)
+ - Some TransactionValidator fixes regarding solidity (#913)
+ - Remove checkSolidity mocks (#908)
+ - Fix: TransactionValidator instance based / TransactionRequester fixed (#914)
+ - Changed Dockerfile to source java and maven from precompiled docker containers. (#929)
+ - Fix grammar in API responses (#884)
+ - Fix error in log statement (#829)
+ - Move sleep inside spawnSolidTransactionsPropagation loop (#911)
+ - Fix solidity propagation from bottom to top (#907)
+
1.5.4
- Update snapshot to 2018-09-17 17:00 UTC (#989)
diff --git a/docker/mvn-entrypoint.sh b/docker/mvn-entrypoint.sh
deleted file mode 100644
index b80c278868..0000000000
--- a/docker/mvn-entrypoint.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#! /bin/bash -eu
-
-set -o pipefail
-
-# Copy files from /usr/share/maven/ref into ${MAVEN_CONFIG}
-# So the initial ~/.m2 is set with expected content.
-# Don't override, as this is just a reference setup
-copy_reference_file() {
- local root="${1}"
- local f="${2%/}"
- local logfile="${3}"
- local rel="${f/${root}/}" # path relative to /usr/share/maven/ref/
- echo "$f" >> "$logfile"
- echo " $f -> $rel" >> "$logfile"
- if [[ ! -e ${MAVEN_CONFIG}/${rel} || $f = *.override ]]
- then
- echo "copy $rel to ${MAVEN_CONFIG}" >> "$logfile"
- mkdir -p "${MAVEN_CONFIG}/$(dirname "${rel}")"
- cp -r "${f}" "${MAVEN_CONFIG}/${rel}";
- fi;
-}
-
-copy_reference_files() {
- local log="$MAVEN_CONFIG/copy_reference_file.log"
-
- if (touch "${log}" > /dev/null 2>&1)
- then
- echo "--- Copying files at $(date)" >> "$log"
- find /usr/share/maven/ref/ -type f -exec bash -eu -c 'copy_reference_file /usr/share/maven/ref/ "$1" "$2"' _ {} "$log" \;
- else
- echo "Can not write to ${log}. Wrong volume permissions? Carrying on ..."
- fi
-}
-
-export -f copy_reference_file
-copy_reference_files
-unset MAVEN_CONFIG
-
-exec "$@"
diff --git a/docker/settings-docker.xml b/docker/settings-docker.xml
deleted file mode 100644
index 586c587c11..0000000000
--- a/docker/settings-docker.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
- /usr/share/maven/ref/repository
-
diff --git a/pom.xml b/pom.xml
index dba69f061d..d6481f5563 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.iota
iri
- 1.5.4
+ 1.5.5
IRI
IOTA Reference Implementation
@@ -93,6 +93,13 @@
2.8.1
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.9.6
+
+
io.undertow
@@ -112,13 +119,6 @@
${undertow.version}
-
-
- com.sanityinc
- jargs
- 2.0-SNAPSHOT
-
-
@@ -171,6 +171,12 @@
0.4.3
+
+ com.beust
+ jcommander
+ 1.72
+
+
@@ -186,6 +192,25 @@
${java-version}
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.0.0
+
+ com.iota.mdxdoclet.MDXDoclet
+ src/main/java
+ false
+
+ -version "${project.version}"
+
+ true
+
+ com.iota
+ mdxdoclet
+ 0.1
+
+
+
org.apache.maven.plugins
maven-shade-plugin
@@ -295,7 +320,6 @@
com.jayway.restassured:rest-assured:2.9.0:jar:null:test:d0d5b6720a58472ab99287c931a8205373d6e7b2
@@ -311,6 +335,12 @@
org.bouncycastle:bcprov-jdk15on:1.58:jar:null:compile:2c9aa1c4e3372b447ba5daabade4adf2a2264b12
+
+ com.fasterxml.jackson.core:jackson-databind:2.9.6:jar:null:compile:cfa4f316351a91bfd95cb0644c6a2c95f52db1fc
+
+
+ com.beust:jcommander:1.72:jar:null:compile:6375e521c1e11d6563d4f25a07ce124ccf8cd171
+
@@ -534,5 +564,4 @@
-
-
+
\ No newline at end of file
diff --git a/src/main/java/com/iota/iri/IRI.java b/src/main/java/com/iota/iri/IRI.java
index 5393b99679..79301105d9 100644
--- a/src/main/java/com/iota/iri/IRI.java
+++ b/src/main/java/com/iota/iri/IRI.java
@@ -1,19 +1,20 @@
package com.iota.iri;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.core.util.StatusPrinter;
-import com.iota.iri.conf.Configuration;
-import com.iota.iri.conf.Configuration.DefaultConfSettings;
+import com.iota.iri.conf.Config;
+import com.iota.iri.conf.ConfigFactory;
+import com.iota.iri.conf.IotaConfig;
import com.iota.iri.service.API;
-import com.sanityinc.jargs.CmdLineParser;
-import com.sanityinc.jargs.CmdLineParser.Option;
-import org.apache.commons.lang3.StringUtils;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.ParameterException;
+
+import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
-import java.util.Optional;
+import java.util.Arrays;
/**
* Main IOTA Reference Implementation starting class.
@@ -22,7 +23,7 @@ public class IRI {
public static final String MAINNET_NAME = "IRI";
public static final String TESTNET_NAME = "IRI Testnet";
- public static final String VERSION = "1.5.4";
+ public static final String VERSION = "1.5.5";
public static void main(String[] args) throws Exception {
// Logging is configured first before any references to Logger or LoggerFactory.
@@ -62,29 +63,17 @@ private static class IRILauncher {
public static Iota iota;
public static API api;
public static IXI ixi;
- public static Configuration configuration;
-
- private static final String TESTNET_FLAG_REQUIRED = "--testnet flag must be turned on to use ";
- public static void main(final String[] args) throws Exception {
+ public static void main(String [] args) throws Exception {
+ IotaConfig config = createConfiguration(args);
+ log.info("Welcome to {} {}", config.isTestnet() ? TESTNET_NAME : MAINNET_NAME, VERSION);
- configuration = new Configuration();
- if (!isValidated(configuration, args)) {
- printUsage();
- return;
- }
-
- log.info("Welcome to {} {}", configuration.booling(DefaultConfSettings.TESTNET) ? TESTNET_NAME : MAINNET_NAME, VERSION);
- iota = new Iota(configuration);
+ iota = new Iota(config);
ixi = new IXI(iota);
api = new API(iota, ixi);
shutdownHook();
- if (configuration.booling(DefaultConfSettings.DEBUG)) {
- log.info("You have set the debug flag. To enable debug output, you need to uncomment the DEBUG appender in the source tree at iri/src/main/resources/logback.xml and re-package iri.jar");
- }
-
- if (configuration.booling(DefaultConfSettings.EXPORT)) {
+ if (config.isExport()) {
File exportDir = new File("export");
if (!exportDir.exists()) {
log.info("Create directory 'export'");
@@ -108,7 +97,8 @@ public static void main(final String[] args) throws Exception {
try {
iota.init();
api.init();
- ixi.init(configuration.string(Configuration.DefaultConfSettings.IXI_DIR));
+ //TODO redundant parameter but we will touch this when we refactor IXI
+ ixi.init(config.getIxiDir());
log.info("IOTA Node initialised correctly.");
} catch (Exception e) {
log.error("Exception during IOTA node initialisation: ", e);
@@ -116,239 +106,6 @@ public static void main(final String[] args) throws Exception {
}
}
- private static boolean isValidated(final Configuration configuration, final String[] args) throws IOException {
-
- boolean configurationInit = configuration.init();
-
- if (args == null || (args.length < 2 && !configurationInit)) {
- log.error("Invalid arguments list. Provide ini-file 'iota.ini' or API port number (i.e. '-p 14600').");
- return false;
- }
-
- final CmdLineParser parser = new CmdLineParser();
-
- final Option config = parser.addStringOption('c', "config");
- final Option port = parser.addStringOption('p', "port");
- final Option rportudp = parser.addStringOption('u', "udp-receiver-port");
- final Option rporttcp = parser.addStringOption('t', "tcp-receiver-port");
- final Option debug = parser.addBooleanOption('d', "debug");
- final Option remote = parser.addBooleanOption("remote");
- final Option remoteLimitApi = parser.addStringOption("remote-limit-api");
- final Option remoteAuth = parser.addStringOption("remote-auth");
- final Option neighbors = parser.addStringOption('n', "neighbors");
- final Option export = parser.addBooleanOption("export");
- final Option zmq = parser.addBooleanOption("zmq-enabled");
- final Option help = parser.addBooleanOption('h', "help");
- final Option testnet = parser.addBooleanOption("testnet");
- final Option revalidate = parser.addBooleanOption("revalidate");
- final Option rescan = parser.addBooleanOption("rescan");
- final Option sendLimit = parser.addStringOption("send-limit");
- final Option sync = parser.addBooleanOption("sync");
- final Option dnsResolutionFalse = parser.addBooleanOption("dns-resolution-false");
- final Option maxPeers = parser.addStringOption("max-peers");
- final Option testnetCoordinator = parser.addStringOption("testnet-coordinator");
- final Option disableCooValidation = parser.addBooleanOption("testnet-no-coo-validation");
- final Option snapshot = parser.addStringOption("snapshot");
- final Option snapshotSignature = parser.addStringOption("snapshot-sig");
- final Option minimalWeightMagnitude = parser.addIntegerOption("mwm");
- final Option milestoneStartIndex = parser.addIntegerOption("milestone-start");
- final Option milestoneKeys = parser.addIntegerOption("milestone-keys");
- final Option snapshotTime = parser.addLongOption("snapshot-timestamp");
- final Option belowMaxDepthTxLimit = parser.addIntegerOption("max-depth-tx-limit");
-
- try {
- parser.parse(args);
- } catch (CmdLineParser.OptionException e) {
- log.error("CLI error: ", e);
- throw new IllegalArgumentException("CLI error: " + e, e);
- }
-
- // optional config file path
- String confFilePath = parser.getOptionValue(config);
- if (confFilePath != null) {
- configuration.put(DefaultConfSettings.CONFIG, confFilePath);
- configuration.init();
- }
-
- //This block cannot be moved down
- final boolean isTestnet = Optional.ofNullable(parser.getOptionValue(testnet)).orElse(Boolean.FALSE)
- || configuration.booling(DefaultConfSettings.TESTNET);
- if (isTestnet) {
- configuration.put(DefaultConfSettings.TESTNET, "true");
- configuration.put(DefaultConfSettings.DB_PATH.name(), "testnetdb");
- configuration.put(DefaultConfSettings.DB_LOG_PATH.name(), "testnetdb.log");
- configuration.put(DefaultConfSettings.COORDINATOR, Configuration.TESTNET_COORDINATOR_ADDRESS);
- configuration.put(DefaultConfSettings.SNAPSHOT_FILE, Configuration.TESTNET_SNAPSHOT_FILE);
- configuration.put(DefaultConfSettings.MILESTONE_START_INDEX, Configuration.TESTNET_MILESTONE_START_INDEX);
- configuration.put(DefaultConfSettings.SNAPSHOT_SIGNATURE_FILE, "");
- configuration.put(DefaultConfSettings.MWM, Configuration.TESTNET_MWM);
- configuration.put(DefaultConfSettings.NUMBER_OF_KEYS_IN_A_MILESTONE,
- Configuration.TESTNET_NUM_KEYS_IN_MILESTONE);
- configuration.put(DefaultConfSettings.TRANSACTION_PACKET_SIZE, Configuration.TESTNET_PACKET_SIZE);
- configuration.put(DefaultConfSettings.REQUEST_HASH_SIZE, Configuration.TESTNET_REQ_HASH_SIZE);
- configuration.put(DefaultConfSettings.SNAPSHOT_TIME, Configuration.TESTNET_GLOBAL_SNAPSHOT_TIME);
- }
-
- // mandatory args
- String inicport = configuration.getIniValue(DefaultConfSettings.PORT.name());
- final String cport = inicport == null ? parser.getOptionValue(port) : inicport;
- if (cport == null) {
- log.error("Invalid arguments list. Provide at least the PORT in iota.ini or with -p option");
- return false;
- } else {
- configuration.put(DefaultConfSettings.PORT, cport);
- }
-
- // optional flags
- if (parser.getOptionValue(help) != null) {
- return false;
- }
-
-
- String cns = parser.getOptionValue(neighbors);
- if (cns == null) {
- log.warn("No neighbor has been specified. Server starting nodeless.");
- cns = StringUtils.EMPTY;
- }
- configuration.put(DefaultConfSettings.NEIGHBORS, cns);
-
- final String vremoteapilimit = parser.getOptionValue(remoteLimitApi);
- if (vremoteapilimit != null) {
- log.debug("The following api calls are not allowed : {} ", vremoteapilimit);
- configuration.put(DefaultConfSettings.REMOTE_LIMIT_API, vremoteapilimit);
- }
-
- final String vremoteauth = parser.getOptionValue(remoteAuth);
- if (vremoteauth != null) {
- log.debug("Remote access requires basic authentication");
- configuration.put(DefaultConfSettings.REMOTE_AUTH, vremoteauth);
- }
-
- final String vrportudp = parser.getOptionValue(rportudp);
- if (vrportudp != null) {
- configuration.put(DefaultConfSettings.UDP_RECEIVER_PORT, vrportudp);
- }
-
- final String vrporttcp = parser.getOptionValue(rporttcp);
- if (vrporttcp != null) {
- configuration.put(DefaultConfSettings.TCP_RECEIVER_PORT, vrporttcp);
- }
-
- if (parser.getOptionValue(remote) != null) {
- log.info("Remote access enabled. Binding API socket to listen any interface.");
- configuration.put(DefaultConfSettings.API_HOST, "0.0.0.0");
- }
-
- if (parser.getOptionValue(export) != null) {
- log.info("Export transaction trytes turned on.");
- configuration.put(DefaultConfSettings.EXPORT, "true");
- }
-
- if (parser.getOptionValue(zmq) != null) {
- configuration.put(DefaultConfSettings.ZMQ_ENABLED, "true");
- }
-
- if (Integer.parseInt(cport) < 1024) {
- log.warn("Warning: api port value seems too low.");
- }
-
- if (parser.getOptionValue(debug) != null) {
- configuration.put(DefaultConfSettings.DEBUG, "true");
- log.info(configuration.allSettings());
- StatusPrinter.print((LoggerContext) LoggerFactory.getILoggerFactory());
- }
-
-
- final String coordinatorAddress = parser.getOptionValue(testnetCoordinator);
- if (coordinatorAddress != null) {
- if (isTestnet) {
- configuration.put(DefaultConfSettings.COORDINATOR, coordinatorAddress);
- } else {
- log.warn(TESTNET_FLAG_REQUIRED + testnetCoordinator.longForm());
- }
- }
-
- final Boolean noCooValidation = parser.getOptionValue(disableCooValidation);
- if (noCooValidation != null) {
- if (isTestnet) {
- configuration.put(DefaultConfSettings.DONT_VALIDATE_TESTNET_MILESTONE_SIG, noCooValidation.toString());
- } else {
- log.warn(TESTNET_FLAG_REQUIRED + noCooValidation);
- }
- }
-
- //TODO check what happens if string is invalid int
- final Integer mwm = parser.getOptionValue(minimalWeightMagnitude);
- if (mwm != null) {
- configuration.put(DefaultConfSettings.MWM, String.valueOf(mwm));
- }
-
- final String snapshotFile = parser.getOptionValue(snapshot);
- if (snapshotFile != null) {
- configuration.put(DefaultConfSettings.SNAPSHOT_FILE, snapshotFile);
- }
-
- final String snapshotSig = parser.getOptionValue(snapshotSignature);
- if (snapshotSig != null) {
- configuration.put(DefaultConfSettings.SNAPSHOT_SIGNATURE_FILE, snapshotSig);
- }
-
- final Integer milestoneStart = parser.getOptionValue(milestoneStartIndex);
- if (milestoneStart != null) {
- configuration.put(DefaultConfSettings.MILESTONE_START_INDEX, String.valueOf(milestoneStart));
- }
-
- final Integer numberOfKeys = parser.getOptionValue(milestoneKeys);
- if (numberOfKeys != null) {
- configuration.put(DefaultConfSettings.NUMBER_OF_KEYS_IN_A_MILESTONE, String.valueOf(numberOfKeys));
- }
-
- final Long snapshotTimestamp = parser.getOptionValue(snapshotTime);
- if (snapshotTimestamp != null) {
- configuration.put(DefaultConfSettings.SNAPSHOT_TIME, String.valueOf(snapshotTimestamp));
- }
-
- if (parser.getOptionValue(revalidate) != null) {
- configuration.put(DefaultConfSettings.REVALIDATE, "true");
- }
-
- if (parser.getOptionValue(rescan) != null) {
- configuration.put(DefaultConfSettings.RESCAN_DB, "true");
- }
-
- if (parser.getOptionValue(dnsResolutionFalse) != null) {
- configuration.put(DefaultConfSettings.DNS_RESOLUTION_ENABLED, "false");
- }
-
-
- final String vsendLimit = parser.getOptionValue(sendLimit);
- if (vsendLimit != null) {
- configuration.put(DefaultConfSettings.SEND_LIMIT, vsendLimit);
- }
-
- final String vmaxPeers = parser.getOptionValue(maxPeers);
- if (vmaxPeers != null) {
- configuration.put(DefaultConfSettings.MAX_PEERS, vmaxPeers);
- }
-
- return true;
- }
-
- private static void printUsage() {
- log.info("Usage: java -jar {}-{}.jar " +
- "[{-n,--neighbors} ''] " +
- "[{-p,--port} 14265] " +
- "[{-c,--config} 'config-file-name'] " +
- "[{-u,--udp-receiver-port} 14600] " +
- "[{-t,--tcp-receiver-port} 15600] " +
- "[{-d,--debug} false] " +
- "[{--testnet} false]" +
- "[{--remote} false]" +
- "[{--remote-auth} string]" +
- "[{--remote-limit-api} string]"
- , MAINNET_NAME, VERSION);
- }
-
private static void shutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("Shutting down IOTA node, please hold tight...");
@@ -361,9 +118,56 @@ private static void shutdownHook() {
}
}, "Shutdown Hook"));
}
- }
- public static boolean validateParams(Configuration configuration, String[] args) throws IOException {
- return IRILauncher.isValidated(configuration, args);
+ private static IotaConfig createConfiguration(String[] args) {
+ IotaConfig iotaConfig = null;
+ String message = "Configuration is created using ";
+ try {
+ boolean testnet = ArrayUtils.contains(args, Config.TESTNET_FLAG);
+ File configFile = chooseConfigFile(args);
+ if (configFile != null) {
+ iotaConfig = ConfigFactory.createFromFile(configFile, testnet);
+ message += configFile.getName() + " and command line args";
+ }
+ else {
+ iotaConfig = ConfigFactory.createIotaConfig(testnet);
+ message += "command line args only";
+ }
+ JCommander jCommander = iotaConfig.parseConfigFromArgs(args);
+ if (iotaConfig.isHelp()) {
+ jCommander.usage();
+ System.exit(0);
+ }
+ } catch (IOException | IllegalArgumentException e) {
+ log.error("There was a problem reading configuration from file: {}", e.getMessage());
+ log.debug("", e);
+ System.exit(-1);
+ } catch (ParameterException e) {
+ log.error("There was a problem parsing commandline arguments: {}", e.getMessage());
+ log.debug("", e);
+ System.exit(-1);
+ }
+
+ log.info(message);
+ log.info("parsed the following cmd args: {}", Arrays.toString(args));
+ return iotaConfig;
+ }
+
+ private static File chooseConfigFile(String[] args) {
+ int index = Math.max(ArrayUtils.indexOf(args, "-c"), ArrayUtils.indexOf(args, "--config"));
+ if (index != -1) {
+ try {
+ String fileName = args[++index];
+ return new File(fileName);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "The file after `-c` or `--config` isn't specified or can't be parsed.", e);
+ }
+ }
+ else if (IotaConfig.CONFIG_FILE.exists()) {
+ return IotaConfig.CONFIG_FILE;
+ }
+ return null;
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/iota/iri/Iota.java b/src/main/java/com/iota/iri/Iota.java
index beea41adf7..368c545c53 100644
--- a/src/main/java/com/iota/iri/Iota.java
+++ b/src/main/java/com/iota/iri/Iota.java
@@ -1,10 +1,10 @@
package com.iota.iri;
-import com.iota.iri.conf.Configuration;
+import com.iota.iri.conf.IotaConfig;
+import com.iota.iri.conf.TipSelConfig;
import com.iota.iri.controllers.TipsViewModel;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.hash.SpongeFactory;
-import com.iota.iri.model.Hash;
import com.iota.iri.network.Node;
import com.iota.iri.network.TransactionRequester;
import com.iota.iri.network.UDPReceiver;
@@ -17,7 +17,6 @@
import com.iota.iri.utils.Pair;
import com.iota.iri.zmq.MessageQ;
import org.apache.commons.lang3.NotImplementedException;
-import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,90 +39,47 @@ public class Iota {
public final Node node;
public final UDPReceiver udpReceiver;
public final Replicator replicator;
- public final Configuration configuration;
- public final Hash coordinator;
+ public final IotaConfig configuration;
public final TipsViewModel tipsViewModel;
public final MessageQ messageQ;
public final TipSelector tipsSelector;
- public final boolean testnet;
- public final int maxPeers;
- public final int udpPort;
- public final int tcpPort;
- public final int maxTipSearchDepth;
-
- public Iota(Configuration configuration) throws IOException {
+ public Iota(IotaConfig configuration) throws IOException {
this.configuration = configuration;
- testnet = configuration.booling(Configuration.DefaultConfSettings.TESTNET);
- maxPeers = configuration.integer(Configuration.DefaultConfSettings.MAX_PEERS);
- udpPort = configuration.integer(Configuration.DefaultConfSettings.UDP_RECEIVER_PORT);
- tcpPort = configuration.integer(Configuration.DefaultConfSettings.TCP_RECEIVER_PORT);
-
- String snapshotFile = configuration.string(Configuration.DefaultConfSettings.SNAPSHOT_FILE);
- String snapshotSigFile = configuration.string(Configuration.DefaultConfSettings.SNAPSHOT_SIGNATURE_FILE);
- Snapshot initialSnapshot = Snapshot.init(snapshotFile, snapshotSigFile, testnet).clone();
- long snapshotTimestamp = configuration.longNum(Configuration.DefaultConfSettings.SNAPSHOT_TIME);
- int milestoneStartIndex = configuration.integer(Configuration.DefaultConfSettings.MILESTONE_START_INDEX);
- int numKeysMilestone = configuration.integer(Configuration.DefaultConfSettings.NUMBER_OF_KEYS_IN_A_MILESTONE);
- double alpha = configuration.doubling(Configuration.DefaultConfSettings.TIPSELECTION_ALPHA.name());
- int belowMaxDepthTxLimit = configuration.integer(
- Configuration.DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT);
-
- boolean dontValidateMilestoneSig = configuration.booling(Configuration.DefaultConfSettings
- .DONT_VALIDATE_TESTNET_MILESTONE_SIG);
- int transactionPacketSize = configuration.integer(Configuration.DefaultConfSettings.TRANSACTION_PACKET_SIZE);
-
- maxTipSearchDepth = configuration.integer(Configuration.DefaultConfSettings.MAX_DEPTH);
- if(testnet) {
- String coordinatorTrytes = configuration.string(Configuration.DefaultConfSettings.COORDINATOR);
- if(StringUtils.isNotEmpty(coordinatorTrytes)) {
- coordinator = new Hash(coordinatorTrytes);
- } else {
- log.warn("No coordinator address given for testnet. Defaulting to "
- + Configuration.TESTNET_COORDINATOR_ADDRESS);
- coordinator = new Hash(Configuration.TESTNET_COORDINATOR_ADDRESS);
- }
- } else {
- coordinator = new Hash(Configuration.MAINNET_COORDINATOR_ADDRESS);
- }
+ Snapshot initialSnapshot = Snapshot.init(configuration).clone();
tangle = new Tangle();
- messageQ = new MessageQ(configuration.integer(Configuration.DefaultConfSettings.ZMQ_PORT),
- configuration.string(Configuration.DefaultConfSettings.ZMQ_IPC),
- configuration.integer(Configuration.DefaultConfSettings.ZMQ_THREADS),
- configuration.booling(Configuration.DefaultConfSettings.ZMQ_ENABLED)
- );
+ messageQ = MessageQ.createWith(configuration);
tipsViewModel = new TipsViewModel();
transactionRequester = new TransactionRequester(tangle, messageQ);
transactionValidator = new TransactionValidator(tangle, tipsViewModel, transactionRequester, messageQ,
- snapshotTimestamp);
- milestone = new Milestone(tangle, coordinator, initialSnapshot, transactionValidator, testnet, messageQ,
- numKeysMilestone, milestoneStartIndex, dontValidateMilestoneSig);
- node = new Node(configuration, tangle, transactionValidator, transactionRequester, tipsViewModel, milestone, messageQ);
- replicator = new Replicator(node, tcpPort, maxPeers, testnet, transactionPacketSize);
- udpReceiver = new UDPReceiver(udpPort, node, configuration.integer(Configuration.DefaultConfSettings.TRANSACTION_PACKET_SIZE));
+ configuration);
+ milestone = new Milestone(tangle, transactionValidator, messageQ, initialSnapshot, configuration);
+ node = new Node(tangle, transactionValidator, transactionRequester, tipsViewModel, milestone, messageQ,
+ configuration);
+ replicator = new Replicator(node, configuration);
+ udpReceiver = new UDPReceiver(node, configuration);
ledgerValidator = new LedgerValidator(tangle, milestone, transactionRequester, messageQ);
tipsSolidifier = new TipsSolidifier(tangle, transactionValidator, tipsViewModel);
- tipsSelector = createTipSelector(milestoneStartIndex, alpha, belowMaxDepthTxLimit);
+ tipsSelector = createTipSelector(configuration);
}
public void init() throws Exception {
initializeTangle();
tangle.init();
- if (configuration.booling(Configuration.DefaultConfSettings.RESCAN_DB)){
+ if (configuration.isRescanDb()){
rescan_db();
}
- boolean revalidate = configuration.booling(Configuration.DefaultConfSettings.REVALIDATE);
- if (revalidate) {
+ if (configuration.isRevalidate()) {
tangle.clearColumn(com.iota.iri.model.Milestone.class);
tangle.clearColumn(com.iota.iri.model.StateDiff.class);
tangle.clearMetadata(com.iota.iri.model.Transaction.class);
}
- milestone.init(SpongeFactory.Mode.CURLP27, ledgerValidator, revalidate);
- transactionValidator.init(testnet, configuration.integer(Configuration.DefaultConfSettings.MWM));
+ milestone.init(SpongeFactory.Mode.CURLP27, ledgerValidator);
+ transactionValidator.init(configuration.isTestnet(), configuration.getMwm());
tipsSolidifier.init();
- transactionRequester.init(configuration.doubling(Configuration.DefaultConfSettings.P_REMOVE_REQUEST.name()));
+ transactionRequester.init(configuration.getpRemoveRequest());
udpReceiver.init();
replicator.init();
node.init();
@@ -166,46 +122,32 @@ public void shutdown() throws Exception {
}
private void initializeTangle() {
- String dbPath = configuration.string(Configuration.DefaultConfSettings.DB_PATH);
- if (testnet) {
- if (dbPath.isEmpty() || dbPath.equals("mainnetdb")) {
- // testnetusers must not use mainnetdb, overwrite it unless an explicit name is set.
- configuration.put(Configuration.DefaultConfSettings.DB_PATH.name(), "testnetdb");
- configuration.put(Configuration.DefaultConfSettings.DB_LOG_PATH.name(), "testnetdb.log");
- }
- } else {
- if (dbPath.isEmpty() || dbPath.equals("testnetdb")) {
- // mainnetusers must not use testnetdb, overwrite it unless an explicit name is set.
- configuration.put(Configuration.DefaultConfSettings.DB_PATH.name(), "mainnetdb");
- configuration.put(Configuration.DefaultConfSettings.DB_LOG_PATH.name(), "mainnetdb.log");
- }
- }
- switch (configuration.string(Configuration.DefaultConfSettings.MAIN_DB)) {
+ switch (configuration.getMainDb()) {
case "rocksdb": {
tangle.addPersistenceProvider(new RocksDBPersistenceProvider(
- configuration.string(Configuration.DefaultConfSettings.DB_PATH),
- configuration.string(Configuration.DefaultConfSettings.DB_LOG_PATH),
- configuration.integer(Configuration.DefaultConfSettings.DB_CACHE_SIZE)));
+ configuration.getDbPath(),
+ configuration.getDbLogPath(),
+ configuration.getDbCacheSize()));
break;
}
default: {
throw new NotImplementedException("No such database type.");
}
}
- if (configuration.booling(Configuration.DefaultConfSettings.EXPORT)) {
+ if (configuration.isExport()) {
tangle.addPersistenceProvider(new FileExportProvider());
}
- if (configuration.booling(Configuration.DefaultConfSettings.ZMQ_ENABLED)) {
+ if (configuration.isZmqEnabled()) {
tangle.addPersistenceProvider(new ZmqPublishProvider(messageQ));
}
}
- private TipSelector createTipSelector(int milestoneStartIndex, double alpha, int belowMaxDepthTxLimit) {
- EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, milestone, testnet, milestoneStartIndex);
+ private TipSelector createTipSelector(TipSelConfig config) {
+ EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, milestone, config);
RatingCalculator ratingCalculator = new CumulativeWeightCalculator(tangle);
TailFinder tailFinder = new TailFinderImpl(tangle);
- Walker walker = new WalkerAlpha(alpha, new SecureRandom(), tangle, messageQ, tailFinder);
- return new TipSelectorImpl(tangle, ledgerValidator, transactionValidator, entryPointSelector, ratingCalculator,
- walker, milestone, maxTipSearchDepth, belowMaxDepthTxLimit);
+ Walker walker = new WalkerAlpha(tailFinder, tangle, messageQ, new SecureRandom(), config);
+ return new TipSelectorImpl(tangle, ledgerValidator, entryPointSelector, ratingCalculator,
+ walker, milestone, config);
}
}
diff --git a/src/main/java/com/iota/iri/Milestone.java b/src/main/java/com/iota/iri/Milestone.java
index 7bec19f472..3dca933d56 100644
--- a/src/main/java/com/iota/iri/Milestone.java
+++ b/src/main/java/com/iota/iri/Milestone.java
@@ -1,5 +1,19 @@
package com.iota.iri;
+import com.iota.iri.conf.ConsensusConfig;
+import com.iota.iri.controllers.AddressViewModel;
+import com.iota.iri.controllers.MilestoneViewModel;
+import com.iota.iri.controllers.TransactionViewModel;
+import com.iota.iri.hash.ISS;
+import com.iota.iri.hash.SpongeFactory;
+import com.iota.iri.model.Hash;
+import com.iota.iri.storage.Tangle;
+import com.iota.iri.utils.Converter;
+import com.iota.iri.zmq.MessageQ;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HttpsURLConnection;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
@@ -12,19 +26,6 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
-import javax.net.ssl.HttpsURLConnection;
-
-import com.iota.iri.controllers.*;
-import com.iota.iri.hash.SpongeFactory;
-import com.iota.iri.zmq.MessageQ;
-import com.iota.iri.storage.Tangle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.iota.iri.hash.ISS;
-import com.iota.iri.model.Hash;
-import com.iota.iri.utils.Converter;
-
import static com.iota.iri.Milestone.Validity.*;
public class Milestone {
@@ -55,33 +56,30 @@ enum Validity {
private final Set analyzedMilestoneCandidates = new HashSet<>();
- public Milestone(final Tangle tangle,
- final Hash coordinator,
- final Snapshot initialSnapshot,
- final TransactionValidator transactionValidator,
- final boolean testnet,
- final MessageQ messageQ,
- final int numOfKeysInMilestone,
- final int milestoneStartIndex,
- final boolean acceptAnyTestnetCoo
- ) {
+ public Milestone(Tangle tangle,
+ TransactionValidator transactionValidator,
+ MessageQ messageQ,
+ Snapshot initialSnapshot, ConsensusConfig config
+ ) {
this.tangle = tangle;
- this.coordinator = coordinator;
- this.latestSnapshot = initialSnapshot;
this.transactionValidator = transactionValidator;
- this.testnet = testnet;
this.messageQ = messageQ;
- this.numOfKeysInMilestone = numOfKeysInMilestone;
- this.milestoneStartIndex = milestoneStartIndex;
+ this.latestSnapshot = initialSnapshot;
+
+ //configure
+ this.testnet = config.isTestnet();
+ this.coordinator = new Hash(config.getCoordinator());
+ this.numOfKeysInMilestone = config.getNumberOfKeysInMilestone();
+ this.milestoneStartIndex = config.getMilestoneStartIndex();
this.latestMilestoneIndex = milestoneStartIndex;
this.latestSolidSubtangleMilestoneIndex = milestoneStartIndex;
- this.acceptAnyTestnetCoo = acceptAnyTestnetCoo;
+ this.acceptAnyTestnetCoo = config.isDontValidateTestnetMilestoneSig();
}
private boolean shuttingDown;
private static int RESCAN_INTERVAL = 5000;
- public void init(final SpongeFactory.Mode mode, final LedgerValidator ledgerValidator, final boolean revalidate) throws Exception {
+ public void init (SpongeFactory.Mode mode, LedgerValidator ledgerValidator) {
this.ledgerValidator = ledgerValidator;
AtomicBoolean ledgerValidatorInitialized = new AtomicBoolean(false);
(new Thread(() -> {
@@ -179,6 +177,10 @@ public void init(final SpongeFactory.Mode mode, final LedgerValidator ledgerVali
}
+ public int getMilestoneStartIndex() {
+ return milestoneStartIndex;
+ }
+
private Validity validateMilestone(SpongeFactory.Mode mode, TransactionViewModel transactionViewModel, int index) throws Exception {
if (index < 0 || index >= 0x200000) {
return INVALID;
diff --git a/src/main/java/com/iota/iri/Snapshot.java b/src/main/java/com/iota/iri/Snapshot.java
index fd820c033a..0d8bfe1e5d 100644
--- a/src/main/java/com/iota/iri/Snapshot.java
+++ b/src/main/java/com/iota/iri/Snapshot.java
@@ -1,5 +1,6 @@
package com.iota.iri;
+import com.iota.iri.conf.SnapshotConfig;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.model.Hash;
import com.iota.iri.utils.IotaIOUtils;
@@ -26,18 +27,18 @@ public class Snapshot {
public final ReadWriteLock rwlock = new ReentrantReadWriteLock();
- public static Snapshot init(String snapshotPath, String snapshotSigPath, boolean testnet) throws IOException {
+ public static Snapshot init(SnapshotConfig config) throws IOException {
//This is not thread-safe (and it is ok)
if (initialSnapshot == null) {
- if (!testnet && !SignedFiles.isFileSignatureValid(snapshotPath, snapshotSigPath, SNAPSHOT_PUBKEY,
- SNAPSHOT_PUBKEY_DEPTH, SNAPSHOT_INDEX)) {
+ String snapshotFile = config.getSnapshotFile();
+ if (!config.isTestnet() && !SignedFiles.isFileSignatureValid(snapshotFile, config.getSnapshotSignatureFile(),
+ SNAPSHOT_PUBKEY, SNAPSHOT_PUBKEY_DEPTH, SNAPSHOT_INDEX)) {
throw new RuntimeException("Snapshot signature failed.");
}
- Map initialState = initInitialState(snapshotPath);
+ Map initialState = initInitialState(snapshotFile);
initialSnapshot = new Snapshot(initialState, 0);
checkStateHasCorrectSupply(initialState);
checkInitialSnapshotIsConsistent(initialState);
-
}
return initialSnapshot;
}
diff --git a/src/main/java/com/iota/iri/TransactionValidator.java b/src/main/java/com/iota/iri/TransactionValidator.java
index bd135c871a..f6b8313381 100644
--- a/src/main/java/com/iota/iri/TransactionValidator.java
+++ b/src/main/java/com/iota/iri/TransactionValidator.java
@@ -1,15 +1,15 @@
package com.iota.iri;
+import com.iota.iri.conf.SnapshotConfig;
import com.iota.iri.controllers.TipsViewModel;
+import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.hash.Curl;
import com.iota.iri.hash.Sponge;
import com.iota.iri.hash.SpongeFactory;
-import com.iota.iri.network.TransactionRequester;
-import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.model.Hash;
-import com.iota.iri.zmq.MessageQ;
+import com.iota.iri.network.TransactionRequester;
import com.iota.iri.storage.Tangle;
-
+import com.iota.iri.zmq.MessageQ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,25 +43,29 @@ public class TransactionValidator {
private final Set newSolidTransactionsTwo = new LinkedHashSet<>();
public TransactionValidator(Tangle tangle, TipsViewModel tipsViewModel, TransactionRequester transactionRequester,
- MessageQ messageQ, long snapshotTimestamp) {
+ MessageQ messageQ, SnapshotConfig config) {
this.tangle = tangle;
this.tipsViewModel = tipsViewModel;
this.transactionRequester = transactionRequester;
this.messageQ = messageQ;
- TransactionValidator.snapshotTimestamp = snapshotTimestamp;
+ TransactionValidator.snapshotTimestamp = config.getSnapshotTime();
TransactionValidator.snapshotTimestampMs = snapshotTimestamp * 1000;
}
public void init(boolean testnet, int mwm) {
+ setMwm(testnet, mwm);
+
+ newSolidThread = new Thread(spawnSolidTransactionsPropagation(), "Solid TX cascader");
+ newSolidThread.start();
+ }
+
+ void setMwm(boolean testnet, int mwm) {
MIN_WEIGHT_MAGNITUDE = mwm;
//lowest allowed MWM encoded in 46 bytes.
- if (!testnet && MIN_WEIGHT_MAGNITUDE<13){
- MIN_WEIGHT_MAGNITUDE = 13;
+ if (!testnet){
+ MIN_WEIGHT_MAGNITUDE = Math.max(MIN_WEIGHT_MAGNITUDE, 13);
}
-
- newSolidThread = new Thread(spawnSolidTransactionsPropagation(), "Solid TX cascader");
- newSolidThread.start();
}
public void shutdown() throws InterruptedException {
@@ -73,7 +77,7 @@ public int getMinWeightMagnitude() {
return MIN_WEIGHT_MAGNITUDE;
}
- private static boolean hasInvalidTimestamp(TransactionViewModel transactionViewModel) {
+ private boolean hasInvalidTimestamp(TransactionViewModel transactionViewModel) {
if (transactionViewModel.getAttachmentTimestamp() == 0) {
return transactionViewModel.getTimestamp() < snapshotTimestamp && !Objects.equals(transactionViewModel.getHash(), Hash.NULL_HASH)
|| transactionViewModel.getTimestamp() > (System.currentTimeMillis() / 1000) + MAX_TIMESTAMP_FUTURE;
@@ -82,7 +86,7 @@ private static boolean hasInvalidTimestamp(TransactionViewModel transactionViewM
|| transactionViewModel.getAttachmentTimestamp() > System.currentTimeMillis() + MAX_TIMESTAMP_FUTURE_MS;
}
- public static void runValidation(TransactionViewModel transactionViewModel, final int minWeightMagnitude) {
+ public void runValidation(TransactionViewModel transactionViewModel, final int minWeightMagnitude) {
transactionViewModel.setMetadata();
transactionViewModel.setAttachmentData();
if(hasInvalidTimestamp(transactionViewModel)) {
@@ -104,17 +108,17 @@ public static void runValidation(TransactionViewModel transactionViewModel, fina
}
}
- public static TransactionViewModel validateTrits(final byte[] trits, int minWeightMagnitude) {
+ public TransactionViewModel validateTrits(final byte[] trits, int minWeightMagnitude) {
TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(trits, 0, trits.length, SpongeFactory.create(SpongeFactory.Mode.CURLP81)));
runValidation(transactionViewModel, minWeightMagnitude);
return transactionViewModel;
}
- public static TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagnitude) {
+ public TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagnitude) {
return validateBytes(bytes, minWeightMagnitude, SpongeFactory.create(SpongeFactory.Mode.CURLP81));
}
- public static TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagnitude, Sponge curl) {
+ public TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagnitude, Sponge curl) {
TransactionViewModel transactionViewModel = new TransactionViewModel(bytes, Hash.calculate(bytes, TransactionViewModel.TRINARY_SIZE, curl));
runValidation(transactionViewModel, minWeightMagnitude);
return transactionViewModel;
@@ -167,44 +171,7 @@ public void addSolidTransaction(Hash hash) {
private Runnable spawnSolidTransactionsPropagation() {
return () -> {
while(!shuttingDown.get()) {
- Set newSolidHashes = new HashSet<>();
- useFirst.set(!useFirst.get());
- synchronized (cascadeSync) {
- if (useFirst.get()) {
- newSolidHashes.addAll(newSolidTransactionsTwo);
- } else {
- newSolidHashes.addAll(newSolidTransactionsOne);
- }
- }
- Iterator cascadeIterator = newSolidHashes.iterator();
- Set hashesToCascade = new HashSet<>();
- while(cascadeIterator.hasNext() && !shuttingDown.get()) {
- try {
- Hash hash = cascadeIterator.next();
- TransactionViewModel transaction = TransactionViewModel.fromHash(tangle, hash);
- Set approvers = transaction.getApprovers(tangle).getHashes();
- for(Hash h: approvers) {
- TransactionViewModel tx = TransactionViewModel.fromHash(tangle, h);
- if(quietQuickSetSolid(tx)) {
- tx.update(tangle, "solid");
- } else {
- if (transaction.isSolid()) {
- addSolidTransaction(hash);
- }
- }
- }
- } catch (Exception e) {
- log.error("Some error", e);
- // TODO: Do something, maybe, or do nothing.
- }
- }
- synchronized (cascadeSync) {
- if (useFirst.get()) {
- newSolidTransactionsTwo.clear();
- } else {
- newSolidTransactionsOne.clear();
- }
- }
+ propagateSolidTransactions();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
@@ -214,6 +181,39 @@ private Runnable spawnSolidTransactionsPropagation() {
};
}
+ void propagateSolidTransactions() {
+ Set newSolidHashes = new HashSet<>();
+ useFirst.set(!useFirst.get());
+ //synchronized to make sure no one is changing the newSolidTransactions collections during addAll
+ synchronized (cascadeSync) {
+ if (useFirst.get()) {
+ newSolidHashes.addAll(newSolidTransactionsTwo);
+ newSolidTransactionsTwo.clear();
+ } else {
+ newSolidHashes.addAll(newSolidTransactionsOne);
+ newSolidTransactionsOne.clear();
+ }
+ }
+ Iterator cascadeIterator = newSolidHashes.iterator();
+ while(cascadeIterator.hasNext() && !shuttingDown.get()) {
+ try {
+ Hash hash = cascadeIterator.next();
+ TransactionViewModel transaction = TransactionViewModel.fromHash(tangle, hash);
+ Set approvers = transaction.getApprovers(tangle).getHashes();
+ for(Hash h: approvers) {
+ TransactionViewModel tx = TransactionViewModel.fromHash(tangle, h);
+ if(quietQuickSetSolid(tx)) {
+ tx.update(tangle, "solid|height");
+ tipsViewModel.setSolid(h);
+ addSolidTransaction(h);
+ }
+ }
+ } catch (Exception e) {
+ log.error("Error while propagating solidity upwards", e);
+ }
+ }
+ }
+
public void updateStatus(TransactionViewModel transactionViewModel) throws Exception {
transactionRequester.clearTransactionRequest(transactionViewModel.getHash());
if(transactionViewModel.getApprovers(tangle).size() == 0) {
@@ -223,6 +223,8 @@ public void updateStatus(TransactionViewModel transactionViewModel) throws Excep
tipsViewModel.removeTipHash(transactionViewModel.getBranchTransactionHash());
if(quickSetSolid(transactionViewModel)) {
+ transactionViewModel.update(tangle, "solid|height");
+ tipsViewModel.setSolid(transactionViewModel.getHash());
addSolidTransaction(transactionViewModel.getHash());
}
}
@@ -266,6 +268,11 @@ private boolean checkApproovee(TransactionViewModel approovee) throws Exception
return approovee.isSolid();
}
+ //for testing
+ boolean isNewSolidTxSetsEmpty () {
+ return newSolidTransactionsOne.isEmpty() && newSolidTransactionsTwo.isEmpty();
+ }
+
public static class StaleTimestampException extends RuntimeException {
public StaleTimestampException (String message) {
super(message);
diff --git a/src/main/java/com/iota/iri/conf/APIConfig.java b/src/main/java/com/iota/iri/conf/APIConfig.java
new file mode 100644
index 0000000000..58fc960b6e
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/APIConfig.java
@@ -0,0 +1,63 @@
+package com.iota.iri.conf;
+
+import java.util.List;
+
+/**
+ * Configurations for node API
+ */
+public interface APIConfig extends Config {
+
+
+ /**
+ * @return {@value Descriptions#PORT}
+ */
+ int getPort();
+
+ /**
+ * @return {@value Descriptions#API_HOST}
+ */
+ String getApiHost();
+
+
+ /**
+ * @return {@value Descriptions#REMOTE_LIMIT_API}
+ */
+ List getRemoteLimitApi();
+
+ /**
+ * @return {@value Descriptions#MAX_FIND_TRANSACTIONS}
+ */
+ int getMaxFindTransactions();
+
+ /**
+ * @return {@value Descriptions#MAX_REQUESTS_LIST}
+ */
+ int getMaxRequestsList();
+
+ /**
+ * @return {@value Descriptions#MAX_GET_TRYTES}
+ */
+ int getMaxGetTrytes();
+
+ /**
+ * @return {@value Descriptions#MAX_BODY_LENGTH}
+ */
+ int getMaxBodyLength();
+
+ /**
+ * @return {@value Descriptions#REMOTE_AUTH}
+ */
+ String getRemoteAuth();
+
+ interface Descriptions {
+ String PORT = "The port that will be used by the API.";
+ String API_HOST = "The host on which the API will listen to. Set to 0.0.0.0 to accept any host.";
+ String REMOTE_LIMIT_API = "Commands that should be ignored by API.";
+ String REMOTE_AUTH = "A string in the form of :. Used to access the API";
+ String MAX_FIND_TRANSACTIONS = "The maximal number of transactions that may be returned by the \"findTransactions\" API call. If the number of transactions found exceeds this number an error will be returned.";
+ String MAX_REQUESTS_LIST = "The maximal number of parameters one can place in an API call. If the number parameters exceeds this number an error will be returned";
+ String MAX_GET_TRYTES = "The maximal number of trytes that may be returned by the \"getTrytes\" API call. If the number of transactions found exceeds this number an error will be returned.";
+ String MAX_BODY_LENGTH = "The maximal number of characters the body of an API call may hold. If a request body length exceeds this number an error will be returned.";
+ String REMOTE = "Open the API interface to any host. Equivalent to \"--api-host 0.0.0.0\"";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/BaseIotaConfig.java b/src/main/java/com/iota/iri/conf/BaseIotaConfig.java
new file mode 100644
index 0000000000..d37d1670fc
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/BaseIotaConfig.java
@@ -0,0 +1,676 @@
+package com.iota.iri.conf;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.ParameterException;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.iota.iri.IRI;
+import com.iota.iri.utils.IotaUtils;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ Note: the fields in this class are being deserialized from Jackson so they must follow Java Bean convention.
+ Meaning that every field must have a getter that is prefixed with `get` unless it is a boolean and then it should be
+ prefixed with `is`.
+ */
+public abstract class BaseIotaConfig implements IotaConfig {
+
+ protected static final String SPLIT_STRING_TO_LIST_REGEX = ",| ";
+
+ private boolean help;
+
+ //API
+ protected int port = Defaults.API_PORT;
+ protected String apiHost = Defaults.API_HOST;
+ protected List remoteLimitApi = new ArrayList<>();
+ protected int maxFindTransactions = Defaults.MAX_FIND_TRANSACTIONS;
+ protected int maxRequestsList = Defaults.MAX_REQUESTS_LIST;
+ protected int maxGetTrytes = Defaults.MAX_GET_TRYTES;
+ protected int maxBodyLength = Defaults.MAX_BODY_LENGTH;
+ protected String remoteAuth = Defaults.REMOTE_AUTH;
+ //We don't have a REMOTE config but we have a remote flag. We must add a field for JCommander
+ private boolean remote;
+
+
+ //Network
+ protected int udpReceiverPort = Defaults.UDP_RECEIVER_PORT;
+ protected int tcpReceiverPort = Defaults.TCP_RECEIVER_PORT;
+ protected double pRemoveRequest = Defaults.P_REMOVE_REQUEST;
+ protected double pDropCacheEntry = Defaults.P_DROP_CACHE_ENTRY;
+ protected int sendLimit = Defaults.SEND_LIMIT;
+ protected int maxPeers = Defaults.MAX_PEERS;
+ protected boolean dnsRefresherEnabled = Defaults.DNS_REFRESHER_ENABLED;
+ protected boolean dnsResolutionEnabled = Defaults.DNS_RESOLUTION_ENABLED;
+ protected List neighbors = new ArrayList<>();
+
+ //IXI
+ protected String ixiDir = Defaults.IXI_DIR;
+
+ //DB
+ protected String dbPath = Defaults.DB_PATH;
+ protected String dbLogPath = Defaults.DB_LOG_PATH;
+ protected int dbCacheSize = Defaults.DB_CACHE_SIZE; //KB
+ protected String mainDb = Defaults.ROCKS_DB;
+ protected boolean export = Defaults.EXPORT;
+ protected boolean revalidate = Defaults.REVALIDATE;
+ protected boolean rescanDb = Defaults.RESCAN_DB;
+
+ //Protocol
+ protected double pReplyRandomTip = Defaults.P_REPLY_RANDOM_TIP;
+ protected double pDropTransaction = Defaults.P_DROP_TRANSACTION;
+ protected double pSelectMilestoneChild = Defaults.P_SELECT_MILESTONE_CHILD;
+ protected double pSendMilestone = Defaults.P_SEND_MILESTONE;
+ protected double pPropagateRequest = Defaults.P_PROPAGATE_REQUEST;
+
+ //ZMQ
+ protected boolean zmqEnabled = Defaults.ZMQ_ENABLED;
+ protected int zmqPort = Defaults.ZMQ_PORT;
+ protected int zmqThreads = Defaults.ZMQ_THREADS;
+ protected String zmqIpc = Defaults.ZMQ_IPC;
+ protected int qSizeNode = Defaults.QUEUE_SIZE;
+ protected int cacheSizeBytes = Defaults.CACHE_SIZE_BYTES;
+
+
+ //Tip Selection
+ protected int maxDepth = Defaults.MAX_DEPTH;
+ protected double alpha = Defaults.ALPHA;
+ private int maxAnalyzedTransactions = Defaults.MAX_ANALYZED_TXS;
+
+ public BaseIotaConfig() {
+ //empty constructor
+ }
+
+ @Override
+ public JCommander parseConfigFromArgs(String[] args) throws ParameterException {
+ //One can invoke help via INI file (feature/bug) so we always create JCommander even if args is empty
+ JCommander jCommander = JCommander.newBuilder()
+ .addObject(this)
+ //This is in order to enable the `--conf` and `--testnet` option
+ .acceptUnknownOptions(true)
+ .allowParameterOverwriting(true)
+ //This is the first line of JCommander Usage
+ .programName("java -jar iri-" + IRI.VERSION + ".jar")
+ .build();
+ if (ArrayUtils.isNotEmpty(args)) {
+ jCommander.parse(args);
+ }
+ return jCommander;
+ }
+
+ @Override
+ public boolean isHelp() {
+ return help;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--help", "-h"} , help = true, hidden = true)
+ public void setHelp(boolean help) {
+ this.help = help;
+ }
+
+ @Override
+ public int getPort() {
+ return port;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--port", "-p"}, description = APIConfig.Descriptions.PORT)
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ @Override
+ public String getApiHost() {
+ return apiHost;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--api-host"}, description = APIConfig.Descriptions.API_HOST)
+ protected void setApiHost(String apiHost) {
+ this.apiHost = apiHost;
+ }
+
+ @JsonIgnore
+ @Parameter(names = {"--remote"}, description = APIConfig.Descriptions.REMOTE)
+ protected void setRemote(boolean remote) {
+ this.apiHost = "0.0.0.0";
+ }
+
+ @Override
+ public List getRemoteLimitApi() {
+ return remoteLimitApi;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--remote-limit-api"}, description = APIConfig.Descriptions.REMOTE_LIMIT_API)
+ protected void setRemoteLimitApi(String remoteLimitApi) {
+ this.remoteLimitApi = IotaUtils.splitStringToImmutableList(remoteLimitApi, SPLIT_STRING_TO_LIST_REGEX);
+ }
+
+ @Override
+ public int getMaxFindTransactions() {
+ return maxFindTransactions;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--max-find-transactions"}, description = APIConfig.Descriptions.MAX_FIND_TRANSACTIONS)
+ protected void setMaxFindTransactions(int maxFindTransactions) {
+ this.maxFindTransactions = maxFindTransactions;
+ }
+
+ @Override
+ public int getMaxRequestsList() {
+ return maxRequestsList;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--max-requests-list"}, description = APIConfig.Descriptions.MAX_REQUESTS_LIST)
+ protected void setMaxRequestsList(int maxRequestsList) {
+ this.maxRequestsList = maxRequestsList;
+ }
+
+ @Override
+ public int getMaxGetTrytes() {
+ return maxGetTrytes;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--max-get-trytes"}, description = APIConfig.Descriptions.MAX_GET_TRYTES)
+ protected void setMaxGetTrytes(int maxGetTrytes) {
+ this.maxGetTrytes = maxGetTrytes;
+ }
+
+ @Override
+ public int getMaxBodyLength() {
+ return maxBodyLength;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--max-body-length"}, description = APIConfig.Descriptions.MAX_BODY_LENGTH)
+ protected void setMaxBodyLength(int maxBodyLength) {
+ this.maxBodyLength = maxBodyLength;
+ }
+
+ @Override
+ public String getRemoteAuth() {
+ return remoteAuth;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--remote-auth"}, description = APIConfig.Descriptions.REMOTE_AUTH)
+ protected void setRemoteAuth(String remoteAuth) {
+ this.remoteAuth = remoteAuth;
+ }
+
+ @Override
+ public int getUdpReceiverPort() {
+ return udpReceiverPort;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"-u", "--udp-receiver-port"}, description = NetworkConfig.Descriptions.UDP_RECEIVER_PORT)
+ public void setUdpReceiverPort(int udpReceiverPort) {
+ this.udpReceiverPort = udpReceiverPort;
+ }
+
+ @Override
+ public int getTcpReceiverPort() {
+ return tcpReceiverPort;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"-t", "--tcp-receiver-port"}, description = NetworkConfig.Descriptions.TCP_RECEIVER_PORT)
+ protected void setTcpReceiverPort(int tcpReceiverPort) {
+ this.tcpReceiverPort = tcpReceiverPort;
+ }
+
+ @Override
+ public double getpRemoveRequest() {
+ return pRemoveRequest;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--p-remove-request"}, description = NetworkConfig.Descriptions.P_REMOVE_REQUEST)
+ protected void setpRemoveRequest(double pRemoveRequest) {
+ this.pRemoveRequest = pRemoveRequest;
+ }
+
+ @Override
+ public int getSendLimit() {
+ return sendLimit;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--send-limit"}, description = NetworkConfig.Descriptions.SEND_LIMIT)
+ protected void setSendLimit(int sendLimit) {
+ this.sendLimit = sendLimit;
+ }
+
+ @Override
+ public int getMaxPeers() {
+ return maxPeers;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--max-peers"}, description = NetworkConfig.Descriptions.MAX_PEERS)
+ protected void setMaxPeers(int maxPeers) {
+ this.maxPeers = maxPeers;
+ }
+
+ @Override
+ public boolean isDnsRefresherEnabled() {
+ return dnsRefresherEnabled;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--dns-refresher"}, description = NetworkConfig.Descriptions.DNS_REFRESHER_ENABLED, arity = 1)
+ protected void setDnsRefresherEnabled(boolean dnsRefresherEnabled) {
+ this.dnsRefresherEnabled = dnsRefresherEnabled;
+ }
+
+ @Override
+ public boolean isDnsResolutionEnabled() {
+ return dnsResolutionEnabled;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--dns-resolution"}, description = NetworkConfig.Descriptions.DNS_RESOLUTION_ENABLED, arity = 1)
+ protected void setDnsResolutionEnabled(boolean dnsResolutionEnabled) {
+ this.dnsResolutionEnabled = dnsResolutionEnabled;
+ }
+
+ @Override
+ public List getNeighbors() {
+ return neighbors;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"-n", "--neighbors"}, description = NetworkConfig.Descriptions.NEIGHBORS)
+ protected void setNeighbors(String neighbors) {
+ this.neighbors = IotaUtils.splitStringToImmutableList(neighbors, SPLIT_STRING_TO_LIST_REGEX);
+ }
+
+ @Override
+ public String getIxiDir() {
+ return ixiDir;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--ixi-dir"}, description = IXIConfig.Descriptions.IXI_DIR)
+ protected void setIxiDir(String ixiDir) {
+ this.ixiDir = ixiDir;
+ }
+
+ @Override
+ public String getDbPath() {
+ return dbPath;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--db-path"}, description = DbConfig.Descriptions.DB_PATH)
+ protected void setDbPath(String dbPath) {
+ this.dbPath = dbPath;
+ }
+
+ @Override
+ public String getDbLogPath() {
+ return dbLogPath;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--db-log-path"}, description = DbConfig.Descriptions.DB_LOG_PATH)
+ protected void setDbLogPath(String dbLogPath) {
+ this.dbLogPath = dbLogPath;
+ }
+
+ @Override
+ public int getDbCacheSize() {
+ return dbCacheSize;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--db-cache-size"}, description = DbConfig.Descriptions.DB_CACHE_SIZE)
+ protected void setDbCacheSize(int dbCacheSize) {
+ this.dbCacheSize = dbCacheSize;
+ }
+
+ @Override
+ public String getMainDb() {
+ return mainDb;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--db"}, description = DbConfig.Descriptions.MAIN_DB)
+ protected void setMainDb(String mainDb) {
+ this.mainDb = mainDb;
+ }
+
+ @Override
+ public boolean isExport() {
+ return export;
+ }
+
+
+ @JsonProperty
+ @Parameter(names = {"--export"}, description = DbConfig.Descriptions.EXPORT)
+ protected void setExport(boolean export) {
+ this.export = export;
+ }
+
+ @Override
+ public boolean isRevalidate() {
+ return revalidate;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--revalidate"}, description = DbConfig.Descriptions.REVALIDATE)
+ protected void setRevalidate(boolean revalidate) {
+ this.revalidate = revalidate;
+ }
+
+ @Override
+ public boolean isRescanDb() {
+ return rescanDb;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--rescan"}, description = DbConfig.Descriptions.RESCAN_DB)
+ protected void setRescanDb(boolean rescanDb) {
+ this.rescanDb = rescanDb;
+ }
+
+ @Override
+ public int getMwm() {
+ return Defaults.MWM;
+ }
+
+ @Override
+ public int getTransactionPacketSize() {
+ return Defaults.PACKET_SIZE;
+ }
+
+ @Override
+ public int getRequestHashSize() {
+ return Defaults.REQ_HASH_SIZE;
+ }
+
+ @Override
+ public double getpReplyRandomTip() {
+ return pReplyRandomTip;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--p-reply-random"}, description = ProtocolConfig.Descriptions.P_REPLY_RANDOM_TIP)
+ protected void setpReplyRandomTip(double pReplyRandomTip) {
+ this.pReplyRandomTip = pReplyRandomTip;
+ }
+
+ @Override
+ public double getpDropTransaction() {
+ return pDropTransaction;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--p-drop-transaction"}, description = ProtocolConfig.Descriptions.P_DROP_TRANSACTION)
+ protected void setpDropTransaction(double pDropTransaction) {
+ this.pDropTransaction = pDropTransaction;
+ }
+
+ @Override
+ public double getpSelectMilestoneChild() {
+ return pSelectMilestoneChild;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--p-select-milestone"}, description = ProtocolConfig.Descriptions.P_SELECT_MILESTONE)
+ protected void setpSelectMilestoneChild(double pSelectMilestoneChild) {
+ this.pSelectMilestoneChild = pSelectMilestoneChild;
+ }
+
+ @Override
+ public double getpSendMilestone() {
+ return pSendMilestone;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--p-send-milestone"}, description = ProtocolConfig.Descriptions.P_SEND_MILESTONE)
+ protected void setpSendMilestone(double pSendMilestone) {
+ this.pSendMilestone = pSendMilestone;
+ }
+
+ @Override
+ public double getpPropagateRequest() {
+ return pPropagateRequest;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--p-propagate-request"}, description = ProtocolConfig.Descriptions.P_PROPAGATE_REQUEST)
+ protected void setpPropagateRequest(double pPropagateRequest) {
+ this.pPropagateRequest = pPropagateRequest;
+ }
+
+ @Override
+ public long getSnapshotTime() {
+ return Defaults.GLOBAL_SNAPSHOT_TIME;
+ }
+
+ @Override
+ public String getSnapshotFile() {
+ return Defaults.SNAPSHOT_FILE;
+ }
+
+ @Override
+ public String getSnapshotSignatureFile() {
+ return Defaults.SNAPSHOT_SIG_FILE;
+ }
+
+ @Override
+ public String getPreviousEpochSpentAddressesFiles() {
+ return Defaults.PREVIOUS_EPOCHS_SPENT_ADDRESSES_TXT;
+ }
+
+ @Override
+ public int getMilestoneStartIndex() {
+ return Defaults.MILESTONE_START_INDEX;
+ }
+
+ @Override
+ public int getNumberOfKeysInMilestone() {
+ return Defaults.NUM_KEYS_IN_MILESTONE;
+ }
+
+ @Override
+ public boolean isZmqEnabled() {
+ return zmqEnabled;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--zmq-enabled", description = ZMQConfig.Descriptions.ZMQ_ENABLED)
+ protected void setZmqEnabled(boolean zmqEnabled) {
+ this.zmqEnabled = zmqEnabled;
+ }
+
+ @Override
+ public int getZmqPort() {
+ return zmqPort;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--zmq-port", description = ZMQConfig.Descriptions.ZMQ_PORT)
+ protected void setZmqPort(int zmqPort) {
+ this.zmqPort = zmqPort;
+ }
+
+ @Override
+ public int getZmqThreads() {
+ return zmqThreads;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--zmq-threads", description = ZMQConfig.Descriptions.ZMQ_PORT)
+ protected void setZmqThreads(int zmqThreads) {
+ this.zmqThreads = zmqThreads;
+ }
+
+ @Override
+ public String getZmqIpc() {
+ return zmqIpc;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--zmq-ipc", description = ZMQConfig.Descriptions.ZMQ_IPC)
+ protected void setZmqIpc(String zmqIpc) {
+ this.zmqIpc = zmqIpc;
+ }
+
+ @Override
+ public int getqSizeNode() {
+ return qSizeNode;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--queue-size", description = NetworkConfig.Descriptions.Q_SIZE_NODE)
+ protected void setqSizeNode(int qSizeNode) {
+ this.qSizeNode = qSizeNode;
+ }
+
+ @Override
+ public double getpDropCacheEntry() {
+ return pDropCacheEntry;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--p-drop-cache", description = NetworkConfig.Descriptions.P_DROP_CACHE_ENTRY)
+ protected void setpDropCacheEntry(double pDropCacheEntry) {
+ this.pDropCacheEntry = pDropCacheEntry;
+ }
+
+ @Override
+ public int getCacheSizeBytes() {
+ return cacheSizeBytes;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--cache-size", description = NetworkConfig.Descriptions.CACHE_SIZE_BYTES)
+ protected void setCacheSizeBytes(int cacheSizeBytes) {
+ this.cacheSizeBytes = cacheSizeBytes;
+ }
+
+ @Override
+ public String getCoordinator() {
+ return Defaults.COORDINATOR_ADDRESS;
+ }
+
+ @Override
+ public boolean isDontValidateTestnetMilestoneSig() {
+ return false;
+ }
+
+ @Override
+ public int getMaxDepth() {
+ return maxDepth;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--max-depth", description = TipSelConfig.Descriptions.MAX_DEPTH)
+ protected void setMaxDepth(int maxDepth) {
+ this.maxDepth = maxDepth;
+ }
+
+ @Override
+ public double getAlpha() {
+ return alpha;
+ }
+
+ @JsonProperty("TIPSELECTION_ALPHA")
+ @Parameter(names = "--alpha", description = TipSelConfig.Descriptions.ALPHA)
+ protected void setAlpha(double alpha) {
+ this.alpha = alpha;
+ }
+
+ @Override
+ public int getBelowMaxDepthTransactionLimit() {
+ return maxAnalyzedTransactions;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--max-analyzed-transactions", description = TipSelConfig.Descriptions.BELOW_MAX_DEPTH_TRANSACTION_LIMIT)
+ protected void setBelowMaxDepthTransactionLimit(int maxAnalyzedTransactions) {
+ this.maxAnalyzedTransactions = maxAnalyzedTransactions;
+ }
+
+ public interface Defaults {
+ //API
+ int API_PORT = 14265;
+ String API_HOST = "localhost";
+ int MAX_FIND_TRANSACTIONS = 100_000;
+ int MAX_REQUESTS_LIST = 1_000;
+ int MAX_GET_TRYTES = 10_000;
+ int MAX_BODY_LENGTH = 1_000_000;
+ String REMOTE_AUTH = "";
+
+ //Network
+ int UDP_RECEIVER_PORT = 14600;
+ int TCP_RECEIVER_PORT = 15600;
+ double P_REMOVE_REQUEST = 0.01d;
+ int SEND_LIMIT = -1;
+ int MAX_PEERS = 0;
+ boolean DNS_REFRESHER_ENABLED = true;
+ boolean DNS_RESOLUTION_ENABLED = true;
+
+ //ixi
+ String IXI_DIR = "ixi";
+
+ //DB
+ String DB_PATH = "mainnetdb";
+ String DB_LOG_PATH = "mainnet.log";
+ int DB_CACHE_SIZE = 100_000;
+ String ROCKS_DB = "rocksdb";
+ boolean EXPORT = false;
+ boolean REVALIDATE = false;
+ boolean RESCAN_DB = false;
+
+ //Protocol
+ double P_REPLY_RANDOM_TIP = 0.66d;
+ double P_DROP_TRANSACTION = 0d;
+ double P_SELECT_MILESTONE_CHILD = 0.7d;
+ double P_SEND_MILESTONE = 0.02d;
+ double P_PROPAGATE_REQUEST = 0.01d;
+ int MWM = 14;
+ int PACKET_SIZE = 1650;
+ int REQ_HASH_SIZE = 46;
+ int QUEUE_SIZE = 1_000;
+ double P_DROP_CACHE_ENTRY = 0.02d;
+ int CACHE_SIZE_BYTES = 150_000;
+
+
+
+ //Zmq
+ int ZMQ_THREADS = 1;
+ String ZMQ_IPC = "ipc://iri";
+ boolean ZMQ_ENABLED = false;
+ int ZMQ_PORT = 5556;
+
+ //TipSel
+ int MAX_DEPTH = 15;
+ double ALPHA = 0.001d;
+
+ //Coo
+ String COORDINATOR_ADDRESS =
+ "KPWCHICGJZXKE9GSUDXZYUAPLHAKAHYHDXNPHENTERYMMBQOPSQIDENXKLKCEYCPVTZQLEEJVYJZV9BWU";
+
+ //Snapshot
+ String SNAPSHOT_FILE = "/snapshotMainnet.txt";
+ String SNAPSHOT_SIG_FILE = "/snapshotMainnet.sig";
+ String PREVIOUS_EPOCHS_SPENT_ADDRESSES_TXT =
+ "/previousEpochsSpentAddresses1.txt /previousEpochsSpentAddresses2.txt";
+ long GLOBAL_SNAPSHOT_TIME = 1537203600;
+ int MILESTONE_START_INDEX = 774_805;
+ int NUM_KEYS_IN_MILESTONE = 20;
+ int MAX_ANALYZED_TXS = 20_000;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/iota/iri/conf/Config.java b/src/main/java/com/iota/iri/conf/Config.java
new file mode 100644
index 0000000000..0a1dbd90d9
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/Config.java
@@ -0,0 +1,24 @@
+package com.iota.iri.conf;
+
+/**
+ * General configuration parameters that every module in IRI needs.
+ */
+public interface Config {
+
+ String TESTNET_FLAG = "--testnet";
+
+ /**
+ * @return {@value Descriptions#TESTNET}
+ */
+ boolean isTestnet();
+
+ interface Descriptions {
+
+ String TESTNET = "Start in testnet mode.";
+ }
+
+ class DescriptionHelper {
+
+ protected static final String PROB_OF = "A number between 0 and 1 that represents the probability of ";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/ConfigFactory.java b/src/main/java/com/iota/iri/conf/ConfigFactory.java
new file mode 100644
index 0000000000..ecde4098d2
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/ConfigFactory.java
@@ -0,0 +1,58 @@
+package com.iota.iri.conf;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.iota.iri.conf.deserializers.CustomBoolDeserializer;
+import com.iota.iri.conf.deserializers.CustomStringDeserializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+public class ConfigFactory {
+
+ public static IotaConfig createIotaConfig(boolean isTestnet) {
+ IotaConfig iotaConfig;
+ if (isTestnet) {
+ iotaConfig = new TestnetConfig();
+ }
+ else {
+ iotaConfig = new MainnetConfig();
+ }
+ return iotaConfig;
+ }
+
+ public static IotaConfig createFromFile(File configFile, boolean testnet) throws IOException,
+ IllegalArgumentException {
+ IotaConfig iotaConfig;
+
+ try (FileInputStream confStream = new FileInputStream(configFile)) {
+ Properties props = new Properties();
+ props.load(confStream);
+ boolean isTestnet = testnet || Boolean.parseBoolean(props.getProperty("TESTNET", "false"));
+ Class extends IotaConfig> iotaConfigClass = isTestnet ? TestnetConfig.class : MainnetConfig.class;
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
+ objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
+ objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
+
+ SimpleModule booleanParser = new SimpleModule("BooleanParser");
+ booleanParser.addDeserializer(Boolean.TYPE, new CustomBoolDeserializer());
+ objectMapper.registerModule(booleanParser);
+
+ SimpleModule stringParser = new SimpleModule("StringParser");
+ stringParser.addDeserializer(String.class, new CustomStringDeserializer());
+ objectMapper.registerModule(stringParser);
+
+ iotaConfig = objectMapper.convertValue(props, iotaConfigClass);
+ }
+ return iotaConfig;
+ }
+
+}
diff --git a/src/main/java/com/iota/iri/conf/Configuration.java b/src/main/java/com/iota/iri/conf/Configuration.java
deleted file mode 100644
index 89ea0c2588..0000000000
--- a/src/main/java/com/iota/iri/conf/Configuration.java
+++ /dev/null
@@ -1,252 +0,0 @@
-package com.iota.iri.conf;
-
-import org.ini4j.Ini;
-import org.ini4j.IniPreferences;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.prefs.Preferences;
-
-/**
- * All those settings are modificable at runtime,
- * but for most of them the node needs to be restarted.
- */
-public class Configuration {
- private Ini ini;
- private Preferences prefs;
-
-
- private final Logger log = LoggerFactory.getLogger(Configuration.class);
-
- private final Map conf = new ConcurrentHashMap<>();
-
- public static final String MAINNET_COORDINATOR_ADDRESS =
- "KPWCHICGJZXKE9GSUDXZYUAPLHAKAHYHDXNPHENTERYMMBQOPSQIDENXKLKCEYCPVTZQLEEJVYJZV9BWU";
- public static final String TESTNET_COORDINATOR_ADDRESS =
- "EQQFCZBIHRHWPXKMTOLMYUYPCN9XLMJPYZVFJSAY9FQHCCLWTOLLUGKKMXYFDBOOYFBLBI9WUEILGECYM";
- public static final String MAINNET_SNAPSHOT_FILE = "/snapshotMainnet.txt";
- public static final String TESTNET_SNAPSHOT_FILE = "/snapshotTestnet.txt";
- public static final String MAINNET_SNAPSHOT_SIG_FILE = "/snapshotMainnet.sig";
-
- public static final String PREVIOUS_EPOCHS_SPENT_ADDRESSES_TXT =
- "/previousEpochsSpentAddresses1.txt /previousEpochsSpentAddresses2.txt";
- public static final String MAINNET_MILESTONE_START_INDEX = "774805";
- public static final String TESTNET_MILESTONE_START_INDEX = "434525";
- public static final String MAINNET_NUM_KEYS_IN_MILESTONE = "20";
- public static final String TESTNET_NUM_KEYS_IN_MILESTONE = "22";
- public static final String GLOBAL_SNAPSHOT_TIME = "1537203600";
- public static final String TESTNET_GLOBAL_SNAPSHOT_TIME = "1522306500";
-
-
- public static final String MAINNET_MWM = "14";
- public static final String TESTNET_MWM = "9";
- public static final String PACKET_SIZE = "1650";
- public static final String TESTNET_PACKET_SIZE = "1653";
- public static final String REQ_HASH_SIZE = "46";
- public static final String TESTNET_REQ_HASH_SIZE = "49";
- public static final String BELOW_MAX_DEPTH_LIMIT = "20000";
-
-
-
- public enum DefaultConfSettings {
- CONFIG,
- PORT,
- API_HOST,
- UDP_RECEIVER_PORT,
- TCP_RECEIVER_PORT,
- TESTNET,
- DEBUG,
- REMOTE_LIMIT_API,
- REMOTE_AUTH,
- NEIGHBORS,
- IXI_DIR,
- DB_PATH,
- DB_LOG_PATH,
- DB_CACHE_SIZE,
- P_REMOVE_REQUEST,
- P_DROP_TRANSACTION,
- P_SELECT_MILESTONE_CHILD,
- P_SEND_MILESTONE,
- P_REPLY_RANDOM_TIP,
- P_PROPAGATE_REQUEST,
- MAIN_DB, EXPORT, // exports transaction trytes to filesystem
- SEND_LIMIT,
- MAX_PEERS,
- DNS_RESOLUTION_ENABLED,
- DNS_REFRESHER_ENABLED,
- COORDINATOR,
- DONT_VALIDATE_TESTNET_MILESTONE_SIG,
- REVALIDATE,
- RESCAN_DB,
- MIN_RANDOM_WALKS,
- MAX_RANDOM_WALKS,
- MAX_FIND_TRANSACTIONS,
- MAX_REQUESTS_LIST,
- MAX_GET_TRYTES,
- MAX_BODY_LENGTH,
- MAX_DEPTH,
- MWM,
- ZMQ_ENABLED,
- ZMQ_PORT,
- ZMQ_IPC,
- ZMQ_THREADS,
- Q_SIZE_NODE,
- P_DROP_CACHE_ENTRY,
- CACHE_SIZE_BYTES,
- SNAPSHOT_FILE,
- SNAPSHOT_SIGNATURE_FILE,
- MILESTONE_START_INDEX,
- NUMBER_OF_KEYS_IN_A_MILESTONE,
- TRANSACTION_PACKET_SIZE,
- REQUEST_HASH_SIZE,
- SNAPSHOT_TIME,
- TIPSELECTION_ALPHA,
- BELOW_MAX_DEPTH_TRANSACTION_LIMIT,
- }
-
-
-
- {
- // defaults
- conf.put(DefaultConfSettings.PORT.name(), "14600");
- conf.put(DefaultConfSettings.API_HOST.name(), "localhost");
- conf.put(DefaultConfSettings.UDP_RECEIVER_PORT.name(), "14600");
- conf.put(DefaultConfSettings.TCP_RECEIVER_PORT.name(), "15600");
- conf.put(DefaultConfSettings.TESTNET.name(), "false");
- conf.put(DefaultConfSettings.DEBUG.name(), "false");
- conf.put(DefaultConfSettings.REMOTE_LIMIT_API.name(), "");
- conf.put(DefaultConfSettings.REMOTE_AUTH.name(), "");
- conf.put(DefaultConfSettings.NEIGHBORS.name(), "");
- conf.put(DefaultConfSettings.IXI_DIR.name(), "ixi");
- conf.put(DefaultConfSettings.DB_PATH.name(), "mainnetdb");
- conf.put(DefaultConfSettings.DB_LOG_PATH.name(), "mainnet.log");
- conf.put(DefaultConfSettings.DB_CACHE_SIZE.name(), "100000"); //KB
- conf.put(DefaultConfSettings.CONFIG.name(), "iota.ini");
- conf.put(DefaultConfSettings.P_REMOVE_REQUEST.name(), "0.01");
- conf.put(DefaultConfSettings.P_DROP_TRANSACTION.name(), "0.0");
- conf.put(DefaultConfSettings.P_SELECT_MILESTONE_CHILD.name(), "0.7");
- conf.put(DefaultConfSettings.P_SEND_MILESTONE.name(), "0.02");
- conf.put(DefaultConfSettings.P_REPLY_RANDOM_TIP.name(), "0.66");
- conf.put(DefaultConfSettings.P_PROPAGATE_REQUEST.name(), "0.01");
- conf.put(DefaultConfSettings.MAIN_DB.name(), "rocksdb");
- conf.put(DefaultConfSettings.EXPORT.name(), "false");
- conf.put(DefaultConfSettings.SEND_LIMIT.name(), "-1.0");
- conf.put(DefaultConfSettings.MAX_PEERS.name(), "0");
- conf.put(DefaultConfSettings.DNS_REFRESHER_ENABLED.name(), "true");
- conf.put(DefaultConfSettings.DNS_RESOLUTION_ENABLED.name(), "true");
- conf.put(DefaultConfSettings.REVALIDATE.name(), "false");
- conf.put(DefaultConfSettings.RESCAN_DB.name(), "false");
- conf.put(DefaultConfSettings.MWM.name(), MAINNET_MWM);
-
- // Pick a number based on best performance
- conf.put(DefaultConfSettings.MIN_RANDOM_WALKS.name(), "5");
- conf.put(DefaultConfSettings.MAX_RANDOM_WALKS.name(), "27");
- // Pick a milestone depth number depending on risk model
- conf.put(DefaultConfSettings.MAX_DEPTH.name(), "15");
-
- conf.put(DefaultConfSettings.MAX_FIND_TRANSACTIONS.name(), "100000");
- conf.put(DefaultConfSettings.MAX_REQUESTS_LIST.name(), "1000");
- conf.put(DefaultConfSettings.MAX_GET_TRYTES.name(), "10000");
- conf.put(DefaultConfSettings.MAX_BODY_LENGTH.name(), "1000000");
- conf.put(DefaultConfSettings.ZMQ_ENABLED.name(), "false");
- conf.put(DefaultConfSettings.ZMQ_PORT.name(), "5556");
- conf.put(DefaultConfSettings.ZMQ_IPC.name(), "ipc://iri");
- conf.put(DefaultConfSettings.ZMQ_THREADS.name(), "2");
-
- conf.put(DefaultConfSettings.Q_SIZE_NODE.name(), "1000");
- conf.put(DefaultConfSettings.P_DROP_CACHE_ENTRY.name(), "0.02");
- conf.put(DefaultConfSettings.CACHE_SIZE_BYTES.name(), "15000");
-
- conf.put(DefaultConfSettings.COORDINATOR.name(), MAINNET_COORDINATOR_ADDRESS);
- conf.put(DefaultConfSettings.DONT_VALIDATE_TESTNET_MILESTONE_SIG.name(), "false");
- conf.put(DefaultConfSettings.SNAPSHOT_FILE.name(), MAINNET_SNAPSHOT_FILE);
- conf.put(DefaultConfSettings.SNAPSHOT_SIGNATURE_FILE.name(), MAINNET_SNAPSHOT_SIG_FILE);
- conf.put(DefaultConfSettings.MILESTONE_START_INDEX.name(), MAINNET_MILESTONE_START_INDEX);
- conf.put(DefaultConfSettings.NUMBER_OF_KEYS_IN_A_MILESTONE.name(), MAINNET_NUM_KEYS_IN_MILESTONE);
- conf.put(DefaultConfSettings.TRANSACTION_PACKET_SIZE.name(), PACKET_SIZE);
- conf.put(DefaultConfSettings.REQUEST_HASH_SIZE.name(), REQ_HASH_SIZE);
- conf.put(DefaultConfSettings.SNAPSHOT_TIME.name(), GLOBAL_SNAPSHOT_TIME);
- conf.put(DefaultConfSettings.TIPSELECTION_ALPHA.name(), "0.001");
- conf.put(DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT.name(), BELOW_MAX_DEPTH_LIMIT);
- }
-
- public boolean init() throws IOException {
- File confFile = new File(string(Configuration.DefaultConfSettings.CONFIG));
- if (confFile.exists()) {
- ini = new Ini(confFile);
- prefs = new IniPreferences(ini);
- return true;
- }
- return false;
- }
-
- public String getIniValue(String k) {
- if (ini != null) {
- return prefs.node("IRI").get(k, null);
- }
- return null;
- }
-
- private String getConfValue(String k) {
- String value = getIniValue(k);
- return value == null ? conf.get(k) : value;
- }
-
- public String allSettings() {
- final StringBuilder settings = new StringBuilder();
- conf.keySet().forEach(t -> settings.append("Set '").append(t).append("'\t -> ").append(getConfValue(t)).append("\n"));
- return settings.toString();
- }
-
- public void put(final String k, final String v) {
- log.debug("Setting {} with {}", k, v);
- conf.put(k, v);
- }
-
- public void put(final DefaultConfSettings d, String v) {
- log.debug("Setting {} with {}", d.name(), v);
- conf.put(d.name(), v);
- }
-
- private String string(String k) {
- return getConfValue(k);
- }
-
- public float floating(String k) {
- return Float.parseFloat(getConfValue(k));
- }
-
- public double doubling(String k) {
- return Double.parseDouble(getConfValue(k));
- }
-
- private int integer(String k) {
- return Integer.parseInt(getConfValue(k));
- }
-
- private boolean booling(String k) {
- return Boolean.parseBoolean(getConfValue(k));
- }
-
- private long longNum(String k) { return Long.parseLong(getConfValue(k)); }
-
- public String string(final DefaultConfSettings d) {
- return string(d.name());
- }
-
- public int integer(final DefaultConfSettings d) {
- return integer(d.name());
- }
-
- public long longNum(final DefaultConfSettings d) {
- return longNum(d.name());
- }
-
- public boolean booling(final DefaultConfSettings d) {
- return booling(d.name());
- }
-}
diff --git a/src/main/java/com/iota/iri/conf/ConsensusConfig.java b/src/main/java/com/iota/iri/conf/ConsensusConfig.java
new file mode 100644
index 0000000000..81c0d8f0d0
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/ConsensusConfig.java
@@ -0,0 +1,10 @@
+package com.iota.iri.conf;
+
+/**
+ * A configuration for all configuration concerned with achieving consensus on the ledger state across different nodes
+ *
+ * @implNote It currently extends two other interfaces. This has been done due to lack of separation of concerns in
+ * the current code base and will be changed in the future
+ */
+public interface ConsensusConfig extends SnapshotConfig, MilestoneConfig {
+}
diff --git a/src/main/java/com/iota/iri/conf/DbConfig.java b/src/main/java/com/iota/iri/conf/DbConfig.java
new file mode 100644
index 0000000000..9b01288c50
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/DbConfig.java
@@ -0,0 +1,54 @@
+package com.iota.iri.conf;
+
+/**
+ * Configurations for tangle database.
+ */
+public interface DbConfig extends Config {
+
+ /**
+ * @return Descriptions#DB_PATH
+ */
+ String getDbPath();
+
+ /**
+ * @return {@value Descriptions#DB_LOG_PATH}
+ */
+ String getDbLogPath();
+
+ /**
+ * @return {@value Descriptions#DB_CACHE_SIZE}
+ */
+ int getDbCacheSize();
+
+ /**
+ * @return {@value Descriptions#MAIN_DB}
+ */
+ String getMainDb();
+
+ /**
+ * @return {@value Descriptions#EXPORT}
+ */
+ boolean isExport();
+
+ /**
+ * @return {@value Descriptions#REVALIDATE}
+ */
+ boolean isRevalidate();
+
+ /**
+ * @return {@value Descriptions#RESCAN_DB}
+ */
+ boolean isRescanDb();
+
+ interface Descriptions {
+
+ String DB_PATH = "The folder where the DB saves its data.";
+ String DB_LOG_PATH = "The folder where the DB logs info";
+ String DB_CACHE_SIZE = "The size of the DB cache in KB";
+ String MAIN_DB = "The DB engine used to store the transactions. Currently only RocksDB is supported.";
+ String EXPORT = "Enable exporting the transaction data to files.";
+ String REVALIDATE = "Reload from the db data about confirmed transaction (milestones), state of the ledger, " +
+ "and transaction metadata.";
+ String RESCAN_DB = "Rescan all transaction metadata (Approvees, Bundles, and Tags)";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/IXIConfig.java b/src/main/java/com/iota/iri/conf/IXIConfig.java
new file mode 100644
index 0000000000..a9cb01a468
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/IXIConfig.java
@@ -0,0 +1,18 @@
+package com.iota.iri.conf;
+
+/**
+ * Configurations for IXI modules
+ */
+public interface IXIConfig extends Config {
+
+ String IXI_DIR = "ixi";
+
+ /**
+ * @return Descriptions#IXI_DIR
+ */
+ String getIxiDir();
+
+ interface Descriptions {
+ String IXI_DIR = "The folder where ixi modules should be added for automatic discovery by IRI.";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/IotaConfig.java b/src/main/java/com/iota/iri/conf/IotaConfig.java
new file mode 100644
index 0000000000..bbd08394a9
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/IotaConfig.java
@@ -0,0 +1,26 @@
+package com.iota.iri.conf;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.ParameterException;
+
+import java.io.File;
+
+/**
+ * A container for all possible configuration parameters of IRI.
+ * In charge of how we parse the configuration from given inputs.
+ */
+public interface IotaConfig extends APIConfig, NodeConfig,
+ IXIConfig, DbConfig, ConsensusConfig, ZMQConfig, TipSelConfig {
+ File CONFIG_FILE = new File("iota.ini");
+
+ /**
+ * Parses the args to populate the configuration object
+ *
+ * @param args command line args
+ * @return {@link JCommander} instance that was used for parsing. It contains metadata about the parsing.
+ * @throws ParameterException if the parsing failed
+ */
+ JCommander parseConfigFromArgs(String[] args) throws ParameterException;
+
+ boolean isHelp();
+}
diff --git a/src/main/java/com/iota/iri/conf/MainnetConfig.java b/src/main/java/com/iota/iri/conf/MainnetConfig.java
new file mode 100644
index 0000000000..7fa250fd04
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/MainnetConfig.java
@@ -0,0 +1,14 @@
+package com.iota.iri.conf;
+
+public class MainnetConfig extends BaseIotaConfig {
+
+ public MainnetConfig() {
+ //All the configs are defined in the super class
+ super();
+ }
+
+ @Override
+ public boolean isTestnet() {
+ return false;
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/MilestoneConfig.java b/src/main/java/com/iota/iri/conf/MilestoneConfig.java
new file mode 100644
index 0000000000..94afaf28b2
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/MilestoneConfig.java
@@ -0,0 +1,23 @@
+package com.iota.iri.conf;
+
+/**
+ * Configs that should be used for tracking milestones
+ */
+public interface MilestoneConfig extends Config {
+
+ /**
+ * @return Descriptions#COORDINATOR
+ */
+ String getCoordinator();
+
+ /**
+ * @return {@value Descriptions#DONT_VALIDATE_TESTNET_MILESTONE_SIG}
+ */
+ boolean isDontValidateTestnetMilestoneSig();
+
+ interface Descriptions {
+
+ String COORDINATOR = "The address of the coordinator";
+ String DONT_VALIDATE_TESTNET_MILESTONE_SIG = "Disable coordinator validation on testnet";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/NetworkConfig.java b/src/main/java/com/iota/iri/conf/NetworkConfig.java
new file mode 100644
index 0000000000..4d7271104d
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/NetworkConfig.java
@@ -0,0 +1,80 @@
+package com.iota.iri.conf;
+
+import java.util.List;
+
+/**
+ * Configurations for the node networking. Including ports, DNS settings, list of neighbors,
+ * and various optimization parameters.
+ */
+public interface NetworkConfig extends Config {
+
+ /**
+ * @return Descriptions#UDP_RECEIVER_PORT
+ */
+ int getUdpReceiverPort();
+
+ /**
+ * @return Descriptions#TCP_RECEIVER_PORT
+ */
+ int getTcpReceiverPort();
+
+ /**
+ * @return Descriptions#P_REMOVE_REQUEST
+ */
+ double getpRemoveRequest();
+
+ /**
+ * @return Descriptions#SEND_LIMIT
+ */
+ int getSendLimit();
+
+ /**
+ * @return Descriptions#MAX_PEERS
+ */
+ int getMaxPeers();
+
+ /**
+ * @return Descriptions#DNS_REFRESHER_ENABLED
+ */
+ boolean isDnsRefresherEnabled();
+
+ /**
+ * @return Descriptions#DNS_RESOLUTION_ENABLED
+ */
+ boolean isDnsResolutionEnabled();
+
+ /**
+ * @return Descriptions#NEIGHBORS
+ */
+ List getNeighbors();
+
+ /**
+ * @return Descriptions#Q_SIZE_NODE
+ */
+ int getqSizeNode();
+
+ /**
+ * @return Descriptions#P_DROP_CACHE_ENTRY
+ */
+ double getpDropCacheEntry();
+
+ /**
+ * @return Descriptions#CACHE_SIZE_BYTES
+ */
+ int getCacheSizeBytes();
+
+ interface Descriptions {
+ String UDP_RECEIVER_PORT = "The UDP Receiver Port.";
+ String TCP_RECEIVER_PORT = "The TCP Receiver Port.";
+ String P_REMOVE_REQUEST = DescriptionHelper.PROB_OF + " stopping to request a transaction. This number should be " +
+ "closer to 0 so non-existing transaction hashes will eventually be removed.";
+ String SEND_LIMIT = "The maximum number of packets that may be sent by this node in a 1 second interval. If this number is below 0 then there is no limit.";
+ String MAX_PEERS = "The maximum number of non mutually tethered connections allowed. Works only in testnet mode";
+ String DNS_REFRESHER_ENABLED = "Reconnect to neighbors that have dynamic IPs.";
+ String DNS_RESOLUTION_ENABLED = "Enable using DNS for neighbor peering.";
+ String NEIGHBORS = "Urls of peer iota nodes.";
+ String Q_SIZE_NODE = "The size of the REPLY, BROADCAST, and RECEIVE network queues.";
+ String P_DROP_CACHE_ENTRY = DescriptionHelper.PROB_OF + "dropping recently seen transactions out of the network cache.";
+ String CACHE_SIZE_BYTES = "The size of the network cache in bytes";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/NodeConfig.java b/src/main/java/com/iota/iri/conf/NodeConfig.java
new file mode 100644
index 0000000000..ae82f56b23
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/NodeConfig.java
@@ -0,0 +1,10 @@
+package com.iota.iri.conf;
+
+/**
+ * A configuration that specifies how the node communicates with other nodes.
+ *
+ * @implNote It currently extends two other interfaces. This has been done due to lack of separation of concerns in
+ * the current code base and will be changed in the future
+ */
+public interface NodeConfig extends ProtocolConfig, NetworkConfig {
+}
diff --git a/src/main/java/com/iota/iri/conf/ProtocolConfig.java b/src/main/java/com/iota/iri/conf/ProtocolConfig.java
new file mode 100644
index 0000000000..20c4526af6
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/ProtocolConfig.java
@@ -0,0 +1,50 @@
+package com.iota.iri.conf;
+
+/**
+ * Configuration for protocol rules. Controls what transactions will be accepted by the network, and how they will
+ * be propagated to other nodes.
+ **/
+public interface ProtocolConfig extends Config {
+
+ /**
+ * @return Descriptions#MWM
+ */
+ int getMwm();
+
+ /**
+ * @return Descriptions#TRANSACTION_PACKET_SIZE
+ */
+ int getTransactionPacketSize();
+
+ /**
+ * @return Descriptions#REQUEST_HASH_SIZE
+ */
+ int getRequestHashSize();
+
+ /**
+ * @return Descriptions#P_REPLY_RANDOM_TIP
+ */
+ double getpReplyRandomTip();
+
+ double getpDropTransaction();
+
+ /**
+ * @return Descriptions#P_SELECT_MILESTONE
+ */
+ double getpSelectMilestoneChild();
+
+ double getpSendMilestone();
+
+ double getpPropagateRequest();
+
+ interface Descriptions {
+ String MWM = "The minimum weight magnitude is the number of trailing 0s that must appear in the end of a transaction hash. Increasing this number by 1 will result in proof of work that is 3 times as hard.";
+ String TRANSACTION_PACKET_SIZE = "The size of the packet in bytes received by a node. In the mainnet the packet size should always be 1650. It consists of 1604 bytes of a received transaction and 46 bytes of a requested transaction hash. This value can be changed in order to create testnets with different rules.";
+ String REQUEST_HASH_SIZE = "The size of the requested hash in a packet. Its size is derived from the minimal MWM value the network accepts. The larger the MWM -> the more trailing zeroes we can ignore -> smaller hash size.";
+ String P_DROP_TRANSACTION = DescriptionHelper.PROB_OF + "dropping a received transaction. This is used only for testing purposes.";
+ String P_SELECT_MILESTONE = DescriptionHelper.PROB_OF + "requesting a milestone transaction from a neighbor. This should be a large since it is imperative that we find milestones to get transactions confirmed";
+ String P_SEND_MILESTONE = DescriptionHelper.PROB_OF + "sending a milestone transaction when the node looks for a random transaction to send to a neighbor.";
+ String P_REPLY_RANDOM_TIP = DescriptionHelper.PROB_OF + "replying to a random transaction request, even though your node doesn't have anything to request.";
+ String P_PROPAGATE_REQUEST = DescriptionHelper.PROB_OF + "propagating the request of a transaction to a neighbor node if it can't be found. This should be low since we don't want to propagate non-existing transactions that spam the network.";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/SnapshotConfig.java b/src/main/java/com/iota/iri/conf/SnapshotConfig.java
new file mode 100644
index 0000000000..011f801d2f
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/SnapshotConfig.java
@@ -0,0 +1,50 @@
+package com.iota.iri.conf;
+
+/**
+ * Configurations for handling global snapshot data
+ */
+public interface SnapshotConfig extends Config {
+
+ /**
+ * @return {@value Descriptions#SNAPSHOT_TIME}
+ */
+ long getSnapshotTime();
+
+ /**
+ * return {@value Descriptions#SNAPSHOT_FILE}
+ */
+ String getSnapshotFile();
+
+ /**
+ * @return {@value Descriptions#SNAPSHOT_SIGNATURE_FILE}
+ */
+ String getSnapshotSignatureFile();
+
+ /**
+ * @return {@value Descriptions#MILESTONE_START_INDEX}
+ */
+ int getMilestoneStartIndex();
+
+ /**
+ * @return {@value Descriptions#NUMBER_OF_KEYS_IN_A_MILESTONE}
+ */
+ int getNumberOfKeysInMilestone();
+
+ /**
+ * @return {@value Descriptions#PREVIOUS_EPOCH_SPENT_ADDRESSES_FILE}
+ */
+ String getPreviousEpochSpentAddressesFiles();
+
+ interface Descriptions {
+
+ String SNAPSHOT_TIME = "Epoch time of the last snapshot.";
+ String SNAPSHOT_FILE = "Path of the file that contains the state of the ledger at the last snapshot.";
+ String SNAPSHOT_SIGNATURE_FILE = "Path to the file that contains a signature for the snapshot file.";
+ String MILESTONE_START_INDEX = "The start index of the milestones. This index is encoded in each milestone " +
+ "transaction by the coordinator.";
+ String NUMBER_OF_KEYS_IN_A_MILESTONE = "The depth of the Merkle tree which in turn determines the number of" +
+ "leaves (private keys) that the coordinator can use to sign a message.";
+ String PREVIOUS_EPOCH_SPENT_ADDRESSES_FILE = "The file that contains the list of all used addresses " +
+ "from previous epochs";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/TestnetConfig.java b/src/main/java/com/iota/iri/conf/TestnetConfig.java
new file mode 100644
index 0000000000..8126dcd82f
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/TestnetConfig.java
@@ -0,0 +1,175 @@
+package com.iota.iri.conf;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.ParameterException;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Objects;
+
+public class TestnetConfig extends BaseIotaConfig {
+
+ protected String coordinator = Defaults.COORDINATOR_ADDRESS;
+ protected boolean dontValidateTestnetMilestoneSig = Defaults.DONT_VALIDATE_MILESTONE_SIG;
+ protected String snapshotFile = Defaults.SNAPSHOT_FILE;
+ protected String snapshotSignatureFile = Defaults.SNAPSHOT_SIG;
+ protected long snapshotTime = Defaults.SNAPSHOT_TIME;
+ protected int mwm = Defaults.MWM;
+ protected int milestoneStartIndex = Defaults.MILESTONE_START_INDEX;
+ protected int numberOfKeysInMilestone = Defaults.KEYS_IN_MILESTONE;
+ protected int transactionPacketSize = Defaults.PACKET_SIZE;
+ protected int requestHashSize = Defaults.REQUEST_HASH_SIZE;
+
+ public TestnetConfig() {
+ super();
+ dbPath = Defaults.DB_PATH;
+ dbLogPath = Defaults.DB_LOG_PATH;
+ }
+
+ @Override
+ public boolean isTestnet() {
+ return true;
+ }
+
+ @Override
+ public String getCoordinator() {
+ return coordinator;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--testnet-coordinator", description = MilestoneConfig.Descriptions.COORDINATOR)
+ protected void setCoordinator(String coordinator) {
+ this.coordinator = coordinator;
+ }
+
+ @Override
+ public boolean isDontValidateTestnetMilestoneSig() {
+ return dontValidateTestnetMilestoneSig;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--testnet-no-coo-validation", description = MilestoneConfig.Descriptions.DONT_VALIDATE_TESTNET_MILESTONE_SIG)
+ protected void setDontValidateTestnetMilestoneSig(boolean dontValidateTestnetMilestoneSig) {
+ this.dontValidateTestnetMilestoneSig = dontValidateTestnetMilestoneSig;
+ }
+
+ @Override
+ public String getSnapshotFile() {
+ return snapshotFile;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--snapshot", description = SnapshotConfig.Descriptions.SNAPSHOT_FILE)
+ protected void setSnapshotFile(String snapshotFile) {
+ this.snapshotFile = snapshotFile;
+ }
+
+ @Override
+ public String getSnapshotSignatureFile() {
+ return snapshotSignatureFile;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--snapshot-sig", description = SnapshotConfig.Descriptions.SNAPSHOT_SIGNATURE_FILE)
+ protected void setSnapshotSignatureFile(String snapshotSignatureFile) {
+ this.snapshotSignatureFile = snapshotSignatureFile;
+ }
+
+ @Override
+ public long getSnapshotTime() {
+ return snapshotTime;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--snapshot-timestamp", description = SnapshotConfig.Descriptions.SNAPSHOT_TIME)
+ protected void setSnapshotTime(long snapshotTime) {
+ this.snapshotTime = snapshotTime;
+ }
+
+ @Override
+ public int getMwm() {
+ return mwm;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--mwm", description = ProtocolConfig.Descriptions.MWM)
+ protected void setMwm(int mwm) {
+ this.mwm = mwm;
+ }
+
+ @Override
+ public int getMilestoneStartIndex() {
+ return milestoneStartIndex;
+ }
+
+ @JsonProperty
+ @Parameter(names = "--milestone-start", description = SnapshotConfig.Descriptions.MILESTONE_START_INDEX)
+ protected void setMilestoneStartIndex(int milestoneStartIndex) {
+ this.milestoneStartIndex = milestoneStartIndex;
+ }
+
+ @Override
+ public int getNumberOfKeysInMilestone() {
+ return numberOfKeysInMilestone;
+ }
+
+ @JsonProperty("NUMBER_OF_KEYS_IN_A_MILESTONE")
+ @Parameter(names = "--milestone-keys", description = SnapshotConfig.Descriptions.NUMBER_OF_KEYS_IN_A_MILESTONE)
+ protected void setNumberOfKeysInMilestone(int numberOfKeysInMilestone) {
+ this.numberOfKeysInMilestone = numberOfKeysInMilestone;
+ }
+
+ @Override
+ public int getTransactionPacketSize() {
+ return transactionPacketSize;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--packet-size"}, description = ProtocolConfig.Descriptions.TRANSACTION_PACKET_SIZE)
+ protected void setTransactionPacketSize(int transactionPacketSize) {
+ this.transactionPacketSize = transactionPacketSize;
+ }
+
+ @Override
+ public int getRequestHashSize() {
+ return requestHashSize;
+ }
+
+ @JsonProperty
+ @Parameter(names = {"--request-hash-size"}, description = ProtocolConfig.Descriptions.REQUEST_HASH_SIZE)
+ public void setRequestHashSize(int requestHashSize) {
+ this.requestHashSize = requestHashSize;
+ }
+
+ @JsonProperty
+ @Override
+ public void setDbPath(String dbPath) {
+ if (Objects.equals(MainnetConfig.Defaults.DB_PATH, dbPath)) {
+ throw new ParameterException("Testnet Db folder cannot be configured to mainnet's db folder");
+ }
+ super.setDbPath(dbPath);
+ }
+
+ @JsonProperty
+ @Override
+ public void setDbLogPath(String dbLogPath) {
+ if (Objects.equals(MainnetConfig.Defaults.DB_LOG_PATH, dbLogPath)) {
+ throw new ParameterException("Testnet Db log folder cannot be configured to mainnet's db log folder");
+ }
+ super.setDbLogPath(dbLogPath);
+ }
+
+ public interface Defaults {
+ String COORDINATOR_ADDRESS = "EQQFCZBIHRHWPXKMTOLMYUYPCN9XLMJPYZVFJSAY9FQHCCLWTOLLUGKKMXYFDBOOYFBLBI9WUEILGECYM";
+ boolean DONT_VALIDATE_MILESTONE_SIG = false;
+ String SNAPSHOT_FILE = "/snapshotTestnet.txt";
+ int REQUEST_HASH_SIZE = 49;
+ String SNAPSHOT_SIG = "/snapshotTestnet.sig";
+ int SNAPSHOT_TIME = 1522306500;
+ int MWM = 9;
+ int MILESTONE_START_INDEX = 434525;
+ int KEYS_IN_MILESTONE = 22;
+ int PACKET_SIZE = 1653;
+ String DB_PATH = "testnetdb";
+ String DB_LOG_PATH = "testnetdb.log";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/TipSelConfig.java b/src/main/java/com/iota/iri/conf/TipSelConfig.java
new file mode 100644
index 0000000000..542ad47eed
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/TipSelConfig.java
@@ -0,0 +1,33 @@
+package com.iota.iri.conf;
+
+/**
+ * Configuration for how we perform tip selections. Tip selection is invoked when a client wants to find tips to
+ * attach its transactions to. The tips are invoked via random walks that start at a certain point in the tangle.
+ * The parameters here affect the length and randomness of this walk.
+ */
+public interface TipSelConfig extends Config {
+
+ /**
+ * @return Descriptions#MAX_DEPTH
+ */
+ int getMaxDepth();
+
+ /**
+ * @return Descriptions#ALPHA
+ */
+ double getAlpha();
+
+ /**
+ * @return Descriptions#BELOW_MAX_DEPTH_TRANSACTION_LIMIT
+ */
+ int getBelowMaxDepthTransactionLimit();
+
+ interface Descriptions {
+
+ String MAX_DEPTH = "The maximal number of previous milestones from where you can perform the random walk";
+ String ALPHA = "Parameter that defines the randomness of the tip selection. " +
+ "Should be a number between 0 to infinity, where 0 is most random and infinity is most deterministic.";
+ String BELOW_MAX_DEPTH_TRANSACTION_LIMIT = "The maximal number of unconfirmed transactions that may be analyzed in " +
+ "order to find the latest milestone the transaction that we are stepping on during the walk approves";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/ZMQConfig.java b/src/main/java/com/iota/iri/conf/ZMQConfig.java
new file mode 100644
index 0000000000..b3a9b304b7
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/ZMQConfig.java
@@ -0,0 +1,18 @@
+package com.iota.iri.conf;
+
+public interface ZMQConfig extends Config {
+
+ boolean isZmqEnabled();
+
+ int getZmqPort();
+
+ int getZmqThreads();
+
+ String getZmqIpc();
+
+ interface Descriptions {
+ String ZMQ_ENABLED = "Enabling zmq channels.";
+ String ZMQ_PORT = "The port used to connect to the ZMQ feed";
+ String ZMQ_IPC = "The path that is used to communicate with ZMQ in IPC";
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/deserializers/CustomBoolDeserializer.java b/src/main/java/com/iota/iri/conf/deserializers/CustomBoolDeserializer.java
new file mode 100644
index 0000000000..c76db45a9f
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/deserializers/CustomBoolDeserializer.java
@@ -0,0 +1,49 @@
+package com.iota.iri.conf.deserializers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+
+/**
+ * Deserialize boolean type.
+ */
+public class CustomBoolDeserializer extends StdDeserializer{
+
+ /**
+ * Default constructor
+ */
+ public CustomBoolDeserializer() {
+ super(Boolean.class);
+ }
+
+ @Override
+ public Boolean deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
+ JsonToken jsonToken = parser.getCurrentToken();
+ if (jsonToken == JsonToken.VALUE_TRUE) {
+ return true;
+ }
+ if (jsonToken == JsonToken.VALUE_FALSE) {
+ return false;
+ }
+ if (jsonToken == JsonToken.VALUE_NULL) {
+ return parseNull(ctxt);
+ }
+ if (jsonToken == JsonToken.VALUE_STRING) {
+ String text = parser.getText().trim();
+ if (StringUtils.isEmpty(text)) {
+ return parseNull(ctxt);
+ }
+ return Boolean.valueOf(text);
+ }
+ return false;
+ }
+
+ private Boolean parseNull(DeserializationContext ctxt) throws IOException {
+ _verifyNullForPrimitive(ctxt);
+ return false;
+ }
+}
diff --git a/src/main/java/com/iota/iri/conf/deserializers/CustomStringDeserializer.java b/src/main/java/com/iota/iri/conf/deserializers/CustomStringDeserializer.java
new file mode 100644
index 0000000000..18103692df
--- /dev/null
+++ b/src/main/java/com/iota/iri/conf/deserializers/CustomStringDeserializer.java
@@ -0,0 +1,26 @@
+package com.iota.iri.conf.deserializers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+import java.io.IOException;
+
+/**
+ * Deserialize string and trims all leading and trailing whitespaces from string.
+ */
+public class CustomStringDeserializer extends StdDeserializer {
+
+ /**
+ * Default constructor
+ */
+ public CustomStringDeserializer() {
+ super(String.class);
+ }
+
+ @Override
+ public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
+ return jsonParser.getValueAsString().trim();
+ }
+}
diff --git a/src/main/java/com/iota/iri/controllers/TipsViewModel.java b/src/main/java/com/iota/iri/controllers/TipsViewModel.java
index 5c71070a49..9c6b6cd458 100644
--- a/src/main/java/com/iota/iri/controllers/TipsViewModel.java
+++ b/src/main/java/com/iota/iri/controllers/TipsViewModel.java
@@ -98,6 +98,12 @@ public int nonSolidSize() {
return tips.size();
}
}
+
+ public int solidSize() {
+ synchronized (sync) {
+ return solidTips.size();
+ }
+ }
public int size() {
synchronized (sync) {
@@ -140,4 +146,4 @@ public Iterator iterator() {
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/iota/iri/controllers/TransactionViewModel.java b/src/main/java/com/iota/iri/controllers/TransactionViewModel.java
index 8b20a5aaae..57d0513d03 100644
--- a/src/main/java/com/iota/iri/controllers/TransactionViewModel.java
+++ b/src/main/java/com/iota/iri/controllers/TransactionViewModel.java
@@ -1,7 +1,5 @@
package com.iota.iri.controllers;
-import java.util.*;
-
import com.iota.iri.model.*;
import com.iota.iri.storage.Indexable;
import com.iota.iri.storage.Persistable;
@@ -9,6 +7,8 @@
import com.iota.iri.utils.Converter;
import com.iota.iri.utils.Pair;
+import java.util.*;
+
public class TransactionViewModel {
private final com.iota.iri.model.Transaction transaction;
@@ -36,6 +36,7 @@ public class TransactionViewModel {
private static final int NONCE_TRINARY_OFFSET = ATTACHMENT_TIMESTAMP_UPPER_BOUND_TRINARY_OFFSET + ATTACHMENT_TIMESTAMP_UPPER_BOUND_TRINARY_SIZE, NONCE_TRINARY_SIZE = 81;
public static final int TRINARY_SIZE = NONCE_TRINARY_OFFSET + NONCE_TRINARY_SIZE;
+ public static final int TRYTES_SIZE = TRINARY_SIZE / 3;
public static final int ESSENCE_TRINARY_OFFSET = ADDRESS_TRINARY_OFFSET, ESSENCE_TRINARY_SIZE = ADDRESS_TRINARY_SIZE + VALUE_TRINARY_SIZE + OBSOLETE_TAG_TRINARY_SIZE + TIMESTAMP_TRINARY_SIZE + CURRENT_INDEX_TRINARY_SIZE + LAST_INDEX_TRINARY_SIZE;
diff --git a/src/main/java/com/iota/iri/network/Node.java b/src/main/java/com/iota/iri/network/Node.java
index f92db11c98..e3c5781737 100644
--- a/src/main/java/com/iota/iri/network/Node.java
+++ b/src/main/java/com/iota/iri/network/Node.java
@@ -2,7 +2,7 @@
import com.iota.iri.Milestone;
import com.iota.iri.TransactionValidator;
-import com.iota.iri.conf.Configuration;
+import com.iota.iri.conf.NodeConfig;
import com.iota.iri.controllers.TipsViewModel;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.hash.SpongeFactory;
@@ -38,7 +38,6 @@ public class Node {
private int RECV_QUEUE_SIZE;
private int REPLY_QUEUE_SIZE;
private static final int PAUSE_BETWEEN_TRANSACTIONS = 1;
- private static double P_SELECT_MILESTONE;
private final AtomicBoolean shuttingDown = new AtomicBoolean(false);
@@ -52,7 +51,7 @@ public class Node {
private final DatagramPacket tipRequestingPacket;
private final ExecutorService executor = Executors.newFixedThreadPool(5);
- private final Configuration configuration;
+ private final NodeConfig configuration;
private final Tangle tangle;
private final TipsViewModel tipsViewModel;
private final TransactionValidator transactionValidator;
@@ -60,16 +59,11 @@ public class Node {
private final TransactionRequester transactionRequester;
private final MessageQ messageQ;
- private double P_DROP_TRANSACTION;
private static final SecureRandom rnd = new SecureRandom();
- private double P_SEND_MILESTONE;
- private double P_REPLY_RANDOM_TIP;
- private double P_PROPAGATE_REQUEST;
private FIFOCache recentSeenBytes;
- private boolean debug;
private static AtomicLong recentSeenBytesMissCount = new AtomicLong(0L);
private static AtomicLong recentSeenBytesHitCount = new AtomicLong(0L);
@@ -80,13 +74,7 @@ public class Node {
public static final ConcurrentSkipListSet rejectedAddresses = new ConcurrentSkipListSet();
private DatagramSocket udpSocket;
- public Node(final Configuration configuration,
- final Tangle tangle,
- final TransactionValidator transactionValidator,
- final TransactionRequester transactionRequester,
- final TipsViewModel tipsViewModel,
- final Milestone milestone,
- final MessageQ messageQ
+ public Node(final Tangle tangle, final TransactionValidator transactionValidator, final TransactionRequester transactionRequester, final TipsViewModel tipsViewModel, final Milestone milestone, final MessageQ messageQ, final NodeConfig configuration
) {
this.configuration = configuration;
this.tangle = tangle;
@@ -95,8 +83,8 @@ public Node(final Configuration configuration,
this.tipsViewModel = tipsViewModel;
this.milestone = milestone;
this.messageQ = messageQ;
- this.reqHashSize = configuration.integer(Configuration.DefaultConfSettings.REQUEST_HASH_SIZE);
- int packetSize = configuration.integer(Configuration.DefaultConfSettings.TRANSACTION_PACKET_SIZE);
+ this.reqHashSize = configuration.getRequestHashSize();
+ int packetSize = configuration.getTransactionPacketSize();
this.sendingPacket = new DatagramPacket(new byte[packetSize], packetSize);
this.tipRequestingPacket = new DatagramPacket(new byte[packetSize], packetSize);
@@ -104,17 +92,11 @@ public Node(final Configuration configuration,
public void init() throws Exception {
- P_DROP_TRANSACTION = configuration.doubling(Configuration.DefaultConfSettings.P_DROP_TRANSACTION.name());
- P_SELECT_MILESTONE = configuration.doubling(Configuration.DefaultConfSettings.P_SELECT_MILESTONE_CHILD.name());
- P_SEND_MILESTONE = configuration.doubling(Configuration.DefaultConfSettings.P_SEND_MILESTONE.name());
- P_REPLY_RANDOM_TIP = configuration.doubling(Configuration.DefaultConfSettings.P_REPLY_RANDOM_TIP.name());
- P_PROPAGATE_REQUEST = configuration.doubling(Configuration.DefaultConfSettings.P_PROPAGATE_REQUEST.name());
- sendLimit = (long) ((configuration.doubling(Configuration.DefaultConfSettings.SEND_LIMIT.name()) * 1000000) / (configuration.integer(Configuration.DefaultConfSettings.TRANSACTION_PACKET_SIZE) * 8));
- debug = configuration.booling(Configuration.DefaultConfSettings.DEBUG);
+ //TODO ask Alon
+ sendLimit = (long) ((configuration.getSendLimit() * 1000000) / (configuration.getTransactionPacketSize() * 8));
- BROADCAST_QUEUE_SIZE = RECV_QUEUE_SIZE = REPLY_QUEUE_SIZE = configuration.integer(Configuration.DefaultConfSettings.Q_SIZE_NODE);
- double pDropCacheEntry = configuration.doubling(Configuration.DefaultConfSettings.P_DROP_CACHE_ENTRY.name());
- recentSeenBytes = new FIFOCache<>(configuration.integer(Configuration.DefaultConfSettings.CACHE_SIZE_BYTES), pDropCacheEntry);
+ BROADCAST_QUEUE_SIZE = RECV_QUEUE_SIZE = REPLY_QUEUE_SIZE = configuration.getqSizeNode();
+ recentSeenBytes = new FIFOCache<>(configuration.getCacheSizeBytes(), configuration.getpDropCacheEntry());
parseNeighborsConfig();
@@ -139,7 +121,7 @@ public DatagramSocket getUdpSocket() {
private Runnable spawnNeighborDNSRefresherThread() {
return () -> {
- if (configuration.booling(Configuration.DefaultConfSettings.DNS_RESOLUTION_ENABLED)) {
+ if (configuration.isDnsResolutionEnabled()) {
log.info("Spawning Neighbor DNS Refresher Thread");
while (!shuttingDown.get()) {
@@ -161,7 +143,7 @@ private Runnable spawnNeighborDNSRefresherThread() {
log.info("{} seems fine.", hostname);
messageQ.publish("dnscc %s", hostname);
} else {
- if (configuration.booling(Configuration.DefaultConfSettings.DNS_REFRESHER_ENABLED)) {
+ if (configuration.isDnsRefresherEnabled()) {
log.info("IP CHANGED for {}! Updating...", hostname);
messageQ.publish("dnscu %s", hostname);
String protocol = (n instanceof TCPNeighbor) ? "tcp://" : "udp://";
@@ -226,13 +208,14 @@ public void preProcessReceivedData(byte[] receivedData, SocketAddress senderAddr
boolean addressMatch = false;
boolean cached = false;
+ double pDropTransaction = configuration.getpDropTransaction();
for (final Neighbor neighbor : getNeighbors()) {
addressMatch = neighbor.matches(senderAddress);
if (addressMatch) {
//Validate transaction
neighbor.incAllTransactions();
- if (rnd.nextDouble() < P_DROP_TRANSACTION) {
+ if (rnd.nextDouble() < pDropTransaction) {
//log.info("Randomly dropping transaction. Stand by... ");
break;
}
@@ -253,7 +236,7 @@ public void preProcessReceivedData(byte[] receivedData, SocketAddress senderAddr
//if not, then validate
receivedTransactionViewModel = new TransactionViewModel(receivedData, Hash.calculate(receivedData, TransactionViewModel.TRINARY_SIZE, SpongeFactory.create(SpongeFactory.Mode.CURLP81)));
receivedTransactionHash = receivedTransactionViewModel.getHash();
- TransactionValidator.runValidation(receivedTransactionViewModel, transactionValidator.getMinWeightMagnitude());
+ transactionValidator.runValidation(receivedTransactionViewModel, transactionValidator.getMinWeightMagnitude());
synchronized (recentSeenBytes) {
recentSeenBytes.put(byteHash, receivedTransactionHash);
@@ -294,7 +277,7 @@ public void preProcessReceivedData(byte[] receivedData, SocketAddress senderAddr
//recentSeenBytes statistics
- if (debug) {
+ if (log.isDebugEnabled()) {
long hitCount, missCount;
if (cached) {
hitCount = recentSeenBytesHitCount.incrementAndGet();
@@ -315,8 +298,8 @@ public void preProcessReceivedData(byte[] receivedData, SocketAddress senderAddr
}
}
- if (!addressMatch && configuration.booling(Configuration.DefaultConfSettings.TESTNET)) {
- int maxPeersAllowed = configuration.integer(Configuration.DefaultConfSettings.MAX_PEERS);
+ if (!addressMatch && configuration.isTestnet()) {
+ int maxPeersAllowed = configuration.getMaxPeers();
String uriString = uriScheme + ":/" + senderAddress.toString();
if (Neighbor.getNumPeers() < maxPeersAllowed) {
log.info("Adding non-tethered neighbor: " + uriString);
@@ -412,7 +395,8 @@ public void replyToRequest(Hash requestedHash, Neighbor neighbor) {
if (requestedHash.equals(Hash.NULL_HASH)) {
//Random Tip Request
try {
- if (transactionRequester.numberOfTransactionsToRequest() > 0 && rnd.nextDouble() < P_REPLY_RANDOM_TIP) {
+ if (transactionRequester.numberOfTransactionsToRequest() > 0
+ && rnd.nextDouble() < configuration.getpReplyRandomTip()) {
neighbor.incRandomTransactionRequests();
transactionPointer = getRandomTipPointer();
transactionViewModel = TransactionViewModel.fromHash(tangle, transactionPointer);
@@ -444,7 +428,7 @@ public void replyToRequest(Hash requestedHash, Neighbor neighbor) {
}
} else {
//trytes not found
- if (!requestedHash.equals(Hash.NULL_HASH) && rnd.nextDouble() < P_PROPAGATE_REQUEST) {
+ if (!requestedHash.equals(Hash.NULL_HASH) && rnd.nextDouble() < configuration.getpPropagateRequest()) {
//request is an actual transaction and missing in request queue add it.
try {
transactionRequester.requestTransaction(requestedHash, false);
@@ -459,7 +443,7 @@ public void replyToRequest(Hash requestedHash, Neighbor neighbor) {
}
private Hash getRandomTipPointer() throws Exception {
- Hash tip = rnd.nextDouble() < P_SEND_MILESTONE ? milestone.latestMilestone : tipsViewModel.getRandomSolidTipHash();
+ Hash tip = rnd.nextDouble() < configuration.getpSendMilestone() ? milestone.latestMilestone : tipsViewModel.getRandomSolidTipHash();
return tip == null ? Hash.NULL_HASH : tip;
}
@@ -480,7 +464,7 @@ public void sendPacket(DatagramPacket sendingPacket, TransactionViewModel transa
synchronized (sendingPacket) {
System.arraycopy(transactionViewModel.getBytes(), 0, sendingPacket.getData(), 0, TransactionViewModel.SIZE);
- Hash hash = transactionRequester.transactionToRequest(rnd.nextDouble() < P_SELECT_MILESTONE);
+ Hash hash = transactionRequester.transactionToRequest(rnd.nextDouble() < configuration.getpSelectMilestoneChild());
System.arraycopy(hash != null ? hash.bytes() : transactionViewModel.getHash().bytes(), 0,
sendingPacket.getData(), TransactionViewModel.SIZE, reqHashSize);
neighbor.send(sendingPacket);
@@ -705,8 +689,9 @@ public static Optional uri(final String uri) {
}
private void parseNeighborsConfig() {
- Arrays.stream(configuration.string(Configuration.DefaultConfSettings.NEIGHBORS).split(" ")).distinct()
- .filter(s -> !s.isEmpty()).map(Node::uri).map(Optional::get)
+ configuration.getNeighbors().stream().distinct()
+ .filter(s -> !s.isEmpty())
+ .map(Node::uri).map(Optional::get)
.filter(u -> isUriValid(u))
.map(u -> newNeighbor(u, true))
.peek(u -> {
diff --git a/src/main/java/com/iota/iri/network/TransactionRequester.java b/src/main/java/com/iota/iri/network/TransactionRequester.java
index 70107e5cba..14cb0179e7 100644
--- a/src/main/java/com/iota/iri/network/TransactionRequester.java
+++ b/src/main/java/com/iota/iri/network/TransactionRequester.java
@@ -23,8 +23,6 @@ public class TransactionRequester {
public static final int MAX_TX_REQ_QUEUE_SIZE = 10000;
- private static volatile long lastTime = System.currentTimeMillis();
-
private static double P_REMOVE_REQUEST;
private static boolean initialized = false;
private final SecureRandom random = new SecureRandom();
@@ -84,48 +82,49 @@ private boolean transactionsToRequestIsFull() {
public Hash transactionToRequest(boolean milestone) throws Exception {
- final long beginningTime = System.currentTimeMillis();
+ // determine which set of transactions to operate on
+ Set primarySet = milestone ? milestoneTransactionsToRequest : transactionsToRequest;
+ Set alternativeSet = milestone ? transactionsToRequest : milestoneTransactionsToRequest;
+ Set requestSet = primarySet.size() == 0 ? alternativeSet : primarySet;
+
+ // determine the first hash in our set that needs to be processed
Hash hash = null;
- Set requestSet;
- if(milestone) {
- requestSet = milestoneTransactionsToRequest;
- if(requestSet.size() == 0) {
- requestSet = transactionsToRequest;
- }
- } else {
- requestSet = transactionsToRequest;
- if(requestSet.size() == 0) {
- requestSet = milestoneTransactionsToRequest;
- }
- }
synchronized (syncObj) {
+ // repeat while we have transactions that shall be requested
while (requestSet.size() != 0) {
+ // remove the first item in our set for further examination
Iterator iterator = requestSet.iterator();
hash = iterator.next();
iterator.remove();
+
+ // if we have received the transaction in the mean time ....
if (TransactionViewModel.exists(tangle, hash)) {
+ // ... dump a log message ...
log.info("Removed existing tx from request list: " + hash);
messageQ.publish("rtl %s", hash);
- } else {
- if (!transactionsToRequestIsFull()) {
- requestSet.add(hash);
- }
- break;
+
+ // ... and continue to the next element in the set
+ continue;
}
+
+ // ... otherwise -> re-add it at the end of the set ...
+ //
+ // Note: we always have enough space since we removed the element before
+ requestSet.add(hash);
+
+ // ... and abort our loop to continue processing with the element we found
+ break;
}
}
+ // randomly drop "non-milestone" transactions so we don't keep on asking for non-existent transactions forever
if(random.nextDouble() < P_REMOVE_REQUEST && !requestSet.equals(milestoneTransactionsToRequest)) {
synchronized (syncObj) {
transactionsToRequest.remove(hash);
}
}
- long now = System.currentTimeMillis();
- if ((now - lastTime) > 10000L) {
- lastTime = now;
- //log.info("Transactions to request = {}", numberOfTransactionsToRequest() + " / " + TransactionViewModel.getNumberOfStoredTransactions() + " (" + (now - beginningTime) + " ms ). " );
- }
+ // return our result
return hash;
}
diff --git a/src/main/java/com/iota/iri/network/UDPReceiver.java b/src/main/java/com/iota/iri/network/UDPReceiver.java
index b43a048a9d..46991cb7ea 100644
--- a/src/main/java/com/iota/iri/network/UDPReceiver.java
+++ b/src/main/java/com/iota/iri/network/UDPReceiver.java
@@ -1,5 +1,6 @@
package com.iota.iri.network;
+import com.iota.iri.conf.NodeConfig;
import com.iota.iri.hash.Sponge;
import com.iota.iri.hash.SpongeFactory;
import com.iota.iri.model.Hash;
@@ -37,10 +38,10 @@ public class UDPReceiver {
private Thread receivingThread;
- public UDPReceiver(final int port, final Node node, int packetSize) {
- this.port = port;
+ public UDPReceiver(Node node, NodeConfig config) {
this.node = node;
- this.packetSize = packetSize;
+ this.port = config.getUdpReceiverPort();
+ this.packetSize = config.getTransactionPacketSize();
this.receivingPacket = new DatagramPacket(new byte[packetSize], packetSize);
}
diff --git a/src/main/java/com/iota/iri/network/replicator/Replicator.java b/src/main/java/com/iota/iri/network/replicator/Replicator.java
index e304bf7e2f..74d54e8dba 100644
--- a/src/main/java/com/iota/iri/network/replicator/Replicator.java
+++ b/src/main/java/com/iota/iri/network/replicator/Replicator.java
@@ -1,5 +1,6 @@
package com.iota.iri.network.replicator;
+import com.iota.iri.conf.NodeConfig;
import com.iota.iri.network.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -13,10 +14,11 @@ public class Replicator {
private final int port;
private ReplicatorSourcePool replicatorSourcePool;
- public Replicator(final Node node, int port, final int maxPeers, final boolean testnet, int transactionPacketSize) {
- this.port = port;
- replicatorSinkPool = new ReplicatorSinkPool(node, port, transactionPacketSize);
- replicatorSourcePool = new ReplicatorSourcePool(replicatorSinkPool, node, maxPeers, testnet);
+ public Replicator(Node node, NodeConfig configuration) {
+ this.port = configuration.getTcpReceiverPort();
+ replicatorSinkPool = new ReplicatorSinkPool(node, port, configuration.getTransactionPacketSize());
+ replicatorSourcePool = new ReplicatorSourcePool(replicatorSinkPool, node, configuration.getMaxPeers(),
+ configuration.isTestnet());
}
public void init() {
diff --git a/src/main/java/com/iota/iri/network/replicator/ReplicatorSinkProcessor.java b/src/main/java/com/iota/iri/network/replicator/ReplicatorSinkProcessor.java
index e9e0d7caf9..8084f243b8 100644
--- a/src/main/java/com/iota/iri/network/replicator/ReplicatorSinkProcessor.java
+++ b/src/main/java/com/iota/iri/network/replicator/ReplicatorSinkProcessor.java
@@ -1,5 +1,9 @@
package com.iota.iri.network.replicator;
+import com.iota.iri.network.TCPNeighbor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
@@ -7,10 +11,6 @@
import java.nio.ByteBuffer;
import java.util.zip.CRC32;
-import com.iota.iri.network.TCPNeighbor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
class ReplicatorSinkProcessor implements Runnable {
private static final Logger log = LoggerFactory.getLogger(ReplicatorSinkProcessor.class);
@@ -124,7 +124,7 @@ public void run() {
if (reason == null || reason.equals("null")) {
reason = "closed";
}
- log.error("***** NETWORK ALERT ***** No sink to host {}:{}, reason: {}", remoteAddress, neighbor.getPort(),
+ log.error("***** NETWORK ALERT ***** No sink to apiHost {}:{}, reason: {}", remoteAddress, neighbor.getPort(),
reason);
synchronized (neighbor) {
Socket sourceSocket = neighbor.getSource();
diff --git a/src/main/java/com/iota/iri/network/replicator/ReplicatorSourceProcessor.java b/src/main/java/com/iota/iri/network/replicator/ReplicatorSourceProcessor.java
index 6f1f45d425..c12ca3e628 100644
--- a/src/main/java/com/iota/iri/network/replicator/ReplicatorSourceProcessor.java
+++ b/src/main/java/com/iota/iri/network/replicator/ReplicatorSourceProcessor.java
@@ -1,5 +1,13 @@
package com.iota.iri.network.replicator;
+import com.iota.iri.conf.MainnetConfig;
+import com.iota.iri.conf.TestnetConfig;
+import com.iota.iri.network.Neighbor;
+import com.iota.iri.network.Node;
+import com.iota.iri.network.TCPNeighbor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
@@ -8,17 +16,6 @@
import java.util.List;
import java.util.zip.CRC32;
-import com.iota.iri.network.TCPNeighbor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.iota.iri.network.Neighbor;
-import com.iota.iri.conf.Configuration;
-import com.iota.iri.hash.Curl;
-import com.iota.iri.model.Hash;
-import com.iota.iri.network.Node;
-import com.iota.iri.controllers.TransactionViewModel;
-
class ReplicatorSourceProcessor implements Runnable {
private static final Logger log = LoggerFactory.getLogger(ReplicatorSourceProcessor.class);
@@ -47,8 +44,8 @@ public ReplicatorSourceProcessor(final ReplicatorSinkPool replicatorSinkPool,
this.testnet = testnet;
this.replicatorSinkPool = replicatorSinkPool;
this.packetSize = testnet
- ? Integer.parseInt(Configuration.TESTNET_PACKET_SIZE)
- : Integer.parseInt(Configuration.PACKET_SIZE);
+ ? TestnetConfig.Defaults.PACKET_SIZE
+ : MainnetConfig.Defaults.PACKET_SIZE;
}
@Override
diff --git a/src/main/java/com/iota/iri/service/API.java b/src/main/java/com/iota/iri/service/API.java
index 5798828ddf..1aa88b3b78 100644
--- a/src/main/java/com/iota/iri/service/API.java
+++ b/src/main/java/com/iota/iri/service/API.java
@@ -3,8 +3,8 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.iota.iri.*;
-import com.iota.iri.conf.Configuration;
-import com.iota.iri.conf.Configuration.DefaultConfSettings;
+import com.iota.iri.conf.APIConfig;
+import com.iota.iri.conf.ConsensusConfig;
import com.iota.iri.controllers.AddressViewModel;
import com.iota.iri.controllers.BundleViewModel;
import com.iota.iri.controllers.TagViewModel;
@@ -44,6 +44,7 @@
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.security.InvalidAlgorithmParameterException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@@ -77,8 +78,6 @@ public class API {
private final static long MAX_TIMESTAMP_VALUE = (long) (Math.pow(3, 27) - 1) / 2; // max positive 27-trits value
- private final int minRandomWalks;
- private final int maxRandomWalks;
private final int maxFindTxs;
private final int maxRequestList;
private final int maxGetTrytes;
@@ -97,24 +96,23 @@ public class API {
public API(Iota instance, IXI ixi) {
this.instance = instance;
this.ixi = ixi;
- minRandomWalks = instance.configuration.integer(DefaultConfSettings.MIN_RANDOM_WALKS);
- maxRandomWalks = instance.configuration.integer(DefaultConfSettings.MAX_RANDOM_WALKS);
- maxFindTxs = instance.configuration.integer(DefaultConfSettings.MAX_FIND_TRANSACTIONS);
- maxRequestList = instance.configuration.integer(DefaultConfSettings.MAX_REQUESTS_LIST);
- maxGetTrytes = instance.configuration.integer(DefaultConfSettings.MAX_GET_TRYTES);
- maxBodyLength = instance.configuration.integer(DefaultConfSettings.MAX_BODY_LENGTH);
- testNet = instance.configuration.booling(DefaultConfSettings.TESTNET);
- milestoneStartIndex = instance.configuration.integer(DefaultConfSettings.MILESTONE_START_INDEX);
+ APIConfig configuration = instance.configuration;
+ maxFindTxs = configuration.getMaxFindTransactions();
+ maxRequestList = configuration.getMaxRequestsList();
+ maxGetTrytes = configuration.getMaxGetTrytes();
+ maxBodyLength = configuration.getMaxBodyLength();
+ testNet = configuration.isTestnet();
+ milestoneStartIndex = ((ConsensusConfig) configuration).getMilestoneStartIndex();
previousEpochsSpentAddresses = new ConcurrentHashMap<>();
-
}
public void init() throws IOException {
readPreviousEpochsSpentAddresses(testNet);
- final int apiPort = instance.configuration.integer(DefaultConfSettings.PORT);
- final String apiHost = instance.configuration.string(DefaultConfSettings.API_HOST);
+ APIConfig configuration = instance.configuration;
+ final int apiPort = configuration.getPort();
+ final String apiHost = configuration.getApiHost();
log.debug("Binding JSON-REST API Undertow server on {}:{}", apiHost, apiPort);
@@ -151,7 +149,10 @@ private void readPreviousEpochsSpentAddresses(boolean isTestnet) throws IOExcept
return;
}
- String[] previousEpochsSpentAddressesFiles = Configuration.PREVIOUS_EPOCHS_SPENT_ADDRESSES_TXT.split(" ");
+ String[] previousEpochsSpentAddressesFiles = instance
+ .configuration
+ .getPreviousEpochSpentAddressesFiles()
+ .split(" ");
for (String previousEpochsSpentAddressesFile : previousEpochsSpentAddressesFiles) {
InputStream in = Snapshot.class.getResourceAsStream(previousEpochsSpentAddressesFile);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
@@ -197,7 +198,7 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
return ErrorResponse.create("COMMAND parameter has not been specified in the request.");
}
- if (instance.configuration.string(DefaultConfSettings.REMOTE_LIMIT_API).contains(command) &&
+ if (instance.configuration.getRemoteLimitApi().contains(command) &&
!sourceAddress.getAddress().isLoopbackAddress()) {
return AccessLimitedResponse.create("COMMAND " + command + " is not available on this node");
}
@@ -216,7 +217,7 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
if (invalidSubtangleStatus()) {
return ErrorResponse
- .create("This operations cannot be executed: The subtangle has not been updated yet.");
+ .create("This operation cannot be executed: The subtangle has not been updated yet.");
}
final String address = (String) request.get("address");
@@ -243,11 +244,11 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
}
case "broadcastTransactions": {
final List trytes = getParameterAsList(request,"trytes", TRYTES_SIZE);
- broadcastTransactionStatement(trytes);
+ broadcastTransactionsStatement(trytes);
return AbstractResponse.createEmptyResponse();
}
case "findTransactions": {
- return findTransactionStatement(request);
+ return findTransactionsStatement(request);
}
case "getBalances": {
final List addresses = getParameterAsList(request,"addresses", HASH_SIZE);
@@ -260,25 +261,18 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
case "getInclusionStates": {
if (invalidSubtangleStatus()) {
return ErrorResponse
- .create("This operations cannot be executed: The subtangle has not been updated yet.");
+ .create("This operation cannot be executed: The subtangle has not been updated yet.");
}
final List transactions = getParameterAsList(request,"transactions", HASH_SIZE);
final List tips = getParameterAsList(request,"tips", HASH_SIZE);
- return getNewInclusionStateStatement(transactions, tips);
+ return getInclusionStatesStatement(transactions, tips);
}
case "getNeighbors": {
return getNeighborsStatement();
}
case "getNodeInfo": {
- String name = instance.configuration.booling(Configuration.DefaultConfSettings.TESTNET) ? IRI.TESTNET_NAME : IRI.MAINNET_NAME;
- return GetNodeInfoResponse.create(name, IRI.VERSION, Runtime.getRuntime().availableProcessors(),
- Runtime.getRuntime().freeMemory(), System.getProperty("java.version"), Runtime.getRuntime().maxMemory(),
- Runtime.getRuntime().totalMemory(), instance.milestone.latestMilestone, instance.milestone.latestMilestoneIndex,
- instance.milestone.latestSolidSubtangleMilestone, instance.milestone.latestSolidSubtangleMilestoneIndex, instance.milestone.milestoneStartIndex,
- instance.node.howManyNeighbors(), instance.node.queuedTransactionsSize(),
- System.currentTimeMillis(), instance.tipsViewModel.size(),
- instance.transactionRequester.numberOfTransactionsToRequest());
+ return getNodeInfoStatement();
}
case "getTips": {
return getTipsStatement();
@@ -288,12 +282,12 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
Optional.of(new Hash (getParameterAsStringAndValidate(request,"reference", HASH_SIZE)))
: Optional.empty();
final int depth = getParameterAsInt(request, "depth");
- if (depth < 0 || depth > instance.tipsSelector.getMaxDepth()) {
+ if (depth < 0 || depth > instance.configuration.getMaxDepth()) {
return ErrorResponse.create("Invalid depth input");
}
try {
- List tips = getTransactionToApproveStatement(depth, reference);
+ List tips = getTransactionsToApproveStatement(depth, reference);
return GetTransactionsToApproveResponse.create(tips.get(0), tips.get(1));
} catch (RuntimeException e) {
@@ -307,8 +301,7 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
}
case "interruptAttachingToTangle": {
- pearlDiver.cancel();
- return AbstractResponse.createEmptyResponse();
+ return interruptAttachingToTangleStatement();
}
case "removeNeighbors": {
List uris = getParameterAsList(request,"uris",0);
@@ -319,7 +312,7 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
case "storeTransactions": {
try {
final List trytes = getParameterAsList(request,"trytes", TRYTES_SIZE);
- storeTransactionStatement(trytes);
+ storeTransactionsStatement(trytes);
return AbstractResponse.createEmptyResponse();
} catch (RuntimeException e) {
//transaction not valid
@@ -338,7 +331,7 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
case "checkConsistency": {
if (invalidSubtangleStatus()) {
return ErrorResponse
- .create("This operations cannot be executed: The subtangle has not been updated yet.");
+ .create("This operation cannot be executed: The subtangle has not been updated yet.");
}
final List transactions = getParameterAsList(request,"tails", HASH_SIZE);
return checkConsistencyStatement(transactions);
@@ -358,18 +351,27 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
} catch (final ValidationException e) {
log.info("API Validation failed: " + e.getLocalizedMessage());
return ErrorResponse.create(e.getLocalizedMessage());
+ } catch (final InvalidAlgorithmParameterException e) {
+ log.info("API InvalidAlgorithmParameter passed: " + e.getLocalizedMessage());
+ return ErrorResponse.create(e.getLocalizedMessage());
} catch (final Exception e) {
- log.error("API Exception: ", e);
+ log.error("API Exception: {}", e.getLocalizedMessage(), e);
return ExceptionResponse.create(e.getLocalizedMessage());
}
}
- private AbstractResponse wereAddressesSpentFromStatement(List addressesStr) throws Exception {
- final List addresses = addressesStr.stream().map(Hash::new).collect(Collectors.toList());
- final boolean[] states = new boolean[addresses.size()];
+ /**
+ * Check if a list of addresses was ever spent from, in the current epoch, or in previous epochs.
+ *
+ * @param addresses List of addresses to check if they were ever spent from.
+ * @return {@link com.iota.iri.service.dto.wereAddressesSpentFrom}
+ **/
+ private AbstractResponse wereAddressesSpentFromStatement(List addresses) throws Exception {
+ final List addressesHash = addresses.stream().map(Hash::new).collect(Collectors.toList());
+ final boolean[] states = new boolean[addressesHash.size()];
int index = 0;
- for (Hash address : addresses) {
+ for (Hash address : addressesHash) {
states[index++] = wasAddressSpentFrom(address);
}
return wereAddressesSpentFrom.create(states);
@@ -424,8 +426,20 @@ private Hash findTail(Hash hash) throws Exception {
}
- private AbstractResponse checkConsistencyStatement(List transactionsList) throws Exception {
- final List transactions = transactionsList.stream().map(Hash::new).collect(Collectors.toList());
+ /**
+ * Checks the consistency of the transactions.
+ * Marks state as false on the following checks
+ * - Transaction does not exist
+ * - Transaction is not a tail
+ * - Missing a reference transaction
+ * - Invalid bundle
+ * - Tails of tails are invalid
+ *
+ * @param tails List of transactions you want to check the consistency for
+ * @return {@link com.iota.iri.service.dto.CheckConsistency}
+ **/
+ private AbstractResponse checkConsistencyStatement(List tails) throws Exception {
+ final List transactions = tails.stream().map(Hash::new).collect(Collectors.toList());
boolean state = true;
String info = "";
@@ -455,8 +469,7 @@ private AbstractResponse checkConsistencyStatement(List transactionsList
instance.milestone.latestSnapshot.rwlock.readLock().lock();
try {
WalkValidatorImpl walkValidator = new WalkValidatorImpl(instance.tangle, instance.ledgerValidator,
- instance.transactionValidator, instance.milestone, instance.tipsSelector.getMaxDepth(),
- instance.configuration.integer(DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT));
+ instance.milestone, instance.configuration);
for (Hash transaction : transactions) {
if (!walkValidator.isValid(transaction)) {
state = false;
@@ -536,6 +549,19 @@ public boolean invalidSubtangleStatus() {
return (instance.milestone.latestSolidSubtangleMilestoneIndex == milestoneStartIndex);
}
+ /**
+ * Temporarily removes a list of neighbors from your node.
+ * The added neighbors will be added again after relaunching IRI.
+ * Remove the neighbors from your config file or make sure you don't supply them in the -n command line option if you want to keep them removed after restart.
+ *
+ * The URI (Unique Resource Identification) for removing neighbors is:
+ * udp://IPADDRESS:PORT
+ *
+ * Returns an {@link com.iota.iri.service.dto.ErrorResponse} if the URI scheme is wrong
+ *
+ * @param uris List of URI elements.
+ * @return {@link com.iota.iri.service.dto.RemoveNeighborsResponse}
+ **/
private AbstractResponse removeNeighborsStatement(List uris) {
int numberOfRemovedNeighbors = 0;
try {
@@ -551,6 +577,14 @@ private AbstractResponse removeNeighborsStatement(List uris) {
return RemoveNeighborsResponse.create(numberOfRemovedNeighbors);
}
+ /**
+ * Returns the raw transaction data (trytes) of a specific transaction.
+ * These trytes can then be easily converted into the actual transaction object.
+ * See utility functions for more details.
+ *
+ * @param hashes List of transaction hashes you want to get trytes from.
+ * @return {@link com.iota.iri.service.dto.GetTrytesResponse}
+ **/
private synchronized AbstractResponse getTrytesStatement(List hashes) throws Exception {
final List elements = new LinkedList<>();
for (final String hash : hashes) {
@@ -581,7 +615,19 @@ public static void incEllapsedTime_getTxToApprove(long ellapsedTime) {
ellapsedTime_getTxToApprove += ellapsedTime;
}
- public synchronized List getTransactionToApproveStatement(int depth, Optional reference) throws Exception {
+ /**
+ * Tip selection which returns trunkTransaction
and branchTransaction
.
+ * The input value depth
determines how many milestones to go back for finding the transactions to approve.
+ * The higher your depth
value, the more work you have to do as you are confirming more transactions.
+ * If the depth
is too large (usually above 15, it depends on the node's configuration) an error will be returned.
+ * The reference
is an optional hash of a transaction you want to approve.
+ * If it can't be found at the specified depth
then an error will be returned.
+ *
+ * @param depth Number of bundles to go back to determine the transactions for approval.
+ * @param reference Hash of transaction to start random-walk from, used to make sure the tips returned reference a given transaction in their past.
+ * @return {@link com.iota.iri.service.dto.GetTransactionsToApproveResponse}
+ **/
+ public synchronized List getTransactionsToApproveStatement(int depth, Optional reference) throws Exception {
if (invalidSubtangleStatus()) {
throw new IllegalStateException("This operations cannot be executed: The subtangle has not been updated yet.");
@@ -606,16 +652,27 @@ private void gatherStatisticsOnTipSelection() {
}
}
+ /**
+ * Returns the list of tips.
+ *
+ * @return {@link com.iota.iri.service.dto.GetTipsResponse}
+ **/
private synchronized AbstractResponse getTipsStatement() throws Exception {
return GetTipsResponse.create(instance.tipsViewModel.getTips().stream().map(Hash::toString).collect(Collectors.toList()));
}
- public void storeTransactionStatement(final List trys) throws Exception {
+ /**
+ * Store transactions into the local storage.
+ * The trytes to be used for this call are returned by attachToTangle
.
+ *
+ * @param trytes List of raw data of transactions to be rebroadcast.
+ **/
+ public void storeTransactionsStatement(final List trytes) throws Exception {
final List elements = new LinkedList<>();
byte[] txTrits = Converter.allocateTritsForTrytes(TRYTES_SIZE);
- for (final String trytes : trys) {
+ for (final String trytesPart : trytes) {
//validate all trytes
- Converter.trits(trytes, txTrits, 0);
+ Converter.trits(trytesPart, txTrits, 0);
final TransactionViewModel transactionViewModel = instance.transactionValidator.validateTrits(txTrits,
instance.transactionValidator.getMinWeightMagnitude());
elements.add(transactionViewModel);
@@ -631,19 +688,63 @@ public void storeTransactionStatement(final List trys) throws Exception
}
}
+ /**
+ * Returns the set of neighbors you are connected with, as well as their activity statistics (or counters).
+ * The activity counters are reset after restarting IRI.
+ *
+ * @return {@link com.iota.iri.service.dto.GetNeighborsResponse}
+ **/
private AbstractResponse getNeighborsStatement() {
return GetNeighborsResponse.create(instance.node.getNeighbors());
}
- private AbstractResponse getNewInclusionStateStatement(final List trans, final List tps) throws Exception {
- final List transactions = trans.stream().map(Hash::new).collect(Collectors.toList());
- final List tips = tps.stream().map(Hash::new).collect(Collectors.toList());
+ /**
+ * Interrupts and completely aborts the attachToTangle
process.
+ *
+ * @return {@link com.iota.iri.service.dto.AbstractResponse}
+ **/
+ private AbstractResponse interruptAttachingToTangleStatement(){
+ pearlDiver.cancel();
+ return AbstractResponse.createEmptyResponse();
+ }
+
+ /**
+ * Returns information about your node.
+ *
+ * @return {@link com.iota.iri.service.dto.GetNodeInfoResponse}
+ **/
+ private AbstractResponse getNodeInfoStatement(){
+ String name = instance.configuration.isTestnet() ? IRI.TESTNET_NAME : IRI.MAINNET_NAME;
+ return GetNodeInfoResponse.create(name, IRI.VERSION, Runtime.getRuntime().availableProcessors(),
+ Runtime.getRuntime().freeMemory(), System.getProperty("java.version"), Runtime.getRuntime().maxMemory(),
+ Runtime.getRuntime().totalMemory(), instance.milestone.latestMilestone, instance.milestone.latestMilestoneIndex,
+ instance.milestone.latestSolidSubtangleMilestone, instance.milestone.latestSolidSubtangleMilestoneIndex, instance.milestone.milestoneStartIndex,
+ instance.node.howManyNeighbors(), instance.node.queuedTransactionsSize(),
+ System.currentTimeMillis(), instance.tipsViewModel.size(),
+ instance.transactionRequester.numberOfTransactionsToRequest());
+ }
+
+ /**
+ * Get the inclusion states of a set of transactions.
+ * This is for determining if a transaction was accepted and confirmed by the network or not.
+ * You can search for multiple tips (and thus, milestones) to get past inclusion states of transactions.
+ *
+ * This API call simply returns a list of boolean values in the same order as the transaction list you submitted, thus you get a true/false whether a transaction is confirmed or not.
+ * Returns an {@link com.iota.iri.service.dto.ErrorResponse} if a tip is missing or the subtangle is not solid
+ *
+ * @param transactions List of transactions you want to get the inclusion state for.
+ * @param tips List of tips (including milestones) you want to search for the inclusion state.
+ * @return {@link com.iota.iri.service.dto.GetInclusionStatesResponse}
+ **/
+ private AbstractResponse getInclusionStatesStatement(final List transactions, final List tips) throws Exception {
+ final List trans = transactions.stream().map(Hash::new).collect(Collectors.toList());
+ final List tps = tips.stream().map(Hash::new).collect(Collectors.toList());
int numberOfNonMetTransactions = transactions.size();
final byte[] inclusionStates = new byte[numberOfNonMetTransactions];
List tipsIndex = new LinkedList<>();
{
- for(Hash tip: tips) {
+ for(Hash tip: tps) {
TransactionViewModel tx = TransactionViewModel.fromHash(instance.tangle, tip);
if (tx.getType() != TransactionViewModel.PREFILLED_SLOT) {
tipsIndex.add(tx.snapshotIndex());
@@ -654,7 +755,7 @@ private AbstractResponse getNewInclusionStateStatement(final List trans,
if(minTipsIndex > 0) {
int maxTipsIndex = tipsIndex.stream().reduce((a,b) -> a > b ? a : b).orElse(0);
int count = 0;
- for(Hash hash: transactions) {
+ for(Hash hash: trans) {
TransactionViewModel transaction = TransactionViewModel.fromHash(instance.tangle, hash);
if(transaction.getType() == TransactionViewModel.PREFILLED_SLOT || transaction.snapshotIndex() == 0) {
inclusionStates[count] = -1;
@@ -670,10 +771,10 @@ private AbstractResponse getNewInclusionStateStatement(final List trans,
Set analyzedTips = new HashSet<>();
Map sameIndexTransactionCount = new HashMap<>();
Map> sameIndexTips = new HashMap<>();
- for (final Hash tip : tips) {
+ for (final Hash tip : tps) {
TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(instance.tangle, tip);
if (transactionViewModel.getType() == TransactionViewModel.PREFILLED_SLOT){
- return ErrorResponse.create("One of the tips absents");
+ return ErrorResponse.create("One of the tips is absent");
}
int snapshotIndex = transactionViewModel.snapshotIndex();
sameIndexTips.putIfAbsent(snapshotIndex, new LinkedList<>());
@@ -681,7 +782,7 @@ private AbstractResponse getNewInclusionStateStatement(final List trans,
}
for(int i = 0; i < inclusionStates.length; i++) {
if(inclusionStates[i] == 0) {
- TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(instance.tangle, transactions.get(i));
+ TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(instance.tangle, trans.get(i));
int snapshotIndex = transactionViewModel.snapshotIndex();
sameIndexTransactionCount.putIfAbsent(snapshotIndex, 0);
sameIndexTransactionCount.put(snapshotIndex, sameIndexTransactionCount.get(snapshotIndex) + 1);
@@ -691,7 +792,7 @@ private AbstractResponse getNewInclusionStateStatement(final List trans,
Queue sameIndexTip = sameIndexTips.get(index);
if (sameIndexTip != null) {
//has tips in the same index level
- if (!exhaustiveSearchWithinIndex(sameIndexTip, analyzedTips, transactions, inclusionStates, sameIndexTransactionCount.get(index), index)) {
+ if (!exhaustiveSearchWithinIndex(sameIndexTip, analyzedTips, trans, inclusionStates, sameIndexTransactionCount.get(index), index)) {
return ErrorResponse.create("The subtangle is not solid");
}
}
@@ -731,7 +832,18 @@ private boolean exhaustiveSearchWithinIndex(Queue nonAnalyzedTransactions,
return true;
}
- private synchronized AbstractResponse findTransactionStatement(final Map request) throws Exception {
+ /**
+ * Find the transactions which match the specified input and return.
+ * All input values are lists, for which a list of return values (transaction hashes), in the same order, is returned for all individual elements.
+ * The input fields can either be bundles, addresses
, tags
or approvees
.
+ * Using multiple of these input fields returns the intersection of the values.
+ *
+ * Returns an {@link com.iota.iri.service.dto.ErrorResponse} if more than maxFindTxs was found
+ *
+ * @param request the map with input fields
+ * @return {@link com.iota.iri.service.dto.FindTransactionsResponse}
+ **/
+ private synchronized AbstractResponse findTransactionsStatement(final Map request) throws Exception {
final Set foundTransactions = new HashSet<>();
boolean containsKey = false;
@@ -831,10 +943,16 @@ private HashSet getParameterAsSet(Map request, String pa
return result;
}
- public void broadcastTransactionStatement(final List trytes2) {
+ /**
+ * Broadcast a list of transactions to all neighbors.
+ * The input trytes for this call are provided by attachToTangle
.
+ *
+ * @param trytes the list of transaction
+ **/
+ public void broadcastTransactionsStatement(final List trytes) {
final List elements = new LinkedList<>();
byte[] txTrits = Converter.allocateTritsForTrytes(TRYTES_SIZE);
- for (final String tryte : trytes2) {
+ for (final String tryte : trytes) {
//validate all trytes
Converter.trits(tryte, txTrits, 0);
final TransactionViewModel transactionViewModel = instance.transactionValidator.validateTrits(txTrits, instance.transactionValidator.getMinWeightMagnitude());
@@ -847,13 +965,26 @@ public void broadcastTransactionStatement(final List trytes2) {
}
}
- private AbstractResponse getBalancesStatement(final List addrss, final List tips, final int threshold) throws Exception {
+
+ /**
+ * Returns the confirmed balance, as viewed by the specified tips
. If you do not specify the referencing tips
, the returned balance is based on the latest confirmed milestone.
+ * In addition to the balances, it also returns the referencing tips
(or milestone), as well as the index with which the confirmed balance was determined.
+ * The balances are returned as a list in the same order as the addresses were provided as input.
+ *
+ * Returns an {@link com.iota.iri.service.dto.ErrorResponse} if tips are not found or inconsistent, or the treshold is invalid
+ *
+ * @param addresses the address to get the balance for
+ * @param tips the tips to find the balance through
+ * @param threshold the confirmation threshold between 0 and 100(incl)
+ * @return {@link com.iota.iri.service.dto.GetBalancesResponse}
+ **/
+ private AbstractResponse getBalancesStatement(final List addresses, final List tips, final int threshold) throws Exception {
if (threshold <= 0 || threshold > 100) {
return ErrorResponse.create("Illegal 'threshold'");
}
- final List addresses = addrss.stream().map(address -> (new Hash(address)))
+ final List addressList = addresses.stream().map(address -> (new Hash(address)))
.collect(Collectors.toCollection(LinkedList::new));
final List hashes;
final Map balances = new HashMap<>();
@@ -866,7 +997,7 @@ private AbstractResponse getBalancesStatement(final List addrss, final L
.collect(Collectors.toCollection(LinkedList::new));
}
try {
- for (final Hash address : addresses) {
+ for (final Hash address : addressList) {
Long value = instance.milestone.latestSnapshot.getBalance(address);
if (value == null) {
value = 0L;
@@ -892,7 +1023,7 @@ private AbstractResponse getBalancesStatement(final List addrss, final L
instance.milestone.latestSnapshot.rwlock.readLock().unlock();
}
- final List elements = addresses.stream().map(address -> balances.get(address).toString())
+ final List elements = addressList.stream().map(address -> balances.get(address).toString())
.collect(Collectors.toCollection(LinkedList::new));
return GetBalancesResponse.create(elements, hashes.stream().map(h -> h.toString()).collect(Collectors.toList()), index);
@@ -914,6 +1045,20 @@ public static void incEllapsedTime_PoW(long ellapsedTime) {
ellapsedTime_PoW += ellapsedTime;
}
+ /**
+ * Attaches the specified transactions (trytes) to the Tangle by doing Proof of Work.
+ * You need to supply branchTransaction
as well as trunkTransaction
(the tips which you're going to validate and reference with this transaction) - both of which you'll get through the getTransactionsToApprove
API call.
+ *
+ * The returned value is a different set of tryte values which you can input into broadcastTransactions
and storeTransactions
.
+ * The last 243 trytes of the return value consist of the: trunkTransaction
+ branchTransaction
+ nonce
.
+ * These are valid trytes which are then accepted by the network.
+ *
+ * @param trunkTransaction the trunk transaction
+ * @param branchTransaction the branch transaction
+ * @param minWeightMagnitude the minimum weight magnitute
+ * @param trytes the list of trytes to attach
+ * @return trytes the list of transactions in trytes
+ **/
public synchronized List attachToTangleStatement(final Hash trunkTransaction, final Hash branchTransaction,
final int minWeightMagnitude, final List trytes) {
final List transactionViewModels = new LinkedList<>();
@@ -981,6 +1126,17 @@ public synchronized List attachToTangleStatement(final Hash trunkTransac
return elements;
}
+ /**
+ * Temporarily add a list of neighbors to your node.
+ * The added neighbors will be removed after relaunching IRI.
+ * Add the neighbors to your config file or supply them in the -n command line option if you want to keep them after restart.
+ *
+ * The URI (Unique Resource Identification) for adding neighbors is:
+ * udp://IPADDRESS:PORT
+ *
+ * @param uris list of neighbors to add
+ * @return {@link com.iota.iri.service.dto.AddedNeighborsResponse}
+ **/
private AbstractResponse addNeighborsStatement(final List uris) {
int numberOfAddedNeighbors = 0;
try {
@@ -1054,7 +1210,7 @@ private static void setupResponseHeaders(final HttpServerExchange exchange) {
}
private HttpHandler addSecurity(final HttpHandler toWrap) {
- String credentials = instance.configuration.string(DefaultConfSettings.REMOTE_AUTH);
+ String credentials = instance.configuration.getRemoteAuth();
if (credentials == null || credentials.isEmpty()) {
return toWrap;
}
@@ -1078,9 +1234,15 @@ public void shutDown() {
}
}
- //only available on testnet
+ /**
+ * Only available on testnet.
+ * Creates, attaches, and broadcasts a transaction with this message
+ *
+ * @param address The address to add the message to
+ * @param message The message to store
+ **/
private synchronized void storeMessageStatement(final String address, final String message) throws Exception {
- final List txToApprove = getTransactionToApproveStatement(3, Optional.empty());
+ final List txToApprove = getTransactionsToApproveStatement(3, Optional.empty());
final int txMessageSize = TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_SIZE / 3;
@@ -1141,6 +1303,6 @@ private synchronized void storeMessageStatement(final String address, final Stri
// do pow
List powResult = attachToTangleStatement(txToApprove.get(0), txToApprove.get(1), 9, transactions);
- broadcastTransactionStatement(powResult);
+ broadcastTransactionsStatement(powResult);
}
}
diff --git a/src/main/java/com/iota/iri/service/TipsSolidifier.java b/src/main/java/com/iota/iri/service/TipsSolidifier.java
index 010d21fbba..c885ccc851 100644
--- a/src/main/java/com/iota/iri/service/TipsSolidifier.java
+++ b/src/main/java/com/iota/iri/service/TipsSolidifier.java
@@ -30,9 +30,17 @@ public TipsSolidifier(final Tangle tangle,
public void init() {
solidityRescanHandle = new Thread(() -> {
+ long lastTime = 0;
while (!shuttingDown) {
try {
scanTipsForSolidity();
+ if (log.isDebugEnabled()) {
+ long now = System.currentTimeMillis();
+ if ((now - lastTime) > 10000L) {
+ lastTime = now;
+ log.debug("#Solid/NonSolid: {}/{}", tipsViewModel.solidSize(), tipsViewModel.nonSolidSize());
+ }
+ }
} catch (Exception e) {
log.error("Error during solidity scan : {}", e);
}
diff --git a/src/main/java/com/iota/iri/service/dto/AbstractResponse.java b/src/main/java/com/iota/iri/service/dto/AbstractResponse.java
index 8dd793f2af..fd66c3d67f 100644
--- a/src/main/java/com/iota/iri/service/dto/AbstractResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/AbstractResponse.java
@@ -5,17 +5,28 @@
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
+/**
+ *
+ * Abstract response.
+ *
+ **/
public abstract class AbstractResponse {
private static class Emptyness extends AbstractResponse {}
private Integer duration;
+ /**
+ * Returns a String that represents this object.
+ *
+ * @return Returns a string representation of this object.
+ */
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
+
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, false);
@@ -26,14 +37,29 @@ public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj, false);
}
+ /**
+ * The duration it took to process this command in milliseconds
+ *
+ * @return The duration.
+ */
public Integer getDuration() {
return duration;
}
+ /**
+ * Sets the duration.
+ *
+ * @param duration The duration
+ */
public void setDuration(Integer duration) {
this.duration = duration;
}
+ /**
+ * Returns an empty AbstractResponse
+ *
+ * @return Returns an empty AbstractResponse
+ */
public static AbstractResponse createEmptyResponse() {
return new Emptyness();
}
diff --git a/src/main/java/com/iota/iri/service/dto/AccessLimitedResponse.java b/src/main/java/com/iota/iri/service/dto/AccessLimitedResponse.java
index 8f8c7bc577..cab0a03df8 100644
--- a/src/main/java/com/iota/iri/service/dto/AccessLimitedResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/AccessLimitedResponse.java
@@ -1,7 +1,7 @@
package com.iota.iri.service.dto;
/**
- * Created by Adrian on 07.01.2017.
+ * This class represents the core API error for accessing a command which is limited by this Node.
*/
public class AccessLimitedResponse extends AbstractResponse {
@@ -13,6 +13,11 @@ public static AbstractResponse create(String error) {
return res;
}
+ /**
+ * Gets the error
+ *
+ * @return The error.
+ */
public String getError() {
return error;
}
diff --git a/src/main/java/com/iota/iri/service/dto/AddedNeighborsResponse.java b/src/main/java/com/iota/iri/service/dto/AddedNeighborsResponse.java
index 683abba34b..a07e4c66ef 100644
--- a/src/main/java/com/iota/iri/service/dto/AddedNeighborsResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/AddedNeighborsResponse.java
@@ -10,6 +10,11 @@ public static AbstractResponse create(int numberOfAddedNeighbors) {
return res;
}
+ /**
+ * Gets the number of added neighbors.
+ *
+ * @return The number of added neighbors.
+ */
public int getAddedNeighbors() {
return addedNeighbors;
}
diff --git a/src/main/java/com/iota/iri/service/dto/AttachToTangleResponse.java b/src/main/java/com/iota/iri/service/dto/AttachToTangleResponse.java
index 62efd60229..6803d840bc 100644
--- a/src/main/java/com/iota/iri/service/dto/AttachToTangleResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/AttachToTangleResponse.java
@@ -11,7 +11,13 @@ public static AbstractResponse create(List elements) {
res.trytes = elements;
return res;
}
-
+
+ /**
+ * The processed transactions which you can input into broadcastTransactions and storeTransactions
+ * The last 243 trytes basically consist of the: trunkTransaction + branchTransaction + nonce.
+ *
+ * @return The trytes.
+ */
public List getTrytes() {
return trytes;
}
diff --git a/src/main/java/com/iota/iri/service/dto/CheckConsistency.java b/src/main/java/com/iota/iri/service/dto/CheckConsistency.java
index 4049301a22..3e9f61a75d 100644
--- a/src/main/java/com/iota/iri/service/dto/CheckConsistency.java
+++ b/src/main/java/com/iota/iri/service/dto/CheckConsistency.java
@@ -3,6 +3,7 @@
public class CheckConsistency extends AbstractResponse {
private boolean state;
+
private String info;
public static AbstractResponse create(boolean state, String info) {
@@ -12,4 +13,21 @@ public static AbstractResponse create(boolean state, String info) {
return res;
}
+ /**
+ * The state of the transaction
+ *
+ * @return The state.
+ */
+ public boolean getState() {
+ return state;
+ }
+
+ /**
+ * Information about the state
+ *
+ * @return The info.
+ */
+ public String getInfo() {
+ return info;
+ }
}
diff --git a/src/main/java/com/iota/iri/service/dto/ErrorResponse.java b/src/main/java/com/iota/iri/service/dto/ErrorResponse.java
index 31b9f8b5ff..430667f436 100644
--- a/src/main/java/com/iota/iri/service/dto/ErrorResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/ErrorResponse.java
@@ -1,5 +1,8 @@
package com.iota.iri.service.dto;
+/**
+ * This class represents the core API error response.
+ **/
public class ErrorResponse extends AbstractResponse {
private String error;
@@ -9,7 +12,12 @@ public static AbstractResponse create(String error) {
res.error = error;
return res;
}
-
+
+ /**
+ * Gets the error
+ *
+ * @return The error.
+ */
public String getError() {
return error;
}
diff --git a/src/main/java/com/iota/iri/service/dto/ExceptionResponse.java b/src/main/java/com/iota/iri/service/dto/ExceptionResponse.java
index 552d737b1c..138f14be80 100644
--- a/src/main/java/com/iota/iri/service/dto/ExceptionResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/ExceptionResponse.java
@@ -1,5 +1,8 @@
package com.iota.iri.service.dto;
+/**
+ * This class represents the core API exception response.
+ **/
public class ExceptionResponse extends AbstractResponse {
private String exception;
@@ -9,7 +12,12 @@ public static AbstractResponse create(String exception) {
res.exception = exception;
return res;
}
-
+
+ /**
+ * Gets the exception
+ *
+ * @return The exception.
+ */
public String getException() {
return exception;
}
diff --git a/src/main/java/com/iota/iri/service/dto/FindTransactionsResponse.java b/src/main/java/com/iota/iri/service/dto/FindTransactionsResponse.java
index 7928ccd2b5..8e63a28234 100644
--- a/src/main/java/com/iota/iri/service/dto/FindTransactionsResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/FindTransactionsResponse.java
@@ -12,6 +12,16 @@ public static AbstractResponse create(List elements) {
return res;
}
+ /**
+ * The transaction hashes which are returned depend on your input.
+ * For each specified input value, the command will return the following:
+ * bundles
: returns the list of transactions which contain the specified bundle hash.
+ * addresses
: returns the list of transactions which have the specified address as an input/output field.
+ * tags
: returns the list of transactions which contain the specified tag value.
+ * approvees
: returns the list of transactions which reference (i.e. confirm) the specified transaction.
+ *
+ * @return The hashes.
+ */
public String[] getHashes() {
return hashes;
}
diff --git a/src/main/java/com/iota/iri/service/dto/GetBalancesResponse.java b/src/main/java/com/iota/iri/service/dto/GetBalancesResponse.java
index c3575f706f..d75214778f 100644
--- a/src/main/java/com/iota/iri/service/dto/GetBalancesResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/GetBalancesResponse.java
@@ -16,14 +16,29 @@ public static AbstractResponse create(List elements, List refere
return res;
}
+ /**
+ * The referencing tips
+ *
+ * @return The references.
+ */
public List getReferences() {
return references;
}
+ /**
+ * The index with which the confirmed balance was determined
+ *
+ * @return The milestoneIndex.
+ */
public int getMilestoneIndex() {
return milestoneIndex;
}
+ /**
+ * The balances as a list in the same order as the addresses were provided as input
+ *
+ * @return The balances.
+ */
public List getBalances() {
return balances;
}
diff --git a/src/main/java/com/iota/iri/service/dto/GetInclusionStatesResponse.java b/src/main/java/com/iota/iri/service/dto/GetInclusionStatesResponse.java
index e376e77b1e..84d4ed78c1 100644
--- a/src/main/java/com/iota/iri/service/dto/GetInclusionStatesResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/GetInclusionStatesResponse.java
@@ -1,7 +1,7 @@
package com.iota.iri.service.dto;
public class GetInclusionStatesResponse extends AbstractResponse {
-
+
private boolean [] states;
public static AbstractResponse create(boolean[] inclusionStates) {
@@ -10,6 +10,12 @@ public static AbstractResponse create(boolean[] inclusionStates) {
return res;
}
+ /**
+ * List of boolean values in the same order as the transaction list you submitted,
+ * thus you get a true/false whether a transaction is confirmed or not.
+ *
+ * @return The states.
+ */
public boolean[] getStates() {
return states;
}
diff --git a/src/main/java/com/iota/iri/service/dto/GetNeighborsResponse.java b/src/main/java/com/iota/iri/service/dto/GetNeighborsResponse.java
index 80188700bb..2f5c8ea37b 100644
--- a/src/main/java/com/iota/iri/service/dto/GetNeighborsResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/GetNeighborsResponse.java
@@ -6,36 +6,76 @@ public class GetNeighborsResponse extends AbstractResponse {
private Neighbor[] neighbors;
+ /**
+ * The list of neighbors, including the following stats:
+ * address, connectionType,
+ * numberOfAllTransactions, numberOfRandomTransactionRequests,
+ * numberOfNewTransactions, numberOfInvalidTransactions, numberOfSentTransactions
+ *
+ * @see {@link com.iota.iri.service.dto.GetNeighborsResponse.Neighbor}
+ * @return the neighbors
+ */
public Neighbor[] getNeighbors() {
return neighbors;
}
-
+
static class Neighbor {
private String address;
public long numberOfAllTransactions, numberOfRandomTransactionRequests, numberOfNewTransactions, numberOfInvalidTransactions, numberOfSentTransactions;
public String connectionType;
+ /**
+ * The address of your peer
+ *
+ * @return the address
+ */
public String getAddress() {
return address;
}
+ /**
+ * Number of all transactions sent (invalid, valid, already-seen)
+ *
+ * @return the number
+ */
public long getNumberOfAllTransactions() {
return numberOfAllTransactions;
}
+ /**
+ * New transactions which were transmitted.
+ *
+ * @return the number
+ */
public long getNumberOfNewTransactions() {
return numberOfNewTransactions;
}
+ /**
+ * Invalid transactions your peer has sent you.
+ * These are transactions with invalid signatures or overall schema.
+ *
+ * @return the number
+ */
public long getNumberOfInvalidTransactions() {
return numberOfInvalidTransactions;
}
+ /**
+ * Amount of transactions send through your peer
+ *
+ * @return the number
+ */
public long getNumberOfSentTransactions() {
return numberOfSentTransactions;
}
+ /**
+ * The method type your peer is using to connect (TCP / UDP)
+ *
+ * @return the connection type
+ */
public String getConnectionType() {
return connectionType;
}
diff --git a/src/main/java/com/iota/iri/service/dto/GetNodeInfoResponse.java b/src/main/java/com/iota/iri/service/dto/GetNodeInfoResponse.java
index cff4f05e40..2f9ef7b66d 100644
--- a/src/main/java/com/iota/iri/service/dto/GetNodeInfoResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/GetNodeInfoResponse.java
@@ -56,70 +56,160 @@ public static AbstractResponse create(String appName, String appVersion, int jre
return res;
}
+ /**
+ * Name of the IOTA software you're currently using (IRI stands for IOTA Reference Implementation)
+ *
+ * @return The app name.
+ */
public String getAppName() {
return appName;
}
-
+
+ /**
+ * The version of the IOTA software you're currently running.
+ *
+ * @return The app version.
+ */
public String getAppVersion() {
return appVersion;
}
+ /**
+ * Available cores on your machine for JRE.
+ *
+ * @return The available processors of the JRE.
+ */
public int getJreAvailableProcessors() {
return jreAvailableProcessors;
}
+ /**
+ * The amount of free memory in the Java Virtual Machine.
+ *
+ * @return The free memory of the JRE.
+ */
public long getJreFreeMemory() {
return jreFreeMemory;
}
+ /**
+ * The maximum amount of memory that the Java virtual machine will attempt to use.
+ *
+ * @return The maximum memory of the JRE.
+ */
public long getJreMaxMemory() {
return jreMaxMemory;
}
+ /**
+ * The total amount of memory in the Java virtual machine.
+ *
+ * @return The total memory of the JRE.
+ */
public long getJreTotalMemory() {
return jreTotalMemory;
}
+ /**
+ * The JRE version this node runs on
+ *
+ * @return The JRE version.
+ */
public String getJreVersion() {
return jreVersion;
}
+ /**
+ * The hash of the latest transaction that was signed off by the coordinator.
+ *
+ * @return The latest milestone.
+ */
public String getLatestMilestone() {
return latestMilestone;
}
+ /**
+ * Index of the latest milestone.
+ *
+ * @return The latest milestone index.
+ */
public int getLatestMilestoneIndex() {
return latestMilestoneIndex;
}
+ /**
+ * The hash of the latest transaction which is solid and is used for sending transactions.
+ * For a milestone to become solid your local node must basically approve the subtangle of coordinator-approved transactions,
+ * and have a consistent view of all referenced transactions.
+ *
+ * @return The latest subtangle milestone hash.
+ */
public String getLatestSolidSubtangleMilestone() {
return latestSolidSubtangleMilestone;
}
+ /**
+ * Index of the latest solid subtangle.
+ *
+ * @return The latest subtangle milestone index.
+ */
public int getLatestSolidSubtangleMilestoneIndex() {
return latestSolidSubtangleMilestoneIndex;
}
+ /**
+ * Gets the start milestone index
+ *
+ * @return The start milestone index.
+ */
public int getMilestoneStartIndex() {
return milestoneStartIndex;
}
+ /**
+ * Number of neighbors you are directly connected with.
+ *
+ * @return The neighbors.
+ */
public int getNeighbors() {
return neighbors;
}
+ /**
+ * Packets which are currently queued up.
+ *
+ * @return The size of the packets queue.
+ */
public int getPacketsQueueSize() {
return packetsQueueSize;
}
+ /**
+ * Current UNIX timestamp.
+ *
+ * @return The time.
+ */
public long getTime() {
return time;
}
+ /**
+ * Number of tips in the network.
+ *
+ * @return The tips.
+ */
public int getTips() {
return tips;
}
+ /**
+ * When a node receives a transaction from one of its neighbors, this transaction is referencing two other transactions t1 and t2 (trunk and branch transaction).
+ * If either t1 or t2 (or both) is not in the node's local database, then the transaction hash of t1 (or t2 or both) is added to the queue of the "transactions to request".
+ * At some point, the node will process this queue and ask for details about transactions in the "transaction to request" queue from one of its neighbors.
+ * By this means, nodes solidify their view of the tangle (i.e. filling in the unknown parts).
+ *
+ * @return The transactions to tequest.
+ */
public int getTransactionsToRequest() {
return transactionsToRequest;
}
diff --git a/src/main/java/com/iota/iri/service/dto/GetTipsResponse.java b/src/main/java/com/iota/iri/service/dto/GetTipsResponse.java
index 7ba9e91c16..496a1d60b1 100644
--- a/src/main/java/com/iota/iri/service/dto/GetTipsResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/GetTipsResponse.java
@@ -12,6 +12,11 @@ public static AbstractResponse create(List elements) {
return res;
}
+ /**
+ * The list of current tips
+ *
+ * @return The hashes.
+ */
public String[] getHashes() {
return hashes;
}
diff --git a/src/main/java/com/iota/iri/service/dto/GetTransactionsToApproveResponse.java b/src/main/java/com/iota/iri/service/dto/GetTransactionsToApproveResponse.java
index 19cf8eb097..d9cd81c3d3 100644
--- a/src/main/java/com/iota/iri/service/dto/GetTransactionsToApproveResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/GetTransactionsToApproveResponse.java
@@ -14,10 +14,20 @@ public static AbstractResponse create(Hash trunkTransactionToApprove, Hash branc
return res;
}
+ /**
+ * The branch transaction
+ *
+ * @return The branch transaction.
+ */
public String getBranchTransaction() {
return branchTransaction;
}
+ /**
+ * The trunk transaction
+ *
+ * @return The trunk transaction.
+ */
public String getTrunkTransaction() {
return trunkTransaction;
}
diff --git a/src/main/java/com/iota/iri/service/dto/GetTrytesResponse.java b/src/main/java/com/iota/iri/service/dto/GetTrytesResponse.java
index 4541c5b781..2fafeb66a7 100644
--- a/src/main/java/com/iota/iri/service/dto/GetTrytesResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/GetTrytesResponse.java
@@ -12,6 +12,11 @@ public static GetTrytesResponse create(List elements) {
return res;
}
+ /**
+ * The raw transaction data (trytes) of the specified transactions
+ *
+ * @return The trytes
+ */
public String [] getTrytes() {
return trytes;
}
diff --git a/src/main/java/com/iota/iri/service/dto/RemoveNeighborsResponse.java b/src/main/java/com/iota/iri/service/dto/RemoveNeighborsResponse.java
index b679dda25c..8cbc96c8f8 100644
--- a/src/main/java/com/iota/iri/service/dto/RemoveNeighborsResponse.java
+++ b/src/main/java/com/iota/iri/service/dto/RemoveNeighborsResponse.java
@@ -10,6 +10,11 @@ public static AbstractResponse create(int numberOfRemovedNeighbors) {
return res;
}
+ /**
+ * The number of removed neighbors.
+ *
+ * @return The number of removed neighbors.
+ */
public int getRemovedNeighbors() {
return removedNeighbors;
}
diff --git a/src/main/java/com/iota/iri/service/dto/wereAddressesSpentFrom.java b/src/main/java/com/iota/iri/service/dto/wereAddressesSpentFrom.java
index 77b8d0a787..d25adbc36c 100644
--- a/src/main/java/com/iota/iri/service/dto/wereAddressesSpentFrom.java
+++ b/src/main/java/com/iota/iri/service/dto/wereAddressesSpentFrom.java
@@ -10,6 +10,11 @@ public static AbstractResponse create(boolean[] inclusionStates) {
return res;
}
+ /**
+ * States of the specified addresses in Boolean
+ *
+ * @return The states.
+ */
public boolean[] getStates() {
return states;
}
diff --git a/src/main/java/com/iota/iri/service/tipselection/TipSelector.java b/src/main/java/com/iota/iri/service/tipselection/TipSelector.java
index 4561a25926..83d4cf279f 100644
--- a/src/main/java/com/iota/iri/service/tipselection/TipSelector.java
+++ b/src/main/java/com/iota/iri/service/tipselection/TipSelector.java
@@ -1,6 +1,7 @@
package com.iota.iri.service.tipselection;
import com.iota.iri.model.Hash;
+
import java.util.List;
import java.util.Optional;
@@ -25,6 +26,4 @@ public interface TipSelector {
* @throws Exception If DB fails to retrieve transactions
*/
List getTransactionsToApprove(int depth, Optional reference) throws Exception;
-
- int getMaxDepth();
}
diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImpl.java
index d1837c6728..f41ea77029 100644
--- a/src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImpl.java
+++ b/src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImpl.java
@@ -1,6 +1,7 @@
package com.iota.iri.service.tipselection.impl;
import com.iota.iri.Milestone;
+import com.iota.iri.conf.TipSelConfig;
import com.iota.iri.controllers.MilestoneViewModel;
import com.iota.iri.model.Hash;
import com.iota.iri.service.tipselection.EntryPointSelector;
@@ -16,21 +17,20 @@ public class EntryPointSelectorImpl implements EntryPointSelector {
private final Tangle tangle;
private final Milestone milestone;
private final boolean testnet;
- private final int milestoneStartIndex;
- public EntryPointSelectorImpl(Tangle tangle, Milestone milestone, boolean testnet, int milestoneStartIndex) {
+ public EntryPointSelectorImpl(Tangle tangle, Milestone milestone, TipSelConfig config) {
this.tangle = tangle;
this.milestone = milestone;
- this.testnet = testnet;
- this.milestoneStartIndex = milestoneStartIndex;
+ this.testnet = config.isTestnet();
}
@Override
public Hash getEntryPoint(int depth) throws Exception {
int milestoneIndex = Math.max(milestone.latestSolidSubtangleMilestoneIndex - depth - 1, 0);
MilestoneViewModel milestoneViewModel =
- MilestoneViewModel.findClosestNextMilestone(tangle, milestoneIndex, testnet, milestoneStartIndex);
+ MilestoneViewModel.findClosestNextMilestone(tangle, milestoneIndex, testnet,
+ milestone.getMilestoneStartIndex());
if (milestoneViewModel != null && milestoneViewModel.getHash() != null) {
return milestoneViewModel.getHash();
}
diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java
index a8ecfaff49..85f9c87766 100644
--- a/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java
+++ b/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java
@@ -2,7 +2,7 @@
import com.iota.iri.LedgerValidator;
import com.iota.iri.Milestone;
-import com.iota.iri.TransactionValidator;
+import com.iota.iri.conf.TipSelConfig;
import com.iota.iri.model.Hash;
import com.iota.iri.model.HashId;
import com.iota.iri.service.tipselection.*;
@@ -28,28 +28,18 @@ public class TipSelectorImpl implements TipSelector {
private final RatingCalculator ratingCalculator;
private final Walker walker;
- private final int maxDepth;
private final LedgerValidator ledgerValidator;
- private final TransactionValidator transactionValidator;
private final Tangle tangle;
private final Milestone milestone;
- private final int belowMaxDepthTxLimit;
-
- @Override
- public int getMaxDepth() {
- return maxDepth;
- }
+ private final TipSelConfig config;
public TipSelectorImpl(Tangle tangle,
LedgerValidator ledgerValidator,
- TransactionValidator transactionValidator,
EntryPointSelector entryPointSelector,
RatingCalculator ratingCalculator,
Walker walkerAlpha,
Milestone milestone,
- int maxDepth,
- int belowMaxDepthTxLimit) {
-
+ TipSelConfig config) {
this.entryPointSelector = entryPointSelector;
this.ratingCalculator = ratingCalculator;
@@ -57,12 +47,10 @@ public TipSelectorImpl(Tangle tangle,
this.walker = walkerAlpha;
//used by walkValidator
- this.maxDepth = maxDepth;
- this.belowMaxDepthTxLimit = belowMaxDepthTxLimit;
this.ledgerValidator = ledgerValidator;
- this.transactionValidator = transactionValidator;
this.tangle = tangle;
this.milestone = milestone;
+ this.config = config;
}
/**
@@ -92,8 +80,7 @@ public List getTransactionsToApprove(int depth, Optional reference)
//random walk
List tips = new LinkedList<>();
- WalkValidator walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestone,
- maxDepth, belowMaxDepthTxLimit);
+ WalkValidator walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, milestone, config);
Hash tip = walker.walk(entryPoint, rating, walkValidator);
tips.add(tip);
diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java
index a1ecef191e..289c1a7df1 100644
--- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java
+++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java
@@ -2,7 +2,7 @@
import com.iota.iri.LedgerValidator;
import com.iota.iri.Milestone;
-import com.iota.iri.TransactionValidator;
+import com.iota.iri.conf.TipSelConfig;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.model.Hash;
import com.iota.iri.service.tipselection.WalkValidator;
@@ -26,28 +26,22 @@
*/
public class WalkValidatorImpl implements WalkValidator {
- private int maxAnalyzedTxs;
-
private final Tangle tangle;
private final Logger log = LoggerFactory.getLogger(WalkValidator.class);
private final LedgerValidator ledgerValidator;
- private final TransactionValidator transactionValidator;
private final Milestone milestone;
+ private final TipSelConfig config;
- private final int maxDepth;
private Set maxDepthOkMemoization;
private Map myDiff;
private Set myApprovedHashes;
- public WalkValidatorImpl(Tangle tangle, LedgerValidator ledgerValidator, TransactionValidator transactionValidator,
- Milestone milestone, int maxDepth, int maxAnalyzedTxs) {
+ public WalkValidatorImpl(Tangle tangle, LedgerValidator ledgerValidator, Milestone milestone, TipSelConfig config) {
this.tangle = tangle;
this.ledgerValidator = ledgerValidator;
- this.transactionValidator = transactionValidator;
this.milestone = milestone;
- this.maxDepth = maxDepth;
- this.maxAnalyzedTxs = maxAnalyzedTxs;
+ this.config = config;
maxDepthOkMemoization = new HashSet<>();
myDiff = new HashMap<>();
@@ -67,7 +61,8 @@ public boolean isValid(Hash transactionHash) throws Exception {
} else if (!transactionViewModel.isSolid()) {
log.debug("Validation failed: {} is not solid", transactionHash);
return false;
- } else if (belowMaxDepth(transactionViewModel.getHash(), milestone.latestSolidSubtangleMilestoneIndex - maxDepth)) {
+ } else if (belowMaxDepth(transactionViewModel.getHash(),
+ milestone.latestSolidSubtangleMilestoneIndex - config.getMaxDepth())) {
log.debug("Validation failed: {} is below max depth", transactionHash);
return false;
} else if (!ledgerValidator.updateDiff(myApprovedHashes, myDiff, transactionViewModel.getHash())) {
@@ -86,10 +81,11 @@ private boolean belowMaxDepth(Hash tip, int lowerAllowedSnapshotIndex) throws Ex
Queue nonAnalyzedTransactions = new LinkedList<>(Collections.singleton(tip));
Set analyzedTransactions = new HashSet<>();
Hash hash;
+ final int maxAnalyzedTransactions = config.getBelowMaxDepthTransactionLimit();
while ((hash = nonAnalyzedTransactions.poll()) != null) {
- if (analyzedTransactions.size() == maxAnalyzedTxs) {
+ if (analyzedTransactions.size() == maxAnalyzedTransactions) {
log.debug("failed below max depth because of exceeding max threshold of {} analyzed transactions",
- maxAnalyzedTxs);
+ maxAnalyzedTransactions);
return true;
}
diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkerAlpha.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkerAlpha.java
index 55580c96d1..2ce445f1bf 100644
--- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkerAlpha.java
+++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkerAlpha.java
@@ -1,5 +1,6 @@
package com.iota.iri.service.tipselection.impl;
+import com.iota.iri.conf.TipSelConfig;
import com.iota.iri.controllers.ApproveeViewModel;
import com.iota.iri.model.Hash;
import com.iota.iri.model.HashId;
@@ -31,12 +32,12 @@ public class WalkerAlpha implements Walker {
private final TailFinder tailFinder;
- public WalkerAlpha(double alpha, Random random, Tangle tangle, MessageQ messageQ, TailFinder tailFinder) {
- this.alpha = alpha;
- this.random = random;
+ public WalkerAlpha(TailFinder tailFinder, Tangle tangle, MessageQ messageQ, Random random, TipSelConfig config) {
this.tangle = tangle;
this.messageQ = messageQ;
this.tailFinder = tailFinder;
+ this.random = random;
+ this.alpha = config.getAlpha();
}
public double getAlpha() {
diff --git a/src/main/java/com/iota/iri/storage/FileExportProvider.java b/src/main/java/com/iota/iri/storage/FileExportProvider.java
index 189f6cecca..aec087b271 100644
--- a/src/main/java/com/iota/iri/storage/FileExportProvider.java
+++ b/src/main/java/com/iota/iri/storage/FileExportProvider.java
@@ -1,7 +1,5 @@
package com.iota.iri.storage;
-import com.iota.iri.controllers.TransactionViewModel;
-import com.iota.iri.model.Hash;
import com.iota.iri.model.Transaction;
import com.iota.iri.utils.Converter;
import com.iota.iri.utils.Pair;
@@ -13,8 +11,8 @@
import java.io.UnsupportedEncodingException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import static com.iota.iri.controllers.TransactionViewModel.TRINARY_SIZE;
@@ -144,6 +142,11 @@ public boolean saveBatch(List> models) throws Excep
return false;
}
+ @Override
+ public void deleteBatch(Collection>> models) throws Exception {
+
+ }
+
@Override
public void clear(Class> column) throws Exception {
diff --git a/src/main/java/com/iota/iri/storage/PersistenceProvider.java b/src/main/java/com/iota/iri/storage/PersistenceProvider.java
index 8c1aadc6b0..24a6f58bc3 100644
--- a/src/main/java/com/iota/iri/storage/PersistenceProvider.java
+++ b/src/main/java/com/iota/iri/storage/PersistenceProvider.java
@@ -1,10 +1,9 @@
package com.iota.iri.storage;
-import com.iota.iri.model.*;
import com.iota.iri.utils.Pair;
+import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -43,6 +42,13 @@ public interface PersistenceProvider {
boolean saveBatch(List> models) throws Exception;
+ /**
+ * Atomically delete all {@code models}.
+ * @param models key value pairs that to be expunged from the db
+ * @throws Exception
+ */
+ void deleteBatch(Collection>> models) throws Exception;
+
void clear(Class> column) throws Exception;
void clearMetadata(Class> column) throws Exception;
}
diff --git a/src/main/java/com/iota/iri/storage/Tangle.java b/src/main/java/com/iota/iri/storage/Tangle.java
index 8708351045..2e5c515afe 100644
--- a/src/main/java/com/iota/iri/storage/Tangle.java
+++ b/src/main/java/com/iota/iri/storage/Tangle.java
@@ -1,13 +1,13 @@
package com.iota.iri.storage;
-import com.iota.iri.model.Hash;
-import com.iota.iri.model.Hashes;
import com.iota.iri.utils.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.*;
-import java.util.concurrent.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
/**
* Created by paul on 3/3/17 for iri.
@@ -67,6 +67,12 @@ public Boolean save(Persistable model, Indexable index) throws Exception {
return exists;
}
+ public void deleteBatch(Collection>> models) throws Exception {
+ for(PersistenceProvider provider: persistenceProviders) {
+ provider.deleteBatch(models);
+ }
+ }
+
public void delete(Class> model, Indexable index) throws Exception {
for(PersistenceProvider provider: persistenceProviders) {
provider.delete(model, index);
diff --git a/src/main/java/com/iota/iri/storage/ZmqPublishProvider.java b/src/main/java/com/iota/iri/storage/ZmqPublishProvider.java
index 14cff92d98..f8f178904b 100644
--- a/src/main/java/com/iota/iri/storage/ZmqPublishProvider.java
+++ b/src/main/java/com/iota/iri/storage/ZmqPublishProvider.java
@@ -1,17 +1,17 @@
package com.iota.iri.storage;
-import java.util.List;
-import java.util.Set;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.model.Hash;
import com.iota.iri.model.Transaction;
import com.iota.iri.utils.Converter;
import com.iota.iri.utils.Pair;
import com.iota.iri.zmq.MessageQ;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
public class ZmqPublishProvider implements PersistenceProvider {
@@ -165,6 +165,11 @@ public boolean saveBatch(List> models) throws Excep
return false;
}
+ @Override
+ public void deleteBatch(Collection>> models) throws Exception {
+
+ }
+
@Override
public void clear(Class> column) throws Exception {
@@ -174,5 +179,4 @@ public void clear(Class> column) throws Exception {
public void clearMetadata(Class> column) throws Exception {
}
-
}
\ No newline at end of file
diff --git a/src/main/java/com/iota/iri/storage/rocksDB/RocksDBPersistenceProvider.java b/src/main/java/com/iota/iri/storage/rocksDB/RocksDBPersistenceProvider.java
index 3c6e4f6a94..2c5dafb3c7 100644
--- a/src/main/java/com/iota/iri/storage/rocksDB/RocksDBPersistenceProvider.java
+++ b/src/main/java/com/iota/iri/storage/rocksDB/RocksDBPersistenceProvider.java
@@ -6,6 +6,7 @@
import com.iota.iri.storage.PersistenceProvider;
import com.iota.iri.utils.IotaIOUtils;
import com.iota.iri.utils.Pair;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.SystemUtils;
import org.rocksdb.*;
import org.rocksdb.util.SizeUnit;
@@ -318,6 +319,31 @@ public boolean saveBatch(List> models) throws Excep
}
}
+ public void deleteBatch(Collection>> models)
+ throws Exception {
+ if (CollectionUtils.isNotEmpty(models)) {
+ try (WriteBatch writeBatch = new WriteBatch()) {
+ models.forEach(entry -> {
+ Indexable indexable = entry.low;
+ byte[] keyBytes = indexable.bytes();
+ ColumnFamilyHandle handle = classTreeMap.get(entry.hi);
+ writeBatch.remove(handle, keyBytes);
+ ColumnFamilyHandle metadataHandle = metadataReference.get(entry.hi);
+ if (metadataReference != null) {
+ writeBatch.remove(metadataHandle, keyBytes);
+ }
+ });
+
+ WriteOptions writeOptions = new WriteOptions()
+ //We are explicit about what happens if the node reboots before a flush to the db
+ .setDisableWAL(false)
+ //We want to make sure deleted data was indeed deleted
+ .setSync(true);
+ db.write(writeOptions, writeBatch);
+ }
+ }
+ }
+
@Override
public void clear(Class> column) throws Exception {
log.info("Deleting: {} entries", column.getSimpleName());
diff --git a/src/main/java/com/iota/iri/utils/IotaUtils.java b/src/main/java/com/iota/iri/utils/IotaUtils.java
index a0f3d93e8c..f5ec0e5f50 100644
--- a/src/main/java/com/iota/iri/utils/IotaUtils.java
+++ b/src/main/java/com/iota/iri/utils/IotaUtils.java
@@ -1,11 +1,26 @@
package com.iota.iri.utils;
import com.iota.iri.model.Hash;
+import org.apache.commons.lang3.StringUtils;
+import java.lang.reflect.Method;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public class IotaUtils {
+
+ public static List splitStringToImmutableList(String string, String regexSplit) {
+ return Arrays.stream(string.split(regexSplit))
+ .filter(StringUtils::isNoneBlank)
+ .collect(Collectors
+ .collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
+ }
+
/**
* Used to create low-memory index keys.
*
@@ -21,4 +36,19 @@ public static ByteBuffer getSubHash(Hash hash, int length) {
return ByteBuffer.wrap(Arrays.copyOf(hash.bytes(), length));
}
+
+ /**
+ * @param clazz Class to inspect
+ * @return All the declared and inherited setter method of {@code clazz}
+ */
+ public static List getAllSetters(Class> clazz) {
+ List setters = new ArrayList<>();
+ while (clazz != Object.class) {
+ setters.addAll(Stream.of(clazz.getDeclaredMethods())
+ .filter(method -> method.getName().startsWith("set"))
+ .collect(Collectors.toList()));
+ clazz = clazz.getSuperclass();
+ }
+ return Collections.unmodifiableList(setters);
+ }
}
diff --git a/src/main/java/com/iota/iri/zmq/MessageQ.java b/src/main/java/com/iota/iri/zmq/MessageQ.java
index 675f312348..e6d8f3e3d9 100644
--- a/src/main/java/com/iota/iri/zmq/MessageQ.java
+++ b/src/main/java/com/iota/iri/zmq/MessageQ.java
@@ -1,5 +1,6 @@
package com.iota.iri.zmq;
+import com.iota.iri.conf.ZMQConfig;
import com.iota.iri.utils.IotaIOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,7 +22,11 @@ public class MessageQ {
private final ExecutorService publisherService = Executors.newSingleThreadExecutor();
- public MessageQ(int port, String ipc, int nthreads, boolean enabled) {
+ public static MessageQ createWith(ZMQConfig config) {
+ return new MessageQ(config.getZmqPort(), config.getZmqIpc(), config.getZmqThreads(), config.isZmqEnabled());
+ }
+
+ private MessageQ(int port, String ipc, int nthreads, boolean enabled) {
if (enabled) {
context = ZMQ.context(nthreads);
publisher = context.socket(ZMQ.PUB);
diff --git a/src/main/resources/previousEpochsSpentAddresses2.txt b/src/main/resources/previousEpochsSpentAddresses2.txt
index fb7da54a7f..a068382419 100644
--- a/src/main/resources/previousEpochsSpentAddresses2.txt
+++ b/src/main/resources/previousEpochsSpentAddresses2.txt
@@ -612903,7 +612903,7 @@ XLHWBDBAEYHYC9VKZLCCEYKYXBVITBOLXTCPOSAVMCULMWF9PGXMFIAOUW9PHDHQQWADBTTTO9JCFVHK
XLHWEDSVGIHHCYMFDOJZ9POORGGW9JNWJNVBMPONOTDAGJWPHBHWWTVSSWXCSMZTF9WILJLRDJQUZ9PLC
XLHWH9YDLHUUBILEYEZAGLSUUCSXCZFDTCJ9ZMMVKYNFBNAMTIOYOYMDHOVYJCLEQIRQIVXAODNJKEMRC
XLHWLQMWQFPPVQZYBZWOA9DJZFOEIIXJABFTOO9HQOUJMMNYZNILGIIBCRBSSFEITDAS9QCSXZALDUDJW
-XLHWORYNXJBDQ9
+XLHWORYNXJBDQ9MTGQVYOFNFWXEYMBKZFQNETTIFQQZUNJRX9NQGQSBTEGBCVSTRCLBYKXOMABMGAWWRW
XLHXJIJDKCQXCBMHUSQLIOSHOZZX9DBPMABHBZK9Z9KEYLFAQWLEJTPAKJSQXPVVJZB9FSXVSNAGUGQIY
XLHYOCVYWHGOFAFGWJ9YELWAELINJACAOOMUOXXOMIDUTBPYOWRSTLYEXPPLQGBJZEGSKGRNMDQZYVCM9
XLHYUJTSPIUBPXPADKSKLMJWXLF9RKERJIVMWGMQGSWOAFXRY9TGIQIIFCXHGCARVEITXKGGDGWP9LYNY
diff --git a/src/test/java/com/iota/iri/IXITest.java b/src/test/java/com/iota/iri/IXITest.java
index 7522cb0d5b..a182596f53 100644
--- a/src/test/java/com/iota/iri/IXITest.java
+++ b/src/test/java/com/iota/iri/IXITest.java
@@ -1,6 +1,5 @@
package com.iota.iri;
-import com.iota.iri.conf.Configuration;
import com.iota.iri.service.dto.AbstractResponse;
import com.iota.iri.service.dto.ErrorResponse;
import com.iota.iri.service.dto.IXIResponse;
diff --git a/src/test/java/com/iota/iri/SnapshotTest.java b/src/test/java/com/iota/iri/SnapshotTest.java
index 5f42842786..7dda55d9dc 100644
--- a/src/test/java/com/iota/iri/SnapshotTest.java
+++ b/src/test/java/com/iota/iri/SnapshotTest.java
@@ -1,6 +1,7 @@
package com.iota.iri;
-import com.iota.iri.conf.Configuration;
+import com.iota.iri.conf.IotaConfig;
+import com.iota.iri.conf.MainnetConfig;
import com.iota.iri.model.Hash;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -21,8 +22,8 @@ public class SnapshotTest {
@BeforeClass
public static void beforeClass() {
try {
- initSnapshot = Snapshot.init(Configuration.MAINNET_SNAPSHOT_FILE,
- Configuration.MAINNET_SNAPSHOT_SIG_FILE, false);
+ IotaConfig config = new MainnetConfig();
+ initSnapshot = Snapshot.init(config);
} catch (IOException e) {
throw new UncheckedIOException("Problem initiating snapshot", e);
}
diff --git a/src/test/java/com/iota/iri/TransactionTestUtils.java b/src/test/java/com/iota/iri/TransactionTestUtils.java
index 4ccca6d9a9..15f1f3ef5b 100644
--- a/src/test/java/com/iota/iri/TransactionTestUtils.java
+++ b/src/test/java/com/iota/iri/TransactionTestUtils.java
@@ -2,8 +2,10 @@
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.controllers.TransactionViewModelTest;
+import com.iota.iri.hash.SpongeFactory;
import com.iota.iri.model.Hash;
import com.iota.iri.utils.Converter;
+import org.apache.commons.lang3.StringUtils;
public class TransactionTestUtils {
@@ -34,4 +36,24 @@ public static TransactionViewModel createTransactionWithTrunkBundleHash(Transact
TransactionViewModel.BUNDLE_TRINARY_OFFSET, TransactionViewModel.BUNDLE_TRINARY_SIZE);
return tx;
}
+
+ public static TransactionViewModel createTransactionWithTrytes(String trytes) {
+ String expandedTrytes = expandTrytes(trytes);
+ byte[] trits = Converter.allocatingTritsFromTrytes(expandedTrytes);
+ return new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits));
+ }
+
+ public static TransactionViewModel createTransactionWithTrunkAndBranch(String trytes, Hash trunk, Hash branch) {
+ String expandedTrytes = expandTrytes(trytes);
+ byte[] trits = Converter.allocatingTritsFromTrytes(expandedTrytes);
+ System.arraycopy(trunk.trits(), 0, trits, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_OFFSET,
+ TransactionViewModel.TRUNK_TRANSACTION_TRINARY_SIZE);
+ System.arraycopy(branch.trits(), 0, trits, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_OFFSET,
+ TransactionViewModel.BRANCH_TRANSACTION_TRINARY_SIZE);
+ return new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits));
+ }
+
+ private static String expandTrytes(String trytes) {
+ return trytes + StringUtils.repeat('9', TransactionViewModel.TRYTES_SIZE - trytes.length());
+ }
}
diff --git a/src/test/java/com/iota/iri/TransactionValidatorTest.java b/src/test/java/com/iota/iri/TransactionValidatorTest.java
index 408b34254e..e253749ed5 100644
--- a/src/test/java/com/iota/iri/TransactionValidatorTest.java
+++ b/src/test/java/com/iota/iri/TransactionValidatorTest.java
@@ -1,6 +1,6 @@
package com.iota.iri;
-import com.iota.iri.conf.Configuration;
+import com.iota.iri.conf.MainnetConfig;
import com.iota.iri.controllers.TipsViewModel;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.hash.SpongeFactory;
@@ -11,12 +11,13 @@
import com.iota.iri.utils.Converter;
import com.iota.iri.zmq.MessageQ;
import org.junit.AfterClass;
+import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
-import static com.iota.iri.controllers.TransactionViewModelTest.getRandomTransactionTrits;
-import static org.junit.Assert.assertEquals;
+import static com.iota.iri.controllers.TransactionViewModelTest.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -39,16 +40,14 @@ public static void setUp() throws Exception {
dbFolder.getRoot().getAbsolutePath(), logFolder.getRoot().getAbsolutePath(),1000));
tangle.init();
TipsViewModel tipsViewModel = new TipsViewModel();
- MessageQ messageQ = new MessageQ(0, "", 0, false);
+ MessageQ messageQ = Mockito.mock(MessageQ.class);
TransactionRequester txRequester = new TransactionRequester(tangle, messageQ);
- txValidator = new TransactionValidator(tangle, tipsViewModel, txRequester, messageQ,
- Long.parseLong(Configuration.GLOBAL_SNAPSHOT_TIME));
- txValidator.init(false, MAINNET_MWM);
+ txValidator = new TransactionValidator(tangle, tipsViewModel, txRequester, messageQ, new MainnetConfig());
+ txValidator.setMwm(false, MAINNET_MWM);
}
@AfterClass
public static void tearDown() throws Exception {
- txValidator.shutdown();
tangle.shutdown();
dbFolder.delete();
logFolder.delete();
@@ -56,7 +55,6 @@ public static void tearDown() throws Exception {
@Test
public void testMinMwm() throws InterruptedException {
- txValidator.shutdown();
txValidator.init(false, 5);
assertTrue(txValidator.getMinWeightMagnitude() == 13);
txValidator.shutdown();
@@ -69,20 +67,20 @@ public void validateBytes() throws Exception {
Converter.copyTrits(0, trits, 0, trits.length);
byte[] bytes = Converter.allocateBytesForTrits(trits.length);
Converter.bytes(trits, bytes);
- TransactionValidator.validateBytes(bytes, MAINNET_MWM);
+ txValidator.validateBytes(bytes, MAINNET_MWM);
}
@Test
public void validateTrits() {
byte[] trits = getRandomTransactionTrits();
Converter.copyTrits(0, trits, 0, trits.length);
- TransactionValidator.validateTrits(trits, MAINNET_MWM);
+ txValidator.validateTrits(trits, MAINNET_MWM);
}
@Test(expected = RuntimeException.class)
public void validateTritsWithInvalidMetadata() {
byte[] trits = getRandomTransactionTrits();
- TransactionValidator.validateTrits(trits, MAINNET_MWM);
+ txValidator.validateTrits(trits, MAINNET_MWM);
}
@Test
@@ -91,7 +89,7 @@ public void validateBytesWithNewCurl() throws Exception {
Converter.copyTrits(0, trits, 0, trits.length);
byte[] bytes = Converter.allocateBytesForTrits(trits.length);
Converter.bytes(trits, 0, bytes, 0, trits.length);
- TransactionValidator.validateBytes(bytes, txValidator.getMinWeightMagnitude(), SpongeFactory.create(SpongeFactory.Mode.CURLP81));
+ txValidator.validateBytes(bytes, txValidator.getMinWeightMagnitude(), SpongeFactory.create(SpongeFactory.Mode.CURLP81));
}
@Test
@@ -136,6 +134,76 @@ private TransactionViewModel getTxWithBranchAndTrunk() throws Exception {
return tx;
}
+ @Test
+ public void testTransactionPropagation() throws Exception {
+ TransactionViewModel leftChildLeaf = TransactionTestUtils.createTransactionWithTrytes("CHILDTX");
+ leftChildLeaf.updateSolid(true);
+ leftChildLeaf.store(tangle);
+
+ TransactionViewModel rightChildLeaf = TransactionTestUtils.createTransactionWithTrytes("CHILDTWOTX");
+ rightChildLeaf.updateSolid(true);
+ rightChildLeaf.store(tangle);
+
+ TransactionViewModel parent = TransactionTestUtils.createTransactionWithTrunkAndBranch("PARENT",
+ leftChildLeaf.getHash(), rightChildLeaf.getHash());
+ parent.updateSolid(false);
+ parent.store(tangle);
+
+ TransactionViewModel parentSibling = TransactionTestUtils.createTransactionWithTrytes("PARENTLEAF");
+ parentSibling.updateSolid(true);
+ parentSibling.store(tangle);
+
+ TransactionViewModel grandParent = TransactionTestUtils.createTransactionWithTrunkAndBranch("GRANDPARENT", parent.getHash(),
+ parentSibling.getHash());
+ grandParent.updateSolid(false);
+ grandParent.store(tangle);
+
+ txValidator.addSolidTransaction(leftChildLeaf.getHash());
+ while (!txValidator.isNewSolidTxSetsEmpty()) {
+ txValidator.propagateSolidTransactions();
+ }
+
+ parent = TransactionViewModel.fromHash(tangle, parent.getHash());
+ Assert.assertTrue("Parent tx was expected to be solid", parent.isSolid());
+ grandParent = TransactionViewModel.fromHash(tangle, grandParent.getHash());
+ Assert.assertTrue("Grandparent was expected to be solid", grandParent.isSolid());
+ }
+
+ @Test
+ public void testTransactionPropagationFailure() throws Exception {
+ TransactionViewModel leftChildLeaf = new TransactionViewModel(getRandomTransactionTrits(), getRandomTransactionHash());
+ leftChildLeaf.updateSolid(true);
+ leftChildLeaf.store(tangle);
+
+ TransactionViewModel rightChildLeaf = new TransactionViewModel(getRandomTransactionTrits(), getRandomTransactionHash());
+ rightChildLeaf.updateSolid(true);
+ rightChildLeaf.store(tangle);
+
+ TransactionViewModel parent = new TransactionViewModel(getRandomTransactionWithTrunkAndBranch(leftChildLeaf.getHash(),
+ rightChildLeaf.getHash()), getRandomTransactionHash());
+ parent.updateSolid(false);
+ parent.store(tangle);
+
+ TransactionViewModel parentSibling = new TransactionViewModel(getRandomTransactionTrits(), getRandomTransactionHash());
+ parentSibling.updateSolid(false);
+ parentSibling.store(tangle);
+
+ TransactionViewModel grandParent = new TransactionViewModel(getRandomTransactionWithTrunkAndBranch(parent.getHash(),
+ parentSibling.getHash()), getRandomTransactionHash());
+ grandParent.updateSolid(false);
+ grandParent.store(tangle);
+
+ txValidator.addSolidTransaction(leftChildLeaf.getHash());
+ while (!txValidator.isNewSolidTxSetsEmpty()) {
+ txValidator.propagateSolidTransactions();
+ }
+
+ parent = TransactionViewModel.fromHash(tangle, parent.getHash());
+ Assert.assertTrue("Parent tx was expected to be solid", parent.isSolid());
+ grandParent = TransactionViewModel.fromHash(tangle, grandParent.getHash());
+ Assert.assertFalse("GrandParent tx was expected to be not solid", grandParent.isSolid());
+ }
+
private TransactionViewModel getTxWithoutBranchAndTrunk() throws Exception {
byte[] trits = getRandomTransactionTrits();
TransactionViewModel tx = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits));
diff --git a/src/test/java/com/iota/iri/conf/ConfigFactoryTest.java b/src/test/java/com/iota/iri/conf/ConfigFactoryTest.java
new file mode 100644
index 0000000000..ff705a6de8
--- /dev/null
+++ b/src/test/java/com/iota/iri/conf/ConfigFactoryTest.java
@@ -0,0 +1,170 @@
+package com.iota.iri.conf;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Tests for the {@link ConfigFactory}
+ */
+public class ConfigFactoryTest {
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ /**
+ * Creates and validates a Testnet {@link IotaConfig}.
+ */
+ @Test
+ public void createIotaConfigTestnet() {
+ IotaConfig iotaConfig = ConfigFactory.createIotaConfig(true);
+ assertTrue("Expected iotaConfig as instance of TestnetConfig.", iotaConfig instanceof TestnetConfig);
+ assertTrue("Expected iotaConfig as Testnet.", iotaConfig.isTestnet());
+ }
+
+ /**
+ * Creates and validates a Mainnet {@link IotaConfig}.
+ */
+ @Test
+ public void createIotaConfigMainnet() {
+ IotaConfig iotaConfig = ConfigFactory.createIotaConfig(false);
+ assertTrue("Expected iotaConfig as instance of MainnetConfig.", iotaConfig instanceof MainnetConfig);
+ assertFalse("Expected iotaConfig as Mainnet.", iotaConfig.isTestnet());
+ }
+
+ /**
+ * Creates and validates a Testnet {@link IotaConfig} with TESTNET=true
in config file and
+ * testnet: false
as method parameter for {@link ConfigFactory#createFromFile(File, boolean)}.
+ * @throws IOException when config file not found.
+ */
+ @Test
+ public void createFromFileTestnetWithTestnetTrueAndFalse() throws IOException {
+ // lets assume in our configFile is TESTNET=true
+ File configFile = createTestnetConfigFile("true");
+
+ // but the parameter is set to testnet=false
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, false);
+ assertTrue("Expected iotaConfig as instance of TestnetConfig.", iotaConfig instanceof TestnetConfig);
+ assertTrue("Expected iotaConfig as Testnet.", iotaConfig.isTestnet());
+ }
+
+ /**
+ * Creates and validates a Testnet {@link IotaConfig} with TESTNET=true
in config file and
+ * testnet: true
as method parameter for {@link ConfigFactory#createFromFile(File, boolean)}.
+ * @throws IOException when config file not found.
+ */
+ @Test
+ public void createFromFileTestnetWithTestnetTrueAndTrue() throws IOException {
+ // lets assume in our configFile is TESTNET=true
+ File configFile = createTestnetConfigFile("true");
+
+ // but the parameter is set to testnet=true
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true);
+ assertTrue("Expected iotaConfig as instance of TestnetConfig.", iotaConfig instanceof TestnetConfig);
+ assertTrue("Expected iotaConfig as Testnet.", iotaConfig.isTestnet());
+ }
+
+ /**
+ * Creates and validates a Testnet {@link IotaConfig} with TESTNET=false
in config file and
+ * testnet: true
as method parameter for {@link ConfigFactory#createFromFile(File, boolean)}.
+ * @throws IOException when config file not found.
+ */
+ @Test
+ public void createFromFileTestnetWithTestnetFalseAndTrue() throws IOException {
+ // lets assume in our configFile is TESTNET=false
+ File configFile = createTestnetConfigFile("false");
+
+ // but the parameter is set to testnet=true
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true);
+ assertTrue("Expected iotaConfig as instance of TestnetConfig.", iotaConfig instanceof TestnetConfig);
+ assertTrue("Expected iotaConfig as Testnet.", iotaConfig.isTestnet());
+ }
+
+ /**
+ * Creates and validates a Mainnet {@link IotaConfig} with TESTNET=false
in config file and
+ * testnet: false
as method parameter for {@link ConfigFactory#createFromFile(File, boolean)}.
+ * @throws IOException when config file not found.
+ */
+ @Test
+ public void createFromFileTestnetWithTestnetFalseAndFalse() throws IOException {
+ // lets assume in our configFile is TESTNET=false
+ File configFile = createTestnetConfigFile("false");
+
+ // but the parameter is set to testnet=true
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, false);
+ assertTrue("Expected iotaConfig as instance of MainnetConfig.", iotaConfig instanceof MainnetConfig);
+ assertFalse("Expected iotaConfig as Mainnet.", iotaConfig.isTestnet());
+ }
+
+ /**
+ * Test if leading and trailing spaces are trimmed from string in properties file.
+ * @throws IOException when config file not found.
+ */
+ @Test
+ public void createFromFileTestnetWithTrailingSpaces() throws IOException {
+ File configFile = createTestnetConfigFile("true");
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true);
+ String expected = "NPCRMHDOMU9QHFFBKFCWFHFJNNQDRNDOGVPEVDVGWKHFUFEXLWJBHXDJFKQGYFRDZBQIFDSJMUCCQVICI";
+ assertEquals("Expected that leading and trailing spaces were trimmed.", expected, iotaConfig.getCoordinator());
+ }
+
+ /**
+ * Test if trailing spaces are correctly trimmed from integer.
+ * @throws IOException when config file not found.
+ */
+ @Test
+ public void createFromFileTestnetWithInteger() throws IOException {
+ File configFile = createTestnetConfigFile("true");
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true);
+ assertEquals("Expected that trailing spaces are trimmed.", 2, iotaConfig.getMilestoneStartIndex());
+ }
+
+ /**
+ * Test if trailing spaces are correctly trimmed from boolean.
+ * @throws IOException when config file not found.
+ */
+ @Test
+ public void createFromFileTestnetWithBoolean() throws IOException {
+ File configFile = createTestnetConfigFile("true");
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true);
+ assertTrue("Expected that ZMQ is enabled.", iotaConfig.isZmqEnabled());
+ }
+
+ /**
+ * Try to create an {@link IotaConfig} from a not existing configFile.
+ * @throws IOException when config file not found.
+ */
+ @Test(expected = FileNotFoundException.class)
+ public void createFromFileTestnetWithFileNotFound() throws IOException {
+ File configFile = new File("doesNotExist.ini");
+ ConfigFactory.createFromFile(configFile, false);
+ }
+
+ private File createTestnetConfigFile(String testnet) throws IOException {
+ Properties properties = new Properties();
+ properties.setProperty("TESTNET", testnet);
+ properties.setProperty("ZMQ_ENABLED", " TRUE ");
+ properties.setProperty("MWM", "9");
+ properties.setProperty("SNAPSHOT_FILE", "conf/snapshot.txt");
+ properties.setProperty("COORDINATOR", " NPCRMHDOMU9QHFFBKFCWFHFJNNQDRNDOGVPEVDVGWKHFUFEXLWJBHXDJFKQGYFRDZBQIFDSJMUCCQVICI ");
+ properties.setProperty("MILESTONE_START_INDEX", "2 ");
+ properties.setProperty("KEYS_IN_MILESTONE", "10");
+ properties.setProperty("MAX_DEPTH", "1000");
+
+ File configFile = folder.newFile("myCustomIotaConfig.ini");
+ FileOutputStream fileOutputStream = new FileOutputStream(configFile);
+ properties.store(fileOutputStream, "Test config file created by Unit test!");
+ fileOutputStream.close();
+
+ return configFile;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/iota/iri/conf/ConfigTest.java b/src/test/java/com/iota/iri/conf/ConfigTest.java
new file mode 100644
index 0000000000..b6af0c4d8d
--- /dev/null
+++ b/src/test/java/com/iota/iri/conf/ConfigTest.java
@@ -0,0 +1,363 @@
+package com.iota.iri.conf;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.iota.iri.utils.IotaUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.core.IsCollectionContaining;
+import org.junit.*;
+import org.junit.runners.MethodSorters;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ConfigTest {
+
+ private static File configFile;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws IOException {
+ configFile = File.createTempFile("config", "ini");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ //clear the file
+ try (Writer writer = new FileWriter(configFile)) {
+ writer.write("");
+ }
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws IOException {
+ FileUtils.forceDelete(configFile);
+ }
+
+ /*
+ Test that iterates over common configs. It also attempts to check different types of types (double, boolean, string)
+ */
+ @Test
+ public void testArgsParsingMainnet() {
+ String[] args = {
+ "-p", "14000",
+ "-u", "13000",
+ "-t", "27000",
+ "-n", "udp://neighbor1 neighbor, tcp://neighbor2",
+ "--api-host", "1.1.1.1",
+ "--remote-limit-api", "call1 call2, call3",
+ "--max-find-transactions", "500",
+ "--max-requests-list", "1000",
+ "--max-get-trytes", "4000",
+ "--max-body-length", "220",
+ "--remote-auth", "2.2.2.2",
+ "--p-remove-request", "0.23",
+ "--send-limit", "1000",
+ "--max-peers", "10",
+ "--dns-refresher", "false",
+ "--dns-resolution", "false",
+ "--ixi-dir", "/ixi",
+ "--db-path", "/db",
+ "--db-log-path", "/dblog",
+ "--zmq-enabled",
+ //we ignore this on mainnet
+ "--mwm", "4",
+ "--testnet-coordinator", "TTTTTTTTT",
+ "--test-no-coo-validation",
+ //this should be ignored everywhere
+ "--fake-config"
+ };
+ IotaConfig iotaConfig = ConfigFactory.createIotaConfig(false);
+ Assert.assertThat("wrong config class created", iotaConfig, CoreMatchers.instanceOf(MainnetConfig.class));
+
+ iotaConfig.parseConfigFromArgs(args);
+ Assert.assertEquals("port value", 14000, iotaConfig.getPort());
+ Assert.assertEquals("udp port", 13000, iotaConfig.getUdpReceiverPort());
+ Assert.assertEquals("tcp port", 27000, iotaConfig.getTcpReceiverPort());
+ Assert.assertEquals("neighbors", Arrays.asList("udp://neighbor1", "neighbor", "tcp://neighbor2"),
+ iotaConfig.getNeighbors());
+ Assert.assertEquals("api host", "1.1.1.1", iotaConfig.getApiHost());
+ Assert.assertEquals("remote limit api", Arrays.asList("call1", "call2", "call3"),
+ iotaConfig.getRemoteLimitApi());
+ Assert.assertEquals("max find transactions", 500, iotaConfig.getMaxFindTransactions());
+ Assert.assertEquals("max requests list", 1000, iotaConfig.getMaxRequestsList());
+ Assert.assertEquals("max get trytes", 4000, iotaConfig.getMaxGetTrytes());
+ Assert.assertEquals("max body length", 220, iotaConfig.getMaxBodyLength());
+ Assert.assertEquals("remote-auth", "2.2.2.2", iotaConfig.getRemoteAuth());
+ Assert.assertEquals("p remove request", 0.23d, iotaConfig.getpRemoveRequest(), 0d);
+ Assert.assertEquals("send limit", 1000, iotaConfig.getSendLimit());
+ Assert.assertEquals("max peers", 10, iotaConfig.getMaxPeers());
+ Assert.assertEquals("dns refresher", false, iotaConfig.isDnsRefresherEnabled());
+ Assert.assertEquals("dns resolution", false, iotaConfig.isDnsResolutionEnabled());
+ Assert.assertEquals("ixi-dir", "/ixi", iotaConfig.getIxiDir());
+ Assert.assertEquals("db path", "/db", iotaConfig.getDbPath());
+ Assert.assertEquals("zmq enabled", true, iotaConfig.isZmqEnabled());
+ Assert.assertNotEquals("mwm", 4, iotaConfig.getMwm());
+ Assert.assertNotEquals("coo", iotaConfig.getCoordinator(), "TTTTTTTTT");
+ Assert.assertEquals("--testnet-no-coo-validation", false, iotaConfig.isDontValidateTestnetMilestoneSig());
+ }
+
+ @Test
+ public void testRemoteFlag() {
+ String[] args = {"--remote"};
+ IotaConfig iotaConfig = ConfigFactory.createIotaConfig(false);
+ iotaConfig.parseConfigFromArgs(args);
+ Assert.assertEquals("The api interface should be open to the public", "0.0.0.0", iotaConfig.getApiHost());
+ }
+
+ @Test
+ public void testArgsParsingTestnet() {
+ String[] args = {
+ "-p", "14000",
+ "-u", "13000",
+ "-t", "27000",
+ "-n", "udp://neighbor1 neighbor, tcp://neighbor2",
+ "--api-host", "1.1.1.1",
+ "--remote-limit-api", "call1 call2, call3",
+ "--max-find-transactions", "500",
+ "--max-requests-list", "1000",
+ "--max-get-trytes", "4000",
+ "--max-body-length", "220",
+ "--remote-auth", "2.2.2.2",
+ "--p-remove-request", "0.23",
+ "--send-limit", "1000",
+ "--max-peers", "10",
+ "--dns-refresher", "false",
+ "--dns-resolution", "false",
+ "--ixi-dir", "/ixi",
+ "--db-path", "/db",
+ "--db-log-path", "/dblog",
+ "--zmq-enabled",
+ //we ignore this on mainnet
+ "--mwm", "4",
+ "--testnet-coordinator", "TTTTTTTTT",
+ "--testnet-no-coo-validation",
+ //this should be ignored everywhere
+ "--fake-config"
+ };
+ IotaConfig iotaConfig = ConfigFactory.createIotaConfig(true);
+ Assert.assertThat("wrong config class created", iotaConfig, CoreMatchers.instanceOf(TestnetConfig.class));
+
+ iotaConfig.parseConfigFromArgs(args);
+ Assert.assertEquals("port value", 14000, iotaConfig.getPort());
+ Assert.assertEquals("udp port", 13000, iotaConfig.getUdpReceiverPort());
+ Assert.assertEquals("tcp port", 27000, iotaConfig.getTcpReceiverPort());
+ Assert.assertEquals("neighbors", Arrays.asList("udp://neighbor1", "neighbor", "tcp://neighbor2"),
+ iotaConfig.getNeighbors());
+ Assert.assertEquals("api host", "1.1.1.1", iotaConfig.getApiHost());
+ Assert.assertEquals("remote limit api", Arrays.asList("call1", "call2", "call3"),
+ iotaConfig.getRemoteLimitApi());
+ Assert.assertEquals("max find transactions", 500, iotaConfig.getMaxFindTransactions());
+ Assert.assertEquals("max requests list", 1000, iotaConfig.getMaxRequestsList());
+ Assert.assertEquals("max get trytes", 4000, iotaConfig.getMaxGetTrytes());
+ Assert.assertEquals("max body length", 220, iotaConfig.getMaxBodyLength());
+ Assert.assertEquals("remote-auth", "2.2.2.2", iotaConfig.getRemoteAuth());
+ Assert.assertEquals("p remove request", 0.23d, iotaConfig.getpRemoveRequest(), 0d);
+ Assert.assertEquals("send limit", 1000, iotaConfig.getSendLimit());
+ Assert.assertEquals("max peers", 10, iotaConfig.getMaxPeers());
+ Assert.assertEquals("dns refresher", false, iotaConfig.isDnsRefresherEnabled());
+ Assert.assertEquals("dns resolution", false, iotaConfig.isDnsResolutionEnabled());
+ Assert.assertEquals("ixi-dir", "/ixi", iotaConfig.getIxiDir());
+ Assert.assertEquals("db path", "/db", iotaConfig.getDbPath());
+ Assert.assertEquals("zmq enabled", true, iotaConfig.isZmqEnabled());
+ Assert.assertEquals("mwm", 4, iotaConfig.getMwm());
+ Assert.assertEquals("coo", "TTTTTTTTT", iotaConfig.getCoordinator());
+ Assert.assertEquals("--testnet-no-coo-validation", true,
+ iotaConfig.isDontValidateTestnetMilestoneSig());
+ }
+
+ @Test
+ public void testIniParsingMainnet() throws Exception {
+ String iniContent = new StringBuilder()
+ .append("[IRI]").append(System.lineSeparator())
+ .append("PORT = 17000").append(System.lineSeparator())
+ .append("NEIGHBORS = udp://neighbor1 neighbor, tcp://neighbor2").append(System.lineSeparator())
+ .append("ZMQ_ENABLED = true").append(System.lineSeparator())
+ .append("P_REMOVE_REQUEST = 0.4").append(System.lineSeparator())
+ .append("MWM = 4").append(System.lineSeparator())
+ .append("FAKE").append(System.lineSeparator())
+ .append("FAKE2 = lies")
+ .toString();
+
+ try (Writer writer = new FileWriter(configFile)) {
+ writer.write(iniContent);
+ }
+
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, false);
+ Assert.assertThat("Wrong config class created", iotaConfig, CoreMatchers.instanceOf(MainnetConfig.class));
+ Assert.assertEquals("PORT", 17000, iotaConfig.getPort());
+ Assert.assertEquals("NEIGHBORS", Arrays.asList("udp://neighbor1", "neighbor", "tcp://neighbor2"),
+ iotaConfig.getNeighbors());
+ Assert.assertEquals("ZMQ_ENABLED", true, iotaConfig.isZmqEnabled());
+ Assert.assertEquals("P_REMOVE_REQUEST", 0.4d, iotaConfig.getpRemoveRequest(), 0);
+ Assert.assertNotEquals("MWM", 4, iotaConfig.getMwm());
+ }
+
+ @Test
+ public void testIniParsingTestnet() throws Exception {
+ String iniContent = new StringBuilder()
+ .append("[IRI]").append(System.lineSeparator())
+ .append("PORT = 17000").append(System.lineSeparator())
+ .append("NEIGHBORS = udp://neighbor1 neighbor, tcp://neighbor2").append(System.lineSeparator())
+ .append("ZMQ_ENABLED = true").append(System.lineSeparator())
+ .append("DNS_RESOLUTION_ENABLED = TRUE").append(System.lineSeparator())
+ .append("EXPORT = FALSE").append(System.lineSeparator())
+ .append("P_REMOVE_REQUEST = 0.4").append(System.lineSeparator())
+ .append("MWM = 4").append(System.lineSeparator())
+ .append("NUMBER_OF_KEYS_IN_A_MILESTONE = 3").append(System.lineSeparator())
+ .append("DONT_VALIDATE_TESTNET_MILESTONE_SIG = true").append(System.lineSeparator())
+ .append("TIPSELECTION_ALPHA = 1.1").append(System.lineSeparator())
+ //doesn't do anything
+ .append("REMOTE")
+ .append("FAKE").append(System.lineSeparator())
+ .append("FAKE2 = lies")
+ .toString();
+
+ try (Writer writer = new FileWriter(configFile)) {
+ writer.write(iniContent);
+ }
+
+ IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true);
+ Assert.assertThat("Wrong config class created", iotaConfig, CoreMatchers.instanceOf(TestnetConfig.class));
+ Assert.assertEquals("PORT", 17000, iotaConfig.getPort());
+ Assert.assertEquals("NEIGHBORS", Arrays.asList("udp://neighbor1", "neighbor", "tcp://neighbor2"),
+ iotaConfig.getNeighbors());
+ Assert.assertEquals("ZMQ_ENABLED", true, iotaConfig.isZmqEnabled());
+ Assert.assertEquals("DNS_RESOLUTION_ENABLED", true, iotaConfig.isDnsResolutionEnabled());
+ Assert.assertEquals("EXPORT", false, iotaConfig.isExport());
+ //true by default
+ Assert.assertEquals("DNS_REFRESHER_ENABLED", true, iotaConfig.isDnsRefresherEnabled());
+ //false by default
+ Assert.assertEquals("RESCAN", false, iotaConfig.isRescanDb());
+ //false by default
+ Assert.assertEquals("REVALIDATE", false, iotaConfig.isRevalidate());
+ Assert.assertEquals("P_REMOVE_REQUEST", 0.4d, iotaConfig.getpRemoveRequest(), 0);
+ Assert.assertEquals("MWM", 4, iotaConfig.getMwm());
+ Assert.assertEquals("NUMBER_OF_KEYS_IN_A_MILESTONE", 3, iotaConfig.getNumberOfKeysInMilestone());
+ Assert.assertEquals("TIPSELECTION_ALPHA", 1.1d, iotaConfig.getAlpha(), 0);
+ Assert.assertEquals("DONT_VALIDATE_TESTNET_MILESTONE_SIG",
+ iotaConfig.isDontValidateTestnetMilestoneSig(), true);
+ //prove that REMOTE did nothing
+ Assert.assertEquals("API_HOST", iotaConfig.getApiHost(), "localhost");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidIni() throws IOException {
+ String iniContent = new StringBuilder()
+ .append("[IRI]").append(System.lineSeparator())
+ .append("REVALIDATE")
+ .toString();
+ try (Writer writer = new FileWriter(configFile)) {
+ writer.write(iniContent);
+ }
+ ConfigFactory.createFromFile(configFile, false);
+ }
+
+ @Test
+ public void backwardsIniCompatibilityTest() {
+ Collection configNames = IotaUtils.getAllSetters(TestnetConfig.class)
+ .stream()
+ .map(this::deriveNameFromSetter)
+ .collect(Collectors.toList());
+ Stream.of(LegacyDefaultConf.values())
+ .map(Enum::name)
+ // make it explicit that we have removed some configs
+ .filter(config -> !ArrayUtils.contains(new String[]{"CONFIG", "TESTNET", "DEBUG",
+ "MIN_RANDOM_WALKS", "MAX_RANDOM_WALKS"}, config))
+ .forEach(config ->
+ Assert.assertThat(configNames, IsCollectionContaining.hasItem(config)));
+ }
+
+ @Test
+ public void testDontValidateMIlestoneSigDefaultValue() {
+ IotaConfig iotaConfig = ConfigFactory.createIotaConfig(true);
+ Assert.assertFalse("By default testnet should be validating milestones",
+ iotaConfig.isDontValidateTestnetMilestoneSig());
+ }
+
+ private String deriveNameFromSetter(Method setter) {
+ JsonIgnore jsonIgnore = setter.getAnnotation(JsonIgnore.class);
+ if (jsonIgnore != null) {
+ return null;
+ }
+
+ JsonProperty jsonProperty = setter.getAnnotation(JsonProperty.class);
+ //Code works w/o annotation but we wish to enforce its usage
+ Assert.assertNotNull("Setter " + setter.getName() + "must have JsonProperty annotation", jsonProperty);
+ if (StringUtils.isEmpty(jsonProperty.value())) {
+ String name = setter.getName().substring(3);
+ name = PropertyNamingStrategy.SNAKE_CASE.nameForSetterMethod(null, null, name);
+ return StringUtils.upperCase(name);
+ }
+
+ return jsonProperty.value();
+ }
+
+ public enum LegacyDefaultConf {
+ CONFIG,
+ PORT,
+ API_HOST,
+ UDP_RECEIVER_PORT,
+ TCP_RECEIVER_PORT,
+ TESTNET,
+ DEBUG,
+ REMOTE_LIMIT_API,
+ REMOTE_AUTH,
+ NEIGHBORS,
+ IXI_DIR,
+ DB_PATH,
+ DB_LOG_PATH,
+ DB_CACHE_SIZE,
+ P_REMOVE_REQUEST,
+ P_DROP_TRANSACTION,
+ P_SELECT_MILESTONE_CHILD,
+ P_SEND_MILESTONE,
+ P_REPLY_RANDOM_TIP,
+ P_PROPAGATE_REQUEST,
+ MAIN_DB, EXPORT, // exports transaction trytes to filesystem
+ SEND_LIMIT,
+ MAX_PEERS,
+ DNS_RESOLUTION_ENABLED,
+ DNS_REFRESHER_ENABLED,
+ COORDINATOR,
+ DONT_VALIDATE_TESTNET_MILESTONE_SIG,
+ REVALIDATE,
+ RESCAN_DB,
+ MIN_RANDOM_WALKS,
+ MAX_RANDOM_WALKS,
+ MAX_FIND_TRANSACTIONS,
+ MAX_REQUESTS_LIST,
+ MAX_GET_TRYTES,
+ MAX_BODY_LENGTH,
+ MAX_DEPTH,
+ MWM,
+ ZMQ_ENABLED,
+ ZMQ_PORT,
+ ZMQ_IPC,
+ ZMQ_THREADS,
+ Q_SIZE_NODE,
+ P_DROP_CACHE_ENTRY,
+ CACHE_SIZE_BYTES,
+ SNAPSHOT_FILE,
+ SNAPSHOT_SIGNATURE_FILE,
+ MILESTONE_START_INDEX,
+ NUMBER_OF_KEYS_IN_A_MILESTONE,
+ TRANSACTION_PACKET_SIZE,
+ REQUEST_HASH_SIZE,
+ SNAPSHOT_TIME,
+ TIPSELECTION_ALPHA,
+ BELOW_MAX_DEPTH_TRANSACTION_LIMIT,
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/iota/iri/conf/ConfigurationTest.java b/src/test/java/com/iota/iri/conf/ConfigurationTest.java
deleted file mode 100644
index 4de8a81d61..0000000000
--- a/src/test/java/com/iota/iri/conf/ConfigurationTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.iota.iri.conf;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by paul on 4/15/17.
- */
-public class ConfigurationTest {
- static TemporaryFolder confFolder = new TemporaryFolder();
- static File iniFile;
-
- @BeforeClass
- public static void setupClas() throws IOException {
- confFolder.create();
- iniFile = confFolder.newFile();
- }
-
- @Before
- public void setUp() throws Exception {
-
- }
-
- @Test
- public void getIniValue() throws Exception {
-
- }
-
- @Test
- public void allSettings() throws Exception {
-
- }
-
- @Test
- public void put() throws Exception {
-
- }
-
- @Test
- public void put1() throws Exception {
-
- }
-
- @Test
- public void floating() throws Exception {
-
- }
-
- @Test
- public void doubling() throws Exception {
-
- }
-
- @Test
- public void string() throws Exception {
-
- }
-
- @Test
- public void integer() throws Exception {
-
- }
-
- @Test
- public void booling() throws Exception {
-
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/com/iota/iri/controllers/BundleViewModelTest.java b/src/test/java/com/iota/iri/controllers/BundleViewModelTest.java
index 328b2d48da..b8dca71094 100644
--- a/src/test/java/com/iota/iri/controllers/BundleViewModelTest.java
+++ b/src/test/java/com/iota/iri/controllers/BundleViewModelTest.java
@@ -1,9 +1,7 @@
package com.iota.iri.controllers;
-import com.iota.iri.conf.Configuration;
import com.iota.iri.storage.Tangle;
import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider;
-import com.iota.iri.storage.rocksDB.RocksDBPersistenceProviderTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/src/test/java/com/iota/iri/controllers/MilestoneViewModelTest.java b/src/test/java/com/iota/iri/controllers/MilestoneViewModelTest.java
index 1cfc709f6f..dcaae8fed2 100644
--- a/src/test/java/com/iota/iri/controllers/MilestoneViewModelTest.java
+++ b/src/test/java/com/iota/iri/controllers/MilestoneViewModelTest.java
@@ -1,7 +1,7 @@
package com.iota.iri.controllers;
-import com.iota.iri.Milestone;
-import com.iota.iri.conf.Configuration;
+import com.iota.iri.conf.MainnetConfig;
+import com.iota.iri.conf.SnapshotConfig;
import com.iota.iri.model.Hash;
import com.iota.iri.storage.Tangle;
import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider;
@@ -168,7 +168,7 @@ public void nextWithSnapshot() throws Exception {
@Test
public void nextGreaterThan() throws Exception {
- int milestoneStartIndex = Integer.parseInt(Configuration.MAINNET_MILESTONE_START_INDEX);
+ int milestoneStartIndex = new MainnetConfig().getMilestoneStartIndex();
int first = milestoneStartIndex + 1;
int next = first + 1;
new MilestoneViewModel(next, new Hash("GBCDEBGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUV99999")).store(tangle);
diff --git a/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java b/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java
index a304dd5d50..7d63b56563 100644
--- a/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java
+++ b/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java
@@ -1,19 +1,24 @@
package com.iota.iri.controllers;
-import com.iota.iri.conf.Configuration;
+import com.iota.iri.conf.MainnetConfig;
import com.iota.iri.hash.SpongeFactory;
import com.iota.iri.model.Hash;
import com.iota.iri.model.Transaction;
-import com.iota.iri.network.TransactionRequester;
import com.iota.iri.storage.Tangle;
import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider;
import com.iota.iri.utils.Converter;
-import org.junit.*;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.Random;
+import java.util.Set;
import static org.junit.Assert.*;
@@ -320,7 +325,9 @@ public void findShouldBeSuccessful() throws Exception {
TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits));
transactionViewModel.store(tangle);
Hash hash = transactionViewModel.getHash();
- Assert.assertArrayEquals(TransactionViewModel.find(tangle, Arrays.copyOf(hash.bytes(), Integer.parseInt(Configuration.REQ_HASH_SIZE))).getBytes(), transactionViewModel.getBytes());
+ Assert.assertArrayEquals(TransactionViewModel.find(tangle,
+ Arrays.copyOf(hash.bytes(), MainnetConfig.Defaults.REQ_HASH_SIZE)).getBytes(),
+ transactionViewModel.getBytes());
}
@Test
@@ -331,7 +338,8 @@ public void findShouldReturnNull() throws Exception {
TransactionViewModel transactionViewModelNoSave = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits));
transactionViewModel.store(tangle);
Hash hash = transactionViewModelNoSave.getHash();
- Assert.assertFalse(Arrays.equals(TransactionViewModel.find(tangle, Arrays.copyOf(hash.bytes(), Integer.parseInt(Configuration.REQ_HASH_SIZE))).getBytes(), transactionViewModel.getBytes()));
+ Assert.assertFalse(Arrays.equals(TransactionViewModel.find(tangle,
+ Arrays.copyOf(hash.bytes(), new MainnetConfig().getRequestHashSize())).getBytes(), transactionViewModel.getBytes()));
}
//@Test
diff --git a/src/test/java/com/iota/iri/integration/APIIntegrationTests.java b/src/test/java/com/iota/iri/integration/APIIntegrationTests.java
index 2ee984bc4c..5eccb7e49f 100644
--- a/src/test/java/com/iota/iri/integration/APIIntegrationTests.java
+++ b/src/test/java/com/iota/iri/integration/APIIntegrationTests.java
@@ -2,10 +2,11 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import com.iota.iri.IRI;
import com.iota.iri.IXI;
import com.iota.iri.Iota;
-import com.iota.iri.conf.Configuration;
+import com.iota.iri.conf.ConfigFactory;
+import com.iota.iri.conf.IXIConfig;
+import com.iota.iri.conf.IotaConfig;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.hash.SpongeFactory;
import com.iota.iri.model.Hash;
@@ -60,7 +61,7 @@ public class APIIntegrationTests {
private static Iota iota;
private static API api;
private static IXI ixi;
- private static Configuration configuration;
+ private static IotaConfig configuration;
private static Logger log = LoggerFactory.getLogger(APIIntegrationTests.class);
@@ -69,17 +70,15 @@ public static void setUp() throws Exception {
if (spawnNode) {
//configure node parameters
log.info("IRI integration tests - initializing node.");
- configuration = new Configuration();
- String[] args = {"-p", portStr};
- configuration.put(Configuration.DefaultConfSettings.TESTNET, "true");
- IRI.validateParams(configuration, args);
TemporaryFolder dbFolder = new TemporaryFolder();
- TemporaryFolder logFolder = new TemporaryFolder();
dbFolder.create();
+ TemporaryFolder logFolder = new TemporaryFolder();
logFolder.create();
- configuration.put(Configuration.DefaultConfSettings.DB_PATH.name(), logFolder.getRoot().getAbsolutePath());
- configuration.put(Configuration.DefaultConfSettings.DB_LOG_PATH.name(), logFolder.getRoot().getAbsolutePath());
- configuration.put(Configuration.DefaultConfSettings.MWM, "1");
+
+ configuration = ConfigFactory.createIotaConfig(true);
+ String[] args = {"-p", portStr, "--testnet", "--db-path", dbFolder.getRoot().getAbsolutePath(), "--db-log-path",
+ logFolder.getRoot().getAbsolutePath(), "--mwm", "1"};
+ configuration.parseConfigFromArgs(args);
//create node
iota = new Iota(configuration);
@@ -90,7 +89,7 @@ public static void setUp() throws Exception {
try {
iota.init();
api.init();
- ixi.init(configuration.string(Configuration.DefaultConfSettings.IXI_DIR));
+ ixi.init(IXIConfig.IXI_DIR);
} catch (final Exception e) {
log.error("Exception during IOTA node initialisation: ", e);
fail("Exception during IOTA node initialisation");
@@ -369,7 +368,7 @@ public void shouldTestattachToTangle() {
request.put("trytes", TRYTES);
request.put("trunkTransaction", NULL_HASH);
request.put("branchTransaction", NULL_HASH);
- request.put("minWeightMagnitude", configuration.integer(Configuration.DefaultConfSettings.MWM));
+ request.put("minWeightMagnitude", configuration.getMwm());
given().
body(gson().toJson(request)).
@@ -391,7 +390,7 @@ private List