mirror of
https://github.com/haveno-dex/haveno-ts.git
synced 2025-11-25 08:53:13 -05:00
support local, stagenet, and mainnet xmr network configurations (#122)
This commit is contained in:
parent
82e43d5940
commit
7871a303eb
4 changed files with 116 additions and 61 deletions
|
|
@ -17,7 +17,7 @@
|
||||||
"plugins": ["@typescript-eslint"],
|
"plugins": ["@typescript-eslint"],
|
||||||
"ignorePatterns": ["node_modules/**", "**/dist/**", "src/protobuf/**"],
|
"ignorePatterns": ["node_modules/**", "**/dist/**", "src/protobuf/**"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
"no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
||||||
"@typescript-eslint/no-var-requires": "off",
|
"@typescript-eslint/no-var-requires": "off",
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,10 @@ Running the [API tests](./src/HavenoClient.test.ts) is the best way to develop a
|
||||||
|
|
||||||
[`HavenoClient.ts`](./src/HavenoClient.ts) provides the client interface to Haveno's backend daemon.
|
[`HavenoClient.ts`](./src/HavenoClient.ts) provides the client interface to Haveno's backend daemon.
|
||||||
|
|
||||||
1. [Run a local Haveno test network](https://github.com/haveno-dex/haveno/blob/master/docs/installing.md) and then shut down the arbitrator, Alice, and Bob or run them as daemons, e.g. `make alice-daemon`. You may omit the arbitrator registration steps since it is done automatically in the tests.
|
1. [Run a local Haveno test network](https://github.com/haveno-dex/haveno/blob/master/docs/installing.md) and then shut down the arbitrator, Alice, and Bob or run them as daemons, e.g. `make alice-daemon-local`. You may omit the arbitrator registration steps since it's done automatically in the tests.
|
||||||
2. Clone this project to the same parent directory as the haveno project: `git clone https://github.com/haveno-dex/haveno-ts`
|
2. Clone this project to the same parent directory as the haveno project: `git clone https://github.com/haveno-dex/haveno-ts`
|
||||||
3. In a new terminal, start envoy with the config in haveno-ts/config/envoy.test.yaml (change absolute path for your system): `docker run --rm --add-host host.docker.internal:host-gateway -it -v ~/git/haveno-ts/config/envoy.test.yaml:/envoy.test.yaml -p 8079:8079 -p 8080:8080 -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8084:8084 -p 8085:8085 -p 8086:8086 envoyproxy/envoy-dev:8a2143613d43d17d1eb35a24b4a4a4c432215606 -c /envoy.test.yaml`
|
3. In a new terminal, start envoy with the config in haveno-ts/config/envoy.test.yaml (change absolute path for your system): `docker run --rm --add-host host.docker.internal:host-gateway -it -v ~/git/haveno-ts/config/envoy.test.yaml:/envoy.test.yaml -p 8079:8079 -p 8080:8080 -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8084:8084 -p 8085:8085 -p 8086:8086 envoyproxy/envoy-dev:8a2143613d43d17d1eb35a24b4a4a4c432215606 -c /envoy.test.yaml`
|
||||||
4. In a new terminal, start the funding wallet. This wallet will be automatically funded in order to fund Alice and Bob during the tests.<br>For example: `cd ~/git/haveno && make funding-wallet`.
|
4. In a new terminal, start the funding wallet. This wallet will be automatically funded in order to fund Alice and Bob during the tests.<br>For example: `cd ~/git/haveno && make funding-wallet-local`.
|
||||||
5. Install protobuf compiler v3.19.1 or later for your system:<br>
|
5. Install protobuf compiler v3.19.1 or later for your system:<br>
|
||||||
mac: `brew install protobuf`<br>
|
mac: `brew install protobuf`<br>
|
||||||
linux: `apt install protobuf-compiler`
|
linux: `apt install protobuf-compiler`
|
||||||
|
|
@ -47,4 +47,4 @@ Running the [API tests](./src/HavenoClient.test.ts) is the best way to develop a
|
||||||
6. Download `protoc-gen-grpc-web` plugin and make executable as [shown here](https://github.com/grpc/grpc-web#code-generator-plugin).
|
6. Download `protoc-gen-grpc-web` plugin and make executable as [shown here](https://github.com/grpc/grpc-web#code-generator-plugin).
|
||||||
7. `cd haveno-ts`
|
7. `cd haveno-ts`
|
||||||
8. `npm install`
|
8. `npm install`
|
||||||
9. `npm test` to run all tests or `npm run test -- -t 'my test'` to run tests by name.
|
9. `npm run test -- --baseCurrencyNetwork=XMR_LOCAL` to run all tests or `npm run test -- --baseCurrencyNetwork=XMR_LOCAL -t "my test"` to run tests by name.
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
"prepare": "scripts/build_protobuf.sh",
|
"prepare": "scripts/build_protobuf.sh",
|
||||||
"pretest": "scripts/build_protobuf.sh",
|
"pretest": "scripts/build_protobuf.sh",
|
||||||
"build": "./scripts/build_dist.sh",
|
"build": "./scripts/build_dist.sh",
|
||||||
"test": "jest ",
|
"test": "jest",
|
||||||
"eslint": "eslint .",
|
"eslint": "eslint .",
|
||||||
"eslintfix": "eslint src/* --fix",
|
"eslintfix": "eslint src/* --fix",
|
||||||
"typedoc": "typedoc ./src/index.ts --entryPointStrategy expand src/ --exclude **/*.test.ts"
|
"typedoc": "typedoc ./src/index.ts --entryPointStrategy expand src/ --exclude **/*.test.ts"
|
||||||
|
|
|
||||||
|
|
@ -14,49 +14,59 @@ import OnlineStatus = UrlConnection.OnlineStatus;
|
||||||
const monerojs = require("monero-javascript"); // TODO (woodser): support typescript and `npm install @types/monero-javascript` in monero-javascript
|
const monerojs = require("monero-javascript"); // TODO (woodser): support typescript and `npm install @types/monero-javascript` in monero-javascript
|
||||||
const GenUtils = monerojs.GenUtils;
|
const GenUtils = monerojs.GenUtils;
|
||||||
const BigInteger = monerojs.BigInteger;
|
const BigInteger = monerojs.BigInteger;
|
||||||
const MoneroNetworkType = monerojs.MoneroNetworkType;
|
|
||||||
const MoneroTxConfig = monerojs.MoneroTxConfig;
|
const MoneroTxConfig = monerojs.MoneroTxConfig;
|
||||||
const MoneroDestination = monerojs.MoneroDestination;
|
const MoneroDestination = monerojs.MoneroDestination;
|
||||||
const MoneroUtils = monerojs.MoneroUtils;
|
const MoneroUtils = monerojs.MoneroUtils;
|
||||||
const TaskLooper = monerojs.TaskLooper;
|
const TaskLooper = monerojs.TaskLooper;
|
||||||
|
|
||||||
// other required imports
|
// other imports
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import net from "net";
|
import net from "net";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import console from "console"; // import console because jest swallows messages in real time
|
import console from "console"; // import console because jest swallows messages in real time
|
||||||
|
import * as os from 'os';
|
||||||
|
|
||||||
// ------------------------------ TEST CONFIG ---------------------------------
|
// ------------------------------ TEST CONFIG ---------------------------------
|
||||||
|
|
||||||
|
enum BaseCurrencyNetwork {
|
||||||
|
XMR_MAINNET = "XMR_MAINNET",
|
||||||
|
XMR_STAGENET = "XMR_STAGENET",
|
||||||
|
XMR_LOCAL = "XMR_LOCAL"
|
||||||
|
}
|
||||||
|
|
||||||
const TestConfig = {
|
const TestConfig = {
|
||||||
logLevel: 1,
|
logLevel: 3,
|
||||||
|
baseCurrencyNetwork: getBaseCurrencyNetwork(),
|
||||||
|
networkType: getBaseCurrencyNetwork() == BaseCurrencyNetwork.XMR_MAINNET ? monerojs.MoneroNetworkType.MAINNET : getBaseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? monerojs.MoneroNetworkType.TESTNET : monerojs.MoneroNetworkType.STAGENET,
|
||||||
moneroBinsDir: "../haveno/.localnet",
|
moneroBinsDir: "../haveno/.localnet",
|
||||||
testDataDir: "./testdata",
|
testDataDir: "./testdata",
|
||||||
networkType: monerojs.MoneroNetworkType.STAGENET,
|
|
||||||
haveno: {
|
haveno: {
|
||||||
path: "../haveno",
|
path: "../haveno",
|
||||||
version: "1.6.2"
|
version: "1.6.2"
|
||||||
},
|
},
|
||||||
monerod: {
|
monerod: {
|
||||||
url: "http://localhost:38081",
|
url: "http://localhost:" + getNetworkStartPort() + "8081", // 18081, 28081, 38081 for mainnet, testnet, stagenet respectively
|
||||||
username: "superuser",
|
username: "",
|
||||||
password: "abctesting123"
|
password: ""
|
||||||
},
|
},
|
||||||
monerod2: {
|
monerod2: {
|
||||||
url: "http://localhost:58081",
|
url: "http://localhost:58081",
|
||||||
username: "superuser",
|
username: "superuser",
|
||||||
password: "abctesting123"
|
password: "abctesting123",
|
||||||
|
p2pBindPort: "58080",
|
||||||
|
rpcBindPort: "58081",
|
||||||
|
zmqRpcBindPort: "58082"
|
||||||
},
|
},
|
||||||
fundingWallet: {
|
fundingWallet: {
|
||||||
url: "http://localhost:38084",
|
url: "http://localhost:" + getNetworkStartPort() + "8084", // 18084, 28084, 38084 for mainnet, testnet, stagenet respectively
|
||||||
username: "rpc_user",
|
username: "rpc_user",
|
||||||
password: "abc123",
|
password: "abc123",
|
||||||
defaultPath: "test_funding_wallet",
|
defaultPath: "funding_wallet-" + getBaseCurrencyNetwork(),
|
||||||
minimumFunding: BigInt("5000000000000")
|
minimumFunding: BigInt("5000000000000")
|
||||||
},
|
},
|
||||||
defaultHavenod: {
|
defaultHavenod: {
|
||||||
logProcessOutput: false, // log output for processes started by tests (except arbitrator, alice, and bob which are configured separately)
|
logProcessOutput: true, // log output for processes started by tests (except arbitrator, alice, and bob which are configured separately)
|
||||||
apiPassword: "apitest",
|
apiPassword: "apitest",
|
||||||
walletUsername: "haveno_user",
|
walletUsername: "haveno_user",
|
||||||
walletDefaultPassword: "password", // only used if account password not set
|
walletDefaultPassword: "password", // only used if account password not set
|
||||||
|
|
@ -65,21 +75,21 @@ const TestConfig = {
|
||||||
autoLogin: true
|
autoLogin: true
|
||||||
},
|
},
|
||||||
startupHavenods: [{
|
startupHavenods: [{
|
||||||
appName: "haveno-XMR_STAGENET_arbitrator", // arbritrator
|
appName: "haveno-" + getBaseCurrencyNetwork() + "_arbitrator", // arbritrator
|
||||||
logProcessOutput: false,
|
logProcessOutput: true,
|
||||||
url: "http://localhost:8079",
|
url: "http://localhost:8079",
|
||||||
accountPasswordRequired: false,
|
accountPasswordRequired: false,
|
||||||
accountPassword: "abctesting123",
|
accountPassword: "abctesting123",
|
||||||
}, {
|
}, {
|
||||||
appName: "haveno-XMR_STAGENET_alice", // alice
|
appName: "haveno-" + getBaseCurrencyNetwork() + "_alice", // alice
|
||||||
logProcessOutput: false,
|
logProcessOutput: true,
|
||||||
url: "http://localhost:8080",
|
url: "http://localhost:8080",
|
||||||
accountPasswordRequired: false,
|
accountPasswordRequired: false,
|
||||||
accountPassword: "abctesting456",
|
accountPassword: "abctesting456",
|
||||||
walletUrl: "http://127.0.0.1:38091",
|
walletUrl: "http://127.0.0.1:38091",
|
||||||
}, {
|
}, {
|
||||||
appName: "haveno-XMR_STAGENET_bob", // bob
|
appName: "haveno-" + getBaseCurrencyNetwork() + "_bob", // bob
|
||||||
logProcessOutput: false,
|
logProcessOutput: true,
|
||||||
url: "http://localhost:8081",
|
url: "http://localhost:8081",
|
||||||
accountPasswordRequired: false,
|
accountPasswordRequired: false,
|
||||||
accountPassword: "abctesting789",
|
accountPassword: "abctesting789",
|
||||||
|
|
@ -91,6 +101,7 @@ const TestConfig = {
|
||||||
daemonPollPeriodMs: 15000,
|
daemonPollPeriodMs: 15000,
|
||||||
maxWalletStartupMs: 10000, // TODO (woodser): make shorter by switching to jni
|
maxWalletStartupMs: 10000, // TODO (woodser): make shorter by switching to jni
|
||||||
maxTimePeerNoticeMs: 3000,
|
maxTimePeerNoticeMs: 3000,
|
||||||
|
maxCpuPct: 0.25,
|
||||||
assetCodes: ["USD", "GBP", "EUR", "ETH", "BTC", "BCH", "LTC", "ZEC"], // primary asset codes
|
assetCodes: ["USD", "GBP", "EUR", "ETH", "BTC", "BCH", "LTC", "ZEC"], // primary asset codes
|
||||||
cryptoAddresses: [{
|
cryptoAddresses: [{
|
||||||
currencyCode: "ETH",
|
currencyCode: "ETH",
|
||||||
|
|
@ -119,9 +130,9 @@ const TestConfig = {
|
||||||
["8085", ["10004", "7780"]],
|
["8085", ["10004", "7780"]],
|
||||||
["8086", ["10005", "7781"]],
|
["8086", ["10005", "7781"]],
|
||||||
]),
|
]),
|
||||||
devPrivilegePrivKey: "6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a", // from DEV_PRIVILEGE_PRIV_KEY
|
arbitratorPrivKey: getArbitratorPrivKey(),
|
||||||
tradeInitTimeout: 60000,
|
tradeInitTimeout: 60000,
|
||||||
timeout: 900000, // timeout in ms for all tests to complete (15 minutes)
|
testTimeout: getBaseCurrencyNetwork() === BaseCurrencyNetwork.XMR_LOCAL ? 900000 : 3000000, // timeout in ms for each test to complete (15 minutes for private network, 50 minutes for public network)
|
||||||
postOffer: { // default post offer config
|
postOffer: { // default post offer config
|
||||||
direction: "buy", // buy or sell xmr
|
direction: "buy", // buy or sell xmr
|
||||||
amount: BigInt("200000000000"), // amount of xmr to trade
|
amount: BigInt("200000000000"), // amount of xmr to trade
|
||||||
|
|
@ -172,13 +183,20 @@ const OFFLINE_ERR_MSG = "Http response at 400 or 500 level";
|
||||||
|
|
||||||
// -------------------------- BEFORE / AFTER TESTS ----------------------------
|
// -------------------------- BEFORE / AFTER TESTS ----------------------------
|
||||||
|
|
||||||
jest.setTimeout(TestConfig.timeout);
|
jest.setTimeout(TestConfig.testTimeout);
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
|
||||||
// set log level for tests
|
// set log level for tests
|
||||||
HavenoUtils.setLogLevel(TestConfig.logLevel);
|
HavenoUtils.setLogLevel(TestConfig.logLevel);
|
||||||
|
|
||||||
|
// initialize funding wallet
|
||||||
|
await initFundingWallet();
|
||||||
|
HavenoUtils.log(0, "Funding wallet balance: " + await fundingWallet.getBalance());
|
||||||
|
HavenoUtils.log(0, "Funding wallet unlocked balance: " + await fundingWallet.getUnlockedBalance());
|
||||||
|
const subaddress = await fundingWallet.createSubaddress(0);
|
||||||
|
HavenoUtils.log(0, "Funding wallet new subaddress: " + subaddress.getAddress());
|
||||||
|
|
||||||
// start configured haveno daemons
|
// start configured haveno daemons
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (const config of TestConfig.startupHavenods) promises.push(initHaveno(config));
|
for (const config of TestConfig.startupHavenods) promises.push(initHaveno(config));
|
||||||
|
|
@ -193,16 +211,13 @@ beforeAll(async () => {
|
||||||
bob = startupHavenods[2];
|
bob = startupHavenods[2];
|
||||||
|
|
||||||
// register arbitrator dispute agent
|
// register arbitrator dispute agent
|
||||||
await arbitrator.registerDisputeAgent("arbitrator", TestConfig.devPrivilegePrivKey);
|
await arbitrator.registerDisputeAgent("arbitrator", TestConfig.arbitratorPrivKey);
|
||||||
|
|
||||||
// connect monero clients
|
// connect monero clients
|
||||||
monerod = await monerojs.connectToDaemonRpc(TestConfig.monerod.url, TestConfig.monerod.username, TestConfig.monerod.password);
|
monerod = await monerojs.connectToDaemonRpc(TestConfig.monerod.url, TestConfig.monerod.username, TestConfig.monerod.password);
|
||||||
aliceWallet = await monerojs.connectToWalletRpc(TestConfig.startupHavenods[1].walletUrl, TestConfig.defaultHavenod.walletUsername, TestConfig.startupHavenods[1].accountPasswordRequired ? TestConfig.startupHavenods[1].accountPassword : TestConfig.defaultHavenod.walletDefaultPassword);
|
aliceWallet = await monerojs.connectToWalletRpc(TestConfig.startupHavenods[1].walletUrl, TestConfig.defaultHavenod.walletUsername, TestConfig.startupHavenods[1].accountPasswordRequired ? TestConfig.startupHavenods[1].accountPassword : TestConfig.defaultHavenod.walletDefaultPassword);
|
||||||
bobWallet = await monerojs.connectToWalletRpc(TestConfig.startupHavenods[2].walletUrl, TestConfig.defaultHavenod.walletUsername, TestConfig.startupHavenods[2].accountPasswordRequired ? TestConfig.startupHavenods[2].accountPassword : TestConfig.defaultHavenod.walletDefaultPassword);
|
bobWallet = await monerojs.connectToWalletRpc(TestConfig.startupHavenods[2].walletUrl, TestConfig.defaultHavenod.walletUsername, TestConfig.startupHavenods[2].accountPasswordRequired ? TestConfig.startupHavenods[2].accountPassword : TestConfig.defaultHavenod.walletDefaultPassword);
|
||||||
|
|
||||||
// initialize funding wallet
|
|
||||||
await initFundingWallet();
|
|
||||||
|
|
||||||
// create test data directory if it doesn't exist
|
// create test data directory if it doesn't exist
|
||||||
if (!fs.existsSync(TestConfig.testDataDir)) fs.mkdirSync(TestConfig.testDataDir);
|
if (!fs.existsSync(TestConfig.testDataDir)) fs.mkdirSync(TestConfig.testDataDir);
|
||||||
});
|
});
|
||||||
|
|
@ -329,7 +344,6 @@ test("Can manage an account", async () => {
|
||||||
const paymentAccount2 = await charlie.getPaymentAccount(paymentAccount.getId());
|
const paymentAccount2 = await charlie.getPaymentAccount(paymentAccount.getId());
|
||||||
testCryptoPaymentAccountsEqual(paymentAccount, paymentAccount2);
|
testCryptoPaymentAccountsEqual(paymentAccount, paymentAccount2);
|
||||||
} catch (err2) {
|
} catch (err2) {
|
||||||
console.log(err2);
|
|
||||||
err = err2;
|
err = err2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -359,16 +373,14 @@ test("Can manage Monero daemon connections", async () => {
|
||||||
charlie = await initHaveno();
|
charlie = await initHaveno();
|
||||||
|
|
||||||
// test default connections
|
// test default connections
|
||||||
const monerodUrl1 = "http://127.0.0.1:38081"; // TODO: (woodser): move to config
|
const monerodUrl1 = "http://127.0.0.1:" + getNetworkStartPort() + "8081"; // TODO: (woodser): move to config
|
||||||
const monerodUrl2 = "http://haveno.exchange:38081";
|
|
||||||
let connections: UrlConnection[] = await charlie.getMoneroConnections();
|
let connections: UrlConnection[] = await charlie.getMoneroConnections();
|
||||||
testConnection(getConnection(connections, monerodUrl1)!, monerodUrl1, OnlineStatus.ONLINE, AuthenticationStatus.AUTHENTICATED, 1);
|
testConnection(getConnection(connections, monerodUrl1)!, monerodUrl1, OnlineStatus.ONLINE, AuthenticationStatus.AUTHENTICATED, 1);
|
||||||
testConnection(getConnection(connections, monerodUrl2)!, monerodUrl2, OnlineStatus.UNKNOWN, AuthenticationStatus.NO_AUTHENTICATION, 2);
|
|
||||||
|
|
||||||
// test default connection
|
// test default connection
|
||||||
let connection: UrlConnection | undefined = await charlie.getMoneroConnection();
|
let connection: UrlConnection | undefined = await charlie.getMoneroConnection();
|
||||||
assert(await charlie.isConnectedToMonero());
|
assert(await charlie.isConnectedToMonero());
|
||||||
testConnection(connection!, monerodUrl1, OnlineStatus.ONLINE, AuthenticationStatus.AUTHENTICATED, 1);
|
testConnection(connection!, monerodUrl1, OnlineStatus.ONLINE, AuthenticationStatus.AUTHENTICATED, 1); // TODO: should be no authentication?
|
||||||
|
|
||||||
// add a new connection
|
// add a new connection
|
||||||
const fooBarUrl = "http://foo.bar";
|
const fooBarUrl = "http://foo.bar";
|
||||||
|
|
@ -395,12 +407,12 @@ test("Can manage Monero daemon connections", async () => {
|
||||||
"--" + monerojs.MoneroNetworkType.toString(TestConfig.networkType).toLowerCase(),
|
"--" + monerojs.MoneroNetworkType.toString(TestConfig.networkType).toLowerCase(),
|
||||||
"--no-igd",
|
"--no-igd",
|
||||||
"--hide-my-port",
|
"--hide-my-port",
|
||||||
"--data-dir", TestConfig.moneroBinsDir + "/stagenet/testnode",
|
"--data-dir", TestConfig.moneroBinsDir + "/" + TestConfig.baseCurrencyNetwork.toLowerCase() + "/testnode",
|
||||||
"--p2p-bind-port", "58080",
|
"--p2p-bind-port", TestConfig.monerod2.p2pBindPort,
|
||||||
"--rpc-bind-port", "58081",
|
"--rpc-bind-port", TestConfig.monerod2.rpcBindPort,
|
||||||
"--rpc-login", "superuser:abctesting123",
|
"--no-zmq"
|
||||||
"--zmq-rpc-bind-port", "58082"
|
|
||||||
];
|
];
|
||||||
|
if (TestConfig.monerod2.username) cmd.push("--rpc-login", TestConfig.monerod2.username + ":" + TestConfig.monerod2.password);
|
||||||
monerod2 = await monerojs.connectToDaemonRpc(cmd);
|
monerod2 = await monerojs.connectToDaemonRpc(cmd);
|
||||||
|
|
||||||
// connection is online and not authenticated
|
// connection is online and not authenticated
|
||||||
|
|
@ -448,7 +460,8 @@ test("Can manage Monero daemon connections", async () => {
|
||||||
connection = await charlie.getMoneroConnection();
|
connection = await charlie.getMoneroConnection();
|
||||||
testConnection(connection!, monerodUrl1, OnlineStatus.ONLINE, AuthenticationStatus.AUTHENTICATED, 1);
|
testConnection(connection!, monerodUrl1, OnlineStatus.ONLINE, AuthenticationStatus.AUTHENTICATED, 1);
|
||||||
|
|
||||||
// stop checking connection periodically
|
// stop auto switch and checking connection periodically
|
||||||
|
await charlie.setAutoSwitch(false);
|
||||||
await charlie.stopCheckingConnection();
|
await charlie.stopCheckingConnection();
|
||||||
|
|
||||||
// remove current connection
|
// remove current connection
|
||||||
|
|
@ -462,7 +475,6 @@ test("Can manage Monero daemon connections", async () => {
|
||||||
await charlie.checkMoneroConnections();
|
await charlie.checkMoneroConnections();
|
||||||
connections = await charlie.getMoneroConnections();
|
connections = await charlie.getMoneroConnections();
|
||||||
testConnection(getConnection(connections, fooBarUrl)!, fooBarUrl, OnlineStatus.OFFLINE, AuthenticationStatus.NO_AUTHENTICATION, 0);
|
testConnection(getConnection(connections, fooBarUrl)!, fooBarUrl, OnlineStatus.OFFLINE, AuthenticationStatus.NO_AUTHENTICATION, 0);
|
||||||
for (const connection of connections) testConnection(connection!, connection.getUrl(), OnlineStatus.OFFLINE, AuthenticationStatus.NO_AUTHENTICATION);
|
|
||||||
|
|
||||||
// set connection to previous url
|
// set connection to previous url
|
||||||
await charlie.setMoneroConnection(fooBarUrl);
|
await charlie.setMoneroConnection(fooBarUrl);
|
||||||
|
|
@ -545,7 +557,7 @@ test("Can start and stop a local Monero node", async() => {
|
||||||
// expect successful start with custom settings
|
// expect successful start with custom settings
|
||||||
const connectionsBefore = await alice.getMoneroConnections();
|
const connectionsBefore = await alice.getMoneroConnections();
|
||||||
const settings: MoneroNodeSettings = new MoneroNodeSettings();
|
const settings: MoneroNodeSettings = new MoneroNodeSettings();
|
||||||
const dataDir = TestConfig.moneroBinsDir + "/stagenet/node1";
|
const dataDir = TestConfig.moneroBinsDir + "/" + TestConfig.baseCurrencyNetwork + "/node1";
|
||||||
const logFile = dataDir + "/test.log";
|
const logFile = dataDir + "/test.log";
|
||||||
const p2pPort = 38080;
|
const p2pPort = 38080;
|
||||||
const rpcPort = 38081;
|
const rpcPort = 38081;
|
||||||
|
|
@ -601,7 +613,7 @@ test("Has a Monero wallet", async () => {
|
||||||
|
|
||||||
// get primary address
|
// get primary address
|
||||||
const primaryAddress = await alice.getXmrPrimaryAddress();
|
const primaryAddress = await alice.getXmrPrimaryAddress();
|
||||||
await MoneroUtils.validateAddress(primaryAddress, MoneroNetworkType.STAGENET);
|
await MoneroUtils.validateAddress(primaryAddress, TestConfig.networkType);
|
||||||
|
|
||||||
// wait for alice to have unlocked balance
|
// wait for alice to have unlocked balance
|
||||||
const tradeAmount = BigInt("250000000000");
|
const tradeAmount = BigInt("250000000000");
|
||||||
|
|
@ -622,7 +634,7 @@ test("Has a Monero wallet", async () => {
|
||||||
// get new subaddresses
|
// get new subaddresses
|
||||||
for (let i = 0; i < 0; i++) {
|
for (let i = 0; i < 0; i++) {
|
||||||
const address = await alice.getXmrNewSubaddress();
|
const address = await alice.getXmrNewSubaddress();
|
||||||
await MoneroUtils.validateAddress(address, MoneroNetworkType.STAGNET);
|
await MoneroUtils.validateAddress(address, TestConfig.networkType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create withdraw tx
|
// create withdraw tx
|
||||||
|
|
@ -796,14 +808,11 @@ test("Can get market depth", async () => {
|
||||||
.toThrow('Currency not found: INVALID_CURRENCY');
|
.toThrow('Currency not found: INVALID_CURRENCY');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Can register as dispute agents", async () => {
|
test("Can register as an arbitrator", async () => {
|
||||||
await arbitrator.registerDisputeAgent("arbitrator", TestConfig.devPrivilegePrivKey);
|
|
||||||
await arbitrator.registerDisputeAgent("mediator", TestConfig.devPrivilegePrivKey);
|
|
||||||
await arbitrator.registerDisputeAgent("refundagent", TestConfig.devPrivilegePrivKey);
|
|
||||||
|
|
||||||
// test bad dispute agent type
|
// test bad dispute agent type
|
||||||
try {
|
try {
|
||||||
await arbitrator.registerDisputeAgent("unsupported type", TestConfig.devPrivilegePrivKey);
|
await arbitrator.registerDisputeAgent("unsupported type", TestConfig.arbitratorPrivKey);
|
||||||
throw new Error("should have thrown error registering bad type");
|
throw new Error("should have thrown error registering bad type");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err.message !== "unknown dispute agent type 'unsupported type'") throw new Error("Unexpected error: " + err.message);
|
if (err.message !== "unknown dispute agent type 'unsupported type'") throw new Error("Unexpected error: " + err.message);
|
||||||
|
|
@ -811,11 +820,14 @@ test("Can register as dispute agents", async () => {
|
||||||
|
|
||||||
// test bad key
|
// test bad key
|
||||||
try {
|
try {
|
||||||
await arbitrator.registerDisputeAgent("arbitrator", "bad key");
|
await arbitrator.registerDisputeAgent("mediator", "bad key");
|
||||||
throw new Error("should have thrown error registering bad key");
|
throw new Error("should have thrown error registering bad key");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err.message !== "invalid registration key") throw new Error("Unexpected error: " + err.message);
|
if (err.message !== "invalid registration key") throw new Error("Unexpected error: " + err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register arbitrator with good key
|
||||||
|
await arbitrator.registerDisputeAgent("arbitrator", TestConfig.arbitratorPrivKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Can get offers", async () => {
|
test("Can get offers", async () => {
|
||||||
|
|
@ -998,7 +1010,7 @@ test("Can prepare for trading", async () => {
|
||||||
|
|
||||||
// fund wallets
|
// fund wallets
|
||||||
const tradeAmount = BigInt("250000000000");
|
const tradeAmount = BigInt("250000000000");
|
||||||
await fundOutputs([aliceWallet, bobWallet], tradeAmount * BigInt("6"), 4);
|
await fundOutputs([aliceWallet, bobWallet], tradeAmount * BigInt("2"), 4);
|
||||||
|
|
||||||
// wait for havenod to observe funds
|
// wait for havenod to observe funds
|
||||||
await wait(TestConfig.walletSyncPeriodMs);
|
await wait(TestConfig.walletSyncPeriodMs);
|
||||||
|
|
@ -1205,7 +1217,7 @@ test("Can complete a trade", async () => {
|
||||||
HavenoUtils.log(1, "Bob done taking offer in " + (Date.now() - startTime) + " ms");
|
HavenoUtils.log(1, "Bob done taking offer in " + (Date.now() - startTime) + " ms");
|
||||||
|
|
||||||
// alice is notified that offer is taken
|
// alice is notified that offer is taken
|
||||||
await wait(1000);
|
await wait(TestConfig.maxTimePeerNoticeMs);
|
||||||
const tradeNotifications = getNotifications(aliceNotifications, NotificationMessage.NotificationType.TRADE_UPDATE);
|
const tradeNotifications = getNotifications(aliceNotifications, NotificationMessage.NotificationType.TRADE_UPDATE);
|
||||||
expect(tradeNotifications.length).toBe(1);
|
expect(tradeNotifications.length).toBe(1);
|
||||||
expect(tradeNotifications[0].getTrade()!.getPhase()).toEqual("DEPOSIT_PUBLISHED");
|
expect(tradeNotifications[0].getTrade()!.getPhase()).toEqual("DEPOSIT_PUBLISHED");
|
||||||
|
|
@ -1282,7 +1294,7 @@ test("Can resolve disputes", async () => {
|
||||||
|
|
||||||
// wait for alice and bob to have unlocked balance for trade
|
// wait for alice and bob to have unlocked balance for trade
|
||||||
const tradeAmount = BigInt("250000000000");
|
const tradeAmount = BigInt("250000000000");
|
||||||
await fundOutputs([aliceWallet, bobWallet], tradeAmount * BigInt("6"), 4);
|
await fundOutputs([aliceWallet, bobWallet], tradeAmount * BigInt("2"), 4);
|
||||||
|
|
||||||
// register to receive notifications
|
// register to receive notifications
|
||||||
const aliceNotifications: NotificationMessage[] = [];
|
const aliceNotifications: NotificationMessage[] = [];
|
||||||
|
|
@ -1749,6 +1761,44 @@ test("Handles unexpected errors during trade initialization", async () => {
|
||||||
|
|
||||||
// ------------------------------- HELPERS ------------------------------------
|
// ------------------------------- HELPERS ------------------------------------
|
||||||
|
|
||||||
|
function getBaseCurrencyNetwork(): BaseCurrencyNetwork {
|
||||||
|
const str = getBaseCurrencyNetworkStr();
|
||||||
|
if (str === "XMR_MAINNET") return BaseCurrencyNetwork.XMR_MAINNET;
|
||||||
|
else if (str === "XMR_STAGENET") return BaseCurrencyNetwork.XMR_STAGENET;
|
||||||
|
else if (str === "XMR_LOCAL") return BaseCurrencyNetwork.XMR_LOCAL;
|
||||||
|
else throw new Error("Unhandled base currency network: " + str);
|
||||||
|
function getBaseCurrencyNetworkStr() {
|
||||||
|
for (const arg of process.argv) {
|
||||||
|
if (arg.indexOf("--baseCurrencyNetwork") === 0) {
|
||||||
|
return arg.substring(arg.indexOf("=") + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error("Must provide base currency network, e.g.: `npm run test -- --baseCurrencyNetwork=XMR_LOCAL -t \"my test\"`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNetworkStartPort() {
|
||||||
|
switch (getBaseCurrencyNetwork()) {
|
||||||
|
case BaseCurrencyNetwork.XMR_MAINNET: return 1;
|
||||||
|
case BaseCurrencyNetwork.XMR_LOCAL: return 2;
|
||||||
|
case BaseCurrencyNetwork.XMR_STAGENET: return 3;
|
||||||
|
default: throw new Error("Unhandled base currency network: " + getBaseCurrencyNetwork());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArbitratorPrivKey() {
|
||||||
|
switch (getBaseCurrencyNetwork()) {
|
||||||
|
case BaseCurrencyNetwork.XMR_MAINNET:
|
||||||
|
throw new Error("Cannot get private key for MAINNET");
|
||||||
|
case BaseCurrencyNetwork.XMR_STAGENET:
|
||||||
|
return "1aa111f817b7fdaaec1c8d5281a1837cc71c336db09b87cf23344a0a4e3bb2cb";
|
||||||
|
case BaseCurrencyNetwork.XMR_LOCAL:
|
||||||
|
return "6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a"; // from DEV_PRIVILEGE_PRIV_KEY
|
||||||
|
default:
|
||||||
|
throw new Error("Unhandled base currency network: " + getBaseCurrencyNetwork());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function initHavenos(numDaemons: number, config?: any) {
|
async function initHavenos(numDaemons: number, config?: any) {
|
||||||
const traderPromises: Promise<HavenoClient>[] = [];
|
const traderPromises: Promise<HavenoClient>[] = [];
|
||||||
for (let i = 0; i < numDaemons; i++) traderPromises.push(initHaveno(config));
|
for (let i = 0; i < numDaemons; i++) traderPromises.push(initHaveno(config));
|
||||||
|
|
@ -1757,7 +1807,7 @@ async function initHavenos(numDaemons: number, config?: any) {
|
||||||
|
|
||||||
async function initHaveno(config?: any): Promise<HavenoClient> {
|
async function initHaveno(config?: any): Promise<HavenoClient> {
|
||||||
config = Object.assign({}, TestConfig.defaultHavenod, config);
|
config = Object.assign({}, TestConfig.defaultHavenod, config);
|
||||||
if (!config.appName) config.appName = "haveno-XMR_STAGENET_instance_" + GenUtils.getUUID();
|
if (!config.appName) config.appName = "haveno-" + TestConfig.baseCurrencyNetwork + "_instance_" + GenUtils.getUUID();
|
||||||
|
|
||||||
// connect to existing server or start new process
|
// connect to existing server or start new process
|
||||||
let havenod;
|
let havenod;
|
||||||
|
|
@ -1786,9 +1836,9 @@ async function initHaveno(config?: any): Promise<HavenoClient> {
|
||||||
// start haveno process using configured ports if available
|
// start haveno process using configured ports if available
|
||||||
const cmd: string[] = [
|
const cmd: string[] = [
|
||||||
"./haveno-daemon",
|
"./haveno-daemon",
|
||||||
"--baseCurrencyNetwork", "XMR_STAGENET",
|
"--baseCurrencyNetwork", TestConfig.baseCurrencyNetwork,
|
||||||
"--useLocalhostForP2P", "true",
|
"--useLocalhostForP2P", TestConfig.baseCurrencyNetwork === BaseCurrencyNetwork.XMR_MAINNET ? "false" : "true", // TODO: disable for stagenet too
|
||||||
"--useDevPrivilegeKeys", "true",
|
"--useDevPrivilegeKeys", TestConfig.baseCurrencyNetwork === BaseCurrencyNetwork.XMR_LOCAL ? "true" : "false",
|
||||||
"--nodePort", TestConfig.proxyPorts.get(proxyPort)![1],
|
"--nodePort", TestConfig.proxyPorts.get(proxyPort)![1],
|
||||||
"--appName", config.appName,
|
"--appName", config.appName,
|
||||||
"--apiPassword", "apitest",
|
"--apiPassword", "apitest",
|
||||||
|
|
@ -1891,7 +1941,7 @@ async function initFundingWallet() {
|
||||||
|
|
||||||
async function startMining() {
|
async function startMining() {
|
||||||
try {
|
try {
|
||||||
await monerod.startMining(await fundingWallet.getPrimaryAddress(), 3);
|
await monerod.startMining(await fundingWallet.getPrimaryAddress(), Math.max(1, Math.floor(os.cpus().length * TestConfig.maxCpuPct)));
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err.message !== "Already mining") throw err;
|
if (err.message !== "Already mining") throw err;
|
||||||
}
|
}
|
||||||
|
|
@ -1953,10 +2003,14 @@ async function waitForUnlockedBalance(amount: bigint, ...wallets: any[]) {
|
||||||
if (!miningNeeded) return;
|
if (!miningNeeded) return;
|
||||||
|
|
||||||
// wait for funds to unlock
|
// wait for funds to unlock
|
||||||
HavenoUtils.log(0, "Mining for unlocked balance of " + amount);
|
HavenoUtils.log(1, "Mining for unlocked balance of " + amount);
|
||||||
await startMining();
|
await startMining();
|
||||||
const promises: Promise<void>[] = [];
|
const promises: Promise<void>[] = [];
|
||||||
for (const wallet of wallets) {
|
for (const wallet of wallets) {
|
||||||
|
if (wallet._wallet === fundingWallet) {
|
||||||
|
const subaddress = await fundingWallet.createSubaddress(0);
|
||||||
|
HavenoUtils.log(0, "Mining to funding wallet. Alternatively, deposit to: " + subaddress.getAddress());
|
||||||
|
}
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
// eslint-disable-next-line no-async-promise-executor
|
||||||
promises.push(new Promise(async (resolve) => {
|
promises.push(new Promise(async (resolve) => {
|
||||||
const taskLooper: any = new TaskLooper(async function() {
|
const taskLooper: any = new TaskLooper(async function() {
|
||||||
|
|
@ -2028,7 +2082,7 @@ async function fundOutputs(wallets: any[], amt: bigint, numOutputs?: number, wai
|
||||||
// collect destinations
|
// collect destinations
|
||||||
const destinations = [];
|
const destinations = [];
|
||||||
for (const wallet of wallets) {
|
for (const wallet of wallets) {
|
||||||
if (await hasUnspentOutputs([wallet], amt, numOutputs, waitForUnlock ? false : undefined)) continue;
|
if (await hasUnspentOutputs([wallet], amt, numOutputs, undefined)) continue;
|
||||||
for (let i = 0; i < numOutputs; i++) {
|
for (let i = 0; i < numOutputs; i++) {
|
||||||
destinations.push(new MoneroDestination((await wallet.createSubaddress()).getAddress(), monerojs.BigInteger(amt.toString())));
|
destinations.push(new MoneroDestination((await wallet.createSubaddress()).getAddress(), monerojs.BigInteger(amt.toString())));
|
||||||
}
|
}
|
||||||
|
|
@ -2056,8 +2110,9 @@ async function fundOutputs(wallets: any[], amt: bigint, numOutputs?: number, wai
|
||||||
// mine until outputs unlock
|
// mine until outputs unlock
|
||||||
if (!waitForUnlock) return;
|
if (!waitForUnlock) return;
|
||||||
let miningStarted = false;
|
let miningStarted = false;
|
||||||
while (!await hasUnspentOutputs(wallets, amt, numOutputs, false)) {
|
while (!await hasUnspentOutputs(wallets, amt, numOutputs, waitForUnlock ? false : undefined)) {
|
||||||
if (!miningStarted) {
|
if (!miningStarted) {
|
||||||
|
HavenoUtils.log(1, "Mining to fund outputs");
|
||||||
await startMining();
|
await startMining();
|
||||||
miningStarted = true;
|
miningStarted = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue