Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PriceNode: Add support for multiple ExchangeRateProviders #4315

Merged

Conversation

cd2357
Copy link
Contributor

@cd2357 cd2357 commented Jun 16, 2020

Extend ExchangeRateService in pricenode to add basic support for multiple providers per currency.

When the service detects that multiple providers have exchange rates for the same currency, it automatically aggregates (averages) these rates into a single ExchangeRate.

The client thus receives a single ExchangeRate per currency, regardless of the number of providers which gathered exchange rates for it (be it a single provider, or multiple). This ensures compatibility with previous and existing clients.

The purpose of this WIP is to test and review whether:

  • this approach to support multiple ExchangeRateProviders is viable
  • the client transparently handles both normal and aggregate rates "as is" (so without any client modifications)
  • the pricenode correctly handles multiple providers (multi-threading, caching of rates, calculation of aggregate price, etc)
  • there are any fundamental showstoppers with this approach (risks, incompatibilities, etc)

Addresses bisq-network/projects#35


(Update 21.07.2020: Add overview of supported currencies + providers)

Supported Currencies and Exchange Providers

In this PR, rates for the following currencies are retrieved from the following exchange providers:

Table 1: Fiat currencies and corresponding exchange providers supported by this PR

AED=[BITPAY, COINGECKO]
AFN=[BITPAY]
ALL=[BITPAY]
AMD=[BITPAY]
ANG=[BITPAY]
AOA=[BITPAY]
ARS=[BITPAY, COINGECKO, COINPAPRIKA]
AUD=[BITPAY, BTCMARKETS, COINGECKO, COINPAPRIKA, IndependentReserve, KRAKEN, QUOINE]
AWG=[BITPAY]
AZN=[BITPAY]
BAM=[BITPAY]
BBD=[BITPAY]
BDT=[BITPAY, COINGECKO]
BGN=[BITPAY]
BHD=[BITPAY, COINGECKO]
BIF=[BITPAY]
BMD=[BITPAY, COINGECKO]
BND=[BITPAY]
BOB=[BITPAY, COINPAPRIKA]
BRL=[BITPAY, COINGECKO, COINPAPRIKA, MercadoBitcoin]
BSD=[BITPAY]
BTN=[BITPAY]
BWP=[BITPAY]
BYN=[BITPAY]
BZD=[BITPAY]
CAD=[BITPAY, COINGECKO, COINPAPRIKA, KRAKEN]
CDF=[BITPAY]
CHF=[BITPAY, COINGECKO, COINPAPRIKA, KRAKEN]
CLP=[BITPAY, COINGECKO, COINPAPRIKA]
CNY=[BITPAY, COINGECKO, COINPAPRIKA]
COP=[BITPAY, COINPAPRIKA]
CRC=[BITPAY]
CUP=[BITPAY]
CVE=[BITPAY]
CZK=[BITPAY, COINGECKO, Coinmate, COINPAPRIKA]
DJF=[BITPAY]
DKK=[BITPAY, COINGECKO, COINPAPRIKA]
DOP=[BITPAY]
DZD=[BITPAY]
EGP=[BITPAY]
ETB=[BITPAY]
EUR=[BITPAY, BINANCE, BITSTAMP, BITBAY, BITFINEX, CexIO, COINGECKO, Coinmate, COINPAPRIKA, EXMO, KRAKEN, QUOINE]
FJD=[BITPAY]
FKP=[BITPAY]
GBP=[BITPAY, BINANCE, BITSTAMP, BITBAY, BITFINEX, CexIO, COINGECKO, COINPAPRIKA, KRAKEN]
GEL=[BITPAY]
GHS=[BITPAY]
GIP=[BITPAY]
GMD=[BITPAY]
GNF=[BITPAY]
GTQ=[BITPAY]
GYD=[BITPAY]
HKD=[BITPAY, COINGECKO, COINPAPRIKA, QUOINE]
HNL=[BITPAY]
HRK=[BITPAY]
HTG=[BITPAY]
HUF=[BITPAY, COINGECKO, COINPAPRIKA]
IDR=[BITPAY, COINGECKO, COINPAPRIKA, LUNO]
ILS=[BITPAY, COINGECKO, COINPAPRIKA]
INR=[BITPAY, COINGECKO, COINPAPRIKA]
IQD=[BITPAY]
IRR=[BITPAY]
ISK=[BITPAY, COINPAPRIKA]
JMD=[BITPAY]
JOD=[BITPAY]
JPY=[BITPAY, BITFINEX, BITFLYER, COINGECKO, COINPAPRIKA, KRAKEN, QUOINE]
KES=[BITPAY]
KGS=[BITPAY]
KHR=[BITPAY]
KMF=[BITPAY]
KPW=[BITPAY]
KRW=[BITPAY, COINGECKO, COINONE, COINPAPRIKA]
KWD=[BITPAY, COINGECKO]
KYD=[BITPAY]
KZT=[BITPAY]
LAK=[BITPAY]
LBP=[BITPAY]
LKR=[BITPAY, COINGECKO]
LRD=[BITPAY]
LSL=[BITPAY]
LYD=[BITPAY]
MAD=[BITPAY]
MDL=[BITPAY]
MGA=[BITPAY]
MKD=[BITPAY]
MMK=[BITPAY, COINGECKO]
MNT=[BITPAY]
MOP=[BITPAY]
MRU=[BITPAY]
MUR=[BITPAY]
MVR=[BITPAY]
MWK=[BITPAY]
MXN=[BITPAY, COINGECKO, COINPAPRIKA]
MYR=[BITPAY, COINGECKO, COINPAPRIKA, LUNO]
MZN=[BITPAY]
NAD=[BITPAY]
NGN=[BITPAY, BINANCE, COINPAPRIKA, LUNO]
NIO=[BITPAY]
NOK=[BITPAY, COINGECKO, COINPAPRIKA]
NPR=[BITPAY]
NZD=[BITPAY, COINGECKO, COINPAPRIKA, IndependentReserve]
OMR=[BITPAY]
PAB=[BITPAY]
PEN=[BITPAY, COINPAPRIKA]
PGK=[BITPAY]
PHP=[BITPAY, COINGECKO, COINPAPRIKA]
PKR=[BITPAY, COINGECKO, COINPAPRIKA]
PLN=[BITPAY, BITBAY, COINGECKO, COINPAPRIKA, EXMO]
PYG=[BITPAY]
QAR=[BITPAY]
RON=[BITPAY]
RSD=[BITPAY]
RUB=[BITPAY, BINANCE, CexIO, COINGECKO, COINPAPRIKA, EXMO]
RWF=[BITPAY]
SAR=[BITPAY, COINGECKO]
SBD=[BITPAY]
SCR=[BITPAY]
SDG=[BITPAY]
SEK=[BITPAY, COINGECKO, COINPAPRIKA]
SGD=[BITPAY, COINGECKO, COINPAPRIKA, QUOINE]
SHP=[BITPAY]
SLL=[BITPAY]
SOS=[BITPAY]
SRD=[BITPAY]
STN=[BITPAY]
SVC=[BITPAY]
SYP=[BITPAY]
SZL=[BITPAY]
THB=[BITPAY, COINGECKO, COINPAPRIKA]
TJS=[BITPAY]
TMT=[BITPAY]
TND=[BITPAY]
TOP=[BITPAY]
TRY=[BITPAY, BINANCE, COINGECKO, COINPAPRIKA, PARIBU]
TTD=[BITPAY]
TWD=[BITPAY, COINGECKO, COINPAPRIKA]
TZS=[BITPAY]
UAH=[BITPAY, BINANCE, COINGECKO, COINPAPRIKA, EXMO]
UGX=[BITPAY]
USD=[BITPAY, BITSTAMP, BITBAY, BITFINEX, CexIO, COINGECKO, COINPAPRIKA, EXMO, HITBTC, IndependentReserve, KRAKEN, QUOINE]
UYU=[BITPAY]
UZS=[BITPAY]
VES=[BITPAY]
VND=[BITPAY, COINGECKO, COINPAPRIKA]
VUV=[BITPAY]
WST=[BITPAY]
XAF=[BITPAY]
XCD=[BITPAY]
XOF=[BITPAY]
XPF=[BITPAY]
YER=[BITPAY]
ZAR=[BITPAY, BINANCE, COINGECKO, COINPAPRIKA, LUNO]
ZMW=[BITPAY]
ZWL=[BITPAY]

Table 2: Altcoins and corresponding exchange providers supported by this PR

AEON=[HITBTC]
BEAM=[BINANCE]
BTM=[HITBTC, HUOBI]
DAI=[BINANCE, BITFINEX]
DASH=[BINANCE, BITBAY, CexIO, Coinmate, EXMO, HITBTC, HUOBI, KRAKEN, POLO]
DCR=[BINANCE, HITBTC, HUOBI, POLO]
DOGE=[BINANCE, EXMO, HITBTC, HUOBI, KRAKEN, POLO]
EMC=[HITBTC]
ETC=[BINANCE, BITFINEX, EXMO, HITBTC, HUOBI, KRAKEN, POLO]
ETH=[BITPAY, BINANCE, BITSTAMP, BITBAY, BITFINEX, BITFLYER, BTCMARKETS, CexIO, COINGECKO, Coinmate, EXMO, HITBTC, HUOBI, KRAKEN, POLO, QUOINE]
FAIR=[HUOBI]
GRIN=[HITBTC]
LTC=[BINANCE, BITSTAMP, BITBAY, BITFINEX, BTCMARKETS, CexIO, COINGECKO, Coinmate, EXMO, HITBTC, HUOBI, KRAKEN, POLO]
NAV=[BINANCE, HITBTC]
PART=[HITBTC]
PIVX=[BINANCE]
USDC=[BITPAY]
XMR=[BINANCE, BITFINEX, EXMO, HITBTC, HUOBI, KRAKEN, POLO]
XRC=[HITBTC]
XZC=[BINANCE, HITBTC, HUOBI]
ZEC=[BINANCE, BITFINEX, EXMO, HITBTC, HUOBI, KRAKEN, POLO]
ZEN=[BINANCE, HITBTC, HUOBI]

(Update 23.07.2020: Simplify and consolidate test overview)

Testing Approach

Tests should specifically check two things:

  • Track 1: API compatibility with existing Bisq clients
  • Track 2: Consistency in the reported prices, across different instances

Table 3: Overview of areas to test

Click to show...
Track 1:

New Pricenode is compatible with existing Bisq clients
Track 2:

Pricenode price feeds are reliable / usable in Bisq trades
Context Bisq clients query the /getAllMarketPrices API on the pricenodes (implemented by ExchangeRateController.getAllMarketPrices()) to retrieve the currency exchange rates.

For the current Bisq clients to be compatible with the pricenode code in this PR, the new pricenode should use the same data structure as current pricenodes when returning price data.
Offer.PRICE_TOLERANCE defines the maximum acceptable price difference between the maker and taker in a trade to be 1%. If maker/taker local prices differ by more than that, the trade will throw an exception and will not be created.
Reason why this matters This PR is only usable if existing Bisq clients in the wild can use them as pricenodes. Different pricenode instances running the PR code could face different circumstances that can influence their price feeds. For example, intermittent connectivity to one or more of the exchanges, etc. If the maker and taker use pricenodes that return prices which are more than 1% apart, trades in Bisq cannot be created.
Testing: General approach Start Bisq clients that use pricenodes based on this PR. If prices are successfully retrieved, test is successful.

Perform a few regtest trades in different configurations. If trades successful, then test is considered successful.
Check prices reported by different pricenodes, at different times, under different conditions. If prices are within <1% of each other, test is successful.
Test cases See Tests 1-4 below See Test 0 below

Useful Pricenode Instance Types

A few specific types of pricenodes can help more easily achieve or simulate the different conditions we need for the tests.

These pricenode types are ONLY used to simplify tests, they don't matter for the actual roll-out.

Table 4: Suggested types of test pricenode instances

Click to show...
Pricenode-PR-1m Pricenode-PR-3m Pricenode-PR-1m-up5pc
Description / Purpose

(Why is such a pricenode useful for tests? What does it simulate?)
Simulates a vanilla pricenode, based on this PR Simulates a pricenode based on this PR, but which has intermittent connectivity to some/all of the exchanges. The higher polling rate simulates that exchanges are only occasionally polled successfuly to retrieve fresh price data Simulates a pricenode based on this PR, but which returns artificially inflated rates (+5%). Can be used to test how a maker/taker setup behaves, should they have massively different prices for the traded currency. Since this situation is not expected to occur (and does not occur normally), this type of pricenode helps to simulate it.
Polling rate

(How often each exchange provider will poll the exchange)
1 min 3 mins 1 min
Modifications

(Adjustments on top of the PR code, to make the instance suitable for tests)
Disable BitcoinAverage Disable BitcoinAverage Disable BitcoinAverage

Artificially inflate returned rates by +5%
Branch

(Test branch containing the modifications mentioned above)
pricenode-test-setup-1m pricenode-test-setup-3m pricenode-test-setup-1m-up5pc
How to install

(For testers who want to setup their own instance. Auto-install script tested with debian 10.)
Show...curl -s https://raw.githubusercontent.com/cd2357/bisq/pricenode-test-setup-1m/pricenode/install_pricenode_debian.sh | sudo bash
Show...curl -s https://raw.githubusercontent.com/cd2357/bisq/pricenode-test-setup-3m/pricenode/install_pricenode_debian.sh | sudo bash
Show...curl -s https://raw.githubusercontent.com/cd2357/bisq/pricenode-test-setup-1m-up5pc/pricenode/install_pricenode_debian.sh | sudo bash
Current live test instances

(Existing live instances, for test purposes. Warning: no uptime guarantees, best-effort availability)
mifoy7xvoeoyvtoi.onion (Pricenode-PR-1m-A)

lzlxdqzj6t7dxjha.onion (Pricenode-PR-1m-B)
jzfd6tanhnc65fhh.onion (Pricenode-PR-3m-A)

p3s7gpl42iq67llv.onion (Pricenode-PR-3m-B)
ii6vfecmp7cf6gky.onion (Pricenode-PR-1m-up5%)

Test Cases

Test 0

Goal / Scenario

This test checks that prices differ by less than 1% across different pricenode instances, in normal situations.

Prerequisites

  1. Make sure you have bash, torsocks, curl and jq installed
  2. Create a local script compare-pricenode-rates.sh and populate it with the following content:

Snippet 1: Content of Test 0 script

Show Snippet 1...
#!/bin/bash

# Define pricenodes

# Base pricenode
pricenodes[0]="http://mifoy7xvoeoyvtoi.onion/getAllMarketPrices"
pricenodeLabels[0]="Pricenode-PR-1m-A"

pricenodes[1]="http://lzlxdqzj6t7dxjha.onion/getAllMarketPrices"
pricenodeLabels[1]="Pricenode-PR-1m-B"

pricenodes[2]="http://jzfd6tanhnc65fhh.onion/getAllMarketPrices"
pricenodeLabels[2]="Pricenode-PR-3m-A"

pricenodes[3]="http://p3s7gpl42iq67llv.onion/getAllMarketPrices"
pricenodeLabels[3]="Pricenode-PR-3m-B"

pricenodes[4]="http://ii6vfecmp7cf6gky.onion/getAllMarketPrices"
pricenodeLabels[4]="Pricenode-PR-1m-up5%"

# One of the current pricenodes, as of v1.3.6
# Chose @alexej996's pricenode from ProvidersRepository.DEFAULT_NODES
pricenodes[5]="http://62nvujg5iou3vu3i.onion/getAllMarketPrices"
pricenodeLabels[5]="Pricenode-v1.3.6"

START_RED_TEXT="\x1b[31m"
END_RED_TEXT="\x1b[0m"

# Define structure that holds retrieved prices
priceData=()

for index in "${!pricenodes[@]}"
do
	pricenode="${pricenodes[$index]}"

	# Get all prices (except for the Coinmarketcap and BitcoinAverage hardcoded prices of 0)
	variable=$(torsocks curl $pricenode | jq '.data[] | select( (.currencyCode != "NON_EXISTING_SYMBOL") and (.currencyCode != "NON_EXISTING_SYMBOL_BA") )')

	# Add to priceData array
	priceData[$index]="$variable"
done

# n = 7 + 20 + x*30 = 27 + x*30 (where x = number of non-reference pricenodes)
# 7 means: the Currency Code column
# 20 means: 19 (for the reference pricenode label) + 1 character for the column separator "|"
# 30 means: 29 (for the non-reference pricenode label) + 1 character for the column separator "|"
# For x = 4 --> n = 27 + 4*30 = 27 + 120 = 147
# For x = 5 --> n = 27 + 5*30 = 27 + 150 = 177
dashes=$(printf "%0.s-" {1..177})

# Print horizontal dashes (begin table header)
printf "%s\n" "$dashes"

# Print table header labels
printf "%-7s" "Code"
for index in "${!pricenodeLabels[@]}"; do
	pricenodeLabel="${pricenodeLabels[$index]}"

	if [ "$index" -eq "0" ]; then

		printf "|%19s" "$pricenodeLabel"

	else

		printf "|%29s" "$pricenodeLabel"

	fi
done
printf "\n" ""

# Print horizontal dashes (end table header)
printf "%s\n" "$dashes"


# For each currencyCode (cc) in the base pricenodes[0] (the base pricenode),
# retrieve and compare prices from ALL listed pricenodes
for cc in $(echo "${priceData[0]}" | jq '.currencyCode'); do

	# First column: print curency code
	printf "%-7s" $cc

	# base price = price of this currency in the base pricenode
	# It is also the price relative to which we calculate price deltas in the other table columns
	basePrice=$(echo "${priceData[0]}" | jq 'select(.currencyCode == '$cc') | .price')

	for index in "${!priceData[@]}"; do

		priceDataX="${priceData[$index]}"

		price=$(echo "$priceDataX" | jq 'select(.currencyCode == '$cc') | .price')
		provider=$(echo "$priceDataX" | jq 'select(.currencyCode == '$cc') | .provider')

		if [ -z "$price" ]; then
			continue
		fi


		if [ "$index" -eq "0" ]; then

			# if this is the base pricenode (index == 0), then print the price with no delta
			# 2nd column: print price (from base provider)
			printf '|%19.8f' $price

		else
			# If this is NOT the base pricenode,
			# delta = difference in percentage, from this pricenode's price to the base pricenode
   			delta=$(jq -n "($price - $basePrice) * 100 / $basePrice" )

			# Check if price delta is bigger than 1% (or lower than -1)
			# Use jq for arithmetic operations, since bash only has rudimentary support for basic integer ops
			if [ $(jq -n "$delta < -1 or $delta > 1") == 'true' ]; then

				# 2nd/3rd/etc column (for non-base pricenode, with delta > 1%) : print price and highlight delta in red
				printf "|%19.8f $START_RED_TEXT(%+6.2f%%)$END_RED_TEXT" $price $delta

			else

				# 2nd/3rd/etc column (for non-base pricenode, with delta <=1%) : print price and delta
				printf "|%19.8f (%+6.2f%%)" $price $delta

			fi

		fi

	done

	printf '\n'
done
  1. Make the script executable
    • chmod +x compare-pricenode-rates.sh

Steps

  1. Execute the script
    • ./compare-pricenode-rates.sh
    • This will query the prices from several test live pricenode instances, based on this PR
  2. Check if the displayed deltas are between -1.00% and 1.00%
    • The deltas for the column Pricenode-PR-1m-up5pc are expected to be roughly around 5%

Here is a sample output of the script:

Snippet 2: Sample output for Test 0 script

