From 35b94268e001f7bae8dd0a73411ef860de85ff3e Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Mon, 6 May 2019 13:46:34 +1000 Subject: [PATCH] Update request.go to fix concurrency nonce issues (#285) * Updates nonce generation to adhere to fifo channel buffer before request executes by routine * removed unused variables, lns etc * Fix requested changes and added in timer that disengages lock if out of scope error occurs * Fixed woopsy daisy issue * Add benchmark, reduce time in force to unlock before stack insertion, add nil check for edge case * Remove unusued waitgroup field * use return nonce.Value and method, rm redundant nonce code, fix tests. * Fix linter issue: unnecessary conversion --- currency/coinmarketcap/coinmarketcap.go | 1 + .../currencyconverterapi.go | 1 + .../currencylayer/currencylayer.go | 1 + .../exchangeratesapi.io/exchangeratesapi.go | 1 + currency/forexprovider/fixer.io/fixer.go | 1 + currency/forexprovider/fixer.io/fixer_test.go | 20 +++++ .../openexchangerates/openexchangerates.go | 1 + exchanges/alphapoint/alphapoint.go | 15 ++-- exchanges/anx/anx.go | 13 +--- exchanges/binance/binance.go | 4 +- exchanges/bitfinex/bitfinex.go | 12 ++- exchanges/bitflyer/bitflyer.go | 2 +- exchanges/bithumb/bithumb.go | 13 ++-- exchanges/bitmex/bitmex.go | 5 +- exchanges/bitstamp/bitstamp.go | 14 ++-- exchanges/bittrex/bittrex.go | 13 ++-- exchanges/btcmarkets/btcmarkets.go | 16 ++-- exchanges/btse/btse.go | 4 +- exchanges/coinbasepro/coinbasepro.go | 9 ++- exchanges/coinut/coinut.go | 9 +-- exchanges/coinut/coinut_websocket.go | 2 +- exchanges/exchange.go | 2 - exchanges/exmo/exmo.go | 11 +-- exchanges/gateio/gateio.go | 3 +- exchanges/gemini/gemini.go | 6 +- exchanges/hitbtc/hitbtc.go | 3 +- exchanges/huobi/huobi.go | 4 +- exchanges/huobihadax/huobihadax.go | 6 +- exchanges/itbit/itbit.go | 12 +-- exchanges/kraken/kraken.go | 11 +-- exchanges/kraken/kraken_types.go | 10 ++- exchanges/kraken/kraken_websocket.go | 4 +- exchanges/lakebtc/lakebtc.go | 12 +-- exchanges/localbitcoins/localbitcoins.go | 14 ++-- exchanges/nonce/nonce.go | 36 +-------- exchanges/nonce/nonce_test.go | 37 ++------- exchanges/okgroup/okgroup.go | 2 +- exchanges/poloniex/poloniex.go | 24 +++--- exchanges/poloniex/poloniex_test.go | 68 +++++++++-------- exchanges/poloniex/poloniex_types.go | 8 +- exchanges/request/request.go | 76 ++++++++++++++++++- exchanges/request/request_test.go | 32 +++++--- exchanges/yobit/yobit.go | 11 ++- exchanges/zb/zb.go | 3 +- exchanges/zb/zb_wrapper.go | 4 +- testdata/configtest.json | 14 ++++ 46 files changed, 312 insertions(+), 258 deletions(-) diff --git a/currency/coinmarketcap/coinmarketcap.go b/currency/coinmarketcap/coinmarketcap.go index 2ec08a6f..60a51dc9 100644 --- a/currency/coinmarketcap/coinmarketcap.go +++ b/currency/coinmarketcap/coinmarketcap.go @@ -730,6 +730,7 @@ func (c *Coinmarketcap) SendHTTPRequest(method, endpoint string, v url.Values, r strings.NewReader(""), result, false, + false, c.Verbose) } diff --git a/currency/forexprovider/currencyconverterapi/currencyconverterapi.go b/currency/forexprovider/currencyconverterapi/currencyconverterapi.go index 909dcde6..e5d7a932 100644 --- a/currency/forexprovider/currencyconverterapi/currencyconverterapi.go +++ b/currency/forexprovider/currencyconverterapi/currencyconverterapi.go @@ -190,6 +190,7 @@ func (c *CurrencyConverter) SendHTTPRequest(endPoint string, values url.Values, nil, &result, auth, + false, c.Verbose) if err != nil { return fmt.Errorf("currency converter API SendHTTPRequest error %s with path %s", diff --git a/currency/forexprovider/currencylayer/currencylayer.go b/currency/forexprovider/currencylayer/currencylayer.go index 3c929978..c759d641 100644 --- a/currency/forexprovider/currencylayer/currencylayer.go +++ b/currency/forexprovider/currencylayer/currencylayer.go @@ -239,5 +239,6 @@ func (c *CurrencyLayer) SendHTTPRequest(endPoint string, values url.Values, resu nil, &result, auth, + false, c.Verbose) } diff --git a/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go b/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go index 4d5f8c8e..d81ab481 100644 --- a/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go +++ b/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go @@ -176,6 +176,7 @@ func (e *ExchangeRates) SendHTTPRequest(endPoint string, values url.Values, resu nil, &result, false, + false, e.Verbose) if err != nil { return fmt.Errorf("exchangeRatesAPI SendHTTPRequest error %s with path %s", diff --git a/currency/forexprovider/fixer.io/fixer.go b/currency/forexprovider/fixer.io/fixer.go index 4a94f96c..0b46bbac 100644 --- a/currency/forexprovider/fixer.io/fixer.go +++ b/currency/forexprovider/fixer.io/fixer.go @@ -263,5 +263,6 @@ func (f *Fixer) SendOpenHTTPRequest(endpoint string, v url.Values, result interf nil, result, auth, + false, f.Verbose) } diff --git a/currency/forexprovider/fixer.io/fixer_test.go b/currency/forexprovider/fixer.io/fixer_test.go index dfc91413..c0f9bbd8 100644 --- a/currency/forexprovider/fixer.io/fixer_test.go +++ b/currency/forexprovider/fixer.io/fixer_test.go @@ -2,6 +2,8 @@ package fixer import ( "testing" + + "github.com/thrasher-/gocryptotrader/currency/forexprovider/base" ) // Please set API key and apikey subscription level for correct due diligence @@ -14,7 +16,20 @@ const ( var f Fixer +var isSetup bool + +func setup(t *testing.T) { + if !isSetup { + err := f.Setup(base.Settings{}) + if err != nil { + t.Fatal("Test Failed - Setup error", err) + } + isSetup = true + } +} + func TestGetRates(t *testing.T) { + setup(t) _, err := f.GetRates("EUR", "AUD") if err == nil { t.Error("test failed - fixer GetRates() error", err) @@ -22,6 +37,7 @@ func TestGetRates(t *testing.T) { } func TestGetLatestRates(t *testing.T) { + setup(t) _, err := f.GetLatestRates("EUR", "AUD") if err == nil { t.Error("test failed - fixer GetLatestRates() error", err) @@ -29,6 +45,7 @@ func TestGetLatestRates(t *testing.T) { } func TestGetHistoricalRates(t *testing.T) { + setup(t) _, err := f.GetHistoricalRates("2013-12-24", "EUR", []string{"AUD,KRW"}) if err == nil { t.Error("test failed - fixer GetHistoricalRates() error", err) @@ -36,6 +53,7 @@ func TestGetHistoricalRates(t *testing.T) { } func TestConvertCurrency(t *testing.T) { + setup(t) _, err := f.ConvertCurrency("AUD", "EUR", "", 1337) if err == nil { t.Error("test failed - fixer ConvertCurrency() error", err) @@ -43,6 +61,7 @@ func TestConvertCurrency(t *testing.T) { } func TestGetTimeSeriesData(t *testing.T) { + setup(t) _, err := f.GetTimeSeriesData("2013-12-24", "2013-12-25", "EUR", []string{"AUD,KRW"}) if err == nil { t.Error("test failed - fixer GetTimeSeriesData() error", err) @@ -50,6 +69,7 @@ func TestGetTimeSeriesData(t *testing.T) { } func TestGetFluctuationData(t *testing.T) { + setup(t) _, err := f.GetFluctuationData("2013-12-24", "2013-12-25", "EUR", []string{"AUD,KRW"}) if err == nil { t.Error("test failed - fixer GetFluctuationData() error", err) diff --git a/currency/forexprovider/openexchangerates/openexchangerates.go b/currency/forexprovider/openexchangerates/openexchangerates.go index d2bdb3a5..f5b5dc27 100644 --- a/currency/forexprovider/openexchangerates/openexchangerates.go +++ b/currency/forexprovider/openexchangerates/openexchangerates.go @@ -263,5 +263,6 @@ func (o *OXR) SendHTTPRequest(endpoint string, values url.Values, result interfa nil, result, false, + false, o.Verbose) } diff --git a/exchanges/alphapoint/alphapoint.go b/exchanges/alphapoint/alphapoint.go index 22e6fa8d..c3234f98 100644 --- a/exchanges/alphapoint/alphapoint.go +++ b/exchanges/alphapoint/alphapoint.go @@ -534,7 +534,7 @@ func (a *Alphapoint) SendHTTPRequest(method, path string, data map[string]interf return errors.New("unable to JSON request") } - return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, false, a.Verbose) + return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, false, false, a.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated request @@ -543,17 +543,14 @@ func (a *Alphapoint) SendAuthenticatedHTTPRequest(method, path string, data map[ return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, a.Name) } - if a.Nonce.Get() == 0 { - a.Nonce.Set(time.Now().UnixNano()) - } else { - a.Nonce.Inc() - } + n := a.Requester.GetNonce(true) headers := make(map[string]string) headers["Content-Type"] = "application/json" data["apiKey"] = a.APIKey - data["apiNonce"] = a.Nonce.Get() - hmac := common.GetHMAC(common.HashSHA256, []byte(a.Nonce.String()+a.ClientID+a.APIKey), []byte(a.APISecret)) + data["apiNonce"] = n + hmac := common.GetHMAC(common.HashSHA256, []byte(n.String()+a.ClientID+a.APIKey), + []byte(a.APISecret)) data["apiSig"] = common.StringToUpper(common.HexEncodeToString(hmac)) path = fmt.Sprintf("%s/ajax/v%s/%s", a.APIUrl, alphapointAPIVersion, path) @@ -562,5 +559,5 @@ func (a *Alphapoint) SendAuthenticatedHTTPRequest(method, path string, data map[ return errors.New("unable to JSON request") } - return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, true, a.Verbose) + return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, true, true, a.Verbose) } diff --git a/exchanges/anx/anx.go b/exchanges/anx/anx.go index 7eccd54f..036e6033 100644 --- a/exchanges/anx/anx.go +++ b/exchanges/anx/anx.go @@ -402,7 +402,7 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) ( // SendHTTPRequest sends an unauthenticated HTTP request func (a *ANX) SendHTTPRequest(path string, result interface{}) error { - return a.SendPayload(http.MethodGet, path, nil, nil, result, false, a.Verbose) + return a.SendPayload(http.MethodGet, path, nil, nil, result, false, false, a.Verbose) } // SendAuthenticatedHTTPRequest sends a authenticated HTTP request @@ -411,14 +411,9 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, a.Name) } - if a.Nonce.Get() == 0 { - a.Nonce.Set(time.Now().UnixNano()) - } else { - a.Nonce.Inc() - } - + n := a.Requester.GetNonce(true) req := make(map[string]interface{}) - req["nonce"] = a.Nonce.String()[0:13] + req["nonce"] = n.String()[0:13] path = fmt.Sprintf("api/%s/%s", anxAPIVersion, path) for key, value := range params { @@ -440,7 +435,7 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf headers["Rest-Sign"] = common.Base64Encode(hmac) headers["Content-Type"] = "application/json" - return a.SendPayload(http.MethodPost, a.APIUrl+path, headers, bytes.NewBuffer(PayloadJSON), result, true, a.Verbose) + return a.SendPayload(http.MethodPost, a.APIUrl+path, headers, bytes.NewBuffer(PayloadJSON), result, true, true, a.Verbose) } // GetFee returns an estimate of fee based on type of transaction diff --git a/exchanges/binance/binance.go b/exchanges/binance/binance.go index 3cf210d7..508f37f3 100644 --- a/exchanges/binance/binance.go +++ b/exchanges/binance/binance.go @@ -594,7 +594,7 @@ func (b *Binance) GetAccount() (*Account, error) { // SendHTTPRequest sends an unauthenticated request func (b *Binance) SendHTTPRequest(path string, result interface{}) error { - return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose) + return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose) } // SendAuthHTTPRequest sends an authenticated HTTP request @@ -630,7 +630,7 @@ func (b *Binance) SendAuthHTTPRequest(method, path string, params url.Values, re Message string `json:"msg"` }{} - err := b.SendPayload(method, path, headers, bytes.NewBuffer(nil), &interim, true, b.Verbose) + err := b.SendPayload(method, path, headers, bytes.NewBuffer(nil), &interim, true, false, b.Verbose) if err != nil { return err } diff --git a/exchanges/bitfinex/bitfinex.go b/exchanges/bitfinex/bitfinex.go index 04567178..2d88d627 100644 --- a/exchanges/bitfinex/bitfinex.go +++ b/exchanges/bitfinex/bitfinex.go @@ -616,6 +616,7 @@ func (b *Bitfinex) WithdrawCryptocurrency(withdrawType, wallet, address, payment &response) } +// WithdrawFIAT requests a withdrawal from a designated fiat wallet func (b *Bitfinex) WithdrawFIAT(withdrawalType, walletType string, withdrawRequest *exchange.WithdrawRequest) ([]Withdrawal, error) { response := []Withdrawal{} req := make(map[string]interface{}) @@ -1000,7 +1001,7 @@ func (b *Bitfinex) CloseMarginFunding(swapID int64) (Offer, error) { // SendHTTPRequest sends an unauthenticated request func (b *Bitfinex) SendHTTPRequest(path string, result interface{}, verbose bool) error { - return b.SendPayload(http.MethodGet, path, nil, nil, result, false, verbose) + return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, verbose) } // SendAuthenticatedHTTPRequest sends an autheticated http request and json @@ -1011,15 +1012,11 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[ b.Name) } - if b.Nonce.Get() == 0 { - b.Nonce.Set(time.Now().UnixNano()) - } else { - b.Nonce.Inc() - } + n := b.Requester.GetNonce(true) req := make(map[string]interface{}) req["request"] = fmt.Sprintf("%s%s", bitfinexAPIVersion, path) - req["nonce"] = b.Nonce.String() + req["nonce"] = n.String() for key, value := range params { req[key] = value @@ -1048,6 +1045,7 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[ nil, result, true, + true, b.Verbose) } diff --git a/exchanges/bitflyer/bitflyer.go b/exchanges/bitflyer/bitflyer.go index 3aadf5d1..3a4b6e7a 100644 --- a/exchanges/bitflyer/bitflyer.go +++ b/exchanges/bitflyer/bitflyer.go @@ -378,7 +378,7 @@ func (b *Bitflyer) GetTradingCommission() { // SendHTTPRequest sends an unauthenticated request func (b *Bitflyer) SendHTTPRequest(path string, result interface{}) error { - return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose) + return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose) } // SendAuthHTTPRequest sends an authenticated HTTP request diff --git a/exchanges/bithumb/bithumb.go b/exchanges/bithumb/bithumb.go index 4b97a987..ae903215 100644 --- a/exchanges/bithumb/bithumb.go +++ b/exchanges/bithumb/bithumb.go @@ -543,7 +543,7 @@ func (b *Bithumb) MarketSellOrder(currency string, units float64) (MarketSell, e // SendHTTPRequest sends an unauthenticated HTTP request func (b *Bithumb) SendHTTPRequest(path string, result interface{}) error { - return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose) + return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated HTTP request to bithumb @@ -556,15 +556,11 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, r params = url.Values{} } - if b.Nonce.Get() == 0 { - b.Nonce.Set(time.Now().UnixNano() / int64(time.Millisecond)) - } else { - b.Nonce.Inc() - } + n := b.Requester.GetNonceMilli().String() params.Set("endpoint", path) payload := params.Encode() - hmacPayload := path + string(0) + payload + string(0) + b.Nonce.String() + hmacPayload := path + string(0) + payload + string(0) + n hmac := common.GetHMAC(common.HashSHA512, []byte(hmacPayload), []byte(b.APISecret)) @@ -573,7 +569,7 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, r headers := make(map[string]string) headers["Api-Key"] = b.APIKey headers["Api-Sign"] = common.Base64Encode([]byte(hmacStr)) - headers["Api-Nonce"] = b.Nonce.String() + headers["Api-Nonce"] = n headers["Content-Type"] = "application/x-www-form-urlencoded" var intermediary json.RawMessage @@ -589,6 +585,7 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, r bytes.NewBufferString(payload), &intermediary, true, + true, b.Verbose) if err != nil { return err diff --git a/exchanges/bitmex/bitmex.go b/exchanges/bitmex/bitmex.go index ff9c6113..4b493f24 100644 --- a/exchanges/bitmex/bitmex.go +++ b/exchanges/bitmex/bitmex.go @@ -850,14 +850,14 @@ func (b *Bitmex) SendHTTPRequest(path string, params Parameter, result interface if err != nil { return err } - err = b.SendPayload(http.MethodGet, encodedPath, nil, nil, &respCheck, false, b.Verbose) + err = b.SendPayload(http.MethodGet, encodedPath, nil, nil, &respCheck, false, false, b.Verbose) if err != nil { return err } return b.CaptureError(respCheck, result) } } - err := b.SendPayload(http.MethodGet, path, nil, nil, &respCheck, false, b.Verbose) + err := b.SendPayload(http.MethodGet, path, nil, nil, &respCheck, false, false, b.Verbose) if err != nil { return err } @@ -907,6 +907,7 @@ func (b *Bitmex) SendAuthenticatedHTTPRequest(verb, path string, params Paramete bytes.NewBuffer([]byte(payload)), &respCheck, true, + false, b.Verbose) if err != nil { return err diff --git a/exchanges/bitstamp/bitstamp.go b/exchanges/bitstamp/bitstamp.go index 498e4010..c40b8cc1 100644 --- a/exchanges/bitstamp/bitstamp.go +++ b/exchanges/bitstamp/bitstamp.go @@ -645,7 +645,7 @@ func (b *Bitstamp) TransferAccountBalance(amount float64, currency, subAccount s // SendHTTPRequest sends an unauthenticated HTTP request func (b *Bitstamp) SendHTTPRequest(path string, result interface{}) error { - return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose) + return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated request @@ -654,19 +654,15 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name) } - if b.Nonce.Get() == 0 { - b.Nonce.Set(time.Now().UnixNano()) - } else { - b.Nonce.Inc() - } + n := b.Requester.GetNonce(true).String() if values == nil { values = url.Values{} } values.Set("key", b.APIKey) - values.Set("nonce", b.Nonce.String()) - hmac := common.GetHMAC(common.HashSHA256, []byte(b.Nonce.String()+b.ClientID+b.APIKey), []byte(b.APISecret)) + values.Set("nonce", n) + hmac := common.GetHMAC(common.HashSHA256, []byte(n+b.ClientID+b.APIKey), []byte(b.APISecret)) values.Set("signature", common.StringToUpper(common.HexEncodeToString(hmac))) if v2 { @@ -691,7 +687,7 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url Error string `json:"error"` }{} - err := b.SendPayload(http.MethodPost, path, headers, readerValues, &interim, true, b.Verbose) + err := b.SendPayload(http.MethodPost, path, headers, readerValues, &interim, true, true, b.Verbose) if err != nil { return err } diff --git a/exchanges/bittrex/bittrex.go b/exchanges/bittrex/bittrex.go index 2527132d..d5139869 100644 --- a/exchanges/bittrex/bittrex.go +++ b/exchanges/bittrex/bittrex.go @@ -493,7 +493,7 @@ func (b *Bittrex) GetDepositHistory(currency string) (WithdrawalHistory, error) // SendHTTPRequest sends an unauthenticated HTTP request func (b *Bittrex) SendHTTPRequest(path string, result interface{}) error { - return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose) + return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated http request to a desired @@ -503,13 +503,10 @@ func (b *Bittrex) SendAuthenticatedHTTPRequest(path string, values url.Values, r return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name) } - if b.Nonce.Get() == 0 { - b.Nonce.Set(time.Now().UnixNano()) - } else { - b.Nonce.Inc() - } + n := b.Requester.GetNonce(true).String() + values.Set("apikey", b.APIKey) - values.Set("nonce", b.Nonce.String()) + values.Set("nonce", n) rawQuery := path + "?" + values.Encode() hmac := common.GetHMAC( common.HashSHA512, []byte(rawQuery), []byte(b.APISecret), @@ -517,7 +514,7 @@ func (b *Bittrex) SendAuthenticatedHTTPRequest(path string, values url.Values, r headers := make(map[string]string) headers["apisign"] = common.HexEncodeToString(hmac) - return b.SendPayload(http.MethodGet, rawQuery, headers, nil, result, true, b.Verbose) + return b.SendPayload(http.MethodGet, rawQuery, headers, nil, result, true, true, b.Verbose) } // GetFee returns an estimate of fee based on type of transaction diff --git a/exchanges/btcmarkets/btcmarkets.go b/exchanges/btcmarkets/btcmarkets.go index 56ca2e26..6c41ab11 100644 --- a/exchanges/btcmarkets/btcmarkets.go +++ b/exchanges/btcmarkets/btcmarkets.go @@ -431,7 +431,7 @@ func (b *BTCMarkets) WithdrawAUD(accountName, accountNumber, bankName, bsbNumber // SendHTTPRequest sends an unauthenticated HTTP request func (b *BTCMarkets) SendHTTPRequest(path string, result interface{}) error { - return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose) + return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose) } // SendAuthenticatedRequest sends an authenticated HTTP request @@ -441,11 +441,8 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result b.Name) } - if b.Nonce.Get() == 0 { - b.Nonce.Set(time.Now().UnixNano()) - } else { - b.Nonce.Inc() - } + n := b.Requester.GetNonce(true).String()[0:13] + var req string payload := []byte("") @@ -454,9 +451,9 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result if err != nil { return err } - req = path + "\n" + b.Nonce.String()[0:13] + "\n" + string(payload) + req = path + "\n" + n + "\n" + string(payload) } else { - req = path + "\n" + b.Nonce.String()[0:13] + "\n" + req = path + "\n" + n + "\n" } hmac := common.GetHMAC(common.HashSHA512, @@ -474,7 +471,7 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result headers["Accept-Charset"] = "UTF-8" headers["Content-Type"] = "application/json" headers["apikey"] = b.APIKey - headers["timestamp"] = b.Nonce.String()[0:13] + headers["timestamp"] = n headers["signature"] = common.Base64Encode(hmac) return b.SendPayload(reqType, @@ -483,6 +480,7 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result bytes.NewBuffer(payload), result, true, + true, b.Verbose) } diff --git a/exchanges/btse/btse.go b/exchanges/btse/btse.go index b99687b3..a0426300 100644 --- a/exchanges/btse/btse.go +++ b/exchanges/btse/btse.go @@ -252,7 +252,7 @@ func (b *BTSE) GetFills(orderID, productID, before, after, limit string) (*Fille // SendHTTPRequest sends an HTTP request to the desired endpoint func (b *BTSE) SendHTTPRequest(method, endpoint string, result interface{}) error { p := fmt.Sprintf("%s/%s", btseAPIURL, endpoint) - return b.SendPayload(method, p, nil, nil, &result, false, b.Verbose) + return b.SendPayload(method, p, nil, nil, &result, false, false, b.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the desired endpoint @@ -278,7 +278,7 @@ func (b *BTSE) SendAuthenticatedHTTPRequest(method, endpoint string, req map[str log.Debugf("Sending %s request to URL %s with params %s\n", method, p, string(payload)) } return b.SendPayload(method, p, headers, strings.NewReader(string(payload)), - &result, true, b.Verbose) + &result, true, false, b.Verbose) } // GetFee returns an estimate of fee based on type of transaction diff --git a/exchanges/coinbasepro/coinbasepro.go b/exchanges/coinbasepro/coinbasepro.go index c5a671cd..9f61b14f 100644 --- a/exchanges/coinbasepro/coinbasepro.go +++ b/exchanges/coinbasepro/coinbasepro.go @@ -792,7 +792,7 @@ func (c *CoinbasePro) GetTrailingVolume() ([]Volume, error) { // SendHTTPRequest sends an unauthenticated HTTP request func (c *CoinbasePro) SendHTTPRequest(path string, result interface{}) error { - return c.SendPayload(http.MethodGet, path, nil, nil, result, false, c.Verbose) + return c.SendPayload(http.MethodGet, path, nil, nil, result, false, false, c.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated HTTP reque @@ -815,12 +815,12 @@ func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params m } } - nonce := c.Nonce.GetValue(c.Name, false).String() - message := nonce + method + "/" + path + string(payload) + n := c.Requester.GetNonce(true).String() + message := n + method + "/" + path + string(payload) hmac := common.GetHMAC(common.HashSHA256, []byte(message), []byte(c.APISecret)) headers := make(map[string]string) headers["CB-ACCESS-SIGN"] = common.Base64Encode(hmac) - headers["CB-ACCESS-TIMESTAMP"] = nonce + headers["CB-ACCESS-TIMESTAMP"] = n headers["CB-ACCESS-KEY"] = c.APIKey headers["CB-ACCESS-PASSPHRASE"] = c.ClientID headers["Content-Type"] = "application/json" @@ -831,6 +831,7 @@ func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params m bytes.NewBuffer(payload), result, true, + true, c.Verbose) } diff --git a/exchanges/coinut/coinut.go b/exchanges/coinut/coinut.go index aee0fc90..236f4ae1 100644 --- a/exchanges/coinut/coinut.go +++ b/exchanges/coinut/coinut.go @@ -338,16 +338,12 @@ func (c *COINUT) SendHTTPRequest(apiRequest string, params map[string]interface{ return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, c.Name) } - if c.Nonce.Get() == 0 { - c.Nonce.Set(time.Now().Unix()) - } else { - c.Nonce.Inc() - } + n := c.Requester.GetNonce(false) if params == nil { params = map[string]interface{}{} } - params["nonce"] = c.Nonce.Get() + params["nonce"] = n params["request"] = apiRequest payload, err := common.JSONEncode(params) @@ -374,6 +370,7 @@ func (c *COINUT) SendHTTPRequest(apiRequest string, params map[string]interface{ bytes.NewBuffer(payload), &rawMsg, authenticated, + true, c.Verbose) if err != nil { return err diff --git a/exchanges/coinut/coinut_websocket.go b/exchanges/coinut/coinut_websocket.go index 7d87e3bc..432b97b2 100644 --- a/exchanges/coinut/coinut_websocket.go +++ b/exchanges/coinut/coinut_websocket.go @@ -225,7 +225,7 @@ func (c *COINUT) GetNonce() int64 { c.Nonce.Inc() } - return c.Nonce.Get() + return int64(c.Nonce.Get()) } // WsSetInstrumentList fetches instrument list and propagates a local cache diff --git a/exchanges/exchange.go b/exchanges/exchange.go index 8b57156d..7df68795 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -13,7 +13,6 @@ import ( "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" "github.com/thrasher-/gocryptotrader/currency" - "github.com/thrasher-/gocryptotrader/exchanges/nonce" "github.com/thrasher-/gocryptotrader/exchanges/orderbook" "github.com/thrasher-/gocryptotrader/exchanges/request" "github.com/thrasher-/gocryptotrader/exchanges/ticker" @@ -262,7 +261,6 @@ type Base struct { APIWithdrawPermissions uint32 APIAuthPEMKeySupport bool APISecret, APIKey, APIAuthPEMKey, ClientID string - Nonce nonce.Nonce TakerFee, MakerFee, Fee float64 BaseCurrencies currency.Currencies AvailablePairs currency.Pairs diff --git a/exchanges/exmo/exmo.go b/exchanges/exmo/exmo.go index 182b96d2..a089d63a 100644 --- a/exchanges/exmo/exmo.go +++ b/exchanges/exmo/exmo.go @@ -371,7 +371,7 @@ func (e *EXMO) GetWalletHistory(date int64) (WalletHistory, error) { // SendHTTPRequest sends an unauthenticated HTTP request func (e *EXMO) SendHTTPRequest(path string, result interface{}) error { - return e.SendPayload(http.MethodGet, path, nil, nil, result, false, e.Verbose) + return e.SendPayload(http.MethodGet, path, nil, nil, result, false, false, e.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated HTTP request @@ -381,12 +381,8 @@ func (e *EXMO) SendAuthenticatedHTTPRequest(method, endpoint string, vals url.Va e.Name) } - if e.Nonce.Get() == 0 { - e.Nonce.Set(time.Now().UnixNano()) - } else { - e.Nonce.Inc() - } - vals.Set("nonce", e.Nonce.String()) + n := e.Requester.GetNonce(true).String() + vals.Set("nonce", n) payload := vals.Encode() hash := common.GetHMAC(common.HashSHA512, @@ -413,6 +409,7 @@ func (e *EXMO) SendAuthenticatedHTTPRequest(method, endpoint string, vals url.Va strings.NewReader(payload), result, true, + true, e.Verbose) } diff --git a/exchanges/gateio/gateio.go b/exchanges/gateio/gateio.go index 2c1c6f32..a2c60ea9 100644 --- a/exchanges/gateio/gateio.go +++ b/exchanges/gateio/gateio.go @@ -391,7 +391,7 @@ func (g *Gateio) CancelExistingOrder(orderID int64, symbol string) (bool, error) // SendHTTPRequest sends an unauthenticated HTTP request func (g *Gateio) SendHTTPRequest(path string, result interface{}) error { - return g.SendPayload(http.MethodGet, path, nil, nil, result, false, g.Verbose) + return g.SendPayload(http.MethodGet, path, nil, nil, result, false, false, g.Verbose) } // CancelAllExistingOrders all orders for a given symbol and side @@ -484,6 +484,7 @@ func (g *Gateio) SendAuthenticatedHTTPRequest(method, endpoint, param string, re strings.NewReader(param), &intermidiary, true, + false, g.Verbose) if err != nil { return err diff --git a/exchanges/gemini/gemini.go b/exchanges/gemini/gemini.go index 228b998a..13e9da76 100644 --- a/exchanges/gemini/gemini.go +++ b/exchanges/gemini/gemini.go @@ -490,7 +490,7 @@ func (g *Gemini) PostHeartbeat() (string, error) { // SendHTTPRequest sends an unauthenticated request func (g *Gemini) SendHTTPRequest(path string, result interface{}) error { - return g.SendPayload(http.MethodGet, path, nil, nil, result, false, g.Verbose) + return g.SendPayload(http.MethodGet, path, nil, nil, result, false, false, g.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the @@ -503,7 +503,7 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st headers := make(map[string]string) req := make(map[string]interface{}) req["request"] = fmt.Sprintf("/v%s/%s", geminiAPIVersion, path) - req["nonce"] = g.Nonce.GetValue(g.Name, false) + req["nonce"] = g.Requester.GetNonce(true).String() for key, value := range params { req[key] = value @@ -528,7 +528,7 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st headers["X-GEMINI-SIGNATURE"] = common.HexEncodeToString(hmac) headers["Cache-Control"] = "no-cache" - return g.SendPayload(method, g.APIUrl+"/v1/"+path, headers, strings.NewReader(""), result, true, g.Verbose) + return g.SendPayload(method, g.APIUrl+"/v1/"+path, headers, strings.NewReader(""), result, true, false, g.Verbose) } // GetFee returns an estimate of fee based on type of transaction diff --git a/exchanges/hitbtc/hitbtc.go b/exchanges/hitbtc/hitbtc.go index 134e4a6a..5ddb1928 100644 --- a/exchanges/hitbtc/hitbtc.go +++ b/exchanges/hitbtc/hitbtc.go @@ -591,7 +591,7 @@ func (h *HitBTC) TransferBalance(currency, from, to string, amount float64) (boo // SendHTTPRequest sends an unauthenticated HTTP request func (h *HitBTC) SendHTTPRequest(path string, result interface{}) error { - return h.SendPayload(http.MethodGet, path, nil, nil, result, false, h.Verbose) + return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated http request @@ -611,6 +611,7 @@ func (h *HitBTC) SendAuthenticatedHTTPRequest(method, endpoint string, values ur bytes.NewBufferString(values.Encode()), result, true, + false, h.Verbose) } diff --git a/exchanges/huobi/huobi.go b/exchanges/huobi/huobi.go index 02f17d0b..badef447 100644 --- a/exchanges/huobi/huobi.go +++ b/exchanges/huobi/huobi.go @@ -831,7 +831,7 @@ func (h *HUOBI) CancelWithdraw(withdrawID int64) (int64, error) { // SendHTTPRequest sends an unauthenticated HTTP request func (h *HUOBI) SendHTTPRequest(path string, result interface{}) error { - return h.SendPayload(http.MethodGet, path, nil, nil, result, false, h.Verbose) + return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose) } // SendAuthenticatedHTTPRequest sends authenticated requests to the HUOBI API @@ -908,7 +908,7 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url body = encoded } - return h.SendPayload(method, urlPath, headers, bytes.NewReader(body), result, true, h.Verbose) + return h.SendPayload(method, urlPath, headers, bytes.NewReader(body), result, true, false, h.Verbose) } // GetFee returns an estimate of fee based on type of transaction diff --git a/exchanges/huobihadax/huobihadax.go b/exchanges/huobihadax/huobihadax.go index 788b038c..3d0ba8a5 100644 --- a/exchanges/huobihadax/huobihadax.go +++ b/exchanges/huobihadax/huobihadax.go @@ -826,7 +826,7 @@ func (h *HUOBIHADAX) CancelWithdraw(withdrawID int64) (int64, error) { // SendHTTPRequest sends an unauthenticated HTTP request func (h *HUOBIHADAX) SendHTTPRequest(path string, result interface{}) error { - return h.SendPayload(http.MethodGet, path, nil, nil, result, false, h.Verbose) + return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose) } // SendAuthenticatedHTTPPostRequest sends authenticated requests to the HUOBI API @@ -853,7 +853,7 @@ func (h *HUOBIHADAX) SendAuthenticatedHTTPPostRequest(method, endpoint, postBody signatureParams.Set("Signature", common.Base64Encode(hmac)) urlPath := common.EncodeURLValues(fmt.Sprintf("%s%s", h.APIUrl, endpoint), signatureParams) - return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(postBodyValues), result, true, h.Verbose) + return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(postBodyValues), result, true, false, h.Verbose) } // SendAuthenticatedHTTPRequest sends authenticated requests to the HUOBI API @@ -879,7 +879,7 @@ func (h *HUOBIHADAX) SendAuthenticatedHTTPRequest(method, endpoint string, value urlPath := common.EncodeURLValues(fmt.Sprintf("%s%s", h.APIUrl, endpoint), values) - return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(""), result, true, h.Verbose) + return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(""), result, true, false, h.Verbose) } // GetFee returns an estimate of fee based on type of transaction diff --git a/exchanges/itbit/itbit.go b/exchanges/itbit/itbit.go index 87795d43..200f7df9 100644 --- a/exchanges/itbit/itbit.go +++ b/exchanges/itbit/itbit.go @@ -343,7 +343,7 @@ func (i *ItBit) WalletTransfer(walletID, sourceWallet, destWallet string, amount // SendHTTPRequest sends an unauthenticated HTTP request func (i *ItBit) SendHTTPRequest(path string, result interface{}) error { - return i.SendPayload(http.MethodGet, path, nil, nil, result, false, i.Verbose) + return i.SendPayload(http.MethodGet, path, nil, nil, result, false, false, i.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated request to itBit @@ -377,22 +377,22 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method, path string, params map[str } } - nonce := i.Nonce.GetValue(i.Name, false).String() + n := i.Requester.GetNonce(true).String() timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10) - message, err := common.JSONEncode([]string{method, urlPath, string(PayloadJSON), nonce, timestamp}) + message, err := common.JSONEncode([]string{method, urlPath, string(PayloadJSON), n, timestamp}) if err != nil { return err } - hash := common.GetSHA256([]byte(nonce + string(message))) + hash := common.GetSHA256([]byte(n + string(message))) hmac := common.GetHMAC(common.HashSHA512, []byte(urlPath+string(hash)), []byte(i.APISecret)) signature := common.Base64Encode(hmac) headers := make(map[string]string) headers["Authorization"] = i.ClientID + ":" + signature headers["X-Auth-Timestamp"] = timestamp - headers["X-Auth-Nonce"] = nonce + headers["X-Auth-Nonce"] = n headers["Content-Type"] = "application/json" var intermediary json.RawMessage @@ -403,7 +403,7 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method, path string, params map[str RequestID string `json:"requestId"` }{} - err = i.SendPayload(method, urlPath, headers, bytes.NewBuffer(PayloadJSON), &intermediary, true, i.Verbose) + err = i.SendPayload(method, urlPath, headers, bytes.NewBuffer(PayloadJSON), &intermediary, true, true, i.Verbose) if err != nil { return err } diff --git a/exchanges/kraken/kraken.go b/exchanges/kraken/kraken.go index 9acb943a..fdf7b714 100644 --- a/exchanges/kraken/kraken.go +++ b/exchanges/kraken/kraken.go @@ -926,7 +926,7 @@ func GetError(apiErrors []string) error { // SendHTTPRequest sends an unauthenticated HTTP requests func (k *Kraken) SendHTTPRequest(path string, result interface{}) error { - return k.SendPayload(http.MethodGet, path, nil, nil, result, false, k.Verbose) + return k.SendPayload(http.MethodGet, path, nil, nil, result, false, false, k.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated HTTP request @@ -937,13 +937,9 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values, } path := fmt.Sprintf("/%s/private/%s", krakenAPIVersion, method) - if k.Nonce.Get() == 0 { - k.Nonce.Set(time.Now().UnixNano()) - } else { - k.Nonce.Inc() - } - params.Set("nonce", k.Nonce.String()) + n := k.Requester.GetNonce(true).String() + params.Set("nonce", n) secret, err := common.Base64Decode(k.APISecret) if err != nil { @@ -972,6 +968,7 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values, strings.NewReader(encoded), result, true, + true, k.Verbose) } diff --git a/exchanges/kraken/kraken_types.go b/exchanges/kraken/kraken_types.go index eb62d7fd..cd245fdc 100644 --- a/exchanges/kraken/kraken_types.go +++ b/exchanges/kraken/kraken_types.go @@ -410,7 +410,7 @@ type WebsocketSubscriptionData struct { Depth int64 `json:"depth,omitempty"` // Optional - depth associated with book subscription in number of levels each side, default 10. Valid Options are: 10, 25, 100, 500, 1000 } -// WebsocketDataResponse holds all data response types +// WebsocketEventResponse holds all data response types type WebsocketEventResponse struct { Event string `json:"event"` Status string `json:"status"` @@ -422,26 +422,32 @@ type WebsocketEventResponse struct { WebsocketErrorResponse } +// WebsocketSubscriptionEventResponse defines a websocket socket event response type WebsocketSubscriptionEventResponse struct { ChannelID int64 `json:"channelID"` } +// WebsocketSubscriptionResponseData defines a websocket subscription response type WebsocketSubscriptionResponseData struct { Name string `json:"name"` } +// WebsocketStatusResponse defines a websocket status response type WebsocketStatusResponse struct { ConnectionID float64 `json:"connectionID"` Version string `json:"version"` } +// WebsocketDataResponse defines a websocket data type type WebsocketDataResponse []interface{} +// WebsocketErrorResponse defines a websocket error response type WebsocketErrorResponse struct { ErrorMessage string `json:"errorMessage"` } -// Holds relevant data for channels to identify what we're doing +// WebsocketChannelData Holds relevant data for channels to identify what we're +// doing type WebsocketChannelData struct { Subscription string Pair currency.Pair diff --git a/exchanges/kraken/kraken_websocket.go b/exchanges/kraken/kraken_websocket.go index facd125a..20eee9e3 100644 --- a/exchanges/kraken/kraken_websocket.go +++ b/exchanges/kraken/kraken_websocket.go @@ -267,7 +267,7 @@ func (k *Kraken) WsHandleDataResponse(response WebsocketDataResponse) { } } -// WsHandleDataResponse classifies the WS response and sends to appropriate handler +// WsHandleEventResponse classifies the WS response and sends to appropriate handler func (k *Kraken) WsHandleEventResponse(response *WebsocketEventResponse) { switch response.Event { case krakenWsHeartbeat: @@ -391,7 +391,7 @@ func getSubscriptionChannelData(id int64) WebsocketChannelData { return WebsocketChannelData{} } -// resubscribeToChannel will attempt to unsubscribe and resubscribe to a channel +// ResubscribeToChannel will attempt to unsubscribe and resubscribe to a channel func (k *Kraken) ResubscribeToChannel(channel string, pair currency.Pair) { // Kraken WS formats pairs with / but config and REST use - formattedPair := strings.ToUpper(strings.Replace(pair.String(), "-", "/", 1)) diff --git a/exchanges/lakebtc/lakebtc.go b/exchanges/lakebtc/lakebtc.go index 80452e18..caec611d 100644 --- a/exchanges/lakebtc/lakebtc.go +++ b/exchanges/lakebtc/lakebtc.go @@ -334,7 +334,7 @@ func (l *LakeBTC) CreateWithdraw(amount float64, accountID string) (Withdraw, er // SendHTTPRequest sends an unauthenticated http request func (l *LakeBTC) SendHTTPRequest(path string, result interface{}) error { - return l.SendPayload(http.MethodGet, path, nil, nil, result, false, l.Verbose) + return l.SendPayload(http.MethodGet, path, nil, nil, result, false, false, l.Verbose) } // SendAuthenticatedHTTPRequest sends an autheticated HTTP request to a LakeBTC @@ -343,13 +343,9 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name) } - if l.Nonce.Get() == 0 { - l.Nonce.Set(time.Now().UnixNano()) - } else { - l.Nonce.Inc() - } + n := l.Requester.GetNonce(true).String() - req := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s", l.Nonce.String(), l.APIKey, method, params) + req := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s", n, l.APIKey, method, params) hmac := common.GetHMAC(common.HashSHA1, []byte(req), []byte(l.APISecret)) if l.Verbose { @@ -371,7 +367,7 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int headers["Authorization"] = "Basic " + common.Base64Encode([]byte(l.APIKey+":"+common.HexEncodeToString(hmac))) headers["Content-Type"] = "application/json-rpc" - return l.SendPayload(http.MethodPost, l.APIUrl, headers, strings.NewReader(string(data)), result, true, l.Verbose) + return l.SendPayload(http.MethodPost, l.APIUrl, headers, strings.NewReader(string(data)), result, true, true, l.Verbose) } // GetFee returns an estimate of fee based on type of transaction diff --git a/exchanges/localbitcoins/localbitcoins.go b/exchanges/localbitcoins/localbitcoins.go index 4606333a..172fee20 100644 --- a/exchanges/localbitcoins/localbitcoins.go +++ b/exchanges/localbitcoins/localbitcoins.go @@ -726,7 +726,7 @@ func (l *LocalBitcoins) GetOrderbook(currency string) (Orderbook, error) { // SendHTTPRequest sends an unauthenticated HTTP request func (l *LocalBitcoins) SendHTTPRequest(path string, result interface{}) error { - return l.SendPayload(http.MethodGet, path, nil, nil, result, false, l.Verbose) + return l.SendPayload(http.MethodGet, path, nil, nil, result, false, false, l.Verbose) } // SendAuthenticatedHTTPRequest sends an authenticated HTTP request to @@ -736,19 +736,15 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, params return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name) } - if l.Nonce.Get() == 0 { - l.Nonce.Set(time.Now().UnixNano()) - } else { - l.Nonce.Inc() - } + n := l.Requester.GetNonce(true).String() path = "/api/" + path encoded := params.Encode() - message := l.Nonce.String() + l.APIKey + path + encoded + message := n + l.APIKey + path + encoded hmac := common.GetHMAC(common.HashSHA256, []byte(message), []byte(l.APISecret)) headers := make(map[string]string) headers["Apiauth-Key"] = l.APIKey - headers["Apiauth-Nonce"] = l.Nonce.String() + headers["Apiauth-Nonce"] = n headers["Apiauth-Signature"] = common.StringToUpper(common.HexEncodeToString(hmac)) headers["Content-Type"] = "application/x-www-form-urlencoded" @@ -760,7 +756,7 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, params path += "?" + encoded } - return l.SendPayload(method, l.APIUrl+path, headers, strings.NewReader(encoded), result, true, l.Verbose) + return l.SendPayload(method, l.APIUrl+path, headers, strings.NewReader(encoded), result, true, true, l.Verbose) } // GetFee returns an estimate of fee based on type of transaction diff --git a/exchanges/nonce/nonce.go b/exchanges/nonce/nonce.go index 7f9bf964..2a863a16 100644 --- a/exchanges/nonce/nonce.go +++ b/exchanges/nonce/nonce.go @@ -2,18 +2,12 @@ package nonce import ( "strconv" - "sync" "sync/atomic" - "time" ) // Nonce struct holds the nonce value type Nonce struct { - // Standard nonce n int64 - // Hash table exclusive exchange specific nonce values - boundedCall map[string]int64 - boundedMtx sync.Mutex } // Inc increments the nonce value @@ -22,12 +16,12 @@ func (n *Nonce) Inc() { } // Get retrives the nonce value -func (n *Nonce) Get() int64 { - return atomic.LoadInt64(&n.n) +func (n *Nonce) Get() Value { + return Value(atomic.LoadInt64(&n.n)) } // GetInc increments and returns the value of the nonce -func (n *Nonce) GetInc() int64 { +func (n *Nonce) GetInc() Value { n.Inc() return n.Get() } @@ -39,34 +33,12 @@ func (n *Nonce) Set(val int64) { // String returns a string version of the nonce func (n *Nonce) String() string { - return strconv.FormatInt(n.Get(), 10) + return n.Get().String() } // Value is a return type for GetValue type Value int64 -// GetValue returns a nonce value and can be set as a higher precision. Values -// stored in an exchange specific hash table using a single locked call. -func (n *Nonce) GetValue(exchName string, nanoPrecision bool) Value { - n.boundedMtx.Lock() - defer n.boundedMtx.Unlock() - - if n.boundedCall == nil { - n.boundedCall = make(map[string]int64) - } - - if n.boundedCall[exchName] == 0 { - if nanoPrecision { - n.boundedCall[exchName] = time.Now().UnixNano() - return Value(n.boundedCall[exchName]) - } - n.boundedCall[exchName] = time.Now().Unix() - return Value(n.boundedCall[exchName]) - } - n.boundedCall[exchName]++ - return Value(n.boundedCall[exchName]) -} - // String is a Value method that changes format to a string func (v Value) String() string { return strconv.FormatInt(int64(v), 10) diff --git a/exchanges/nonce/nonce_test.go b/exchanges/nonce/nonce_test.go index e93968a8..a4923bed 100644 --- a/exchanges/nonce/nonce_test.go +++ b/exchanges/nonce/nonce_test.go @@ -1,7 +1,6 @@ package nonce import ( - "strconv" "testing" "time" ) @@ -10,7 +9,7 @@ func TestInc(t *testing.T) { var nonce Nonce nonce.Set(1) nonce.Inc() - expected := int64(2) + expected := Value(2) result := nonce.Get() if result != expected { t.Errorf("Test failed. Expected %d got %d", expected, result) @@ -20,7 +19,7 @@ func TestInc(t *testing.T) { func TestGet(t *testing.T) { var nonce Nonce nonce.Set(112321313) - expected := int64(112321313) + expected := Value(112321313) result := nonce.Get() if expected != result { t.Errorf("Test failed. Expected %d got %d", expected, result) @@ -30,7 +29,7 @@ func TestGet(t *testing.T) { func TestGetInc(t *testing.T) { var nonce Nonce nonce.Set(1) - expected := int64(2) + expected := Value(2) result := nonce.GetInc() if expected != result { t.Errorf("Test failed. Expected %d got %d", expected, result) @@ -40,7 +39,7 @@ func TestGetInc(t *testing.T) { func TestSet(t *testing.T) { var nonce Nonce nonce.Set(1) - expected := int64(1) + expected := Value(1) result := nonce.Get() if expected != result { t.Errorf("Test failed. Expected %d got %d", expected, result) @@ -55,30 +54,10 @@ func TestString(t *testing.T) { if expected != result { t.Errorf("Test failed. Expected %s got %s", expected, result) } -} -func TestGetValue(t *testing.T) { - var nonce Nonce - timeNowNano := strconv.FormatInt(time.Now().UnixNano(), 10) - time.Sleep(time.Millisecond * 100) - nValue := nonce.GetValue("dingdong", true).String() - - if timeNowNano == nValue { - t.Error("Test failed - GetValue() error, incorrect values") - } - - if len(nValue) != 19 { - t.Error("Test failed - GetValue() error, incorrect values") - } - - timeNowUnix := nonce.GetValue("dongding", false) - if len(timeNowUnix.String()) != 10 { - t.Error("Test failed - GetValue() error, incorrect values") - } - - n := nonce.GetValue("dongding", false) - if n != timeNowUnix+1 { - t.Error("Test failed - GetValue() error, incorrect values") + v := nonce.Get() + if expected != v.String() { + t.Errorf("Test failed. Expected %s got %s", expected, result) } } @@ -94,7 +73,7 @@ func TestNonceConcurrency(t *testing.T) { time.Sleep(time.Second) result := nonce.Get() - expected := int64(12312 + 1000) + expected := Value(12312 + 1000) if expected != result { t.Errorf("Test failed. Expected %d got %d", expected, result) } diff --git a/exchanges/okgroup/okgroup.go b/exchanges/okgroup/okgroup.go index aa61a5a6..1f255e81 100644 --- a/exchanges/okgroup/okgroup.go +++ b/exchanges/okgroup/okgroup.go @@ -632,7 +632,7 @@ func (o *OKGroup) SendHTTPRequest(httpMethod, requestType, requestPath string, d errCap := errCapFormat{} errCap.Result = true - err = o.SendPayload(strings.ToUpper(httpMethod), path, headers, bytes.NewBuffer(payload), &intermediary, authenticated, o.Verbose) + err = o.SendPayload(strings.ToUpper(httpMethod), path, headers, bytes.NewBuffer(payload), &intermediary, authenticated, false, o.Verbose) if err != nil { return err } diff --git a/exchanges/poloniex/poloniex.go b/exchanges/poloniex/poloniex.go index 8d1c4cd5..d4c6574d 100644 --- a/exchanges/poloniex/poloniex.go +++ b/exchanges/poloniex/poloniex.go @@ -2,6 +2,7 @@ package poloniex import ( "bytes" + "encoding/json" "errors" "fmt" "net/http" @@ -479,14 +480,21 @@ func (p *Poloniex) GetAuthenticatedTradeHistory(start, end, limit int64) (Authen } values.Set("currencyPair", "all") - var result AuthenticatedTradeHistoryAll + var result json.RawMessage - err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexTradeHistory, values, &result.Data) + err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexTradeHistory, values, &result) if err != nil { return AuthenticatedTradeHistoryAll{}, err } - return result, nil + var nodata []interface{} + err = json.Unmarshal(result, &nodata) + if err == nil { + return AuthenticatedTradeHistoryAll{}, nil + } + + var mainResult AuthenticatedTradeHistoryAll + return mainResult, json.Unmarshal(result, &mainResult.Data) } // PlaceOrder places a new order on the exchange @@ -856,6 +864,7 @@ func (p *Poloniex) SendHTTPRequest(path string, result interface{}) error { nil, result, false, + false, p.Verbose) } @@ -869,13 +878,9 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values headers["Content-Type"] = "application/x-www-form-urlencoded" headers["Key"] = p.APIKey - if p.Nonce.Get() == 0 { - p.Nonce.Set(time.Now().UnixNano()) - } else { - p.Nonce.Inc() - } + n := p.Requester.GetNonce(true).String() - values.Set("nonce", p.Nonce.String()) + values.Set("nonce", n) values.Set("command", endpoint) hmac := common.GetHMAC(common.HashSHA512, @@ -892,6 +897,7 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values bytes.NewBufferString(values.Encode()), result, true, + true, p.Verbose) } diff --git a/exchanges/poloniex/poloniex_test.go b/exchanges/poloniex/poloniex_test.go index bb273932..7c80c5f1 100644 --- a/exchanges/poloniex/poloniex_test.go +++ b/exchanges/poloniex/poloniex_test.go @@ -19,25 +19,27 @@ const ( canManipulateRealOrders = false ) -func TestSetDefaults(t *testing.T) { - p.SetDefaults() -} +var isSetup bool func TestSetup(t *testing.T) { - cfg := config.GetConfig() - cfg.LoadConfig("../../testdata/configtest.json") - poloniexConfig, err := cfg.GetExchangeConfig("Poloniex") - if err != nil { - t.Error("Test Failed - Poloniex Setup() init error") + if !isSetup { + cfg := config.GetConfig() + cfg.LoadConfig("../../testdata/configtest.json") + poloniexConfig, err := cfg.GetExchangeConfig("Poloniex") + if err != nil { + t.Error("Test Failed - Poloniex Setup() init error") + } + poloniexConfig.AuthenticatedAPISupport = true + poloniexConfig.APIKey = apiKey + poloniexConfig.APISecret = apiSecret + p.SetDefaults() + p.Setup(&poloniexConfig) + isSetup = true } - poloniexConfig.AuthenticatedAPISupport = true - poloniexConfig.APIKey = apiKey - poloniexConfig.APISecret = apiSecret - - p.Setup(&poloniexConfig) } func TestGetTicker(t *testing.T) { + t.Parallel() _, err := p.GetTicker() if err != nil { t.Error("Test faild - Poloniex GetTicker() error") @@ -45,6 +47,7 @@ func TestGetTicker(t *testing.T) { } func TestGetVolume(t *testing.T) { + t.Parallel() _, err := p.GetVolume() if err != nil { t.Error("Test faild - Poloniex GetVolume() error") @@ -52,6 +55,7 @@ func TestGetVolume(t *testing.T) { } func TestGetOrderbook(t *testing.T) { + t.Parallel() _, err := p.GetOrderbook("BTC_XMR", 50) if err != nil { t.Error("Test faild - Poloniex GetOrderbook() error", err) @@ -59,6 +63,7 @@ func TestGetOrderbook(t *testing.T) { } func TestGetTradeHistory(t *testing.T) { + t.Parallel() _, err := p.GetTradeHistory("BTC_XMR", "", "") if err != nil { t.Error("Test faild - Poloniex GetTradeHistory() error", err) @@ -66,6 +71,7 @@ func TestGetTradeHistory(t *testing.T) { } func TestGetChartData(t *testing.T) { + t.Parallel() _, err := p.GetChartData("BTC_XMR", "1405699200", "1405699400", "300") if err != nil { t.Error("Test faild - Poloniex GetChartData() error", err) @@ -73,6 +79,7 @@ func TestGetChartData(t *testing.T) { } func TestGetCurrencies(t *testing.T) { + t.Parallel() _, err := p.GetCurrencies() if err != nil { t.Error("Test faild - Poloniex GetCurrencies() error", err) @@ -80,6 +87,7 @@ func TestGetCurrencies(t *testing.T) { } func TestGetLoanOrders(t *testing.T) { + t.Parallel() _, err := p.GetLoanOrders("BTC") if err != nil { t.Error("Test faild - Poloniex GetLoanOrders() error", err) @@ -101,6 +109,7 @@ func setFeeBuilder() *exchange.FeeBuilder { // TestGetFeeByTypeOfflineTradeFee logic test func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + t.Parallel() var feeBuilder = setFeeBuilder() p.GetFeeByType(feeBuilder) if apiKey == "" || apiSecret == "" { @@ -115,7 +124,7 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { } func TestGetFee(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) var feeBuilder = setFeeBuilder() @@ -135,14 +144,6 @@ func TestGetFee(t *testing.T) { t.Error(err) } - // CryptocurrencyTradeFee IsMaker - feeBuilder = setFeeBuilder() - feeBuilder.IsMaker = true - if resp, err := p.GetFee(feeBuilder); resp != float64(0.001) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp) - t.Error(err) - } - // CryptocurrencyTradeFee Negative purchase price feeBuilder = setFeeBuilder() feeBuilder.PurchasePrice = -1000 @@ -195,7 +196,8 @@ func TestGetFee(t *testing.T) { } func TestFormatWithdrawPermissions(t *testing.T) { - p.SetDefaults() + t.Parallel() + TestSetup(t) expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText + " & " + exchange.NoFiatWithdrawalsText withdrawPermissions := p.FormatWithdrawPermissions() @@ -206,7 +208,7 @@ func TestFormatWithdrawPermissions(t *testing.T) { } func TestGetActiveOrders(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) var getOrdersRequest = exchange.GetOrdersRequest{ @@ -222,7 +224,7 @@ func TestGetActiveOrders(t *testing.T) { } func TestGetOrderHistory(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) var getOrdersRequest = exchange.GetOrdersRequest{ @@ -248,7 +250,7 @@ func areTestAPIKeysSet() bool { } func TestSubmitOrder(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) if areTestAPIKeysSet() && !canManipulateRealOrders { @@ -276,7 +278,7 @@ func TestSubmitOrder(t *testing.T) { } func TestCancelExchangeOrder(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) if areTestAPIKeysSet() && !canManipulateRealOrders { @@ -303,7 +305,7 @@ func TestCancelExchangeOrder(t *testing.T) { } func TestCancelAllExchangeOrders(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) if areTestAPIKeysSet() && !canManipulateRealOrders { @@ -334,6 +336,7 @@ func TestCancelAllExchangeOrders(t *testing.T) { } func TestModifyOrder(t *testing.T) { + t.Parallel() _, err := p.ModifyOrder(&exchange.ModifyOrder{OrderID: "1337", Price: 1337}) if err == nil { t.Error("Test Failed - ModifyOrder() error") @@ -341,7 +344,7 @@ func TestModifyOrder(t *testing.T) { } func TestWithdraw(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) var withdrawCryptoRequest = exchange.WithdrawRequest{ Amount: 100, @@ -364,7 +367,7 @@ func TestWithdraw(t *testing.T) { } func TestWithdrawFiat(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) if areTestAPIKeysSet() && !canManipulateRealOrders { @@ -380,7 +383,7 @@ func TestWithdrawFiat(t *testing.T) { } func TestWithdrawInternationalBank(t *testing.T) { - p.SetDefaults() + t.Parallel() TestSetup(t) if areTestAPIKeysSet() && !canManipulateRealOrders { @@ -396,6 +399,9 @@ func TestWithdrawInternationalBank(t *testing.T) { } func TestGetDepositAddress(t *testing.T) { + t.Parallel() + TestSetup(t) + if areTestAPIKeysSet() { _, err := p.GetDepositAddress(currency.DASH, "") if err != nil { diff --git a/exchanges/poloniex/poloniex_types.go b/exchanges/poloniex/poloniex_types.go index cdb574ec..c4faae61 100644 --- a/exchanges/poloniex/poloniex_types.go +++ b/exchanges/poloniex/poloniex_types.go @@ -163,8 +163,8 @@ type OpenOrdersResponse struct { Data []Order } -// AuthentictedTradeHistory holds client trade history information -type AuthentictedTradeHistory struct { +// AuthenticatedTradeHistory holds client trade history information +type AuthenticatedTradeHistory struct { GlobalTradeID int64 `json:"globalTradeID"` TradeID int64 `json:"tradeID,string"` Date string `json:"date"` @@ -179,12 +179,12 @@ type AuthentictedTradeHistory struct { // AuthenticatedTradeHistoryAll holds the full client trade history type AuthenticatedTradeHistoryAll struct { - Data map[string][]AuthentictedTradeHistory + Data map[string][]AuthenticatedTradeHistory } // AuthenticatedTradeHistoryResponse is a response type for trade history type AuthenticatedTradeHistoryResponse struct { - Data []AuthentictedTradeHistory + Data []AuthenticatedTradeHistory } // ResultingTrades holds resultant trade information diff --git a/exchanges/request/request.go b/exchanges/request/request.go index 2454ef16..fa37c015 100644 --- a/exchanges/request/request.go +++ b/exchanges/request/request.go @@ -13,6 +13,7 @@ import ( "time" "github.com/thrasher-/gocryptotrader/common" + "github.com/thrasher-/gocryptotrader/exchanges/nonce" log "github.com/thrasher-/gocryptotrader/logger" ) @@ -36,7 +37,10 @@ type Requester struct { timeoutRetryAttempts int m sync.Mutex Jobs chan Job + disengage chan struct{} WorkerStarted bool + Nonce nonce.Nonce + fifoLock sync.Mutex } // RateLimit struct @@ -214,6 +218,7 @@ func New(name string, authLimit, unauthLimit *RateLimit, httpRequester *http.Cli AuthLimit: authLimit, Name: name, Jobs: make(chan Job, maxRequestJobs), + disengage: make(chan struct{}, 1), timeoutRetryAttempts: defaultTimeoutRetryAttempts, } } @@ -391,29 +396,39 @@ func (r *Requester) worker() { } // SendPayload handles sending HTTP/HTTPS requests -func (r *Requester) SendPayload(method, path string, headers map[string]string, body io.Reader, result interface{}, authRequest, verbose bool) error { +func (r *Requester) SendPayload(method, path string, headers map[string]string, body io.Reader, result interface{}, authRequest, nonceEnabled, verbose bool) error { + if !nonceEnabled { + r.lock() + } + if r == nil || r.Name == "" { + r.unlock() return errors.New("not initiliased, SetDefaults() called before making request?") } if !IsValidMethod(method) { + r.unlock() return fmt.Errorf("incorrect method supplied %s: supported %s", method, supportedMethods) } if path == "" { + r.unlock() return errors.New("invalid path") } req, err := r.checkRequest(method, path, body, headers) if err != nil { + r.unlock() return err } if !r.RequiresRateLimiter() { + r.unlock() return r.DoRequest(req, path, body, result, authRequest, verbose) } if len(r.Jobs) == maxRequestJobs { + r.unlock() return errors.New("max request jobs reached") } @@ -443,6 +458,7 @@ func (r *Requester) SendPayload(method, path string, headers map[string]string, log.Debugf("%s request. Attaching new job.", r.Name) } r.Jobs <- newJob + r.unlock() if verbose { log.Debugf("%s request. Waiting for job to complete.", r.Name) @@ -455,6 +471,34 @@ func (r *Requester) SendPayload(method, path string, headers map[string]string, return resp.Error } +// GetNonce returns a nonce for requests. This locks and enforces concurrent +// nonce FIFO on the buffered job channel +func (r *Requester) GetNonce(isNano bool) nonce.Value { + r.lock() + if r.Nonce.Get() == 0 { + if isNano { + r.Nonce.Set(time.Now().UnixNano()) + } else { + r.Nonce.Set(time.Now().Unix()) + } + return r.Nonce.Get() + } + r.Nonce.Inc() + return r.Nonce.Get() +} + +// GetNonceMilli returns a nonce for requests. This locks and enforces concurrent +// nonce FIFO on the buffered job channel this is for millisecond +func (r *Requester) GetNonceMilli() nonce.Value { + r.lock() + if r.Nonce.Get() == 0 { + r.Nonce.Set(time.Now().UnixNano() / int64(time.Millisecond)) + return r.Nonce.Get() + } + r.Nonce.Inc() + return r.Nonce.Get() +} + // SetProxy sets a proxy address to the client transport func (r *Requester) SetProxy(p *url.URL) error { if p.String() == "" { @@ -467,3 +511,33 @@ func (r *Requester) SetProxy(p *url.URL) error { } return nil } + +// lock locks and sets up an issue timer, if something errors out of scope it +// automatically unlocks +func (r *Requester) lock() { + if r.disengage == nil { + r.disengage = make(chan struct{}, 1) + } + var wg sync.WaitGroup + r.fifoLock.Lock() + wg.Add(1) + go func() { + timer := time.NewTimer(50 * time.Millisecond) + wg.Done() + select { + case <-timer.C: + log.Errorf("Unlocking due to possible error for %s", r.Name) + r.fifoLock.Unlock() + + case <-r.disengage: + return + } + }() + wg.Wait() +} + +// unlock unlocks mtx and shuts down a timer +func (r *Requester) unlock() { + r.disengage <- struct{}{} + r.fifoLock.Unlock() +} diff --git a/exchanges/request/request_test.go b/exchanges/request/request_test.go index 0cbed585..bf8f8901 100644 --- a/exchanges/request/request_test.go +++ b/exchanges/request/request_test.go @@ -199,8 +199,8 @@ func TestCheckRequest(t *testing.T) { } func TestDoRequest(t *testing.T) { - var test *Requester - err := test.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, true) + var test = new(Requester) + err := test.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true) if err == nil { t.Fatal("not iniitalised") } @@ -211,17 +211,17 @@ func TestDoRequest(t *testing.T) { } r.Name = "bitfinex" - err = r.SendPayload("BLAH", "https://www.google.com", nil, nil, nil, false, true) + err = r.SendPayload("BLAH", "https://www.google.com", nil, nil, nil, false, false, true) if err == nil { t.Fatal("unexpected values") } - err = r.SendPayload(http.MethodGet, "", nil, nil, nil, false, true) + err = r.SendPayload(http.MethodGet, "", nil, nil, nil, false, false, true) if err == nil { t.Fatal("unexpected values") } - err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, true) + err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true) if err != nil { t.Fatal("unexpected values") } @@ -233,7 +233,7 @@ func TestDoRequest(t *testing.T) { r.SetRateLimit(false, time.Second, 0) r.SetRateLimit(true, time.Second, 0) - err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, true) + err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true) if err != nil { t.Fatal("unexpected values") } @@ -250,7 +250,7 @@ func TestDoRequest(t *testing.T) { t.Fatal("unexepcted values") } - err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, true) + err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true) if err != nil { t.Fatal("unexpected values") } @@ -261,27 +261,27 @@ func TestDoRequest(t *testing.T) { t.Fatal("unexepcted values") } - err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, true, true) + err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, true, false, true) if err != nil { t.Fatal("unexpected values") } var result interface{} - err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, true) + err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false, true) if err != nil { t.Fatal(err) } headers := make(map[string]string) headers["content-type"] = "content/text" - err = r.SendPayload(http.MethodPost, "https://bitfinex.com", headers, nil, result, false, true) + err = r.SendPayload(http.MethodPost, "https://bitfinex.com", headers, nil, result, false, false, true) if err != nil { t.Fatal(err) } r.StartCycle() r.UnauthLimit.SetRequests(100) - err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false) + err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false, false) if err != nil { t.Fatal("unexpected values") } @@ -297,7 +297,7 @@ func TestDoRequest(t *testing.T) { } r.HTTPClient.Timeout = 1 * time.Second - err = r.SendPayload(http.MethodPost, "https://httpstat.us/200?sleep=20000", nil, nil, nil, false, true) + err = r.SendPayload(http.MethodPost, "https://httpstat.us/200?sleep=20000", nil, nil, nil, false, false, true) if err == nil { t.Fatal(err) } @@ -322,3 +322,11 @@ func TestDoRequest(t *testing.T) { t.Error("failed to set proxy") } } + +func BenchmarkRequestLockMech(b *testing.B) { + var r = new(Requester) + var meep interface{} + for n := 0; n < b.N; n++ { + r.SendPayload(http.MethodGet, "127.0.0.1", nil, nil, &meep, false, false, false) + } +} diff --git a/exchanges/yobit/yobit.go b/exchanges/yobit/yobit.go index ba472d13..9626b702 100644 --- a/exchanges/yobit/yobit.go +++ b/exchanges/yobit/yobit.go @@ -336,6 +336,7 @@ func (y *Yobit) SendHTTPRequest(path string, result interface{}) error { nil, result, false, + false, y.Verbose) } @@ -350,12 +351,9 @@ func (y *Yobit) SendAuthenticatedHTTPRequest(path string, params url.Values, res params = url.Values{} } - if y.Nonce.Get() == 0 { - y.Nonce.Set(time.Now().Unix()) - } else { - y.Nonce.Inc() - } - params.Set("nonce", y.Nonce.String()) + n := y.Requester.GetNonce(false).String() + + params.Set("nonce", n) params.Set("method", path) encoded := params.Encode() @@ -381,6 +379,7 @@ func (y *Yobit) SendAuthenticatedHTTPRequest(path string, params url.Values, res strings.NewReader(encoded), result, true, + true, y.Verbose) } diff --git a/exchanges/zb/zb.go b/exchanges/zb/zb.go index 3ffdd1d4..35256f6e 100644 --- a/exchanges/zb/zb.go +++ b/exchanges/zb/zb.go @@ -361,7 +361,7 @@ func (z *ZB) GetCryptoAddress(currency currency.Code) (UserAddress, error) { // SendHTTPRequest sends an unauthenticated HTTP request func (z *ZB) SendHTTPRequest(path string, result interface{}) error { - return z.SendPayload(http.MethodGet, path, nil, nil, result, false, z.Verbose) + return z.SendPayload(http.MethodGet, path, nil, nil, result, false, false, z.Verbose) } // SendAuthenticatedHTTPRequest sends authenticated requests to the zb API @@ -397,6 +397,7 @@ func (z *ZB) SendAuthenticatedHTTPRequest(httpMethod string, params url.Values, strings.NewReader(""), &intermediary, true, + false, z.Verbose) if err != nil { return err diff --git a/exchanges/zb/zb_wrapper.go b/exchanges/zb/zb_wrapper.go index 5cfc81a5..0502f9f6 100644 --- a/exchanges/zb/zb_wrapper.go +++ b/exchanges/zb/zb_wrapper.go @@ -346,7 +346,7 @@ func (z *ZB) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([]exc Amount: order.TotalAmount, Exchange: z.Name, OrderDate: orderDate, - Price: float64(order.Price), + Price: order.Price, OrderSide: orderSide, CurrencyPair: symbol, }) @@ -403,7 +403,7 @@ func (z *ZB) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([]exc Amount: order.TotalAmount, Exchange: z.Name, OrderDate: orderDate, - Price: float64(order.Price), + Price: order.Price, OrderSide: orderSide, CurrencyPair: symbol, }) diff --git a/testdata/configtest.json b/testdata/configtest.json index f9feba93..3730c972 100644 --- a/testdata/configtest.json +++ b/testdata/configtest.json @@ -1319,5 +1319,19 @@ "supportedExchanges": "ANX,Kraken" } ], + "connectionMonitor": { + "preferredDNSList": [ + "8.8.8.8", + "8.8.4.4", + "1.1.1.1", + "1.0.0.1" + ], + "preferredDomainList": [ + "www.google.com", + "www.cloudflare.com", + "www.facebook.com" + ], + "checkInterval": 1000000000 + }, "fiatDispayCurrency": "" } \ No newline at end of file