Merge 57cc8e2b78
into 64acf86fbe
This commit is contained in:
commit
2a325f0cf7
|
@ -1,6 +1,7 @@
|
|||
package haveno.common.config;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import com.google.gson.Gson;
|
||||
import joptsimple.AbstractOptionSpec;
|
||||
import joptsimple.ArgumentAcceptingOptionSpec;
|
||||
import joptsimple.HelpFormatter;
|
||||
|
@ -20,6 +21,7 @@ import java.io.OutputStream;
|
|||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -45,6 +47,7 @@ import static java.util.stream.Collectors.toList;
|
|||
* when adding or modifying options. Furthermore, while accessor methods are often useful
|
||||
* when mocking an object in a testing context, this class is designed for testability
|
||||
* without needing to be mocked. See {@code ConfigTests} for examples.
|
||||
*
|
||||
* @see #Config(String...)
|
||||
* @see #Config(String, File, String...)
|
||||
*/
|
||||
|
@ -135,6 +138,12 @@ public class Config {
|
|||
public final File defaultAppDataDir;
|
||||
public final File defaultConfigFile;
|
||||
|
||||
// Public key list
|
||||
public final List<String> privateNotificationPublicKeys;
|
||||
public final List<String> filterPublicKeys;
|
||||
public final List<String> arbitratorPublicKeys;
|
||||
public final List<String> alertPublicKeys;
|
||||
|
||||
// Options supported only at the command-line interface (cli)
|
||||
public final boolean helpRequested;
|
||||
public final File configFile;
|
||||
|
@ -167,7 +176,7 @@ public class Config {
|
|||
public final boolean dumpStatistics;
|
||||
public final boolean ignoreDevMsg;
|
||||
public final List<String> providers;
|
||||
public final List<String> seedNodes;
|
||||
public final List<String> seedNodes = new ArrayList<>();
|
||||
public final List<String> banList;
|
||||
public final boolean useLocalhostForP2P;
|
||||
public final int maxConnections;
|
||||
|
@ -203,6 +212,12 @@ public class Config {
|
|||
public final boolean bypassMempoolValidation;
|
||||
public final boolean passwordRequired;
|
||||
|
||||
public final double makerFeePct;
|
||||
public final double takerFeePct;
|
||||
public final double penaltyFeePct;
|
||||
public final boolean arbitratorAssignsTradeFeeAddress;
|
||||
|
||||
|
||||
// Properties derived from options but not exposed as options themselves
|
||||
public final File torDir;
|
||||
public final File walletDir;
|
||||
|
@ -220,6 +235,7 @@ public class Config {
|
|||
* to the actual system user data directory and/or real Haveno application data
|
||||
* directory. Most production use cases will favor calling the
|
||||
* {@link #Config(String, File, String...)} constructor directly.
|
||||
*
|
||||
* @param args zero or more command line arguments in the form "--optName=optValue"
|
||||
* @throws ConfigException if any problems are encountered during option parsing
|
||||
* @see #Config(String, File, String...)
|
||||
|
@ -240,9 +256,10 @@ public class Config {
|
|||
* will take precedence. Note that the {@value HELP} and {@value CONFIG_FILE} options
|
||||
* are supported only at the command line and are disallowed within the config file
|
||||
* itself.
|
||||
* @param defaultAppName typically "Haveno" or similar
|
||||
*
|
||||
* @param defaultAppName typically "Haveno" or similar
|
||||
* @param defaultUserDataDir typically the OS-specific user data directory location
|
||||
* @param args zero or more command line arguments in the form "--optName=optValue"
|
||||
* @param args zero or more command line arguments in the form "--optName=optValue"
|
||||
* @throws ConfigException if any problems are encountered during option parsing
|
||||
*/
|
||||
public Config(String defaultAppName, File defaultUserDataDir, String... args) {
|
||||
|
@ -257,7 +274,7 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<String> configFileOpt =
|
||||
parser.accepts(CONFIG_FILE, format("Specify configuration file. " +
|
||||
"Relative paths will be prefixed by %s location.", APP_DATA_DIR))
|
||||
"Relative paths will be prefixed by %s location.", APP_DATA_DIR))
|
||||
.withRequiredArg()
|
||||
.ofType(String.class)
|
||||
.defaultsTo(DEFAULT_CONFIG_FILE_NAME);
|
||||
|
@ -336,7 +353,7 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<Boolean> ignoreLocalXmrNodeOpt = // TODO: update this to ignore local XMR node
|
||||
parser.accepts(IGNORE_LOCAL_XMR_NODE,
|
||||
"If set to true a Monero node running locally will be ignored")
|
||||
"If set to true a Monero node running locally will be ignored")
|
||||
.withRequiredArg()
|
||||
.ofType(Boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
@ -356,21 +373,21 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<Boolean> useDevModeOpt =
|
||||
parser.accepts(USE_DEV_MODE,
|
||||
"Enables dev mode which is used for convenience for developer testing")
|
||||
"Enables dev mode which is used for convenience for developer testing")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
||||
ArgumentAcceptingOptionSpec<Boolean> useDevModeHeaderOpt =
|
||||
parser.accepts(USE_DEV_MODE_HEADER,
|
||||
"Use dev mode css scheme to distinguish dev instances.")
|
||||
"Use dev mode css scheme to distinguish dev instances.")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
||||
ArgumentAcceptingOptionSpec<Boolean> useDevPrivilegeKeysOpt =
|
||||
parser.accepts(USE_DEV_PRIVILEGE_KEYS, "If set to true all privileged features requiring a private " +
|
||||
"key to be enabled are overridden by a dev key pair (This is for developers only!)")
|
||||
"key to be enabled are overridden by a dev key pair (This is for developers only!)")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
@ -383,9 +400,9 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<Boolean> ignoreDevMsgOpt =
|
||||
parser.accepts(IGNORE_DEV_MSG, "If set to true all signed " +
|
||||
"network_messages from haveno developers are ignored (Global " +
|
||||
"alert, Version update alert, Filters for offers, nodes or " +
|
||||
"trading account data)")
|
||||
"network_messages from haveno developers are ignored (Global " +
|
||||
"alert, Version update alert, Filters for offers, nodes or " +
|
||||
"trading account data)")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
@ -398,7 +415,7 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<String> seedNodesOpt =
|
||||
parser.accepts(SEED_NODES, "Override hard coded seed nodes as comma separated list e.g. " +
|
||||
"'rxdkppp3vicnbgqt.onion:8002,mfla72c4igh5ta2t.onion:8002'")
|
||||
"'rxdkppp3vicnbgqt.onion:8002,mfla72c4igh5ta2t.onion:8002'")
|
||||
.withRequiredArg()
|
||||
.withValuesSeparatedBy(',')
|
||||
.describedAs("host:port[,...]");
|
||||
|
@ -430,22 +447,22 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<String> socks5ProxyHttpAddressOpt =
|
||||
parser.accepts(SOCKS_5_PROXY_HTTP_ADDRESS,
|
||||
"A proxy address to be used for Http requests (should be non-Tor)")
|
||||
"A proxy address to be used for Http requests (should be non-Tor)")
|
||||
.withRequiredArg()
|
||||
.describedAs("host:port")
|
||||
.defaultsTo("");
|
||||
|
||||
ArgumentAcceptingOptionSpec<Path> torrcFileOpt =
|
||||
parser.accepts(TORRC_FILE, "An existing torrc-file to be sourced for Tor. Note that torrc-entries, " +
|
||||
"which are critical to Haveno's correct operation, cannot be overwritten.")
|
||||
"which are critical to Haveno's correct operation, cannot be overwritten.")
|
||||
.withRequiredArg()
|
||||
.describedAs("File")
|
||||
.withValuesConvertedBy(new PathConverter(PathProperties.FILE_EXISTING, PathProperties.READABLE));
|
||||
|
||||
ArgumentAcceptingOptionSpec<String> torrcOptionsOpt =
|
||||
parser.accepts(TORRC_OPTIONS, "A list of torrc-entries to amend to Haveno's torrc. Note that " +
|
||||
"torrc-entries, which are critical to Haveno's flawless operation, cannot be overwritten. " +
|
||||
"[torrc options line, torrc option, ...]")
|
||||
"torrc-entries, which are critical to Haveno's flawless operation, cannot be overwritten. " +
|
||||
"[torrc options line, torrc option, ...]")
|
||||
.withRequiredArg()
|
||||
.withValuesConvertedBy(RegexMatcher.regex("^([^\\s,]+\\s[^,]+,?\\s*)+$"))
|
||||
.defaultsTo("");
|
||||
|
@ -457,7 +474,7 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<Integer> torControlPortOpt =
|
||||
parser.accepts(TOR_CONTROL_PORT,
|
||||
"The control port of an already running Tor service to be used by Haveno.")
|
||||
"The control port of an already running Tor service to be used by Haveno.")
|
||||
.availableUnless(TORRC_FILE, TORRC_OPTIONS)
|
||||
.withRequiredArg()
|
||||
.ofType(int.class)
|
||||
|
@ -472,7 +489,7 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<Path> torControlCookieFileOpt =
|
||||
parser.accepts(TOR_CONTROL_COOKIE_FILE, "The cookie file for authenticating against the already " +
|
||||
"running Tor service. Use in conjunction with --" + TOR_CONTROL_USE_SAFE_COOKIE_AUTH)
|
||||
"running Tor service. Use in conjunction with --" + TOR_CONTROL_USE_SAFE_COOKIE_AUTH)
|
||||
.availableIf(TOR_CONTROL_PORT)
|
||||
.availableUnless(TOR_CONTROL_PASSWORD)
|
||||
.withRequiredArg()
|
||||
|
@ -481,7 +498,7 @@ public class Config {
|
|||
|
||||
OptionSpecBuilder torControlUseSafeCookieAuthOpt =
|
||||
parser.accepts(TOR_CONTROL_USE_SAFE_COOKIE_AUTH,
|
||||
"Use the SafeCookie method when authenticating to the already running Tor service.")
|
||||
"Use the SafeCookie method when authenticating to the already running Tor service.")
|
||||
.availableIf(TOR_CONTROL_COOKIE_FILE);
|
||||
|
||||
OptionSpecBuilder torStreamIsolationOpt =
|
||||
|
@ -550,21 +567,21 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<String> socks5DiscoverModeOpt =
|
||||
parser.accepts(SOCKS5_DISCOVER_MODE, "Specify discovery mode for Bitcoin nodes. " +
|
||||
"One or more of: [ADDR, DNS, ONION, ALL] (comma separated, they get OR'd together).")
|
||||
"One or more of: [ADDR, DNS, ONION, ALL] (comma separated, they get OR'd together).")
|
||||
.withRequiredArg()
|
||||
.describedAs("mode[,...]")
|
||||
.defaultsTo("ALL");
|
||||
|
||||
ArgumentAcceptingOptionSpec<Boolean> useAllProvidedNodesOpt =
|
||||
parser.accepts(USE_ALL_PROVIDED_NODES,
|
||||
"Set to true if connection of bitcoin nodes should include clear net nodes")
|
||||
"Set to true if connection of bitcoin nodes should include clear net nodes")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
||||
ArgumentAcceptingOptionSpec<String> userAgentOpt =
|
||||
parser.accepts(USER_AGENT,
|
||||
"User agent at btc node connections")
|
||||
"User agent at btc node connections")
|
||||
.withRequiredArg()
|
||||
.defaultsTo("Haveno");
|
||||
|
||||
|
@ -587,28 +604,28 @@ public class Config {
|
|||
|
||||
ArgumentAcceptingOptionSpec<Boolean> preventPeriodicShutdownAtSeedNodeOpt =
|
||||
parser.accepts(PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE,
|
||||
"Prevents periodic shutdown at seed nodes")
|
||||
"Prevents periodic shutdown at seed nodes")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
||||
ArgumentAcceptingOptionSpec<Boolean> republishMailboxEntriesOpt =
|
||||
parser.accepts(REPUBLISH_MAILBOX_ENTRIES,
|
||||
"Republish mailbox messages at startup")
|
||||
"Republish mailbox messages at startup")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
||||
ArgumentAcceptingOptionSpec<Boolean> bypassMempoolValidationOpt =
|
||||
parser.accepts(BYPASS_MEMPOOL_VALIDATION,
|
||||
"Prevents mempool check of trade parameters")
|
||||
"Prevents mempool check of trade parameters")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
||||
ArgumentAcceptingOptionSpec<Boolean> passwordRequiredOpt =
|
||||
parser.accepts(PASSWORD_REQUIRED,
|
||||
"Requires a password for creating a Haveno account")
|
||||
"Requires a password for creating a Haveno account")
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class)
|
||||
.defaultsTo(false);
|
||||
|
@ -696,7 +713,7 @@ public class Config {
|
|||
this.dumpStatistics = options.valueOf(dumpStatisticsOpt);
|
||||
this.ignoreDevMsg = options.valueOf(ignoreDevMsgOpt);
|
||||
this.providers = options.valuesOf(providersOpt);
|
||||
this.seedNodes = options.valuesOf(seedNodesOpt);
|
||||
this.seedNodes.addAll(options.valuesOf(seedNodesOpt));
|
||||
this.banList = options.valuesOf(banListOpt);
|
||||
this.useLocalhostForP2P = !this.baseCurrencyNetwork.isMainnet() && options.valueOf(useLocalhostForP2POpt);
|
||||
this.maxConnections = options.valueOf(maxConnectionsOpt);
|
||||
|
@ -739,6 +756,31 @@ public class Config {
|
|||
this.torDir = mkdir(btcNetworkDir, "tor");
|
||||
this.walletDir = mkdir(btcNetworkDir, "wallet");
|
||||
|
||||
// Get network specific settings
|
||||
File jsonFile = new File(btcNetworkDir.getAbsolutePath() + "/network.json");
|
||||
try {
|
||||
if(!jsonFile.exists()) {
|
||||
jsonFile.createNewFile();
|
||||
String json = new Gson().toJson(new NetworkJSONFile());
|
||||
Files.writeString(jsonFile.toPath(), json);
|
||||
}
|
||||
NetworkJSONFile network_info = new Gson().fromJson(Files.readString(jsonFile.toPath()), NetworkJSONFile.class);
|
||||
this.alertPublicKeys = network_info.getAlertKeys();
|
||||
this.arbitratorPublicKeys = network_info.getArbitratorKeys();
|
||||
this.filterPublicKeys = network_info.getFilterKeys();
|
||||
this.privateNotificationPublicKeys = network_info.getPrivateNotificationKeys();
|
||||
|
||||
this.makerFeePct = network_info.getMaker_ratio();
|
||||
this.takerFeePct = network_info.getTaker_ratio();
|
||||
this.penaltyFeePct = network_info.getTaker_ratio();
|
||||
this.arbitratorAssignsTradeFeeAddress = network_info.getArbitratorAssignsTradeFeeAddress();
|
||||
|
||||
for(NetworkJSONFile.NetworkJSONFileSeedNode seedNode : network_info.getSeedNodes()) {
|
||||
seedNodes.add(seedNode.onionAddress);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ConfigException("Failed to process network.json file: ", e);
|
||||
}
|
||||
// Assign values to special-case static fields
|
||||
APP_DATA_DIR_VALUE = appDataDir;
|
||||
BASE_CURRENCY_NETWORK_VALUE = baseCurrencyNetwork;
|
||||
|
@ -779,7 +821,6 @@ public class Config {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// == STATIC UTILS ===================================================================
|
||||
|
||||
private static String randomAppName() {
|
||||
|
@ -804,6 +845,7 @@ public class Config {
|
|||
/**
|
||||
* Creates {@value APP_DATA_DIR} including any nonexistent parent directories. Does
|
||||
* nothing if the directory already exists.
|
||||
*
|
||||
* @return the given directory, now guaranteed to exist
|
||||
*/
|
||||
private static File mkAppDataDir(File dir) {
|
||||
|
@ -820,6 +862,7 @@ public class Config {
|
|||
/**
|
||||
* Creates child directory assuming parent directories already exist. Does nothing if
|
||||
* the directory already exists.
|
||||
*
|
||||
* @return the child directory, now guaranteed to exist
|
||||
*/
|
||||
private static File mkdir(File parent, String child) {
|
||||
|
@ -843,10 +886,11 @@ public class Config {
|
|||
* because of its large number of subclasses, injecting the Guice-managed
|
||||
* {@link Config} class is not worth the effort. {@link #appDataDir} should be
|
||||
* favored in all other cases.
|
||||
*
|
||||
* @throws NullPointerException if the static value has not yet been assigned, i.e. if
|
||||
* the Guice-managed {@link Config} class has not yet been instantiated elsewhere.
|
||||
* This should never be the case, as Guice wiring always happens before any
|
||||
* {@code Overlay} class is instantiated.
|
||||
* the Guice-managed {@link Config} class has not yet been instantiated elsewhere.
|
||||
* This should never be the case, as Guice wiring always happens before any
|
||||
* {@code Overlay} class is instantiated.
|
||||
*/
|
||||
public static File appDataDir() {
|
||||
return checkNotNull(APP_DATA_DIR_VALUE, "The static appDataDir has not yet " +
|
||||
|
@ -873,6 +917,7 @@ public class Config {
|
|||
* the <a href="https://en.wikipedia.org/wiki/Law_of_Demeter">Law of Demeter</a>. The
|
||||
* non-static {@link #baseCurrencyNetwork} property should be favored whenever
|
||||
* possible.
|
||||
*
|
||||
* @see #baseCurrencyNetwork()
|
||||
*/
|
||||
public static NetworkParameters baseCurrencyNetworkParameters() {
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
package haveno.common.config;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NetworkJSONFile {
|
||||
|
||||
private List<String> alertKeys = new ArrayList<>();
|
||||
private List<String> arbitratorKeys = new ArrayList<>();
|
||||
private List<String> filterKeys = new ArrayList<>();
|
||||
private List<String> privateNotificationKeys = new ArrayList<>();
|
||||
|
||||
private Boolean arbitratorAssignsTradeFeeAddress = true;
|
||||
private Double maker_ratio = 0.0015;
|
||||
private Double taker_ratio = 0.0075;
|
||||
private Double penalty_ratio = 0.02;
|
||||
/*
|
||||
private static final boolean ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS_DEFAULT = true;
|
||||
private static final double TAKER_RATIO_DEFAULT = 0.0015;
|
||||
private static final double MAKER_RATIO_DEFAULT = 0.0075;
|
||||
private static final double PENALTY_RATIO_DEFAULT = 0.02;*/
|
||||
|
||||
private List<NetworkJSONFileSeedNode> seedNodes = new ArrayList<>();
|
||||
|
||||
public boolean getArbitratorAssignsTradeFeeAddress() {
|
||||
return arbitratorAssignsTradeFeeAddress;
|
||||
}
|
||||
|
||||
public void setArbitratorAssignsTradeFeeAddress(Boolean arbitratorAssignsTradeFeeAddress) {
|
||||
this.arbitratorAssignsTradeFeeAddress = arbitratorAssignsTradeFeeAddress;
|
||||
}
|
||||
|
||||
public double getTaker_ratio() {
|
||||
return taker_ratio;
|
||||
}
|
||||
|
||||
public void setTaker_ratio(Double taker_ratio) {
|
||||
this.taker_ratio = taker_ratio;
|
||||
}
|
||||
|
||||
public double getMaker_ratio() {
|
||||
return maker_ratio;
|
||||
}
|
||||
|
||||
public void setMaker_ratio(Double maker_ratio) {
|
||||
this.maker_ratio = maker_ratio;
|
||||
}
|
||||
|
||||
public double getPenalty_ratio() {
|
||||
return penalty_ratio;
|
||||
}
|
||||
|
||||
public void setPenalty_ratio(Double penalty_ratio) {
|
||||
this.penalty_ratio = penalty_ratio;
|
||||
}
|
||||
|
||||
public List<String> getAlertKeys() {
|
||||
if(privateNotificationKeys == null || privateNotificationKeys.size() < 1) throw new NetworkJSONParseException("alertKeys needs to be a populated list of public keys!");
|
||||
return alertKeys;
|
||||
}
|
||||
|
||||
public void setAlertKeys(List<String> alertKeys) {
|
||||
this.alertKeys = alertKeys;
|
||||
}
|
||||
|
||||
public List<String> getArbitratorKeys() {
|
||||
if(privateNotificationKeys == null || privateNotificationKeys.size() < 1) throw new NetworkJSONParseException("arbitratorKeys needs to be a populated list of public keys!");
|
||||
return arbitratorKeys;
|
||||
}
|
||||
|
||||
public void setArbitratorKeys(List<String> arbitratorKeys) {
|
||||
this.arbitratorKeys = arbitratorKeys;
|
||||
}
|
||||
|
||||
public List<String> getFilterKeys() {
|
||||
if(privateNotificationKeys == null || privateNotificationKeys.size() < 1) throw new NetworkJSONParseException("filterKeys needs to be a populated list of public keys!");
|
||||
return filterKeys;
|
||||
}
|
||||
|
||||
public void setFilterKeys(List<String> filterKeys) {
|
||||
this.filterKeys = filterKeys;
|
||||
}
|
||||
|
||||
public List<String> getPrivateNotificationKeys() {
|
||||
if(privateNotificationKeys == null || privateNotificationKeys.size() < 1) throw new NetworkJSONParseException("privateNotificationKeys needs to be a populated list of public keys!");
|
||||
return privateNotificationKeys;
|
||||
}
|
||||
|
||||
public void setPrivateNotificationKeys(List<String> privateNotificationKeys) {
|
||||
this.privateNotificationKeys = privateNotificationKeys;
|
||||
}
|
||||
|
||||
public List<NetworkJSONFileSeedNode> getSeedNodes() {
|
||||
if(seedNodes == null || seedNodes.size() < 1) throw new NetworkJSONParseException("seedNodes needs to be a populated list of seed nodes!");
|
||||
return seedNodes;
|
||||
}
|
||||
|
||||
public void setSeedNodes(List<NetworkJSONFileSeedNode> seedNodes) {
|
||||
this.seedNodes = seedNodes;
|
||||
}
|
||||
|
||||
class NetworkJSONFileSeedNode {
|
||||
String onionAddress;
|
||||
String info;
|
||||
}
|
||||
|
||||
class NetworkJSONParseException extends ConfigException {
|
||||
public NetworkJSONParseException(String format, Object... args) {
|
||||
super(format, args);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ import com.google.inject.name.Named;
|
|||
import haveno.common.app.DevEnv;
|
||||
import haveno.common.config.Config;
|
||||
import haveno.common.crypto.KeyRing;
|
||||
import haveno.core.trade.HavenoUtils;
|
||||
import haveno.core.user.User;
|
||||
import haveno.network.p2p.P2PService;
|
||||
import haveno.network.p2p.storage.HashMapChangedListener;
|
||||
|
@ -109,7 +110,7 @@ public class AlertManager {
|
|||
"026c581ad773d987e6bd10785ac7f7e0e64864aedeb8bce5af37046de812a37854",
|
||||
"025b058c9f2c60d839669dbfa5578cf5a8117d60e6b70e2f0946f8a691273c6a36");
|
||||
case XMR_MAINNET:
|
||||
return List.of();
|
||||
return HavenoUtils.havenoSetup.getConfig().alertPublicKeys;
|
||||
default:
|
||||
throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork());
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import haveno.common.config.Config;
|
|||
import haveno.common.crypto.KeyRing;
|
||||
import haveno.common.crypto.PubKeyRing;
|
||||
import haveno.common.proto.network.NetworkEnvelope;
|
||||
import haveno.core.trade.HavenoUtils;
|
||||
import haveno.network.p2p.DecryptedMessageWithPubKey;
|
||||
import haveno.network.p2p.NodeAddress;
|
||||
import haveno.network.p2p.P2PService;
|
||||
|
@ -108,7 +109,7 @@ public class PrivateNotificationManager implements MessageListener {
|
|||
"026c581ad773d987e6bd10785ac7f7e0e64864aedeb8bce5af37046de812a37854",
|
||||
"025b058c9f2c60d839669dbfa5578cf5a8117d60e6b70e2f0946f8a691273c6a36");
|
||||
case XMR_MAINNET:
|
||||
return List.of();
|
||||
return HavenoUtils.havenoSetup.getConfig().privateNotificationPublicKeys;
|
||||
default:
|
||||
throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork());
|
||||
}
|
||||
|
|
|
@ -384,6 +384,8 @@ public class HavenoSetup {
|
|||
p2PService.getP2PDataStorage().readFromResources(postFix, completeHandler);
|
||||
}
|
||||
|
||||
public Config getConfig() {return config;}
|
||||
|
||||
private synchronized void resetStartupTimeout() {
|
||||
if (p2pNetworkAndWalletInitialized != null && p2pNetworkAndWalletInitialized.get()) return; // skip if already initialized
|
||||
if (startupTimeout != null) startupTimeout.stop();
|
||||
|
|
|
@ -116,9 +116,7 @@ public class FilterManager {
|
|||
|
||||
publicKeys = useDevPrivilegeKeys ?
|
||||
Collections.singletonList(DevEnv.DEV_PRIVILEGE_PUB_KEY) :
|
||||
List.of("0358d47858acdc41910325fce266571540681ef83a0d6fedce312bef9810793a27",
|
||||
"029340c3e7d4bb0f9e651b5f590b434fecb6175aeaa57145c7804ff05d210e534f",
|
||||
"034dc7530bf66ffd9580aa98031ea9a18ac2d269f7c56c0e71eca06105b9ed69f9");
|
||||
config.filterPublicKeys;
|
||||
|
||||
banFilter.setBannedNodePredicate(this::isNodeAddressBannedFromNetwork);
|
||||
}
|
||||
|
|
|
@ -189,9 +189,9 @@ public class CreateOfferService {
|
|||
useMarketBasedPriceValue,
|
||||
amountAsLong,
|
||||
minAmountAsLong,
|
||||
HavenoUtils.MAKER_FEE_PCT,
|
||||
HavenoUtils.TAKER_FEE_PCT,
|
||||
HavenoUtils.PENALTY_FEE_PCT,
|
||||
HavenoUtils.havenoSetup.getConfig().makerFeePct,
|
||||
HavenoUtils.havenoSetup.getConfig().takerFeePct,
|
||||
HavenoUtils.havenoSetup.getConfig().penaltyFeePct,
|
||||
securityDepositAsDouble,
|
||||
securityDepositAsDouble,
|
||||
baseCurrencyCode,
|
||||
|
|
|
@ -40,6 +40,7 @@ import haveno.common.config.Config;
|
|||
import haveno.common.crypto.KeyRing;
|
||||
import haveno.core.filter.FilterManager;
|
||||
import haveno.core.support.dispute.agent.DisputeAgentManager;
|
||||
import haveno.core.trade.HavenoUtils;
|
||||
import haveno.core.user.User;
|
||||
import haveno.network.p2p.storage.payload.ProtectedStorageEntry;
|
||||
import java.util.ArrayList;
|
||||
|
@ -49,7 +50,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||
@Slf4j
|
||||
@Singleton
|
||||
public class ArbitratorManager extends DisputeAgentManager<Arbitrator> {
|
||||
|
||||
@Inject
|
||||
public ArbitratorManager(KeyRing keyRing,
|
||||
ArbitratorService arbitratorService,
|
||||
|
@ -79,7 +79,7 @@ public class ArbitratorManager extends DisputeAgentManager<Arbitrator> {
|
|||
"02a1a458df5acf4ab08fdca748e28f33a955a30854c8c1a831ee733dca7f0d2fcd",
|
||||
"0374dd70f3fa6e47ec5ab97932e1cec6233e98e6ae3129036b17118650c44fd3de");
|
||||
case XMR_MAINNET:
|
||||
return new ArrayList<String>();
|
||||
return HavenoUtils.havenoSetup.getConfig().arbitratorPublicKeys;
|
||||
default:
|
||||
throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork());
|
||||
}
|
||||
|
|
|
@ -37,12 +37,39 @@ Run `./gradlew generateKeypairs`. A list of public/private keypairs will print t
|
|||
|
||||
For demonstration, we can use the first generated public/private keypair for all roles, but you can customize as desired.
|
||||
|
||||
Hardcode the public key(s) in these files:
|
||||
The public keys are stored in the `network.json` file inside the appdata folder, which resolves to these locations by default with the appName `haveno-XMR_MAINNET_Seed_1002` would resolve to `~/.local/share/haveno-XMR_MAINNET_Seed_1002/xmr_mainnet/network.json`
|
||||
Here is an example config:
|
||||
|
||||
- [AlertManager.java](https://github.com/haveno-dex/haveno/blob/1bf83ecb8baa06b6bfcc30720f165f20b8f77025/core/src/main/java/haveno/core/alert/AlertManager.java#L111)
|
||||
- [ArbitratorManager.java](https://github.com/haveno-dex/haveno/blob/1bf83ecb8baa06b6bfcc30720f165f20b8f77025/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java#L81)
|
||||
- [FilterManager.java](https://github.com/haveno-dex/haveno/blob/1bf83ecb8baa06b6bfcc30720f165f20b8f77025/core/src/main/java/haveno/core/filter/FilterManager.java#L117)
|
||||
- [PrivateNotificationManager.java](https://github.com/haveno-dex/haveno/blob/mainnet_placeholders/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java#L110)
|
||||
```json
|
||||
{
|
||||
"alertKeys": [
|
||||
"03894c9184e7a59a55e3fc14cfeae6df446b4a216a401ae7fb59bc83bf340a0ac7"
|
||||
],
|
||||
"arbitratorKeys": [
|
||||
"03894c9184e7a59a55e3fc14cfeae6df446b4a216a401ae7fb59bc83bf340a0ac7"
|
||||
],
|
||||
"filterKeys": [
|
||||
"03894c9184e7a59a55e3fc14cfeae6df446b4a216a401ae7fb59bc83bf340a0ac7"
|
||||
],
|
||||
"privateNotificationKeys": [
|
||||
"03894c9184e7a59a55e3fc14cfeae6df446b4a216a401ae7fb59bc83bf340a0ac7"
|
||||
],
|
||||
"arbitratorAssignsTradeFeeAddress": true,
|
||||
"maker_ratio": 0.0025,
|
||||
"taker_ratio": 0.0075,
|
||||
"penalty_ratio": 0.02,
|
||||
"seedNodes":[
|
||||
{
|
||||
"onionAddress": "example.onion:1002",
|
||||
"info": "@nobody"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Fill in the JSON file with the network's settings or replace it with the provided `network.json`
|
||||
|
||||
## Change the default folder name for Haveno application data
|
||||
|
||||
|
@ -142,4 +169,4 @@ To build the installers for distribution, first change `XMR_STAGENET` to `XMR_MA
|
|||
|
||||
Then [follow instructions](https://github.com/haveno-dex/haveno/blob/master/desktop/package/README.md) to build the installers for distribution.
|
||||
|
||||
Alternatively, the installers are built automatically by GitHub.
|
||||
Alternatively, the installers are built automatically by GitHub.
|
||||
|
|
Loading…
Reference in New Issue