Click to show...
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Code   |  Pricenode-PR-1m-A|            Pricenode-PR-1m-B|            Pricenode-PR-3m-A|            Pricenode-PR-3m-B|         Pricenode-PR-1m-up5%|             Pricenode-v1.3.6
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
"AED"  |     40002.75300000|     40002.75300000 ( +0.00%)|     40003.17350000 ( +0.00%)|     40002.75300000 ( +0.00%)|     42002.89065000 ( +5.00%)|     40181.04000000 ( +0.45%)
"AEON" |         0.00003166|         0.00003166 ( +0.00%)|         0.00003166 ( +0.00%)|         0.00003166 ( +0.00%)|         0.00003324 ( +5.00%)
"AFN"  |    836578.68000000|    836578.68000000 ( +0.00%)|    836578.68000000 ( +0.00%)|    836578.68000000 ( +0.00%)|    878407.61400000 ( +5.00%)|    840159.06000000 ( +0.43%)
"ALL"  |   1150840.25000000|   1150840.25000000 ( +0.00%)|   1150840.25000000 ( +0.00%)|   1150840.25000000 ( +0.00%)|   1208382.26250000 ( +5.00%)|   1154945.14000000 ( +0.36%)
"AMD"  |   5246221.88000000|   5246221.88000000 ( +0.00%)|   5246221.88000000 ( +0.00%)|   5246221.88000000 ( +0.00%)|   5508532.97400000 ( +5.00%)|   5268674.62000000 ( +0.43%)
"ANG"  |     19551.29000000|     19551.29000000 ( +0.00%)|     19551.29000000 ( +0.00%)|     19551.29000000 ( +0.00%)|     20528.85450000 ( +5.00%)|     19634.96000000 ( +0.43%)
"AOA"  |   6119224.04000000|   6119224.04000000 ( +0.00%)|   6119224.04000000 ( +0.00%)|   6119224.04000000 ( +0.00%)|   6425185.24200000 ( +5.00%)|   6145413.05000000 ( +0.43%)
"ARS"  |    785560.84184636|    785560.84184636 ( +0.00%)|    786390.72081288 ( +0.11%)|    786402.27614622 ( +0.11%)|    825722.38995353 ( +5.11%)|    789307.51000000 ( +0.48%)
"AUD"  |     15250.41907538|     15250.41907538 ( +0.00%)|     15256.54993051 ( +0.04%)|     15257.39564479 ( +0.05%)|     16020.26542703 ( +5.05%)|     15295.03000000 ( +0.29%)
"AWG"  |     19607.31000000|     19607.31000000 ( +0.00%)|     19607.31000000 ( +0.00%)|     19607.31000000 ( +0.00%)|     20587.67550000 ( +5.00%)|     19691.23000000 ( +0.43%)
"AZN"  |     18545.25000000|     18545.25000000 ( +0.00%)|     18545.25000000 ( +0.00%)|     18545.25000000 ( +0.00%)|     19472.51250000 ( +5.00%)|     18624.62000000 ( +0.43%)
"BAM"  |     18148.00000000|     18148.00000000 ( +0.00%)|     18148.00000000 ( +0.00%)|     18148.00000000 ( +0.00%)|     19055.40000000 ( +5.00%)|     18225.67000000 ( +0.43%)
"BBD"  |     21785.90000000|     21785.90000000 ( +0.00%)|     21785.90000000 ( +0.00%)|     21785.90000000 ( +0.00%)|     22875.19500000 ( +5.00%)|     21879.14000000 ( +0.43%)
"BDT"  |    923414.85600000|    923414.85600000 ( +0.00%)|    923424.56200000 ( +0.00%)|    923414.85600000 ( +0.00%)|    969585.59880000 ( +5.00%)|    927517.76000000 ( +0.44%)
"BEAM" |         0.00003710|         0.00003710 ( +0.00%)|         0.00003700 ( -0.27%)|         0.00003710 ( +0.00%)|         0.00003895 ( +5.00%)
"BGN"  |     18145.68000000|     18145.68000000 ( +0.00%)|     18145.68000000 ( +0.00%)|     18145.68000000 ( +0.00%)|     19052.96400000 ( +5.00%)|     18218.48000000 ( +0.40%)
"BHD"  |      4102.25100000|      4102.25100000 ( +0.00%)|      4102.29400000 ( +0.00%)|      4102.25100000 ( +0.00%)|      4307.36355000 ( +5.00%)|      4120.43000000 ( +0.44%)
"BIF"  |  20996162.67000000|  20996162.67000000 ( +0.00%)|  20996162.67000000 ( +0.00%)|  20996162.67000000 ( +0.00%)|  22045970.80350000 ( +5.00%)|  21086021.88000000 ( +0.43%)
"BMD"  |     10891.17800000|     10891.17800000 ( +0.00%)|     10891.29250000 ( +0.00%)|     10891.17800000 ( +0.00%)|     11435.73690000 ( +5.00%)|     10939.57000000 ( +0.44%)
"BND"  |     15021.14000000|     15021.14000000 ( +0.00%)|     15021.14000000 ( +0.00%)|     15021.14000000 ( +0.00%)|     15772.19700000 ( +5.00%)|     15085.43000000 ( +0.43%)
"BOB"  |     75180.43619251|     75180.43619251 ( +0.00%)|     75301.21307466 ( +0.16%)|     75301.21307466 ( +0.16%)|     79066.27372839 ( +5.17%)|     75529.82000000 ( +0.46%)
"BRL"  |     56003.42102960|     56013.40102960 ( +0.02%)|     56038.90797542 ( +0.06%)|     56048.41397542 ( +0.08%)|     58850.83467420 ( +5.08%)|     55860.03000000 ( -0.26%)
"BSD"  |     10892.95000000|     10892.95000000 ( +0.00%)|     10892.95000000 ( +0.00%)|     10892.95000000 ( +0.00%)|     11437.59750000 ( +5.00%)|     10939.57000000 ( +0.43%)
"BTM"  |         0.00000868|         0.00000867 ( -0.05%)|         0.00000869 ( +0.11%)|         0.00000868 ( +0.00%)|         0.00000911 ( +5.00%)
"BTN"  |    814949.23000000|    814949.23000000 ( +0.00%)|    814949.23000000 ( +0.00%)|    814949.23000000 ( +0.00%)|    855696.69150000 ( +5.00%)|    818437.04000000 ( +0.43%)
"BWP"  |    124550.12000000|    124550.12000000 ( +0.00%)|    124550.12000000 ( +0.00%)|    124550.12000000 ( +0.00%)|    130777.62600000 ( +5.00%)|    125083.17000000 ( +0.43%)
"BYN"  |     26302.27000000|     26302.27000000 ( +0.00%)|     26302.27000000 ( +0.00%)|     26302.27000000 ( +0.00%)|     27617.38350000 ( +5.00%)|     26414.84000000 ( +0.43%)
"BZD"  |     21954.60000000|     21954.60000000 ( +0.00%)|     21954.60000000 ( +0.00%)|     21954.60000000 ( +0.00%)|     23052.33000000 ( +5.00%)|     22048.56000000 ( +0.43%)
"CAD"  |     14551.33804798|     14551.33804798 ( +0.00%)|     14532.10911445 ( -0.13%)|     14564.97161445 ( +0.09%)|     15291.17269518 ( +5.08%)|     14549.57000000 ( -0.01%)
"CDF"  |  21404648.32000000|  21404648.32000000 ( +0.00%)|  21404648.32000000 ( +0.00%)|  21404648.32000000 ( +0.00%)|  22474880.73600000 ( +5.00%)|  21496255.77000000 ( +0.43%)
"CHF"  |      9994.88941745|      9994.88941745 ( +0.00%)|     10005.24181468 ( +0.10%)|     10002.91331468 ( +0.08%)|     10503.05898042 ( +5.08%)|     10035.75000000 ( +0.41%)
"CLP"  |   8336711.44552104|   8336711.44552104 ( +0.00%)|   8346424.40040044 ( +0.12%)|   8345642.25940044 ( +0.11%)|   8762924.37237046 ( +5.11%)|   8377522.99000000 ( +0.49%)
"CNY"  |     76232.50052341|     76232.50052341 ( +0.00%)|     76314.67843299 ( +0.11%)|     76314.14409966 ( +0.11%)|     80129.85130464 ( +5.11%)|     76585.74000000 ( +0.46%)
"COP"  |  40326234.55820105|  40326234.55820105 ( +0.00%)|  40391422.01141513 ( +0.16%)|  40391422.01141513 ( +0.16%)|  42410993.11198589 ( +5.17%)|  40766418.37000000 ( +1.09%)
"CRC"  |   6334449.25000000|   6334449.25000000 ( +0.00%)|   6334449.25000000 ( +0.00%)|   6334449.25000000 ( +0.00%)|   6651171.71250000 ( +5.00%)|   6361559.38000000 ( +0.43%)
"CUP"  |    280493.48000000|    280493.48000000 ( +0.00%)|    280493.48000000 ( +0.00%)|    280493.48000000 ( +0.00%)|    294518.15400000 ( +5.00%)|    281693.94000000 ( +0.43%)
"CVE"  |   1028022.23000000|   1028022.23000000 ( +0.00%)|   1028022.23000000 ( +0.00%)|   1028022.23000000 ( +0.00%)|   1079423.34150000 ( +5.00%)|   1032421.95000000 ( +0.43%)
"CZK"  |    243973.97812490|    243973.97812490 ( +0.00%)|    244171.88025222 ( +0.08%)|    244169.91650222 ( +0.08%)|    256378.41232733 ( +5.08%)|    243412.00000000 ( -0.23%)
"DAI"  |         0.00009326|         0.00009326 ( +0.00%)|         0.00009371 ( +0.48%)|         0.00009371 ( +0.48%)|         0.00009792 ( +5.00%)
"DASH" |         0.00722625|         0.00722614 ( -0.00%)|         0.00723000 ( +0.05%)|         0.00722895 ( +0.04%)|         0.00758756 ( +5.00%)|         0.00727949 ( +0.74%)
"DCR"  |         0.00140889|         0.00140889 ( +0.00%)|         0.00141063 ( +0.12%)|         0.00141014 ( +0.09%)|         0.00147933 ( +5.00%)|         0.00141224 ( +0.24%)
"DJF"  |   1938945.24000000|   1938945.24000000 ( +0.00%)|   1938945.24000000 ( +0.00%)|   1938945.24000000 ( +0.00%)|   2035892.50200000 ( +5.00%)|   1947243.53000000 ( +0.43%)
"DKK"  |     69124.90699594|     69124.90699594 ( +0.00%)|     69193.58258838 ( +0.10%)|     69198.89858838 ( +0.11%)|     72658.84351780 ( +5.11%)|     69407.80000000 ( +0.41%)
"DOGE" |         0.00000029|         0.00000029 ( +0.03%)|         0.00000029 ( +0.01%)|         0.00000029 ( +0.00%)|         0.00000031 ( +5.00%)|         0.00000029 ( -1.49%)
"DOP"  |    637782.27000000|    637782.27000000 ( +0.00%)|    637782.27000000 ( +0.00%)|    637782.27000000 ( +0.00%)|    669671.38350000 ( +5.00%)|    640511.84000000 ( +0.43%)
"DZD"  |   1392827.15000000|   1392827.15000000 ( +0.00%)|   1392827.15000000 ( +0.00%)|   1392827.15000000 ( +0.00%)|   1462468.50750000 ( +5.00%)|   1398410.82000000 ( +0.40%)
"EGP"  |    174045.62000000|    174045.62000000 ( +0.00%)|    174045.62000000 ( +0.00%)|    174045.62000000 ( +0.00%)|    182747.90100000 ( +5.00%)|    174854.81000000 ( +0.46%)
"EMC"  |         0.00000561|         0.00000561 ( +0.00%)|         0.00000561 ( +0.00%)|         0.00000561 ( +0.00%)|         0.00000589 ( +5.00%)
"ETB"  |    383704.19000000|    383704.19000000 ( +0.00%)|    383704.19000000 ( +0.00%)|    383704.19000000 ( +0.00%)|    402889.39950000 ( +5.00%)|    385619.86000000 ( +0.50%)
"ETC"  |         0.00065594|         0.00065594 ( +0.00%)|         0.00065596 ( +0.00%)|         0.00065609 ( +0.02%)|         0.00068874 ( +5.00%)|         0.00065644 ( +0.08%)
"ETH"  |         0.02902069|         0.02901775 ( -0.01%)|         0.02902128 ( +0.00%)|         0.02902363 ( +0.01%)|         0.03046897 ( +4.99%)|         0.02894501 ( -0.26%)
"EUR"  |      9326.87000714|      9329.28917381 ( +0.03%)|      9325.68233727 ( -0.01%)|      9329.09608727 ( +0.02%)|      9796.90364163 ( +5.04%)|      9350.47000000 ( +0.25%)
"FAIR" |         0.00000019|         0.00000019 ( +0.00%)|         0.00000019 ( +0.00%)|         0.00000019 ( +0.00%)|         0.00000020 ( +5.00%)
"FJD"  |     23174.75000000|     23174.75000000 ( +0.00%)|     23174.75000000 ( +0.00%)|     23174.75000000 ( +0.00%)|     24333.48750000 ( +5.00%)|     23366.92000000 ( +0.83%)
"FKP"  |      8418.49000000|      8418.49000000 ( +0.00%)|      8418.49000000 ( +0.00%)|      8418.49000000 ( +0.00%)|      8839.41450000 ( +5.00%)|      8448.62000000 ( +0.36%)
"GBP"  |      8460.83625155|      8463.39321053 ( +0.03%)|      8454.09880665 ( -0.08%)|      8460.31844430 ( -0.01%)|      8889.45881365 ( +5.07%)|      8476.89000000 ( +0.19%)
"GEL"  |     33659.22000000|     33659.22000000 ( +0.00%)|     33659.22000000 ( +0.00%)|     33659.22000000 ( +0.00%)|     35342.18100000 ( +5.00%)|     33803.27000000 ( +0.43%)
"GHS"  |     63070.19000000|     63070.19000000 ( +0.00%)|     63070.19000000 ( +0.00%)|     63070.19000000 ( +0.00%)|     66223.69950000 ( +5.00%)|     63340.11000000 ( +0.43%)
"GIP"  |      8418.49000000|      8418.49000000 ( +0.00%)|      8418.49000000 ( +0.00%)|      8418.49000000 ( +0.00%)|      8839.41450000 ( +5.00%)|      8448.62000000 ( +0.36%)
"GMD"  |    564363.78000000|    564363.78000000 ( +0.00%)|    564363.78000000 ( +0.00%)|    564363.78000000 ( +0.00%)|    592581.96900000 ( +5.00%)|    566779.14000000 ( +0.43%)
"GNF"  | 104735721.94000000| 104735721.94000000 ( +0.00%)| 104735721.94000000 ( +0.00%)| 104735721.94000000 ( +0.00%)| 109972508.03700000 ( +5.00%)| 105183969.08000000 ( +0.43%)
"GRIN" |         0.00005477|         0.00005477 ( +0.00%)|         0.00005477 ( +0.00%)|         0.00005477 ( +0.00%)|         0.00005751 ( +5.00%)
"GTQ"  |     83867.31000000|     83867.31000000 ( +0.00%)|     83867.31000000 ( +0.00%)|     83867.31000000 ( +0.00%)|     88060.67550000 ( +5.00%)|     84226.25000000 ( +0.43%)
"GYD"  |   2277302.12000000|   2277302.12000000 ( +0.00%)|   2277302.12000000 ( +0.00%)|   2277302.12000000 ( +0.00%)|   2391167.22600000 ( +5.00%)|   2287048.50000000 ( +0.43%)
"HKD"  |     84555.06592274|     84555.06592274 ( +0.00%)|     84623.29831523 ( +0.08%)|     84622.85456523 ( +0.08%)|     88853.99729349 ( +5.08%)|     84785.50000000 ( +0.27%)
"HNL"  |    271615.73000000|    271615.73000000 ( +0.00%)|    271615.73000000 ( +0.00%)|    271615.73000000 ( +0.00%)|    285196.51650000 ( +5.00%)|    272668.79000000 ( +0.39%)
"HRK"  |     69747.56000000|     69747.56000000 ( +0.00%)|     69747.56000000 ( +0.00%)|     69747.56000000 ( +0.00%)|     73234.93800000 ( +5.00%)|     70013.25000000 ( +0.38%)
"HTG"  |   1209748.46000000|   1209748.46000000 ( +0.00%)|   1209748.46000000 ( +0.00%)|   1209748.46000000 ( +0.00%)|   1270235.88300000 ( +5.00%)|   1214925.93000000 ( +0.43%)
"HUF"  |   3223107.32943980|   3223107.32943980 ( +0.00%)|   3226354.88342511 ( +0.10%)|   3226557.33975844 ( +0.11%)|   3387885.20674636 ( +5.11%)|   3236285.92000000 ( +0.41%)
"IDR"  | 158914492.12672377| 158914492.12672377 ( +0.00%)| 159032581.04399110 ( +0.07%)| 159041955.35224110 ( +0.08%)| 166994053.11985317 ( +5.08%)| 159157131.68000000 ( +0.15%)
"ILS"  |     37164.10771638|     37164.10771638 ( +0.00%)|     37204.17044290 ( +0.11%)|     37203.90977624 ( +0.11%)|     39064.10526505 ( +5.11%)|     36238.50000000 ( -2.49%)
"INR"  |    815114.63455575|    815114.63455575 ( +0.00%)|    815956.89844875 ( +0.10%)|    815987.53878208 ( +0.11%)|    856786.91572118 ( +5.11%)|    818827.94000000 ( +0.46%)
"IQD"  |  12962611.45000000|  12962611.45000000 ( +0.00%)|  12962611.45000000 ( +0.00%)|  12962611.45000000 ( +0.00%)|  13610742.02250000 ( +5.00%)|  13018088.74000000 ( +0.43%)
"IRR"  | 458647693.43000000| 458647693.43000000 ( +0.00%)| 458647693.43000000 ( +0.00%)| 458647693.43000000 ( +0.00%)| 481580078.10150003 ( +5.00%)| 460610610.31000000 ( +0.43%)
"ISK"  |   1472732.80182033|   1472732.80182033 ( +0.00%)|   1475097.86250079 ( +0.16%)|   1475097.86250079 ( +0.16%)|   1548852.75562583 ( +5.17%)|   1479029.91000000 ( +0.43%)
"JMD"  |   1601099.14000000|   1601099.14000000 ( +0.00%)|   1601099.14000000 ( +0.00%)|   1601099.14000000 ( +0.00%)|   1681154.09700000 ( +5.00%)|   1607951.51000000 ( +0.43%)
"JOD"  |      7723.10000000|      7723.10000000 ( +0.00%)|      7723.10000000 ( +0.00%)|      7723.10000000 ( +0.00%)|      8109.25500000 ( +5.00%)|      7756.16000000 ( +0.43%)
"JPY"  |   1151334.77828006|   1151756.77828000 ( +0.04%)|   1152317.29071760 ( +0.09%)|   1151971.10709967 ( +0.06%)|   1209863.09580348 ( +5.08%)|   1153066.84000000 ( +0.15%)
"KES"  |   1174151.17000000|   1174151.17000000 ( +0.00%)|   1174151.17000000 ( +0.00%)|   1174151.17000000 ( +0.00%)|   1232858.72850000 ( +5.00%)|   1179066.89000000 ( +0.42%)
"KGS"  |    839262.49000000|    839262.49000000 ( +0.00%)|    839262.49000000 ( +0.00%)|    839262.49000000 ( +0.00%)|    881225.61450000 ( +5.00%)|    843231.77000000 ( +0.47%)
"KHR"  |  44671991.23000000|  44671991.23000000 ( +0.00%)|  44671991.23000000 ( +0.00%)|  44671991.23000000 ( +0.00%)|  46905590.79150000 ( +5.00%)|  44852238.51000000 ( +0.40%)
"KMF"  |   4572863.97000000|   4572863.97000000 ( +0.00%)|   4572863.97000000 ( +0.00%)|   4572863.97000000 ( +0.00%)|   4801507.16850000 ( +5.00%)|   4592434.88000000 ( +0.43%)
"KPW"  |   9803655.72000000|   9803655.72000000 ( +0.00%)|   9803655.72000000 ( +0.00%)|   9803655.72000000 ( +0.00%)|  10293838.50600000 ( +5.00%)|   9845613.33000000 ( +0.43%)
"KRW"  |  13011981.92402978|  13011981.92402978 ( +0.00%)|  13023072.23446963 ( +0.09%)|  13022462.70546963 ( +0.08%)|  13673585.84074311 ( +5.08%)|  13108723.08000000 ( +0.74%)
"KWD"  |      3331.65150000|      3331.65150000 ( +0.00%)|      3331.68650000 ( +0.00%)|      3331.65150000 ( +0.00%)|      3498.23407500 ( +5.00%)|      3345.87000000 ( +0.43%)
"KYD"  |      9076.92000000|      9076.92000000 ( +0.00%)|      9076.92000000 ( +0.00%)|      9076.92000000 ( +0.00%)|      9530.76600000 ( +5.00%)|      9115.77000000 ( +0.43%)
"KZT"  |   4523335.25000000|   4523335.25000000 ( +0.00%)|   4523335.25000000 ( +0.00%)|   4523335.25000000 ( +0.00%)|   4749502.01250000 ( +5.00%)|   4542694.18000000 ( +0.43%)
"LAK"  |  98744599.00000000|  98744599.00000000 ( +0.00%)|  98744599.00000000 ( +0.00%)|  98744599.00000000 ( +0.00%)| 103681828.95000000 ( +5.00%)|  99167205.38000000 ( +0.43%)
"LBP"  |  16475033.84000000|  16475033.84000000 ( +0.00%)|  16475033.84000000 ( +0.00%)|  16475033.84000000 ( +0.00%)|  17298785.53200000 ( +5.00%)|  16584388.68000000 ( +0.66%)
"LKR"  |   2022479.66750000|   2022479.66750000 ( +0.00%)|   2022500.92550000 ( +0.00%)|   2022479.66750000 ( +0.00%)|   2123603.65087500 ( +5.00%)|   2031465.93000000 ( +0.44%)
"LRD"  |   2170420.81000000|   2170420.81000000 ( +0.00%)|   2170420.81000000 ( +0.00%)|   2170420.81000000 ( +0.00%)|   2278941.85050000 ( +5.00%)|   2179709.76000000 ( +0.43%)
"LSL"  |    180387.27000000|    180387.27000000 ( +0.00%)|    180387.27000000 ( +0.00%)|    180387.27000000 ( +0.00%)|    189406.63350000 ( +5.00%)|    181159.29000000 ( +0.43%)
"LTC"  |         0.00520197|         0.00520252 ( +0.01%)|         0.00520473 ( +0.05%)|         0.00520228 ( +0.01%)|         0.00546206 ( +5.00%)|         0.00521081 ( +0.17%)
"LYD"  |     15141.20000000|     15141.20000000 ( +0.00%)|     15141.20000000 ( +0.00%)|     15141.20000000 ( +0.00%)|     15898.26000000 ( +5.00%)|     15206.00000000 ( +0.43%)
"MAD"  |    102066.95000000|    102066.95000000 ( +0.00%)|    102066.95000000 ( +0.00%)|    102066.95000000 ( +0.00%)|    107170.29750000 ( +5.00%)|    102520.18000000 ( +0.44%)
"MDL"  |    182111.76000000|    182111.76000000 ( +0.00%)|    182111.76000000 ( +0.00%)|    182111.76000000 ( +0.00%)|    191217.34800000 ( +5.00%)|    182891.16000000 ( +0.43%)
"MGA"  |  41529374.93000000|  41529374.93000000 ( +0.00%)|  41529374.93000000 ( +0.00%)|  41529374.93000000 ( +0.00%)|  43605843.67650000 ( +5.00%)|  41679763.10000000 ( +0.36%)
"MKD"  |    571721.12000000|    571721.12000000 ( +0.00%)|    571721.12000000 ( +0.00%)|    571721.12000000 ( +0.00%)|    600307.17600000 ( +5.00%)|    574167.97000000 ( +0.43%)
"MMK"  |  14815106.87200000|  14815106.87200000 ( +0.00%)|  14815262.59200000 ( +0.00%)|  14815106.87200000 ( +0.00%)|  15555862.21560000 ( +5.00%)|  14880933.23000000 ( +0.44%)
"MNT"  |  30983738.11000000|  30983738.11000000 ( +0.00%)|  30983738.11000000 ( +0.00%)|  30983738.11000000 ( +0.00%)|  32532925.01550000 ( +5.00%)|  31114731.17000000 ( +0.42%)
"MOP"  |     86943.37000000|     86943.37000000 ( +0.00%)|     86943.37000000 ( +0.00%)|     86943.37000000 ( +0.00%)|     91290.53850000 ( +5.00%)|     87315.47000000 ( +0.43%)
"MRU"  |    410991.03000000|    410991.03000000 ( +0.00%)|    410991.03000000 ( +0.00%)|    410991.03000000 ( +0.00%)|    431540.58150000 ( +5.00%)
"MUR"  |    437351.97000000|    437351.97000000 ( +0.00%)|    437351.97000000 ( +0.00%)|    437351.97000000 ( +0.00%)|    459219.56850000 ( +5.00%)|    439114.38000000 ( +0.40%)
"MVR"  |    167751.44000000|    167751.44000000 ( +0.00%)|    167751.44000000 ( +0.00%)|    167751.44000000 ( +0.00%)|    176139.01200000 ( +5.00%)|    168469.38000000 ( +0.43%)
"MWK"  |   8033551.22000000|   8033551.22000000 ( +0.00%)|   8033551.22000000 ( +0.00%)|   8033551.22000000 ( +0.00%)|   8435228.78100000 ( +5.00%)|   8067933.15000000 ( +0.43%)
"MXN"  |    238749.38376607|    238749.38376607 ( +0.00%)|    239010.07404824 ( +0.11%)|    239004.95271491 ( +0.11%)|    250955.20035065 ( +5.11%)|    238737.44000000 ( -0.01%)
"MYR"  |     46222.79720864|     46222.79720864 ( +0.00%)|     46260.22656651 ( +0.08%)|     46259.98306651 ( +0.08%)|     48572.98221984 ( +5.08%)|     46001.00000000 ( -0.48%)
"MZN"  |    769859.17000000|    769859.17000000 ( +0.00%)|    769859.17000000 ( +0.00%)|    769859.17000000 ( +0.00%)|    808352.12850000 ( +5.00%)|    773154.00000000 ( +0.43%)
"NAD"  |    180387.27000000|    180387.27000000 ( +0.00%)|    180387.27000000 ( +0.00%)|    180387.27000000 ( +0.00%)|    189406.63350000 ( +5.00%)|    181159.29000000 ( +0.43%)
"NAV"  |         0.00001141|         0.00001141 ( +0.00%)|         0.00001141 ( +0.00%)|         0.00001141 ( +0.00%)|         0.00001199 ( +5.00%)
"NGN"  |   4637347.02849490|   4641630.27849490 ( +0.09%)|   4632751.55117233 ( -0.10%)|   4639104.55117233 ( +0.04%)|   4873333.29123095 ( +5.09%)|   4239083.52000000 ( -8.59%)
"NIO"  |    376678.24000000|    376678.24000000 ( +0.00%)|    376678.24000000 ( +0.00%)|    376678.24000000 ( +0.00%)|    395512.15200000 ( +5.00%)|    378618.53000000 ( +0.52%)
"NOK"  |     99196.66071913|     99196.66071913 ( +0.00%)|     99283.49738014 ( +0.09%)|     99302.80938014 ( +0.11%)|    104267.94984915 ( +5.11%)|     99572.74000000 ( +0.38%)
"NPR"  |   1303897.33000000|   1303897.33000000 ( +0.00%)|   1303897.33000000 ( +0.00%)|   1303897.33000000 ( +0.00%)|   1369092.19650000 ( +5.00%)|   1309477.74000000 ( +0.43%)
"NZD"  |     16389.07967228|     16389.07967228 ( +0.00%)|     16400.48701996 ( +0.07%)|     16402.21426996 ( +0.08%)|     17222.32498346 ( +5.08%)|     16477.13000000 ( +0.54%)
"OMR"  |      4193.62000000|      4193.62000000 ( +0.00%)|      4193.62000000 ( +0.00%)|      4193.62000000 ( +0.00%)|      4403.30100000 ( +5.00%)|      4211.02000000 ( +0.41%)
"PAB"  |     10892.95000000|     10892.95000000 ( +0.00%)|     10892.95000000 ( +0.00%)|     10892.95000000 ( +0.00%)|     11437.59750000 ( +5.00%)|     10939.57000000 ( +0.43%)
"PART" |         0.00006887|         0.00006887 ( +0.00%)|         0.00006887 ( +0.00%)|         0.00006887 ( +0.00%)|         0.00007231 ( +5.00%)
"PEN"  |     38280.16013105|     38280.16013105 ( +0.00%)|     38341.65695877 ( +0.16%)|     38341.65695877 ( +0.16%)|     40258.73980671 ( +5.17%)|     38458.06000000 ( +0.46%)
"PGK"  |     38356.80000000|     38356.80000000 ( +0.00%)|     38356.80000000 ( +0.00%)|     38356.80000000 ( +0.00%)|     40274.64000000 ( +5.00%)|     38507.29000000 ( +0.39%)
"PHP"  |    535479.72458717|    535479.72458717 ( +0.00%)|    535950.48694844 ( +0.09%)|    536053.03028177 ( +0.11%)|    562855.68179586 ( +5.11%)|    537789.28000000 ( +0.43%)
"PIVX" |         0.00004025|         0.00004025 ( +0.00%)|         0.00004025 ( +0.00%)|         0.00004025 ( +0.00%)|         0.00004226 ( +5.00%)
"PKR"  |   1812311.32698277|   1812311.32698277 ( +0.00%)|   1814265.17415460 ( +0.11%)|   1814252.47282127 ( +0.11%)|   1904965.09646233 ( +5.11%)|   1820891.49000000 ( +0.47%)
"PLN"  |     38462.18555291|     38464.24955291 ( +0.01%)|     38502.52790935 ( +0.10%)|     38475.64890935 ( +0.04%)|     40412.93225481 ( +5.07%)|     39700.00000000 ( +3.22%)
"PYG"  |  75525093.57000000|  75525093.57000000 ( +0.00%)|  75525093.57000000 ( +0.00%)|  75525093.57000000 ( +0.00%)|  79301348.24849999 ( +5.00%)|  75848325.28000000 ( +0.43%)
"QAR"  |     39658.51000000|     39658.51000000 ( +0.00%)|     39658.51000000 ( +0.00%)|     39658.51000000 ( +0.00%)|     41641.43550000 ( +5.00%)|     39828.24000000 ( +0.43%)
"RON"  |     44922.53000000|     44922.53000000 ( +0.00%)|     44922.53000000 ( +0.00%)|     44922.53000000 ( +0.00%)|     47168.65650000 ( +5.00%)|     45044.77000000 ( +0.27%)
"RSD"  |   1093325.47000000|   1093325.47000000 ( +0.00%)|   1093325.47000000 ( +0.00%)|   1093325.47000000 ( +0.00%)|   1147991.74350000 ( +5.00%)|   1096910.72000000 ( +0.33%)
"RUB"  |    785163.63511583|    785029.12011583 ( -0.02%)|    784890.37257308 ( -0.03%)|    784944.63007308 ( -0.03%)|    824854.13157674 ( +5.06%)|    773132.57000000 ( -1.53%)
"RWF"  |  10375535.64000000|  10375535.64000000 ( +0.00%)|  10375535.64000000 ( +0.00%)|  10375535.64000000 ( +0.00%)|  10894312.42200000 ( +5.00%)|  10419940.77000000 ( +0.43%)
"SAR"  |     40851.73100000|     40851.73100000 ( +0.00%)|     40852.16000000 ( +0.00%)|     40851.73100000 ( +0.00%)|     42894.31755000 ( +5.00%)|     41033.65000000 ( +0.45%)
"SBD"  |     90198.15000000|     90198.15000000 ( +0.00%)|     90198.15000000 ( +0.00%)|     90198.15000000 ( +0.00%)|     94708.05750000 ( +5.00%)|     90434.38000000 ( +0.26%)
"SCR"  |    192358.65000000|    192358.65000000 ( +0.00%)|    192358.65000000 ( +0.00%)|    192358.65000000 ( +0.00%)|    201976.58250000 ( +5.00%)|    193156.53000000 ( +0.41%)
"SDG"  |    602380.18000000|    602380.18000000 ( +0.00%)|    602380.18000000 ( +0.00%)|    602380.18000000 ( +0.00%)|    632499.18900000 ( +5.00%)|    604958.24000000 ( +0.43%)
"SEK"  |     95463.86517788|     95463.86517788 ( +0.00%)|     95556.01621862 ( +0.10%)|     95565.99655195 ( +0.11%)|    100344.29637955 ( +5.11%)|     95000.00000000 ( -0.49%)
"SGD"  |     15016.65674036|     15016.65674036 ( +0.00%)|     15028.10255016 ( +0.08%)|     15028.71255016 ( +0.08%)|     15780.14817766 ( +5.08%)|     15108.00000000 ( +0.61%)
"SHP"  |      8418.49000000|      8418.49000000 ( +0.00%)|      8418.49000000 ( +0.00%)|      8418.49000000 ( +0.00%)|      8839.41450000 ( +5.00%)|      8448.62000000 ( +0.36%)
"SLL"  | 106287969.96000000| 106287969.96000000 ( +0.00%)| 106287969.96000000 ( +0.00%)| 106287969.96000000 ( +0.00%)| 111602368.45800000 ( +5.00%)| 106742859.86000000 ( +0.43%)
"SOS"  |   6372376.22000000|   6372376.22000000 ( +0.00%)|   6372376.22000000 ( +0.00%)|   6372376.22000000 ( +0.00%)|   6690995.03100000 ( +5.00%)|   6399648.66000000 ( +0.43%)
"SRD"  |     81239.63000000|     81239.63000000 ( +0.00%)|     81239.63000000 ( +0.00%)|     81239.63000000 ( +0.00%)|     85301.61150000 ( +5.00%)|     81587.32000000 ( +0.43%)
"STN"  |    228751.97000000|    228751.97000000 ( +0.00%)|    228751.97000000 ( +0.00%)|    228751.97000000 ( +0.00%)|    240189.56850000 ( +5.00%)
"SVC"  |     95306.71000000|     95306.71000000 ( +0.00%)|     95306.71000000 ( +0.00%)|     95306.71000000 ( +0.00%)|    100072.04550000 ( +5.00%)|     95714.60000000 ( +0.43%)
"SYP"  |   5578888.27000000|   5578888.27000000 ( +0.00%)|   5578888.27000000 ( +0.00%)|   5578888.27000000 ( +0.00%)|   5857832.68350000 ( +5.00%)|   5602059.61000000 ( +0.42%)
"SZL"  |    180387.27000000|    180387.27000000 ( +0.00%)|    180387.27000000 ( +0.00%)|    180387.27000000 ( +0.00%)|    189406.63350000 ( +5.00%)|    181159.29000000 ( +0.43%)
"THB"  |    342669.66074014|    342669.66074014 ( +0.00%)|    343002.73305792 ( +0.10%)|    343036.63005792 ( +0.11%)|    360188.46156082 ( +5.11%)|    344235.46000000 ( +0.46%)
"TJS"  |    112319.59000000|    112319.59000000 ( +0.00%)|    112319.59000000 ( +0.00%)|    112319.59000000 ( +0.00%)|    117935.56950000 ( +5.00%)|    112800.29000000 ( +0.43%)
"TMT"  |     38234.26000000|     38234.26000000 ( +0.00%)|     38234.26000000 ( +0.00%)|     38234.26000000 ( +0.00%)|     40145.97300000 ( +5.00%)|     38397.89000000 ( +0.43%)
"TND"  |     30119.01000000|     30119.01000000 ( +0.00%)|     30119.01000000 ( +0.00%)|     30119.01000000 ( +0.00%)|     31624.96050000 ( +5.00%)|     30247.91000000 ( +0.43%)
"TOP"  |     24726.67000000|     24726.67000000 ( +0.00%)|     24726.67000000 ( +0.00%)|     24726.67000000 ( +0.00%)|     25963.00350000 ( +5.00%)|     24832.50000000 ( +0.43%)
"TRY"  |     75883.33789843|     75883.33789843 ( +0.00%)|     75842.53747346 ( -0.05%)|     75912.60427346 ( +0.04%)|     79730.70448713 ( +5.07%)|     76512.66000000 ( +0.83%)
"TTD"  |     73661.11000000|     73661.11000000 ( +0.00%)|     73661.11000000 ( +0.00%)|     73661.11000000 ( +0.00%)|     77344.16550000 ( +5.00%)|     73976.36000000 ( +0.43%)
"TWD"  |    319237.54958844|    319237.54958844 ( +0.00%)|    319581.72978243 ( +0.11%)|    319579.49211576 ( +0.11%)|    335558.46672155 ( +5.11%)|    320759.14000000 ( +0.48%)
"TZS"  |  25326110.61000000|  25326110.61000000 ( +0.00%)|  25326110.61000000 ( +0.00%)|  25326110.61000000 ( +0.00%)|  26592416.14050000 ( +5.00%)|  25434501.10000000 ( +0.43%)
"UAH"  |    301403.44422875|    301316.34822875 ( -0.03%)|    301511.44203539 ( +0.04%)|    301597.26963539 ( +0.06%)|    316677.13311716 ( +5.07%)|    303029.82000000 ( +0.54%)
"UGX"  |  40223480.28000000|  40223480.28000000 ( +0.00%)|  40223480.28000000 ( +0.00%)|  40223480.28000000 ( +0.00%)|  42234654.29400000 ( +5.00%)|  40395628.42000000 ( +0.43%)
"USD"  |     10858.60474464|     10859.39057798 ( +0.01%)|     10857.05683682 ( -0.01%)|     10861.43608682 ( +0.03%)|     11407.03489116 ( +5.05%)|     10952.36000000 ( +0.86%)
"USDC" |         0.00009180|         0.00009180 ( +0.00%)|         0.00009180 ( +0.00%)|         0.00009180 ( +0.00%)|         0.00009639 ( +5.00%)
"UYU"  |    461922.07000000|    461922.07000000 ( +0.00%)|    461922.07000000 ( +0.00%)|    461922.07000000 ( +0.00%)|    485018.17350000 ( +5.00%)|    463606.38000000 ( +0.36%)
"UZS"  | 111217027.67000000| 111217027.67000000 ( +0.00%)| 111217027.67000000 ( +0.00%)| 111217027.67000000 ( +0.00%)| 116777879.05350001 ( +5.00%)| 111693013.45000000 ( +0.43%)
"VES"  |2666027922.40000000|2666027922.40000000 ( +0.00%)|2666027922.40000000 ( +0.00%)|2666027922.40000000 ( +0.00%)|2799329318.52000000 ( +5.00%)|2677437968.21000000 ( +0.43%)
"VND"  | 252689786.01935992| 252689786.01935992 ( +0.00%)| 252946960.26364875 ( +0.10%)| 252960241.38531540 ( +0.11%)| 265608253.45458117 ( +5.11%)| 253728389.83000000 ( +0.41%)
"VUV"  |   1252122.54000000|   1252122.54000000 ( +0.00%)|   1252122.54000000 ( +0.00%)|   1252122.54000000 ( +0.00%)|   1314728.66700000 ( +5.00%)|   1258082.05000000 ( +0.48%)
"WST"  |     28683.85000000|     28683.85000000 ( +0.00%)|     28683.85000000 ( +0.00%)|     28683.85000000 ( +0.00%)|     30118.04250000 ( +5.00%)|     28824.73000000 ( +0.49%)
"XAF"  |   6095529.32000000|   6095529.32000000 ( +0.00%)|   6095529.32000000 ( +0.00%)|   6095529.32000000 ( +0.00%)|   6400305.78600000 ( +5.00%)|   6116889.96000000 ( +0.35%)
"XCD"  |     29438.74000000|     29438.74000000 ( +0.00%)|     29438.74000000 ( +0.00%)|     29438.74000000 ( +0.00%)|     30910.67700000 ( +5.00%)|     29564.74000000 ( +0.43%)
"XMR"  |         0.00748821|         0.00748876 ( +0.01%)|         0.00749621 ( +0.11%)|         0.00749039 ( +0.03%)|         0.00786320 ( +5.01%)|         0.00748999 ( +0.02%)
"XOF"  |   6095529.32000000|   6095529.32000000 ( +0.00%)|   6095529.32000000 ( +0.00%)|   6095529.32000000 ( +0.00%)|   6400305.78600000 ( +5.00%)|   6116889.96000000 ( +0.35%)
"XPF"  |   1108899.11000000|   1108899.11000000 ( +0.00%)|   1108899.11000000 ( +0.00%)|   1108899.11000000 ( +0.00%)|   1164344.06550000 ( +5.00%)|   1112785.04000000 ( +0.35%)
"XRC"  |         0.00038990|         0.00038990 ( +0.00%)|         0.00038990 ( +0.00%)|         0.00038990 ( +0.00%)|         0.00040939 ( +5.00%)
"XZC"  |         0.00050490|         0.00050457 ( -0.07%)|         0.00050460 ( -0.06%)|         0.00050460 ( -0.06%)|         0.00053014 ( +5.00%)
"YER"  |   2726506.16000000|   2726506.16000000 ( +0.00%)|   2726506.16000000 ( +0.00%)|   2726506.16000000 ( +0.00%)|   2862831.46800000 ( +5.00%)|   2738175.04000000 ( +0.43%)
"ZAR"  |    184222.77864286|    184222.77864286 ( +0.00%)|    184335.27170859 ( +0.06%)|    184338.21850859 ( +0.06%)|    193555.12943402 ( +5.07%)|    180480.58000000 ( -2.03%)
"ZEC"  |         0.00653942|         0.00653890 ( -0.01%)|         0.00654290 ( +0.05%)|         0.00653756 ( -0.03%)|         0.00686652 ( +5.00%)|         0.00653492 ( -0.07%)
"ZEN"  |         0.00076831|         0.00076800 ( -0.04%)|         0.00076925 ( +0.12%)|         0.00076835 ( +0.00%)|         0.00080673 ( +5.00%)
"ZMW"  |    198503.53000000|    198503.53000000 ( +0.00%)|    198503.53000000 ( +0.00%)|    198503.53000000 ( +0.00%)|    208428.70650000 ( +5.00%)|    199353.08000000 ( +0.43%)
"ZWL"  |   3507530.16000000|   3507530.16000000 ( +0.00%)|   3507530.16000000 ( +0.00%)|   3507530.16000000 ( +0.00%)|   3682906.66800000 ( +5.00%)|   3522541.66000000 ( +0.43%)

Success criteria

The test is successful if, in the table outputted by the script, all the deltas in columns

  • Pricenode-PR-1m-A
  • Pricenode-PR-1m-B
  • Pricenode-PR-3m-A
  • Pricenode-PR-3m-B

have a value between -1.00% and 1.00%.

Tests 1-4

Goals / Scenarios

Test Goals Scenario Pricenodes used
All (1-4) Existing Bisq clients can retrieve pricenode data from pricenodes running this PR code
1 Trades are successful when using distinct, healthy pricenode instances Maker and Seller each use a separate pricenode instance running this PR's code

Both instances are healthy, polling exchanges every 1 minute
Pricenode-PR-1m-A

Pricenode-PR-1m-B
2 Trades are successful when one of the pricenodes used exhibits intermittent connectivity to exchanges Maker and Seller each use a separate pricenode instance running this PR's code

One uses a healthy instance (polling every minute), the other uses an instance with intermittent connectivity to exchanges, which is simulated by a 3 minute polling interval
Pricenode-PR-1m-A

Pricenode-PR-3m-A
3 Trades are successful when using distinct pricenodes, both of which exhibit intermittent connectivity to exchanges Maker and Seller each use a separate pricenode instance running this PR's code

Both instances have intermittent connectivity to exchanges, which is simulated by a 3 minute polling interval
Pricenode-PR-3m-A

Pricenode-PR-3m-B
4 Trades are PREVENTED from happening and fail gracefully, when price values differ by more than 1% between Maker and Taker, for any reason Maker and Seller each use a separate pricenode instance running this PR's code

One instance is healthy (polling every minute), the other one also polls every minute but returns artificially inflated rates by +5%
Pricenode-PR-1m-A

Pricenode-PR-1m-up5pc

How to execute

  1. Fulfill prerequisites described below
  2. For each of the tests (1-4)
    • Run through all steps described below
  3. Optional: free up resources
    • After running all tests, delete the temp-Bisq-PR-4315 folder to free up disk space

Prerequisites

  1. Make sure you have at least 5GB free space
    • Will be used by gradlew to build different artefacts
  2. Make sure you have bitcoind and bitcoin-cli installed
    • They should point to a recent installation of Bitcoin Core
  3. Make sure you have git and git-lfs installed
  4. Create a temp folder which will contain all the data for these tests
    • mkdir temp-Bisq-PR-4315
    • cd temp-Bisq-PR-4315
  5. Clone the latest Bisq code, which will be used to run the different clients and nodes necessary for the tests
    • git clone https://github.com/bisq-network/bisq.git
    • cd bisq
  6. Build the necessary artefacts for the tests
    • In the same folder, run make
  7. In the same folder, create a script init_aliases.sh with the following content:

