mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-03 18:56:59 +01:00
Disable BitcoinAverage
Disable BitcoinAverage provider. Keep it registered as a provider to ensure that the data structure returned by the pricenode to the Bisq clients contain the hardcoded "btcAverageTs" key.
This commit is contained in:
parent
8d335441c3
commit
4dc24e5606
7 changed files with 19 additions and 148 deletions
|
@ -469,7 +469,6 @@ configure(project(':pricenode')) {
|
|||
exclude(module: 'commons-codec')
|
||||
}
|
||||
compile("org.knowm.xchange:xchange-bitbay:$knowmXchangeVersion")
|
||||
compile("org.knowm.xchange:xchange-bitcoinaverage:$knowmXchangeVersion")
|
||||
compile("org.knowm.xchange:xchange-btcmarkets:$knowmXchangeVersion")
|
||||
compile("org.knowm.xchange:xchange-binance:$knowmXchangeVersion")
|
||||
compile("org.knowm.xchange:xchange-bitfinex:$knowmXchangeVersion")
|
||||
|
|
|
@ -5,7 +5,6 @@ Run the following commands:
|
|||
|
||||
heroku create
|
||||
heroku buildpacks:add heroku/gradle
|
||||
heroku config:set BITCOIN_AVG_PUBKEY=[your pubkey] BITCOIN_AVG_PRIVKEY=[your privkey]
|
||||
git push heroku master
|
||||
curl https://your-app-123456.herokuapp.com/getAllMarketPrices
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ Operating a production pricenode is a valuable service to the Bisq network, and
|
|||
|
||||
To run a pricenode, you will need:
|
||||
|
||||
- [BitcoinAverage API keys](https://bitcoinaverage.com/en/plans). Free plans are fine for local development or personal nodes; paid plans should be used for well-known production nodes.
|
||||
- JDK 8 if you want to build and run a node locally.
|
||||
- The `tor` binary (e.g. `brew install tor`) if you want to run a hidden service locally.
|
||||
|
||||
|
@ -40,21 +39,6 @@ curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/pricenode/ins
|
|||
|
||||
At the end of the installer script, it should print your Tor onion hostname.
|
||||
|
||||
### Setting your BitcoinAverage API keys
|
||||
|
||||
Open `/etc/default/bisq-pricenode.env` in a text editor and look for these lines:
|
||||
```bash
|
||||
BITCOIN_AVG_PUBKEY=foo
|
||||
BITCOIN_AVG_PRIVKEY=bar
|
||||
```
|
||||
|
||||
Add your pubkey and privkey and then reload/restart bisq-pricenode service:
|
||||
|
||||
```bash
|
||||
systemctl daemon-reload
|
||||
systemctl restart bisq-pricenode
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
To manually test endpoints, run each of the following:
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
BITCOIN_AVG_PUBKEY=foo
|
||||
BITCOIN_AVG_PRIVKEY=bar
|
||||
JAVA_OPTS=""
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
while true
|
||||
do
|
||||
echo `date` "(Re)-starting node"
|
||||
BITCOIN_AVG_PUBKEY=$BTCAVERAGE_PUBKEY BITCOIN_AVG_PRIVKEY=$BTCAVERAGE_PRIVKEY java -jar ./build/libs/bisq-pricenode.jar 2 2
|
||||
java -jar ./build/libs/bisq-pricenode.jar 2 2
|
||||
echo `date` "node terminated unexpectedly!!"
|
||||
sleep 3
|
||||
done
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
package bisq.price.spot;
|
||||
|
||||
import bisq.price.spot.providers.BitcoinAverage;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
@ -167,10 +165,6 @@ class ExchangeRateService {
|
|||
t.printStackTrace();
|
||||
}
|
||||
|
||||
if (provider instanceof BitcoinAverage.Local) {
|
||||
metadata.put("btcAverageTs", timestamp);
|
||||
}
|
||||
|
||||
String prefix = provider.getPrefix();
|
||||
metadata.put(prefix + "Ts", timestamp);
|
||||
metadata.put(prefix + "Count", exchangeRates.size());
|
||||
|
|
|
@ -19,141 +19,38 @@ package bisq.price.spot.providers;
|
|||
|
||||
import bisq.price.spot.ExchangeRate;
|
||||
import bisq.price.spot.ExchangeRateProvider;
|
||||
import bisq.common.util.Hex;
|
||||
|
||||
import org.knowm.xchange.bitcoinaverage.dto.marketdata.BitcoinAverageTicker;
|
||||
import org.knowm.xchange.bitcoinaverage.dto.marketdata.BitcoinAverageTickers;
|
||||
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* See the BitcoinAverage API documentation at https://apiv2.bitcoinaverage.com/#ticker-data-all
|
||||
* Stub implementation (similar to #CoinMarketCap) for backward compatibility with legacy
|
||||
* Bisq clients
|
||||
*/
|
||||
public abstract class BitcoinAverage extends ExchangeRateProvider {
|
||||
@Component
|
||||
class BitcoinAverage extends ExchangeRateProvider {
|
||||
|
||||
/**
|
||||
* Max number of requests allowed per month on the BitcoinAverage developer plan.
|
||||
* Note the actual max value is 45,000; we use the more conservative value below to
|
||||
* ensure we do not exceed it. See https://bitcoinaverage.com/en/plans.
|
||||
*/
|
||||
private static final double MAX_REQUESTS_PER_MONTH = 42_514;
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
private final String symbolSet;
|
||||
|
||||
private String pubKey;
|
||||
private Mac mac;
|
||||
|
||||
/**
|
||||
* @param symbolSet "global" or "local"; see https://apiv2.bitcoinaverage.com/#supported-currencies
|
||||
*/
|
||||
public BitcoinAverage(String name, String prefix, double pctMaxRequests, String symbolSet, Environment env) {
|
||||
super(name, prefix, refreshIntervalFor(pctMaxRequests));
|
||||
this.symbolSet = symbolSet;
|
||||
this.pubKey = env.getRequiredProperty("BITCOIN_AVG_PUBKEY");
|
||||
this.mac = initMac(env.getRequiredProperty("BITCOIN_AVG_PRIVKEY"));
|
||||
public BitcoinAverage() {
|
||||
// Simulate a deactivated BitcoinAverage provider
|
||||
// We still need the class to exist and be registered as a provider though,
|
||||
// because the returned data structure must contain the "btcAverageTs" key
|
||||
// for backward compatibility with Bisq clients which hardcode that key
|
||||
super("BA", "btcAverage", Duration.ofMinutes(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CoinMarketCap#doGet()
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<ExchangeRate> doGet() {
|
||||
|
||||
return getTickersKeyedByCurrency().entrySet().stream()
|
||||
.filter(e -> supportedCurrency(e.getKey()))
|
||||
.map(e ->
|
||||
new ExchangeRate(
|
||||
e.getKey(),
|
||||
e.getValue().getLast(),
|
||||
e.getValue().getTimestamp(),
|
||||
this.getName()
|
||||
)
|
||||
)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private boolean supportedCurrency(String currencyCode) {
|
||||
// ignore Venezuelan bolivars as the "official" exchange rate is just wishful thinking
|
||||
// we should use this API with a custom provider instead: http://api.bitcoinvenezuela.com/1
|
||||
return !"VEF".equals(currencyCode);
|
||||
}
|
||||
|
||||
private Map<String, BitcoinAverageTicker> getTickersKeyedByCurrency() {
|
||||
// go from a map with keys like "BTCUSD", "BTCVEF"
|
||||
return getTickersKeyedByCurrencyPair().entrySet().stream()
|
||||
// to a map with keys like "USD", "VEF"
|
||||
.collect(Collectors.toMap(e -> e.getKey().substring(3), Map.Entry::getValue));
|
||||
}
|
||||
|
||||
private Map<String, BitcoinAverageTicker> getTickersKeyedByCurrencyPair() {
|
||||
return restTemplate.exchange(
|
||||
RequestEntity
|
||||
.get(UriComponentsBuilder
|
||||
.fromUriString("https://apiv2.bitcoinaverage.com/indices/{symbol-set}/ticker/all?crypto=BTC")
|
||||
.buildAndExpand(symbolSet)
|
||||
.toUri())
|
||||
.header("X-signature", getAuthSignature())
|
||||
.build(),
|
||||
BitcoinAverageTickers.class
|
||||
).getBody().getTickers();
|
||||
}
|
||||
|
||||
protected String getAuthSignature() {
|
||||
String payload = String.format("%s.%s", Instant.now().getEpochSecond(), pubKey);
|
||||
return String.format("%s.%s", payload, Hex.encode(mac.doFinal(payload.getBytes(Charsets.UTF_8))));
|
||||
}
|
||||
|
||||
private static Mac initMac(String privKey) {
|
||||
String algorithm = "HmacSHA256";
|
||||
SecretKey secretKey = new SecretKeySpec(privKey.getBytes(Charsets.UTF_8), algorithm);
|
||||
try {
|
||||
Mac mac = Mac.getInstance(algorithm);
|
||||
mac.init(secretKey);
|
||||
return mac;
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static Duration refreshIntervalFor(double pctMaxRequests) {
|
||||
long requestsPerMonth = (long) (MAX_REQUESTS_PER_MONTH * pctMaxRequests);
|
||||
return Duration.ofDays(31).dividedBy(requestsPerMonth);
|
||||
}
|
||||
|
||||
|
||||
@Component
|
||||
@Order(1)
|
||||
public static class Global extends BitcoinAverage {
|
||||
public Global(Environment env) {
|
||||
super("BTCA_G", "btcAverageG", 0.3, "global", env);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component
|
||||
@Order(2)
|
||||
public static class Local extends BitcoinAverage {
|
||||
public Local(Environment env) {
|
||||
super("BTCA_L", "btcAverageL", 0.7, "local", env);
|
||||
}
|
||||
HashSet<ExchangeRate> exchangeRates = new HashSet<>();
|
||||
exchangeRates.add(new ExchangeRate("NON_EXISTING_SYMBOL_BA", 0, 0L, getName()));
|
||||
return exchangeRates;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue