mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-11-16 15:58:08 +00:00
add deployment guide and support for mainnet
This commit is contained in:
parent
05520d51a3
commit
a5663e1411
9 changed files with 272 additions and 29 deletions
97
Makefile
97
Makefile
|
@ -340,4 +340,99 @@ user3-desktop-stagenet:
|
||||||
monerod:
|
monerod:
|
||||||
./.localnet/monerod \
|
./.localnet/monerod \
|
||||||
--bootstrap-daemon-address auto \
|
--bootstrap-daemon-address auto \
|
||||||
--rpc-access-control-origins http://localhost:8080 \
|
--rpc-access-control-origins http://localhost:8080 \
|
||||||
|
|
||||||
|
seednode:
|
||||||
|
./haveno-seednode$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1002 \
|
||||||
|
--appName=haveno-XMR_MAINNET_Seed_1002 \
|
||||||
|
--xmrNode=http://127.0.0.1:18081
|
||||||
|
|
||||||
|
seednode2:
|
||||||
|
./haveno-seednode$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1003 \
|
||||||
|
--appName=haveno-XMR_MAINNET_Seed_1003 \
|
||||||
|
--xmrNode=http://127.0.0.1:18081
|
||||||
|
|
||||||
|
arbitrator-daemon:
|
||||||
|
# Arbitrator needs to be registered before making trades
|
||||||
|
./haveno-daemon$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1100 \
|
||||||
|
--appName=haveno-XMR_MAINNET_arbitrator \
|
||||||
|
--apiPassword=apitest \
|
||||||
|
--apiPort=1200 \
|
||||||
|
--passwordRequired=false \
|
||||||
|
--xmrNode=http://127.0.0.1:18081
|
||||||
|
|
||||||
|
# Arbitrator needs to be registered before making trades
|
||||||
|
arbitrator-desktop:
|
||||||
|
./haveno-desktop$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1100 \
|
||||||
|
--appName=haveno-XMR_MAINNET_arbitrator \
|
||||||
|
--apiPassword=apitest \
|
||||||
|
--apiPort=1200 \
|
||||||
|
--xmrNode=http://127.0.0.1:18081
|
||||||
|
|
||||||
|
user1-daemon:
|
||||||
|
./haveno-daemon$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1101 \
|
||||||
|
--appName=haveno-XMR_MAINNET_user1 \
|
||||||
|
--apiPassword=apitest \
|
||||||
|
--apiPort=1201 \
|
||||||
|
--passwordRequired=false
|
||||||
|
|
||||||
|
user1-desktop:
|
||||||
|
./haveno-desktop$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1101 \
|
||||||
|
--appName=haveno-XMR_MAINNET_user1 \
|
||||||
|
--apiPassword=apitest \
|
||||||
|
--apiPort=1201
|
||||||
|
|
||||||
|
user2-daemon:
|
||||||
|
./haveno-daemon$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1102 \
|
||||||
|
--appName=haveno-XMR_MAINNET_user2 \
|
||||||
|
--apiPassword=apitest \
|
||||||
|
--apiPort=1202 \
|
||||||
|
--passwordRequired=false
|
||||||
|
|
||||||
|
user2-desktop:
|
||||||
|
./haveno-desktop$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1102 \
|
||||||
|
--appName=haveno-XMR_MAINNET_user2 \
|
||||||
|
--apiPassword=apitest \
|
||||||
|
--apiPort=1202
|
||||||
|
|
||||||
|
user3-desktop:
|
||||||
|
./haveno-desktop$(APP_EXT) \
|
||||||
|
--baseCurrencyNetwork=XMR_MAINNET \
|
||||||
|
--useLocalhostForP2P=false \
|
||||||
|
--useDevPrivilegeKeys=false \
|
||||||
|
--nodePort=1103 \
|
||||||
|
--appName=haveno-XMR_MAINNET_user3 \
|
||||||
|
--apiPassword=apitest \
|
||||||
|
--apiPort=1203
|
|
@ -143,7 +143,7 @@ public class FilterManager {
|
||||||
|
|
||||||
// On mainNet we expect to have received a filter object, if not show a popup to the user to inform the
|
// On mainNet we expect to have received a filter object, if not show a popup to the user to inform the
|
||||||
// Haveno devs.
|
// Haveno devs.
|
||||||
if (Config.baseCurrencyNetwork().isMainnet() && getFilter() == null) {
|
if (Config.baseCurrencyNetwork().isMainnet() && getFilter() == null && filterWarningHandler != null) {
|
||||||
filterWarningHandler.accept(Res.get("popup.warning.noFilter"));
|
filterWarningHandler.accept(Res.get("popup.warning.noFilter"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class XmrNodes {
|
||||||
new XmrNode(MoneroNodesOption.PUBLIC, null, null, "stagenet.melo.tools", 38081, 3, null),
|
new XmrNode(MoneroNodesOption.PUBLIC, null, null, "stagenet.melo.tools", 38081, 3, null),
|
||||||
new XmrNode(MoneroNodesOption.PUBLIC, null, null, "node.sethforprivacy.com", 38089, 3, null),
|
new XmrNode(MoneroNodesOption.PUBLIC, null, null, "node.sethforprivacy.com", 38089, 3, null),
|
||||||
new XmrNode(MoneroNodesOption.PUBLIC, null, null, "node2.sethforprivacy.com", 38089, 3, null),
|
new XmrNode(MoneroNodesOption.PUBLIC, null, null, "node2.sethforprivacy.com", 38089, 3, null),
|
||||||
new XmrNode(MoneroNodesOption.PUBLIC, null, "plowsof3t5hogddwabaeiyrno25efmzfxyro2vligremt7sxpsclfaid.onion", null, 38089, 2, null)
|
new XmrNode(MoneroNodesOption.PUBLIC, null, "plowsof3t5hogddwabaeiyrno25efmzfxyro2vligremt7sxpsclfaid.onion", null, 38089, 3, null)
|
||||||
);
|
);
|
||||||
case XMR_MAINNET:
|
case XMR_MAINNET:
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
|
|
|
@ -2182,8 +2182,8 @@ popup.shutDownInProgress.headline=Shut down in progress
|
||||||
popup.shutDownInProgress.msg=Shutting down application can take a few seconds.\nPlease don't interrupt this process.
|
popup.shutDownInProgress.msg=Shutting down application can take a few seconds.\nPlease don't interrupt this process.
|
||||||
|
|
||||||
popup.attention.forTradeWithId=Attention required for trade with ID {0}
|
popup.attention.forTradeWithId=Attention required for trade with ID {0}
|
||||||
popup.attention.newFeatureDuplicateOffer=Welcome to the Haveno test instance!\n\n\
|
popup.attention.welcome.test=Welcome to the Haveno test instance!\n\n\
|
||||||
This platform allows you to test Haveno's protocol. The user interface is still very rough and some parts are not yet implemented or stable. We suggest to test only the basic functions, like opening or taking a trade. Make sure to follow the instructions[HYPERLINK:https://github.com/haveno-dex/haveno/blob/master/docs/installing.md].\n\n\
|
This platform allows you to test Haveno's protocol. Make sure to follow the instructions[HYPERLINK:https://github.com/haveno-dex/haveno/blob/master/docs/installing.md].\n\n\
|
||||||
If you encounter any problem, please let us know by opening an issue[HYPERLINK:https://github.com/haveno-dex/haveno/issues/new].\n\n\
|
If you encounter any problem, please let us know by opening an issue[HYPERLINK:https://github.com/haveno-dex/haveno/issues/new].\n\n\
|
||||||
This is a test instance. Do not use real money!
|
This is a test instance. Do not use real money!
|
||||||
|
|
||||||
|
|
42
core/src/test/java/haveno/core/util/GenerateKeypairs.java
Normal file
42
core/src/test/java/haveno/core/util/GenerateKeypairs.java
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package haveno.core.util;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.ECKey;
|
||||||
|
import org.bitcoinj.core.Utils;
|
||||||
|
|
||||||
|
import haveno.common.crypto.Encryption;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This utility generates and prints public/private keypairs
|
||||||
|
* which can be used to register arbitrators on the network.
|
||||||
|
*/
|
||||||
|
public class GenerateKeypairs {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// generate public/private keypairs
|
||||||
|
List<SecretKey> secretKeys = new ArrayList<SecretKey>();
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
secretKeys.add(Encryption.generateSecretKey(256));
|
||||||
|
}
|
||||||
|
|
||||||
|
// print keypairs
|
||||||
|
System.out.println("Private keys:");
|
||||||
|
for (SecretKey sk : secretKeys) {
|
||||||
|
String privKey = Utils.HEX.encode(sk.getEncoded());
|
||||||
|
System.out.println(privKey);
|
||||||
|
}
|
||||||
|
System.out.println("Corresponding public keys:");
|
||||||
|
for (SecretKey sk : secretKeys) {
|
||||||
|
String privKey = Utils.HEX.encode(sk.getEncoded());
|
||||||
|
ECKey ecKey = ECKey.fromPrivate(new BigInteger(1, Utils.HEX.decode(privKey)));
|
||||||
|
String pubKey = Utils.HEX.encode(ecKey.getPubKey());
|
||||||
|
System.out.println(pubKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import haveno.common.Timer;
|
||||||
import haveno.common.UserThread;
|
import haveno.common.UserThread;
|
||||||
import haveno.common.app.DevEnv;
|
import haveno.common.app.DevEnv;
|
||||||
import haveno.common.app.Version;
|
import haveno.common.app.Version;
|
||||||
|
import haveno.common.config.BaseCurrencyNetwork;
|
||||||
import haveno.common.config.Config;
|
import haveno.common.config.Config;
|
||||||
import haveno.common.file.CorruptedStorageFileHandler;
|
import haveno.common.file.CorruptedStorageFileHandler;
|
||||||
import haveno.common.util.Tuple2;
|
import haveno.common.util.Tuple2;
|
||||||
|
@ -272,16 +273,17 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
|
||||||
|
|
||||||
UserThread.execute(() -> getShowAppScreen().set(true));
|
UserThread.execute(() -> getShowAppScreen().set(true));
|
||||||
|
|
||||||
// We only show the popup if the user has already set up any traditional account. For new users it is not a rule
|
// show welcome message if not mainnet
|
||||||
// change and for crypto its not relevant.
|
if (Config.baseCurrencyNetwork() != BaseCurrencyNetwork.XMR_MAINNET) {
|
||||||
String key = "newFeatureDuplicateOffer";
|
String key = "welcome.test";
|
||||||
if (DontShowAgainLookup.showAgain(key)) {
|
if (DontShowAgainLookup.showAgain(key)) {
|
||||||
UserThread.runAfter(() -> {
|
UserThread.runAfter(() -> {
|
||||||
new Popup().attention(Res.get("popup.attention.newFeatureDuplicateOffer")).
|
new Popup().attention(Res.get("popup.attention.welcome.test")).
|
||||||
dontShowAgainId(key)
|
dontShowAgainId(key)
|
||||||
.closeButtonText(Res.get("shared.iUnderstand"))
|
.closeButtonText(Res.get("shared.iUnderstand"))
|
||||||
.show();
|
.show();
|
||||||
}, 1);
|
}, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
113
docs/deployment-guide.md
Normal file
113
docs/deployment-guide.md
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
# Deployment Guide
|
||||||
|
|
||||||
|
This guide describes how to deploy a Haveno network by:
|
||||||
|
|
||||||
|
- Building Haveno
|
||||||
|
- Starting a Monero node
|
||||||
|
- Building and starting price nodes
|
||||||
|
- Creating and registering seed nodes
|
||||||
|
- Generating keypairs with privileges for arbitrators and developers
|
||||||
|
- Creating and registering arbitrators
|
||||||
|
- Setting a network filter
|
||||||
|
- Building Haveno installers for distribution
|
||||||
|
|
||||||
|
## Build Haveno
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/haveno-dex/haveno.git
|
||||||
|
cd haveno
|
||||||
|
git checkout <latest tag>
|
||||||
|
make clean && make
|
||||||
|
```
|
||||||
|
|
||||||
|
See [installing.md](installing.md) for more detail.
|
||||||
|
|
||||||
|
## Start a Monero node
|
||||||
|
|
||||||
|
Seed nodes and arbitrators should use a local, trusted Monero node.
|
||||||
|
|
||||||
|
Arbitrators require a trusted node in order to submit and flush transactions from the pool.
|
||||||
|
|
||||||
|
Start a Monero node by running `make monerod` for mainnet or `make monerod-stagenet` for stagenet.
|
||||||
|
|
||||||
|
## Build and start price nodes
|
||||||
|
|
||||||
|
The price node is separated from Haveno and is to be run as a standalone service. To deploy a pricenode on both Tor and clearnet, see the instructions on the repository: https://github.com/haveno-dex/haveno-pricenode
|
||||||
|
|
||||||
|
## Create and register seed nodes
|
||||||
|
|
||||||
|
From the root of the repository, run `make seednode` to run a seednode on Monero's mainnet or `make seednode-stagenet` to run a seednode on Monero's stagenet.
|
||||||
|
|
||||||
|
The node will print its onion address to the console.
|
||||||
|
|
||||||
|
If you are building a network from scratch: for each seednode, record the onion address in `core/src/main/resources/xmr_<network>.seednodes` and remove unused seed nodes from `xmr_<network>.seednodes`. Be careful to record full addresses correctly.
|
||||||
|
|
||||||
|
Rebuild the seed nodes any time the list of registered seed nodes changes.
|
||||||
|
|
||||||
|
Each seed node requires a locally running Monero node. You can use the default port or configure it manually with `--xmrNode`, `--xmrNodeUsername`, and `--xmrNodePassword`.
|
||||||
|
|
||||||
|
## Generate keypairs with arbitrator privileges
|
||||||
|
|
||||||
|
1. Run core/src/test/java/haveno/core/util/GenerateKeypairs.java to generate public/private keypairs for arbitrator privileges.
|
||||||
|
2. Add arbitrator public keys to the corresponding network type in ArbitratorManager.java `getPubKeyList()`.
|
||||||
|
3. Rebuild using `make skip-tests`.
|
||||||
|
|
||||||
|
## Generate keypairs with developer privileges
|
||||||
|
|
||||||
|
Developer keypairs are able to set the network's filter object, which can filter out offers, onions, currencies, payment methods, etc.
|
||||||
|
|
||||||
|
1. Run core/src/test/java/haveno/core/util/GenerateKeypairs.java to generate public/private keypairs for developer privileges.
|
||||||
|
2. Set developer public keys in the constructor of FilterManager.java.
|
||||||
|
3. Rebuild using `make skip-tests`.
|
||||||
|
|
||||||
|
## Set XMR address to collect trade fees
|
||||||
|
|
||||||
|
Set the XMR address to collect trade fees in /Users/woodser/git/haveno/core/src/main/java/haveno/core/trade/HavenoUtils.java `getTradeFeeAddress()`.
|
||||||
|
|
||||||
|
## Create and register arbitrators
|
||||||
|
|
||||||
|
Before running the arbitrator, remember that at least one seednode should already be deployed and its address listed in `core/src/main/resources/xmr_<network>.seednodes`.
|
||||||
|
|
||||||
|
Run `make arbitrator-desktop` to run an arbitrator on Monero's mainnet or `make arbitrator-desktop-stagenet` to run an arbitrator on Monero's stagenet.
|
||||||
|
|
||||||
|
The Haveno GUI will open. If on mainnet, ignore the error about not receiving a filter object which is not added yet. Click on the `Account` tab and then press `ctrl + r`. A prompt will open asking to enter the key to register the arbitrator. Use a key generated in the previous steps and complete the registration. The arbitrator is now registered and ready to accept requests of dispute resolution.
|
||||||
|
|
||||||
|
Remember that for the network to run correctly and people to be able to open and accept trades, at least one arbitrator must be registered on the network.
|
||||||
|
|
||||||
|
IMPORTANT: Do not reuse keypairs, and remember to revoke the private keypair to terminate the arbitrator.
|
||||||
|
|
||||||
|
## Register a filter object on mainnet
|
||||||
|
|
||||||
|
On mainnet, the p2p network is expected to have a filter object to filter out offers, onions, currencies, payment methods, etc.
|
||||||
|
|
||||||
|
To set the network's filter object:
|
||||||
|
|
||||||
|
1. Enter `ctrl + f` in the arbitrator or other Haveno instance to open the Filter window.
|
||||||
|
2. Enter a developer private key from the previous steps and click "Add Filter" to register.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> If all seed nodes are restarted at the same time, arbitrators and the filter object will become unregistered and will need to be re-registered.
|
||||||
|
|
||||||
|
## Start users for testing
|
||||||
|
|
||||||
|
Start user1 on Monero's mainnet using `make user1-desktop` or Monero's stagenet using `make user1-desktop-stagenet`.
|
||||||
|
|
||||||
|
Similarly, start user2 on Monero's mainnet using `make user2-desktop` or Monero's stagenet using `make user2-desktop-stagenet`.
|
||||||
|
|
||||||
|
Test trades among the users and arbitrator.
|
||||||
|
|
||||||
|
## Build Haveno installers for distribution
|
||||||
|
|
||||||
|
See https://github.com/haveno-dex/haveno/blob/master/desktop/package/README.md.
|
||||||
|
|
||||||
|
## Deploy to a VPS
|
||||||
|
|
||||||
|
Haveno's services should be deployed to a VPS for reliable uptime.
|
||||||
|
|
||||||
|
Seednodes can be installed as a system service.
|
||||||
|
|
||||||
|
Arbitrators can be started in a Screen session and then detached to run in the background.
|
||||||
|
|
||||||
|
Some good hints about how to secure a VPS are in [Monero's meta repository](https://github.com/monero-project/meta/blob/master/SERVER_SETUP_HARDENING.md).
|
||||||
|
|
||||||
|
TODO: gather and document scripts for VPS management
|
5
docs/operation-manual.md
Normal file
5
docs/operation-manual.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Operation Manual
|
||||||
|
|
||||||
|
## Manually open dispute by keyboard shortcut
|
||||||
|
|
||||||
|
In the event a dispute does not open properly, try manually reopening the dispute with a keyboard shortcut: `ctrl+o`.
|
|
@ -1,14 +0,0 @@
|
||||||
# Operation Manual
|
|
||||||
|
|
||||||
This operation manual describes how to operate a Haveno network by:
|
|
||||||
|
|
||||||
- Forking Haveno
|
|
||||||
- Creating and registering seed nodes
|
|
||||||
- Creating and registering arbitrators
|
|
||||||
- Building binaries of the application
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
## Manually open dispute by keyboard shortcut
|
|
||||||
|
|
||||||
In the event a dispute does not open properly, try manually reopening the dispute with a keyboard shortcut: `ctrl+o`
|
|
Loading…
Reference in a new issue