Snippet 3: init_aliases.sh script for Tests 1-4

Click to show Snippet 3...
#!/bin/bash

PRICENODE_PR_1M_A="mifoy7xvoeoyvtoi.onion"
PRICENODE_PR_1M_B="lzlxdqzj6t7dxjha.onion"
PRICENODE_PR_3M_A="jzfd6tanhnc65fhh.onion"
PRICENODE_PR_3M_B="p3s7gpl42iq67llv.onion"
PRICENODE_PR_1M_UP5PC="ii6vfecmp7cf6gky.onion"


### Common aliases for all tests

alias start-seednode-1='./bisq-seednode \
		--baseCurrencyNetwork=BTC_REGTEST \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--fullDaoNode=true \
		--rpcUser=bisqdao \
		--rpcPassword=bsq \
		--rpcBlockNotificationPort=5120 \
		--nodePort=2002 \
		--userDataDir=.localnet \
		--appName=seednode'

alias start-seednode-2='./bisq-seednode \
		--baseCurrencyNetwork=BTC_REGTEST \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--fullDaoNode=true \
		--rpcUser=bisqdao \
		--rpcPassword=bsq \
		--rpcBlockNotificationPort=5121 \
		--nodePort=3002 \
		--userDataDir=.localnet \
		--appName=seednode2'

alias start-mediator='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--useLocalhostForP2P=false \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useDevPrivilegeKeys=true \
		--nodePort=4444 \
		--appDataDir=.localnet/mediator \
		--appName=Mediator'


### Aliases for Test 1

alias start-alice-test-1='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--providers="$PRICENODE_PR_1M_A" \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--nodePort=5555 \
		--fullDaoNode=true \
		--rpcUser=bisqdao \
		--rpcPassword=bsq \
		--rpcBlockNotificationPort=5122 \
		--genesisBlockHeight=111 \
		--genesisTxId=30af0050040befd8af25068cc697e418e09c2d8ebd8d411d2240591b9ec203cf \
		--appDataDir=.localnet/alice \
		--appName="Alice - Test 1"'

alias start-bob-test-1='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--providers="$PRICENODE_PR_1M_B" \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--nodePort=6666 \
		--appDataDir=.localnet/bob \
		--appName="Bob - Test 1"'


### Aliases for Test 2

alias start-alice-test-2='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--providers="$PRICENODE_PR_1M_A" \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--nodePort=5555 \
		--fullDaoNode=true \
		--rpcUser=bisqdao \
		--rpcPassword=bsq \
		--rpcBlockNotificationPort=5122 \
		--genesisBlockHeight=111 \
		--genesisTxId=30af0050040befd8af25068cc697e418e09c2d8ebd8d411d2240591b9ec203cf \
		--appDataDir=.localnet/alice \
		--appName="Alice - Test 2"'

alias start-bob-test-2='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--providers="$PRICENODE_PR_3M_A" \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--nodePort=6666 \
		--appDataDir=.localnet/bob \
		--appName="Bob - Test 2"'


### Aliases for Test 3

alias start-alice-test-3='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--providers="$PRICENODE_PR_3M_A" \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--nodePort=5555 \
		--fullDaoNode=true \
		--rpcUser=bisqdao \
		--rpcPassword=bsq \
		--rpcBlockNotificationPort=5122 \
		--genesisBlockHeight=111 \
		--genesisTxId=30af0050040befd8af25068cc697e418e09c2d8ebd8d411d2240591b9ec203cf \
		--appDataDir=.localnet/alice \
		--appName="Alice - Test 3"'

alias start-bob-test-3='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--providers="$PRICENODE_PR_3M_B" \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--nodePort=6666 \
		--appDataDir=.localnet/bob \
		--appName="Bob - Test 3"'


### Aliases for Test 4

alias start-alice-test-4='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--providers="$PRICENODE_PR_1M_A" \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--nodePort=5555 \
		--fullDaoNode=true \
		--rpcUser=bisqdao \
		--rpcPassword=bsq \
		--rpcBlockNotificationPort=5122 \
		--genesisBlockHeight=111 \
		--genesisTxId=30af0050040befd8af25068cc697e418e09c2d8ebd8d411d2240591b9ec203cf \
		--appDataDir=.localnet/alice \
		--appName="Alice - Test 4"'

alias start-bob-test-4='./bisq-desktop \
		--baseCurrencyNetwork=BTC_REGTEST \
		--providers="$PRICENODE_PR_1M_UP5PC" \
		--seedNodes="$(cat .localnet/seednode/btc_regtest/tor/hiddenservice/hostname):2002,$(cat .localnet/seednode2/btc_regtest/tor/hiddenservice/hostname):3002" \
		--useLocalhostForP2P=false \
		--useDevPrivilegeKeys=true \
		--nodePort=6666 \
		--appDataDir=.localnet/bob \
		--appName="Bob - Test 4"'

Steps

All commands below are executed in the .../temp-Bisq-PR-4315/bisq folder.

1. Start regtest bitcoin daemon

  • In a new terminal window:
    • make bitcoind
  • This will start a headless regtest bitcoind daemon

2. Start 1st seednode

  • In a new terminal window:
    • source init_aliases.sh && start-seednode-1
  • This will start a headless Bisq instance (regtest seednode)

3. Start 2nd seednode

  • In a new terminal window:
    • source init_aliases.sh && start-seednode-2
  • This will start another headless Bisq instance (regtest seednode)

