Refactor fiat rates usage
This commit is contained in:
parent
a4f7f5b965
commit
210ec75a3d
152
api/worker.go
152
api/worker.go
@ -1010,24 +1010,27 @@ func (w *Worker) getEthereumContractBalanceFromBlockchain(addrDesc, contract bch
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetContractBaseRate returns contract rate in base coin from the ticker or DB at the blocktime. Zero blocktime means now.
|
||||
func (w *Worker) GetContractBaseRate(ticker *common.CurrencyRatesTicker, contract string, blocktime int64) (float64, bool) {
|
||||
// GetContractBaseRate returns contract rate in base coin from the ticker or DB at the timestamp. Zero timestamp means now.
|
||||
func (w *Worker) GetContractBaseRate(ticker *common.CurrencyRatesTicker, token string, timestamp int64) (float64, bool) {
|
||||
if ticker == nil {
|
||||
return 0, false
|
||||
}
|
||||
rate, found := ticker.GetTokenRate(contract)
|
||||
rate, found := ticker.GetTokenRate(token)
|
||||
if !found {
|
||||
var date time.Time
|
||||
if blocktime == 0 {
|
||||
date = time.Now().UTC()
|
||||
if timestamp == 0 {
|
||||
ticker = w.fiatRates.GetCurrentTicker("", token)
|
||||
} else {
|
||||
date = time.Unix(blocktime, 0).UTC()
|
||||
tickers, err := w.fiatRates.GetTickersForTimestamps([]int64{timestamp}, "", token)
|
||||
if err != nil || tickers == nil || len(*tickers) == 0 {
|
||||
ticker = nil
|
||||
} else {
|
||||
ticker = (*tickers)[0]
|
||||
}
|
||||
}
|
||||
ticker, _ = w.db.FiatRatesFindTicker(&date, "", contract)
|
||||
if ticker == nil {
|
||||
return 0, false
|
||||
}
|
||||
rate, found = ticker.GetTokenRate(contract)
|
||||
rate, found = ticker.GetTokenRate(token)
|
||||
}
|
||||
|
||||
return float64(rate), found
|
||||
@ -1564,12 +1567,13 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
|
||||
func (w *Worker) setFiatRateToBalanceHistories(histories BalanceHistories, currencies []string) error {
|
||||
for i := range histories {
|
||||
bh := &histories[i]
|
||||
t := time.Unix(int64(bh.Time), 0)
|
||||
ticker, err := w.db.FiatRatesFindTicker(&t, "", "")
|
||||
if err != nil {
|
||||
glog.Errorf("Error finding ticker by date %v. Error: %v", t, err)
|
||||
tickers, err := w.fiatRates.GetTickersForTimestamps([]int64{int64(bh.Time)}, "", "")
|
||||
if err != nil || tickers == nil || len(*tickers) == 0 {
|
||||
glog.Errorf("Error finding ticker by date %v. Error: %v", bh.Time, err)
|
||||
continue
|
||||
} else if ticker == nil {
|
||||
}
|
||||
ticker := (*tickers)[0]
|
||||
if ticker == nil {
|
||||
continue
|
||||
}
|
||||
if len(currencies) == 0 {
|
||||
@ -1818,16 +1822,29 @@ func removeEmpty(stringSlice []string) []string {
|
||||
// getFiatRatesResult checks if CurrencyRatesTicker contains all necessary data and returns formatted result
|
||||
func (w *Worker) getFiatRatesResult(currencies []string, ticker *common.CurrencyRatesTicker, token string) (*FiatTicker, error) {
|
||||
if token != "" {
|
||||
if len(currencies) != 1 {
|
||||
return nil, NewAPIError("Rates for token only for a single currency", true)
|
||||
}
|
||||
rate := ticker.TokenRateInCurrency(token, currencies[0])
|
||||
if rate <= 0 {
|
||||
rate = -1
|
||||
rates := make(map[string]float32)
|
||||
if len(currencies) == 0 {
|
||||
for currency := range ticker.Rates {
|
||||
currency = strings.ToLower(currency)
|
||||
rate := ticker.TokenRateInCurrency(token, currency)
|
||||
if rate <= 0 {
|
||||
rate = -1
|
||||
}
|
||||
rates[currency] = rate
|
||||
}
|
||||
} else {
|
||||
for _, currency := range currencies {
|
||||
currency = strings.ToLower(currency)
|
||||
rate := ticker.TokenRateInCurrency(token, currency)
|
||||
if rate <= 0 {
|
||||
rate = -1
|
||||
}
|
||||
rates[currency] = rate
|
||||
}
|
||||
}
|
||||
return &FiatTicker{
|
||||
Timestamp: ticker.Timestamp.UTC().Unix(),
|
||||
Rates: map[string]float32{currencies[0]: rate},
|
||||
Rates: rates,
|
||||
}, nil
|
||||
}
|
||||
if len(currencies) == 0 {
|
||||
@ -1853,36 +1870,6 @@ func (w *Worker) getFiatRatesResult(currencies []string, ticker *common.Currency
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetFiatRatesForBlockID returns fiat rates for block height or block hash
|
||||
func (w *Worker) GetFiatRatesForBlockID(blockID string, currencies []string, token string) (*FiatTicker, error) {
|
||||
var ticker *common.CurrencyRatesTicker
|
||||
bi, err := w.getBlockInfoFromBlockID(blockID)
|
||||
if err != nil {
|
||||
if err == bchain.ErrBlockNotFound {
|
||||
return nil, NewAPIError(fmt.Sprintf("Block %v not found", blockID), true)
|
||||
}
|
||||
return nil, NewAPIError(fmt.Sprintf("Block %v not found, error: %v", blockID, err), false)
|
||||
}
|
||||
dbi := &db.BlockInfo{Time: bi.Time} // get Unix timestamp from block
|
||||
tm := time.Unix(dbi.Time, 0) // convert it to Time object
|
||||
vsCurrency := ""
|
||||
currencies = removeEmpty(currencies)
|
||||
if len(currencies) == 1 {
|
||||
vsCurrency = currencies[0]
|
||||
}
|
||||
ticker, err = w.db.FiatRatesFindTicker(&tm, vsCurrency, token)
|
||||
if err != nil {
|
||||
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
|
||||
} else if ticker == nil {
|
||||
return nil, NewAPIError(fmt.Sprintf("No tickers available for %s", tm), true)
|
||||
}
|
||||
result, err := w.getFiatRatesResult(currencies, ticker, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetCurrentFiatRates returns last available fiat rates
|
||||
func (w *Worker) GetCurrentFiatRates(currencies []string, token string) (*FiatTicker, error) {
|
||||
vsCurrency := ""
|
||||
@ -1927,47 +1914,64 @@ func (w *Worker) GetFiatRatesForTimestamps(timestamps []int64, currencies []stri
|
||||
if len(currencies) == 1 {
|
||||
vsCurrency = currencies[0]
|
||||
}
|
||||
|
||||
ret := &FiatTickers{}
|
||||
for _, timestamp := range timestamps {
|
||||
date := time.Unix(timestamp, 0)
|
||||
date = date.UTC()
|
||||
ticker, err := w.db.FiatRatesFindTicker(&date, vsCurrency, token)
|
||||
if err != nil {
|
||||
glog.Errorf("Error finding ticker for date %v. Error: %v", date, err)
|
||||
ret.Tickers = append(ret.Tickers, FiatTicker{Timestamp: date.Unix(), Rates: makeErrorRates(currencies)})
|
||||
continue
|
||||
} else if ticker == nil {
|
||||
ret.Tickers = append(ret.Tickers, FiatTicker{Timestamp: date.Unix(), Rates: makeErrorRates(currencies)})
|
||||
tickers, err := w.fiatRates.GetTickersForTimestamps(timestamps, vsCurrency, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tickers == nil {
|
||||
return nil, NewAPIError("No tickers found", true)
|
||||
}
|
||||
if len(*tickers) != len(timestamps) {
|
||||
glog.Error("GetFiatRatesForTimestamps: number of tickers does not match timestamps ", len(*tickers), ", ", len(timestamps))
|
||||
return nil, NewAPIError("No tickers found", false)
|
||||
}
|
||||
fiatTickers := make([]FiatTicker, len(*tickers))
|
||||
for i, t := range *tickers {
|
||||
if t == nil {
|
||||
fiatTickers[i] = FiatTicker{Timestamp: timestamps[i], Rates: makeErrorRates(currencies)}
|
||||
continue
|
||||
}
|
||||
result, err := w.getFiatRatesResult(currencies, ticker, token)
|
||||
result, err := w.getFiatRatesResult(currencies, t, token)
|
||||
if err != nil {
|
||||
if apiErr, ok := err.(*APIError); ok {
|
||||
if apiErr.Public {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ret.Tickers = append(ret.Tickers, FiatTicker{Timestamp: date.Unix(), Rates: makeErrorRates(currencies)})
|
||||
fiatTickers[i] = FiatTicker{Timestamp: timestamps[i], Rates: makeErrorRates(currencies)}
|
||||
continue
|
||||
}
|
||||
ret.Tickers = append(ret.Tickers, *result)
|
||||
fiatTickers[i] = *result
|
||||
}
|
||||
return ret, nil
|
||||
return &FiatTickers{Tickers: fiatTickers}, nil
|
||||
}
|
||||
|
||||
// GetFiatRatesForBlockID returns fiat rates for block height or block hash
|
||||
func (w *Worker) GetFiatRatesForBlockID(blockID string, currencies []string, token string) (*FiatTicker, error) {
|
||||
bi, err := w.getBlockInfoFromBlockID(blockID)
|
||||
if err != nil {
|
||||
if err == bchain.ErrBlockNotFound {
|
||||
return nil, NewAPIError(fmt.Sprintf("Block %v not found", blockID), true)
|
||||
}
|
||||
return nil, NewAPIError(fmt.Sprintf("Block %v not found, error: %v", blockID, err), false)
|
||||
}
|
||||
tickers, err := w.GetFiatRatesForTimestamps([]int64{bi.Time}, currencies, token)
|
||||
if err != nil || tickers == nil || len(tickers.Tickers) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return &tickers.Tickers[0], nil
|
||||
}
|
||||
|
||||
// GetAvailableVsCurrencies returns the list of available versus currencies for exchange rates
|
||||
func (w *Worker) GetAvailableVsCurrencies(timestamp int64, token string) (*AvailableVsCurrencies, error) {
|
||||
date := time.Unix(timestamp, 0)
|
||||
date = date.UTC()
|
||||
|
||||
ticker, err := w.db.FiatRatesFindTicker(&date, "", strings.ToLower(token))
|
||||
tickers, err := w.fiatRates.GetTickersForTimestamps([]int64{timestamp}, "", token)
|
||||
if err != nil {
|
||||
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
|
||||
} else if ticker == nil {
|
||||
return nil, NewAPIError(fmt.Sprintf("No tickers found for date %v.", date), true)
|
||||
}
|
||||
|
||||
if tickers == nil || len(*tickers) == 0 {
|
||||
return nil, NewAPIError("No tickers found", true)
|
||||
}
|
||||
ticker := (*tickers)[0]
|
||||
keys := make([]string, 0, len(ticker.Rates))
|
||||
for k := range ticker.Rates {
|
||||
keys = append(keys, k)
|
||||
|
||||
@ -140,19 +140,15 @@ func init() {
|
||||
}
|
||||
|
||||
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
|
||||
func GetCoinNameFromConfig(configfile string) (string, string, string, error) {
|
||||
data, err := ioutil.ReadFile(configfile)
|
||||
if err != nil {
|
||||
return "", "", "", errors.Annotatef(err, "Error reading file %v", configfile)
|
||||
}
|
||||
func GetCoinNameFromConfig(configFileContent []byte) (string, string, string, error) {
|
||||
var cn struct {
|
||||
CoinName string `json:"coin_name"`
|
||||
CoinShortcut string `json:"coin_shortcut"`
|
||||
CoinLabel string `json:"coin_label"`
|
||||
}
|
||||
err = json.Unmarshal(data, &cn)
|
||||
err := json.Unmarshal(configFileContent, &cn)
|
||||
if err != nil {
|
||||
return "", "", "", errors.Annotatef(err, "Error parsing file %v", configfile)
|
||||
return "", "", "", errors.Annotatef(err, "Error parsing config file ")
|
||||
}
|
||||
return cn.CoinName, cn.CoinShortcut, cn.CoinLabel, nil
|
||||
}
|
||||
|
||||
25
blockbook.go
25
blockbook.go
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
@ -158,7 +157,13 @@ func mainWithExitCode() int {
|
||||
return exitCodeFatal
|
||||
}
|
||||
|
||||
coin, coinShortcut, coinLabel, err := coins.GetCoinNameFromConfig(*configFile)
|
||||
configFileContent, err := os.ReadFile(*configFile)
|
||||
if err != nil {
|
||||
glog.Errorf("Error reading file %v, %v", configFile, err)
|
||||
return exitCodeFatal
|
||||
}
|
||||
|
||||
coin, coinShortcut, coinLabel, err := coins.GetCoinNameFromConfig(configFileContent)
|
||||
if err != nil {
|
||||
glog.Error("config: ", err)
|
||||
return exitCodeFatal
|
||||
@ -274,7 +279,7 @@ func mainWithExitCode() int {
|
||||
return exitCodeFatal
|
||||
}
|
||||
|
||||
if fiatRates, err = fiat.NewFiatRates(index, *configFile, onNewFiatRatesTicker); err != nil {
|
||||
if fiatRates, err = fiat.NewFiatRates(index, configFileContent, onNewFiatRatesTicker); err != nil {
|
||||
glog.Error("fiatRates ", err)
|
||||
return exitCodeFatal
|
||||
}
|
||||
@ -363,7 +368,7 @@ func mainWithExitCode() int {
|
||||
|
||||
if internalServer != nil || publicServer != nil || chain != nil {
|
||||
// start fiat rates downloader only if not shutting down immediately
|
||||
initDownloaders(index, chain, *configFile)
|
||||
initDownloaders(index, chain, configFileContent)
|
||||
waitForSignalAndShutdown(internalServer, publicServer, chain, 10*time.Second)
|
||||
}
|
||||
|
||||
@ -697,24 +702,18 @@ func computeFeeStats(stopCompute chan os.Signal, blockFrom, blockTo int, db *db.
|
||||
return err
|
||||
}
|
||||
|
||||
func initDownloaders(db *db.RocksDB, chain bchain.BlockChain, configFile string) {
|
||||
func initDownloaders(db *db.RocksDB, chain bchain.BlockChain, configFileContent []byte) {
|
||||
if fiatRates.Enabled {
|
||||
go fiatRates.RunDownloader()
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
glog.Errorf("Error reading file %v, %v", configFile, err)
|
||||
return
|
||||
}
|
||||
|
||||
var config struct {
|
||||
FourByteSignatures string `json:"fourByteSignatures"`
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &config)
|
||||
err := json.Unmarshal(configFileContent, &config)
|
||||
if err != nil {
|
||||
glog.Errorf("Error parsing config file %v, %v", configFile, err)
|
||||
glog.Errorf("Error parsing config file %v, %v", *configFile, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -37,7 +36,7 @@ type RatesDownloaderInterface interface {
|
||||
UpdateHistoricalTokenTickers() error
|
||||
}
|
||||
|
||||
// FiatRates stores FiatRates API parameters
|
||||
// FiatRates is used to fetch and refresh fiat rates
|
||||
type FiatRates struct {
|
||||
Enabled bool
|
||||
periodSeconds int64
|
||||
@ -62,19 +61,15 @@ type FiatRates struct {
|
||||
}
|
||||
|
||||
// NewFiatRates initializes the FiatRates handler
|
||||
func NewFiatRates(db *db.RocksDB, configFile string, callback OnNewFiatRatesTicker) (*FiatRates, error) {
|
||||
func NewFiatRates(db *db.RocksDB, configFileContent []byte, callback OnNewFiatRatesTicker) (*FiatRates, error) {
|
||||
var config struct {
|
||||
FiatRates string `json:"fiat_rates"`
|
||||
FiatRatesParams string `json:"fiat_rates_params"`
|
||||
FiatRatesVsCurrencies string `json:"fiat_rates_vs_currencies"`
|
||||
}
|
||||
data, err := os.ReadFile(configFile)
|
||||
err := json.Unmarshal(configFileContent, &config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading file %v, %v", configFile, err)
|
||||
}
|
||||
err = json.Unmarshal(data, &config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing config file %v, %v", configFile, err)
|
||||
return nil, fmt.Errorf("error parsing config file, %v", err)
|
||||
}
|
||||
|
||||
var fr = &FiatRates{
|
||||
@ -83,7 +78,7 @@ func NewFiatRates(db *db.RocksDB, configFile string, callback OnNewFiatRatesTick
|
||||
}
|
||||
|
||||
if config.FiatRates == "" || config.FiatRatesParams == "" {
|
||||
glog.Infof("FiatRates config (%v) is empty, not downloading fiat rates", configFile)
|
||||
glog.Infof("FiatRates config is empty, not downloading fiat rates")
|
||||
fr.Enabled = false
|
||||
return fr, nil
|
||||
}
|
||||
@ -176,22 +171,30 @@ func (fr *FiatRates) getTokenTickersForTimestamps(timestamps []int64, vsCurrency
|
||||
currentTicker := fr.GetCurrentTicker("", token)
|
||||
tickers := make([]*common.CurrencyRatesTicker, len(timestamps))
|
||||
var prevTicker *common.CurrencyRatesTicker
|
||||
var prevTs int64
|
||||
var err error
|
||||
for i, t := range timestamps {
|
||||
// check if the token is available in the current ticker - if not, return nil ticker instead of wasting time in costly DB searches
|
||||
if currentTicker != nil {
|
||||
var ticker *common.CurrencyRatesTicker
|
||||
date := time.Unix(t, 0)
|
||||
// if previously found ticker is newer than this one (token tickers may not be in DB for every day), skip search in DB
|
||||
if prevTicker != nil && !date.After(prevTicker.Timestamp) {
|
||||
if prevTicker != nil && t >= prevTs && !date.After(prevTicker.Timestamp) {
|
||||
ticker = prevTicker
|
||||
prevTs = t
|
||||
} else {
|
||||
ticker, _ := fr.db.FiatRatesFindTicker(&date, vsCurrency, token)
|
||||
ticker, err = fr.db.FiatRatesFindTicker(&date, vsCurrency, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prevTicker = ticker
|
||||
prevTs = t
|
||||
}
|
||||
// if ticker not found in DB, use current ticker
|
||||
if ticker == nil {
|
||||
tickers[i] = currentTicker
|
||||
prevTicker = currentTicker
|
||||
prevTs = t
|
||||
} else {
|
||||
tickers[i] = ticker
|
||||
}
|
||||
@ -202,6 +205,9 @@ func (fr *FiatRates) getTokenTickersForTimestamps(timestamps []int64, vsCurrency
|
||||
|
||||
// GetTickersForTimestamps returns tickers for slice of timestamps, that contain requested vsCurrency and token
|
||||
func (fr *FiatRates) GetTickersForTimestamps(timestamps []int64, vsCurrency string, token string) (*[]*common.CurrencyRatesTicker, error) {
|
||||
if !fr.Enabled {
|
||||
return nil, nil
|
||||
}
|
||||
// token rates are not in memory, them load from DB
|
||||
if token != "" {
|
||||
return fr.getTokenTickersForTimestamps(timestamps, vsCurrency, token)
|
||||
@ -210,12 +216,13 @@ func (fr *FiatRates) GetTickersForTimestamps(timestamps []int64, vsCurrency stri
|
||||
defer fr.mux.RUnlock()
|
||||
tickers := make([]*common.CurrencyRatesTicker, len(timestamps))
|
||||
var prevTicker *common.CurrencyRatesTicker
|
||||
var prevTs int64
|
||||
for i, t := range timestamps {
|
||||
dailyTs := normalizedUnix(t, secondsInDay)
|
||||
dailyTs := ceilUnix(t, secondsInDay)
|
||||
// use higher granularity only for non daily timestamps
|
||||
if t != dailyTs {
|
||||
if t >= fr.fiveMinutesTickersFrom && t <= fr.fiveMinutesTickersTo {
|
||||
if ticker, found := fr.fiveMinutesTickers[normalizedUnix(t, secondsInFiveMinutes)]; found && ticker != nil {
|
||||
if ticker, found := fr.fiveMinutesTickers[ceilUnix(t, secondsInFiveMinutes)]; found && ticker != nil {
|
||||
if common.IsSuitableTicker(ticker, vsCurrency, token) {
|
||||
tickers[i] = ticker
|
||||
continue
|
||||
@ -223,7 +230,7 @@ func (fr *FiatRates) GetTickersForTimestamps(timestamps []int64, vsCurrency stri
|
||||
}
|
||||
}
|
||||
if t >= fr.hourlyTickersFrom && t <= fr.hourlyTickersTo {
|
||||
if ticker, found := fr.hourlyTickers[normalizedUnix(t, secondsInHour)]; found && ticker != nil {
|
||||
if ticker, found := fr.hourlyTickers[ceilUnix(t, secondsInHour)]; found && ticker != nil {
|
||||
if common.IsSuitableTicker(ticker, vsCurrency, token) {
|
||||
tickers[i] = ticker
|
||||
continue
|
||||
@ -231,7 +238,7 @@ func (fr *FiatRates) GetTickersForTimestamps(timestamps []int64, vsCurrency stri
|
||||
}
|
||||
}
|
||||
}
|
||||
if prevTicker != nil && dailyTs >= prevTicker.Timestamp.Unix() {
|
||||
if prevTicker != nil && t >= prevTs && t <= prevTicker.Timestamp.Unix() {
|
||||
tickers[i] = prevTicker
|
||||
continue
|
||||
} else {
|
||||
@ -245,15 +252,17 @@ func (fr *FiatRates) GetTickersForTimestamps(timestamps []int64, vsCurrency stri
|
||||
if common.IsSuitableTicker(ticker, vsCurrency, token) {
|
||||
tickers[i] = ticker
|
||||
prevTicker = ticker
|
||||
prevTs = t
|
||||
break
|
||||
} else {
|
||||
found = false
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
tickers[i] = fr.currentTicker
|
||||
prevTicker = fr.currentTicker
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
tickers[i] = fr.currentTicker
|
||||
prevTicker = fr.currentTicker
|
||||
prevTs = t
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,22 +275,31 @@ func (fr *FiatRates) logTickersInfo() {
|
||||
len(fr.fiveMinutesTickers), time.Unix(fr.fiveMinutesTickersFrom, 0).Format("2006-01-02 15:04"), time.Unix(fr.fiveMinutesTickersTo, 0).Format("2006-01-02 15:04"))
|
||||
}
|
||||
|
||||
func normalizedTimeUnix(t time.Time, granularity int64) int64 {
|
||||
return normalizedUnix(t.UTC().Unix(), granularity)
|
||||
func roundTimeUnix(t time.Time, granularity int64) int64 {
|
||||
return roundUnix(t.UTC().Unix(), granularity)
|
||||
}
|
||||
|
||||
func normalizedUnix(t int64, granularity int64) int64 {
|
||||
func roundUnix(t int64, granularity int64) int64 {
|
||||
unix := t + (granularity >> 1)
|
||||
return unix - unix%granularity
|
||||
}
|
||||
|
||||
func ceilUnix(t int64, granularity int64) int64 {
|
||||
unix := t + (granularity - 1)
|
||||
return unix - unix%granularity
|
||||
}
|
||||
|
||||
// loadDailyTickers loads daily tickers to cache
|
||||
func (fr *FiatRates) loadDailyTickers() error {
|
||||
fr.mux.Lock()
|
||||
defer fr.mux.Unlock()
|
||||
fr.dailyTickers = make(map[int64]*common.CurrencyRatesTicker)
|
||||
err := fr.db.FiatRatesGetAllTickers(func(ticker *common.CurrencyRatesTicker) error {
|
||||
normalizedTime := normalizedTimeUnix(ticker.Timestamp, secondsInDay)
|
||||
normalizedTime := roundTimeUnix(ticker.Timestamp, secondsInDay)
|
||||
if normalizedTime == fr.dailyTickersFrom {
|
||||
// there are multiple tickers on the first day, use only the first one
|
||||
return nil
|
||||
}
|
||||
// remove token rates from cache to save memory (tickers with token rates are hundreds of kb big)
|
||||
ticker.TokenRates = nil
|
||||
if len(fr.dailyTickers) > 0 {
|
||||
@ -321,8 +339,8 @@ func (fr *FiatRates) tickersToMap(tickers *[]common.CurrencyRatesTicker, granula
|
||||
to := int64(0)
|
||||
for i := range *tickers {
|
||||
ticker := (*tickers)[i]
|
||||
normalizedTime := normalizedTimeUnix(ticker.Timestamp, granularitySeconds)
|
||||
dailyTime := normalizedTimeUnix(ticker.Timestamp, secondsInDay)
|
||||
normalizedTime := roundTimeUnix(ticker.Timestamp, granularitySeconds)
|
||||
dailyTime := roundTimeUnix(ticker.Timestamp, secondsInDay)
|
||||
dailyTicker, found := fr.dailyTickers[dailyTime]
|
||||
if !found {
|
||||
// if not found in historical tickers, use current ticker
|
||||
|
||||
@ -132,18 +132,7 @@ func TestFiatRates(t *testing.T) {
|
||||
// mocked CoinGecko API
|
||||
configJSON := `{"fiat_rates": "coingecko", "fiat_rates_params": "{\"url\": \"` + mockServer.URL + `\", \"coin\": \"ethereum\",\"platformIdentifier\":\"ethereum\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 60}"}`
|
||||
|
||||
configFile, err := os.CreateTemp("", "config*.json")
|
||||
if err != nil {
|
||||
t.Fatalf("FiatRates configFile error: %v", err)
|
||||
}
|
||||
if _, err := configFile.WriteString(configJSON); err != nil {
|
||||
t.Fatalf("FiatRates configFile WriteString error: %v", err)
|
||||
}
|
||||
if err := configFile.Close(); err != nil {
|
||||
t.Fatalf("FiatRates configFile Close error: %v", err)
|
||||
}
|
||||
|
||||
fiatRates, err := NewFiatRates(d, configFile.Name(), nil)
|
||||
fiatRates, err := NewFiatRates(d, []byte(configJSON), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("FiatRates init error: %v", err)
|
||||
}
|
||||
|
||||
@ -580,7 +580,11 @@ func (s *PublicServer) amountSpan(a *api.Amount, td *TemplateData, classes strin
|
||||
if td.TxTicker == nil {
|
||||
date := time.Unix(td.Tx.Blocktime, 0).UTC()
|
||||
secondary := strings.ToLower(td.SecondaryCoin)
|
||||
ticker, _ := s.db.FiatRatesFindTicker(&date, secondary, "")
|
||||
var ticker *common.CurrencyRatesTicker
|
||||
tickers, err := s.fiatRates.GetTickersForTimestamps([]int64{int64(td.Tx.Blocktime)}, "", "")
|
||||
if err == nil && tickers != nil && len(*tickers) > 0 {
|
||||
ticker = (*tickers)[0]
|
||||
}
|
||||
if ticker != nil {
|
||||
td.TxSecondaryCoinRate = float64(ticker.Rates[secondary])
|
||||
// the ticker is from the midnight, valid for the whole day before
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -121,8 +121,15 @@ func setupPublicHTTPServer(parser bchain.BlockChainParser, chain bchain.BlockCha
|
||||
glog.Fatal("txCache: ", err)
|
||||
}
|
||||
|
||||
// mocked CoinGecko API
|
||||
configJSON := `{"fiat_rates": "coingecko", "fiat_rates_params": "{\"url\": \"none\", \"coin\": \"ethereum\",\"platformIdentifier\":\"ethereum\",\"platformVsCurrency\": \"usd\",\"periodSeconds\": 60}"}`
|
||||
fiatRates, err := fiat.NewFiatRates(d, []byte(configJSON), nil)
|
||||
if err != nil {
|
||||
glog.Fatal("fiatRates ", err)
|
||||
}
|
||||
|
||||
// s.Run is never called, binding can be to any port
|
||||
s, err := NewPublicServer("localhost:12345", "", d, chain, mempool, txCache, "", metrics, is, &fiat.FiatRates{}, false)
|
||||
s, err := NewPublicServer("localhost:12345", "", d, chain, mempool, txCache, "", metrics, is, fiatRates, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -187,37 +194,37 @@ func insertFiatRate(date string, rates map[string]float32, tokenRates map[string
|
||||
|
||||
// initTestFiatRates initializes test data for /api/v2/tickers endpoint
|
||||
func initTestFiatRates(d *db.RocksDB) error {
|
||||
if err := insertFiatRate("20180320020000", map[string]float32{
|
||||
if err := insertFiatRate("20180320000000", map[string]float32{
|
||||
"usd": 2000.0,
|
||||
"eur": 1300.0,
|
||||
}, nil, d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := insertFiatRate("20180320030000", map[string]float32{
|
||||
if err := insertFiatRate("20180321000000", map[string]float32{
|
||||
"usd": 2001.0,
|
||||
"eur": 1301.0,
|
||||
}, nil, d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := insertFiatRate("20180320040000", map[string]float32{
|
||||
if err := insertFiatRate("20180322000000", map[string]float32{
|
||||
"usd": 2002.0,
|
||||
"eur": 1302.0,
|
||||
}, nil, d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := insertFiatRate("20180321055521", map[string]float32{
|
||||
if err := insertFiatRate("20180324000000", map[string]float32{
|
||||
"usd": 2003.0,
|
||||
"eur": 1303.0,
|
||||
}, nil, d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := insertFiatRate("20191121140000", map[string]float32{
|
||||
if err := insertFiatRate("20191121000000", map[string]float32{
|
||||
"usd": 7814.5,
|
||||
"eur": 7100.0,
|
||||
}, nil, d); err != nil {
|
||||
return err
|
||||
}
|
||||
return insertFiatRate("20191121143015", map[string]float32{
|
||||
return insertFiatRate("20191122000000", map[string]float32{
|
||||
"usd": 7914.5,
|
||||
"eur": 7134.1,
|
||||
}, nil, d)
|
||||
@ -323,7 +330,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
contentType: "text/html; charset=utf-8",
|
||||
body: []string{
|
||||
`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1.0,shrink-to-fit=no"><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous"><link rel="stylesheet" href="/static/css/main.min.2.css"><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script><script src="/static/js/main.min.2.js"></script><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="description" content="Trezor Fake Coin Explorer"><title>Trezor Fake Coin Explorer</title></head><body><header id="header"><nav class="navbar navbar-expand-lg"><div class="container"><a class="navbar-brand" href="/" title="Home"><span class="trezor-logo"></span><span style="padding-left: 140px;">Fake Coin Explorer</span></a><button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarSupportedContent"><ul class="navbar-nav m-md-auto"><li class="nav-item pe-xl-4"><a href="/blocks" class="nav-link">Blocks</a></li><li class="nav-item"><a href="/" class="nav-link">Status</a></li></ul><span class="navbar-form"><form class="d-flex" id="search" action="/search" method="get"><input name="q" type="text" class="form-control form-control-lg" placeholder="Search for block, transaction, address or xpub" focus="true"><button class="btn" type="submit"><span class="search-icon"></span></button></form></span></div></div></nav></header><main id="wrap"><div class="container"><h1>Application status</h1><h3><span class="badge bg-warning text-white p-3 w-100" style="white-space: break-spaces;">Synchronization with backend is disabled, the state of index is not up to date.</span></h3><div class="row"><div class="col-lg-6"><table class="table data-table info-table"><tbody><tr><td style="white-space: nowrap;"><h3>Blockbook</h3></td><td></td></tr><tr><td>Coin</td><td>Fakecoin</td></tr><tr><td>Host</td><td></td></tr><tr><td>Version / Commit / Build</td><td>unknown / <a href="https://github.com/trezor/blockbook/commit/unknown" target="_blank" rel="noopener noreferrer">unknown</a> / unknown</td></tr><tr><td>Synchronized</td><td><h6 class="badge bg-success">true</h6></td></tr><tr><td>Last Block</td><td><a href="/block/225494">225<span class="ns">494</span></a></td></tr><tr><td>Last Block Update</td><td>`,
|
||||
`</td></tr><tr><td>Mempool in Sync</td><td><h6 class="badge bg-danger">false</h6></td></tr><tr><td>Last Mempool Update</td><td></td></tr><tr><td>Transactions in Mempool</td><td><a href="/mempool">0</a></td></tr><tr><td>Size On Disk</td>`,
|
||||
`</td></tr><tr><td>Mempool in Sync</td><td><h6 class="badge bg-danger">false</h6></td></tr><tr><td>Last Mempool Update</td><td></td></tr><tr><td>Transactions in Mempool</td><td><a href="/mempool">0</a></td></tr><tr><td>Current Fiat rates</td>`,
|
||||
`</td></tr></tbody></table></div><div class="col-lg-6"><table class="table data-table info-table"><tbody><tr><td style="white-space: nowrap;"><h3>Backend</h3></td><td></td></tr><tr><td>Chain</td><td>fakecoin</td></tr><tr><td>Version</td><td>001001</td></tr><tr><td>Subversion</td><td>/Fakecoin:0.0.1/</td></tr><tr><td>Last Block</td><td>2</td></tr><tr><td>Difficulty</td><td></td></tr></tbody></table></div></div><span class="text-muted">Blockbook - blockchain indexer for Trezor Suite https://trezor.io/trezor-suite. Do not use for any other purpose.</span></div></main><footer id="footer"><div class="container"><nav class="navbar navbar-dark"><span class="navbar-nav"><a class="nav-link" href="https://satoshilabs.com/" target="_blank" rel="noopener noreferrer">Created by SatoshiLabs</a></span><span class="navbar-nav ml-md-auto"><a class="nav-link" href="https://trezor.io/terms-of-use" target="_blank" rel="noopener noreferrer">Terms of Use</a></span><span class="navbar-nav ml-md-auto d-md-flex d-none"><a class="nav-link" href="https://trezor.io/" target="_blank" rel="noopener noreferrer">Trezor</a></span><span class="navbar-nav ml-md-auto d-md-flex d-none"><a class="nav-link" href="https://trezor.io/trezor-suite" target="_blank" rel="noopener noreferrer">Suite</a></span><span class="navbar-nav ml-md-auto d-md-flex d-none"><a class="nav-link" href="https://trezor.io/support" target="_blank" rel="noopener noreferrer">Support</a></span><span class="navbar-nav ml-md-auto"><a class="nav-link" href="/sendtx">Send Transaction</a></span><span class="navbar-nav ml-md-auto d-lg-flex d-none"><a class="nav-link" href="https://trezor.io/compare" target="_blank" rel="noopener noreferrer">Don't have a Trezor? Get one!</a></span></nav></div></footer></body></html>`,
|
||||
},
|
||||
},
|
||||
@ -485,12 +492,12 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apiFiatRates missing currency",
|
||||
name: "apiFiatRates all currencies",
|
||||
r: newGetRequest(ts.URL + "/api/v2/tickers"),
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}`,
|
||||
`{"ts":1574380800,"rates":{"eur":7134.1,"usd":7914.5}}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -499,16 +506,16 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"ts":1574346615,"rates":{"usd":7914.5}}`,
|
||||
`{"ts":1574380800,"rates":{"usd":7914.5}}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apiFiatRates get rate by exact timestamp",
|
||||
r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd×tamp=1574344800"),
|
||||
r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd×tamp=1521545531"),
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"ts":1574344800,"rates":{"usd":7814.5}}`,
|
||||
`{"ts":1521590400,"rates":{"usd":2001}}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -544,25 +551,25 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"ts":1574344800,"rates":{"eur":7100}}`,
|
||||
`{"ts":1574380800,"rates":{"eur":7134.1}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apiMultiFiatRates all currencies",
|
||||
r: newGetRequest(ts.URL + "/api/v2/multi-tickers?timestamp=1574344800,1574346615"),
|
||||
r: newGetRequest(ts.URL + "/api/v2/multi-tickers?timestamp=1574344800,1521677000"),
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`[{"ts":1574344800,"rates":{"eur":7100,"usd":7814.5}},{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}]`,
|
||||
`[{"ts":1574380800,"rates":{"eur":7134.1,"usd":7914.5}},{"ts":1521849600,"rates":{"eur":1303,"usd":2003}}]`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apiMultiFiatRates get EUR rate",
|
||||
r: newGetRequest(ts.URL + "/api/v2/multi-tickers?timestamp=1574344800,1574346615¤cy=eur"),
|
||||
r: newGetRequest(ts.URL + "/api/v2/multi-tickers?timestamp=1521545531,1574346615¤cy=eur"),
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`[{"ts":1574344800,"rates":{"eur":7100}},{"ts":1574346615,"rates":{"eur":7134.1}}]`,
|
||||
`[{"ts":1521590400,"rates":{"eur":1301}},{"ts":1574380800,"rates":{"eur":7134.1}}]`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -571,7 +578,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"ts":1521511200,"rates":{"usd":2000}}`,
|
||||
`{"ts":1521504000,"rates":{"usd":2000}}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -580,7 +587,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"ts":1521611721,"rates":{"usd":2003}}`,
|
||||
`{"ts":1521676800,"rates":{"usd":2002}}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -589,7 +596,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"ts":1574346615,"rates":{"eur":7134.1}}`,
|
||||
`{"ts":1574380800,"rates":{"eur":7134.1}}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -607,7 +614,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"ts":1574346615,"available_currencies":["eur","usd"]}`,
|
||||
`{"ts":1574380800,"available_currencies":["eur","usd"]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -778,7 +785,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","sentToSelf":"0","rates":{"eur":1303,"usd":2003}}]`,
|
||||
`[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","sentToSelf":"0","rates":{"eur":1302,"usd":2002}}]`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -787,7 +794,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`[{"time":1521514800,"txs":1,"received":"9876","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"9000","sent":"9876","sentToSelf":"9000","rates":{"eur":1303,"usd":2003}}]`,
|
||||
`[{"time":1521514800,"txs":1,"received":"9876","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"9000","sent":"9876","sentToSelf":"9000","rates":{"eur":1302,"usd":2002}}]`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -796,7 +803,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`[{"time":1521514800,"txs":1,"received":"9876","sent":"0","sentToSelf":"0","rates":{"eur":1301}},{"time":1521594000,"txs":1,"received":"9000","sent":"9876","sentToSelf":"9000","rates":{"eur":1303}}]`,
|
||||
`[{"time":1521514800,"txs":1,"received":"9876","sent":"0","sentToSelf":"0","rates":{"eur":1301}},{"time":1521594000,"txs":1,"received":"9000","sent":"9876","sentToSelf":"9000","rates":{"eur":1302}}]`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -814,7 +821,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1303,"usd":2003}}]`,
|
||||
`[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1302,"usd":2002}}]`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -841,7 +848,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`[{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1303,"usd":2003}}]`,
|
||||
`[{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1302,"usd":2002}}]`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1210,7 +1217,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"currencies": []string{},
|
||||
},
|
||||
},
|
||||
want: `{"id":"18","data":{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}}`,
|
||||
want: `{"id":"18","data":{"ts":1574380800,"rates":{"eur":7134.1,"usd":7914.5}}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getCurrentFiatRates usd",
|
||||
@ -1220,7 +1227,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"currencies": []string{"usd"},
|
||||
},
|
||||
},
|
||||
want: `{"id":"19","data":{"ts":1574346615,"rates":{"usd":7914.5}}}`,
|
||||
want: `{"id":"19","data":{"ts":1574380800,"rates":{"usd":7914.5}}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getCurrentFiatRates eur",
|
||||
@ -1230,7 +1237,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"currencies": []string{"eur"},
|
||||
},
|
||||
},
|
||||
want: `{"id":"20","data":{"ts":1574346615,"rates":{"eur":7134.1}}}`,
|
||||
want: `{"id":"20","data":{"ts":1574380800,"rates":{"eur":7134.1}}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getCurrentFiatRates incorrect currency",
|
||||
@ -1291,10 +1298,10 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
Method: "getFiatRatesForTimestamps",
|
||||
Params: map[string]interface{}{
|
||||
"currencies": []string{"usd"},
|
||||
"timestamps": []int64{1574346615},
|
||||
"timestamps": []int64{1574380800},
|
||||
},
|
||||
},
|
||||
want: `{"id":"26","data":{"tickers":[{"ts":1574346615,"rates":{"usd":7914.5}}]}}`,
|
||||
want: `{"id":"26","data":{"tickers":[{"ts":1574380800,"rates":{"usd":7914.5}}]}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getFiatRatesForTimestamps closest date, eur",
|
||||
@ -1305,7 +1312,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"timestamps": []int64{1521507600},
|
||||
},
|
||||
},
|
||||
want: `{"id":"27","data":{"tickers":[{"ts":1521511200,"rates":{"eur":1300}}]}}`,
|
||||
want: `{"id":"27","data":{"tickers":[{"ts":1521590400,"rates":{"eur":1301}}]}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getFiatRatesForTimestamps multiple timestamps usd",
|
||||
@ -1316,7 +1323,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"timestamps": []int64{1570346615, 1574346615},
|
||||
},
|
||||
},
|
||||
want: `{"id":"28","data":{"tickers":[{"ts":1574344800,"rates":{"usd":7814.5}},{"ts":1574346615,"rates":{"usd":7914.5}}]}}`,
|
||||
want: `{"id":"28","data":{"tickers":[{"ts":1574294400,"rates":{"usd":7814.5}},{"ts":1574380800,"rates":{"usd":7914.5}}]}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getFiatRatesForTimestamps multiple timestamps eur",
|
||||
@ -1327,7 +1334,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"timestamps": []int64{1570346615, 1574346615},
|
||||
},
|
||||
},
|
||||
want: `{"id":"29","data":{"tickers":[{"ts":1574344800,"rates":{"eur":7100}},{"ts":1574346615,"rates":{"eur":7134.1}}]}}`,
|
||||
want: `{"id":"29","data":{"tickers":[{"ts":1574294400,"rates":{"eur":7100}},{"ts":1574380800,"rates":{"eur":7134.1}}]}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getFiatRatesForTimestamps multiple timestamps with an error",
|
||||
@ -1338,7 +1345,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"timestamps": []int64{1570346615, 1574346615, 2000000000},
|
||||
},
|
||||
},
|
||||
want: `{"id":"30","data":{"tickers":[{"ts":1574344800,"rates":{"usd":7814.5}},{"ts":1574346615,"rates":{"usd":7914.5}},{"ts":2000000000,"rates":{"usd":-1}}]}}`,
|
||||
want: `{"id":"30","data":{"tickers":[{"ts":1574294400,"rates":{"usd":7814.5}},{"ts":1574380800,"rates":{"usd":7914.5}},{"ts":2000000000,"rates":{"usd":-1}}]}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getFiatRatesForTimestamps multiple errors",
|
||||
@ -1359,7 +1366,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"timestamp": 1570346615,
|
||||
},
|
||||
},
|
||||
want: `{"id":"32","data":{"ts":1574344800,"available_currencies":["eur","usd"]}}`,
|
||||
want: `{"id":"32","data":{"ts":1574294400,"available_currencies":["eur","usd"]}}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getBalanceHistory Addr2",
|
||||
@ -1369,7 +1376,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"descriptor": "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz",
|
||||
},
|
||||
},
|
||||
want: `{"id":"33","data":[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","sentToSelf":"0","rates":{"eur":1303,"usd":2003}}]}`,
|
||||
want: `{"id":"33","data":[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","sentToSelf":"0","rates":{"eur":1302,"usd":2002}}]}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getBalanceHistory xpub",
|
||||
@ -1379,7 +1386,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
"descriptor": dbtestdata.Xpub,
|
||||
},
|
||||
},
|
||||
want: `{"id":"34","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1303,"usd":2003}}]}`,
|
||||
want: `{"id":"34","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1302,"usd":2002}}]}`,
|
||||
},
|
||||
{
|
||||
name: "websocket getBalanceHistory xpub from=1521504000&to=1521590400 currencies=[usd]",
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
{{range $c := .SecondaryCurrencies}}
|
||||
<div class="col-3"><a href="?secondary={{$c}}&use_secondary=true">{{$c}}</a></div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user