4. Start mediator

  • In a new terminal window:
    • source init_aliases.sh && start-mediator
  • This will open a Bisq window for mediation and arbitration
  • Register mediator agent
    • In this Bisq application window, go to Account
    • Press Cmd+N or Ctrl+N (a popup will appear)
    • Click Unlock
    • Click Register
  • Register refund agent
    • In this Bisq application window, go to Account
    • Press Cmd+D or Ctrl+D (a popup will appear)
    • Click Unlock
    • Click Register

5. Start 1st trader (Alice)

  • In a new terminal window:
    • source init_aliases.sh && start-alice-test-X
      • where X is the number of the test (e.g. 1, 2, 3 or 4)
      • The different values of X will cause different pricenodes to be used, as per each test scenario
  • This will open a Bisq window that can be used to simulate a trader (Alice)

6. Start 2nd trader (Bob)

  • In a new terminal window:
    • source init_aliases.sh && start-bob-test-X
      • where X is the number of the test (e.g. 1, 2, 3 or 4)
      • The different values of X will cause different pricenodes to be used, as per each test scenario
  • This will open a Bisq window that can be used to simulate another trader (Bob)

7. Optional: If Alice and Bob wallets are empty, generate some regtest BTC for them

  • In a new terminal window:
    • make block
  • This will bring the balance of Alice' and Bob's Bisq wallets to 10 BTC each

8. Perform a trade between Alice and Bob

  • Alice: Create a Sell BTC (for USD) order
  • Bob: Find Alice's offer and take it
  • Alice/Bob: Perform all steps of the trade, until trade complete

9. Stop all test daemons and processes

  • Close the 3 Bisq application windows (Mediator, Alice, Bob)
  • Interrupt / close the 3 headless processes (bitcoind, seednode, seednode2)

Success criteria

  • For tests 1-3
    • If the trade SUCCEEDED, then the test is successful
  • For test 4
    • If the trade FAILED GRACEFULLY (when Bob tried to take Alice's offer), then the test is successful
      • failed gracefully = Bob (the Taker) sees an error popup when attempting to take the trade, but after confirming the popup, Bob's Bisq application is still usable (application does not hang, does not close automatically, simply allows Bob to continue using it after error is acknowledged)
    • Because test 4 attempts to simulate an artificial price difference of 5% between the traders, which SHOULD result in a failure to trade

Test 5

Goal / Scenario

This test checks that a pricenode is still running and provides a price feed, in case any exchange API is suddenly unreachable or returns an unexpected HTTP error code.

Prerequisites

1. A running (test) pricenode

Steps

1. Choose a currency that is supported by a single provider

  • For example, ANG is only covered by Bitpay

2. Ensure the pricenode is up and running

  • Check by accessing http://localhost:8080/getAllMarketPrices on the pricenode (if it returns a json, then it's up and running)
  • Check that the price feed json contains a price for ANG (as a child of the data array)
    • The elements are sorted alphabetically, so you can visually scroll through and find it

3. Make that API endpoint completely unreachable from the pricenode

  • In the pricenode, edit the /etc/hosts file and add a line containing 127.0.0.1 bitpay.com

4. Monitor the pricende log until it shows failed connections to Bitpay

  • sudo journalctl -u bisq-pricenode -e
  • This will show you the pricenode log in real time
  • Keep it open until you see it reporting an error that it cannot connect to Bitpay
    • At most within 1-2 minutes, when Bitpay is polled again

5. Open http://localhost:8080/getAllMarketPrices on the pricenode

  • Check that the price feed still contains a price for ANG

Snippet 1: Sample log output indicating unreachable exchange API endpoint

Click to show...
Aug 02 11:40:44 user bisq-pricenode[20859]: Aug-02 11:40:44.093 [Timer-24] WARN  b.p.s.p.Bitpay: refresh failed org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://bitpay.com/rates": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:674)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:636)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:610)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.spot.providers.Bitpay.getTickers(Bitpay.java:92)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.spot.providers.Bitpay.doGet(Bitpay.java:62)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.spot.providers.Bitpay.doGet(Bitpay.java:45)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.PriceProvider.refresh(PriceProvider.java:78)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.PriceProvider.access$000(PriceProvider.java:31)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.PriceProvider$1.run(PriceProvider.java:64)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.util.TimerThread.run(Timer.java:506)
Aug 02 11:40:44 user bisq-pricenode[20859]: Caused by: java.net.ConnectException: Connection refused (Connection refused)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.Socket.connect(Socket.java:609)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:289)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:173)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:182)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:265)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:372)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:191)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1187)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1081)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:168)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:660)
Aug 02 11:40:44 user bisq-pricenode[20859]:         ... 10 common frames omitted
Aug 02 11:40:44 user bisq-pricenode[20859]: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://bitpay.com/rates": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:674)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:636)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:610)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.spot.providers.Bitpay.getTickers(Bitpay.java:92)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.spot.providers.Bitpay.doGet(Bitpay.java:62)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.spot.providers.Bitpay.doGet(Bitpay.java:45)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.PriceProvider.refresh(PriceProvider.java:78)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.PriceProvider.access$000(PriceProvider.java:31)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at bisq.price.PriceProvider$1.run(PriceProvider.java:64)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.util.TimerThread.run(Timer.java:506)
Aug 02 11:40:44 user bisq-pricenode[20859]: Caused by: java.net.ConnectException: Connection refused (Connection refused)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/java.net.Socket.connect(Socket.java:609)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:289)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:173)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:182)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:265)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:372)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:191)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1187)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1081)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:168)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
Aug 02 11:40:44 user bisq-pricenode[20859]:         at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:660)
Aug 02 11:40:44 user bisq-pricenode[20859]:         ... 10 common frames omitted

Success criteria

The test is successful if in the last step, the pricenode

  • still returns a price feed (a json output)
  • the price feed still contains an element for ANG

@cd2357 cd2357 requested a review from cbeams as a code owner June 16, 2020 19:46
@cd2357 cd2357 force-pushed the xchange-integration-introduce-aggregate-rates branch from 92bc006 to 09845a9 Compare June 16, 2020 19:57
Copy link
Member

@cbeams cbeams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NACK. I just had a few minutes to run through these changes right now, and so have added some mostly style-related change requests. I'd like to actually run and test everything myself as well, but will have to get to that later.

@cbeams
Copy link
Member

cbeams commented Jun 17, 2020

Nit: It's probably better to mark a PR as a draft using GitHub's built-in support than to prefix it with [WIP]. Perhaps the @bisq-network/bisq-maintainers have something to say about that as well.

@cd2357 cd2357 marked this pull request as draft June 17, 2020 09:18
@cbeams
Copy link
Member

cbeams commented Jun 17, 2020

There has been some discussion in the project issue (bisq-network/projects#35) about how this change will impact the the way we tolerance differences between prices on the maker and taker side. ("allowance" as @sqrrm called it). Is this something you gave further thought to, @cd2357?

In any case, I wouldn't want to see this change merged and rolled out without a real live testing effort. We really need to try to break this before rolling it out. The changes look reasonable from what little time I've given to reviewing them, but there's no substitute for a real test plan. Could you lay out how you want to do that?

@cd2357 cd2357 force-pushed the xchange-integration-introduce-aggregate-rates branch from 306bca7 to 38680ca Compare July 20, 2020 15:55
cd2357 added 12 commits July 20, 2020 18:14
Update sanity check methods to allow for deeper and more comprehensive
validations of the input data. Accept full ExchangeRateProviders in the
method signatures, instead of just the provider prefix, to allow for
more complex sanity checks within those validation methods.
Add support for aggregate rates in the ExchangeRateService. If multiple
ExchangeRateProviders contain rates for the same currency, then these
rates will be automatically aggregated (averaged) into one.

This allows the service to transparently scale to multiple providers for
 any specific currency.

The clients index the rates received from the pricenode by currency
code, which means they expect at most a single rate per currency. By
aggregating rates from multiple providers into one per currency, the
ExchangeRateService provides more accurate price data. At the same time,
the service API data structure remains intact, thus preserving backward
compatibility with all clients.
Add support for a few exchanges to demonstrate and test the pricenode
aggregate rates.

The chose exchanges were selected because they each provide a varied
list of fiat and altcoins, with a substantial overlap between them. This
 provides a robust initial set of datapoints and scenarios for aggregate
  rates.
Revert from latest v5.0.0 to v4.2.2, since the newer version libraries
are compiled with Java 11, so they cannot be used as part of the Bisq
build process which still partially relies on Java 10.
Update comments to reflect bisq-network/style#5 guideline
Update the name of exception variables to ex for
consistency and better readability.
Simplify if-else block to avoid redundant use of else-if
in combination with an empty check and a return statement.
Remove Order annotation from rate providers, which was
used in the case that multiple providers would retrieve
rates for the same currency.

The ExchangeRateService now handles such scenarios, thus
eliminating the need for deciding provider precedence via
the Order annotation.
Remove public modifier in their class definitions to
preserve their package-private scope.
Give a more accurate name to the abstract test class
which contains common methods used by all
ExchangeRateProvider tests, like BinanceTest or KrakenTest.

Mark this test class as abstract, to indicate that it
should not be run as a standalone test.
Retrieve the exchange rates in bulk, when possible. This reduces
the number of calls the pricenode makes to the exchange API from N =
"number of exchange rates to retrieve" to N = 1.

The replaced approach, which made a separate call to the exchange API
for each exchange rate, was sometimes failing due to reaching API rate
limits.
Reuse sets of supported currencies between pricenode classes and tests.
@cd2357 cd2357 force-pushed the xchange-integration-introduce-aggregate-rates branch from 38680ca to 7fc5191 Compare July 20, 2020 16:15
@cd2357
Copy link
Contributor Author

cd2357 commented Jul 21, 2020

There has been some discussion in the project issue (bisq-network/projects#35) about how this change will impact the the way we tolerance differences between prices on the maker and taker side. ("allowance" as @sqrrm called it). Is this something you gave further thought to, @cd2357?

In any case, I wouldn't want to see this change merged and rolled out without a real live testing effort. We really need to try to break this before rolling it out. The changes look reasonable from what little time I've given to reviewing them, but there's no substitute for a real test plan. Could you lay out how you want to do that?

Good points.

I put some thought into how this PR can be tested, see the updated PR description above.

To summarize the key points:

  • I found two things that should be tested (testing tracks 1 and 2 above) :
    • whether the new response of the /getAllMarketPrices/ pricenode API is compatible with current Bisq clients, and
    • whether the new pricenodes have relatively stable price outputs across different instances (reported rates are within <1%, even if some instances may face intermittent connectivity issues to some exchanges, or poll at slightly different times than other pricenode instances)

For testing track 1, a few regtest scenarios are probably good enough to confirm things work as expected.

For testing track 2, a script can query different pricenode instances to help the tester visually confirm that, at the point of running the script, prices are within <1%. This should confirm that the computed exchange rates across pricenode instances are stable enough, and that the Bisq "price delta allowance" / "price tolerance" is not violated. A sample output of the script is included above. A few sample "Pricenode-PR" instances (test pricenodes based on this PR) are also provided, for test purposes.

@cbeams : Is this a generally good direction for the tests?

If yes, I can flesh out some of the TBDs above and prepare more detailed step-by-step test instructions. I can also provide the price comparison script I used for track 2.

If no, what am I missing? Are there other considerations, in addition to testing tracks 1 and 2 above? Thanks.

(Update 22.07.2020: Updated onion addresses of test live instances + added track 2 script content)

(Update 23.07.2020: Consolidated relevant tables / scripts and moved them to PR description above. Also added specific tests.)

@cbeams
Copy link
Member

cbeams commented Jul 21, 2020

@cbeams : Is this a generally good direction for the tests?

Thanks for the effort, @cd2357. I'll read through this and share my thoughts. Others are welcome to weigh in too.

@cbeams
Copy link
Member

cbeams commented Jul 23, 2020

Disclaimer: I've taken about 15 minutes to go through everything you've posted above. I haven't been hands on with it, and I haven't scrutinized it closely enough to really poke holes in it, but I wanted to get back sooner than later. With that said, in general, the thinking and approach looks great; I'm impressed by the amount of effort you've put into it already.

One question I don't believe you addressed above: what actually happens in the failure mode of the price tolerance being out of range, i.e. over 1% difference? How do users know what went wrong, and how, if at all, can they recover? The answer to this question shouldn't be much different than the status quo, i.e. before applying this patch, but it's just a failure mode I've never personally seen. Do we give people good error messages, etc? It could be argued that that's out of scope for this change, but since this change considerably increases the likelihood of this failure mode occurring, we should make sure the failure is a graceful as it can be.

So I don't have much more detailed feedback, other than that this seems directionally correct. Ideally, you'd find someone to pair up with this on and really complete the testing together in real-time, as opposed to just asking someone to review the plan. Two sets of eyes / minds would probably really help in a situation like this (and would probably be more fun less tedious than doing it alone). Any volunteers, @bisq-network/bisq-devs? Maybe pairing up on this is something you could bring up on the next dev call (I haven't been tracking the plan for those calls, just an idea).

Another note would be that once whatever diligence is done on the testing front and it seems reasonable to roll this out, I'd suggest having everyone involved (pricenode operators, bisq maintainers) primed and ready to roll back as soon as we start seeing something unexpected. For example, make sure the changes in this PR are as easy to revert as possible (multiple commits are fine—you can revert a whole merge, just want to make sure it doesn't have any extra stuff that might make the revert complicated). And make sure that the pricenode operators know that this upgrade is a relatively risky one and that we might call for a rollback (or upgrade to the new, reverted version) in short order.

I hope that helps, I realize it's all pretty high level and perhaps obvious, but that's about as much time as I have to spend on this for now.

@cd2357
Copy link
Contributor Author

cd2357 commented Jul 23, 2020

@cbeams thanks for the feedback.

One question I don't believe you addressed above: what actually happens in the failure mode of the price tolerance being out of range, i.e. over 1% difference? How do users know what went wrong, and how, if at all, can they recover? (...) We should make sure the failure is a graceful as it can be.

Good point, I hadn't specifically considered it, but I will add a test which ensures this edge case fails gracefully.

Technically, any quick and massive price movement of any currency would cause this (for example, a 3% move within 1-2 minutes). Since pricenodes don't poll the exchangs at the exact same times, but perhaps a few seconds apart from each other, in such a case different pricenodes could get considerably different inputs from exchanges and therefore report rates to Bisq clients which may be "out of range" (more than 1% apart across different instances). However, after 1-2 minutes, when all pricenodes get a chance to poll the exchanges again and update their rates, they would then all be at the relatively same level again, reporting rates "within range".

About testing, I'll write out the specific steps of the tests and ask for tester volunteers on keybase.

About rolling out, you're right, I'll coordinate with @wiz to make sure this is done safely (and there's a contingency rollback plan, in case smth goes wrong).

Thanks again for the input. It is a tedious PR, but hopefully the effort will be worth it.

@cd2357 cd2357 changed the title [WIP] PriceNode: Add support for multiple ExchangeRateProviders PriceNode: Add support for multiple ExchangeRateProviders Jul 23, 2020
@cd2357 cd2357 marked this pull request as ready for review July 23, 2020 18:11
@cd2357
Copy link
Contributor Author

cd2357 commented Jul 23, 2020

Removed [WIP] prefix and unmarked the PR as draft, to indicate it's not "work in progress" anymore, but it's ready for tests and further reviews.

@cd2357
Copy link
Contributor Author

cd2357 commented Jul 23, 2020

Ran all tests (0-4) in a local regtest setup, all successful.

Will coordinate with other volunteers to see if tests also work fine for them (or if the steps are simple and clear enough).

@wiz
Copy link
Member

wiz commented Jul 23, 2020

Thanks for your hard work on this PR. I can't wait to start reviewing it. My first thoughts are:

  1. Since we're going to lose hundreds of currencies supported on Bitcoin Average, going down to this new subset of only 12 fiat currencies and 14 crypto currencies, we need to verify this is sufficient for Bisq traders in terms of what is currently actively traded, on a conceptual level.

  2. After we verify the new concept makes sense, we need to review the code to make sure the weighted averages work as intended, and test the data works on Bisq nodes without any modifications. Previously some Bisq nodes had issues when JSON elements went missing, so we might need to add dummy empty sets for certain things during the transition period.

  3. Once we verify things don't immediately blow up from 1 or 2 above, we can start the actual testing by mixing and matching old BA pricenodes and new non-BA pricenodes with test offers and test trades. The most important thing is that all prices are displayed the same (within tolerances) using a Bisq node only connected to old nodes, and a Bisq node only connected to new nodes.

  4. For the actual upgrade later on, in theory if everything works properly, we should even be able to upgrade all the pricenodes separately, but it's probably a good idea to upgrade them all at the same time to avoid minimal fluctuations, so we would have to coordinate a time for all pricenode operators to be online at once.

@sqrrm
Copy link
Member

sqrrm commented Jul 24, 2020

Thanks for the efforts on this PR. Rolling this out will need caution, but the main risks are usability. That could probably be helped by making sure the client handles faults better, as has been discussed.

I also have concerns regarding the loss of currencies. In particular the latin american ones seem to be missing. We should make an effort to not reduce usability in any market. Getting any market started is really tedious work and we should make sure to not lose any of that. I haven't read the code yet, but could we run this in parallel with BA for those currencies we don't yet have our own aggregation for?

@Emzy
Copy link
Contributor

Emzy commented Aug 7, 2020

ACK
No problems installing it.
It's up on:
http://emzyprwrcz22h2fzhsbqd3deoe5hkqdm5yfy4geuqcdqqicgoor65iad.onion/getAllMarketPrices

Copy link
Member

@sqrrm sqrrm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks good to me.

Requiring Java 11 is likely not a problem as we're never shipping this, all price node operators build from source. I can't see any other issues with that either, but still worth keeping in mind.

There are still heaps of codacy complaints. Some seem legit, some are probably just settings that are too strict.

@@ -57,7 +57,7 @@ configure(subprojects) {
junitVersion = '4.12'
jupiterVersion = '5.3.2'
kotlinVersion = '1.3.41'
knowmXchangeVersion = '4.3.3'
knowmXchangeVersion = '4.4.2'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New import, haven't seen any mention of this in the discussion. Anything new carries a risk, and perhaps more so when upgrading versions as the project in question already knows it's being used by bisq. In this case this is for price nodes so bisq wallets are not affected, lowering the risk.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the library that abstract away the different exchange integrations. Since we want to have the most up-to-date integration possible (e.g. broadest set of exchanges, support for most recent exchange API versions, etc) it makes sense to use the latest version of this lib.

Removed unused imports from pricenode classes.
Apply various changes in coding style, required by the Codacy check.
Rewrite a few generic parts of the code to be more specific in what they
 handle, or how they handle the resulting data structure.
@cd2357 cd2357 force-pushed the xchange-integration-introduce-aggregate-rates branch from 233af83 to d972a75 Compare August 8, 2020 15:13
@cd2357
Copy link
Contributor Author

cd2357 commented Aug 8, 2020

@sqrrm I addressed your comments above. Also, the Codacy checks now all pass.

@wiz
Copy link
Member

wiz commented Aug 8, 2020

Okay, all 5 of the @bisq-network/pricenode-operators have created instances of this PR branch, so we are ready to begin the full testing using our staging environment. Onion hostnames are listed in bisq-network/projects#35 (comment)

wiz added a commit to wiz/bisq that referenced this pull request Aug 8, 2020
Pending merge of bisq-network#4315 and rough consensus to proceed with migration plan in bisq-network/projects#35

wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid (@wiz)
emzyprwrcz22h2fzhsbqd3deoe5hkqdm5yfy4geuqcdqqicgoor65iad (@Emzy)
6b7jpqiy2ejq3m7jskem6cuverg7xelhhuf3d2nvooucayoeapo2m3qd (@devinbileck)
aprcndeiwdrkbf4fq7iozxbd27dl72oeo76n7zmjwdi4z34agdrnheyd (@mrosseel)
ro7nv73awqs3ga2qtqeqawrjpbxwarsazznszvr6whv7tes5ehffopid (@alexej996)
wiz added a commit to wiz/bisq that referenced this pull request Aug 9, 2020
Pending merge of bisq-network#4315 and rough consensus to proceed with migration plan in bisq-network/projects#35

wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid (@wiz)
emzyprwrcz22h2fzhsbqd3deoe5hkqdm5yfy4geuqcdqqicgoor65iad (@Emzy)
devinpndvdwll4wiqcyq5e7itezmarg7rzicrvf6brzkwxdm374kmmyd (@devinbileck)
aprcndeiwdrkbf4fq7iozxbd27dl72oeo76n7zmjwdi4z34agdrnheyd (@mrosseel)
ro7nv73awqs3ga2qtqeqawrjpbxwarsazznszvr6whv7tes5ehffopid (@alexej996)
wiz added a commit to wiz/bisq that referenced this pull request Aug 9, 2020
Pending merge of bisq-network#4315 and rough consensus to proceed with migration plan in bisq-network/projects#35

wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid (@wiz)
emzypricpidesmyqg2hc6dkwitqzaxrqnpkdg3ae2wef5znncu2ambqd (@Emzy)
devinpndvdwll4wiqcyq5e7itezmarg7rzicrvf6brzkwxdm374kmmyd (@devinbileck)
aprcndeiwdrkbf4fq7iozxbd27dl72oeo76n7zmjwdi4z34agdrnheyd (@mrosseel)
ro7nv73awqs3ga2qtqeqawrjpbxwarsazznszvr6whv7tes5ehffopid (@alexej996)
@wiz
Copy link
Member

wiz commented Aug 9, 2020

@sqrrm as we discussed on Keybase, the only "issue" I've found so far is the precision of the prices from the pricenodes being much more precise now that they're calculated averages. Other than the prices looking a bit strange with lots of decimals it shouldn't cause any actual issues, right?

@sqrrm
Copy link
Member

sqrrm commented Aug 10, 2020

@cd2357 code looks good. Let's run it a bit to see that it's stable.

@wiz I don't think there are any other issues but it would be good to verify as well.

@wiz
Copy link
Member

wiz commented Aug 13, 2020

@sqrrm If you watch the messages in keybase://chat/bisq#ops-alerts you can see the new pricenodes are quite stable, in sync with each other, using the new price indices. The only concern is the $100 difference from BA index and Bisq index for USD, EUR, and a few other markets which we can warn users about by using an in-app broadcast message.

@sqrrm
Copy link
Member

sqrrm commented Aug 14, 2020

From what I see most feeds have a diff of .5% or something in that range. Would be good to know why it's such a consistent large difference. It's good that we have a consistent feed, but it might be a problem if it's a fair bit off the BA feed. Also looking at some of the major exchanges their prices are closer to the BA feed than the Bisq index. Perhaps volume weighting is needed?

Copy link
Member

@sqrrm sqrrm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

I haven't tested it myself, but several contributors are now running the nodes and we can see a consistent feed. To deploy this we still need to tune the feed, but the PR as such looks good to me.

@sqrrm sqrrm requested a review from cbeams August 14, 2020 20:26
Copy link
Member

@wiz wiz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK - this PR completes Phase 1 of the project bisq-network/projects#35 - We will tweak the index weighting in another PR later as part of Phase 2 of the project after testing is completed.

@cbeams
Copy link
Member

cbeams commented Aug 17, 2020

I've gone back through the nits in my NACK at #4315 (review) and approved the changes. Thanks, all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants