Skip to content

Commit

Permalink
Dont let BestQuote fail if one miner fails
Browse files Browse the repository at this point in the history
Closes #5
  • Loading branch information
mrz1836 committed Nov 11, 2020
1 parent f93317e commit ebd0130
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 9 deletions.
23 changes: 16 additions & 7 deletions best_quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,40 @@ func (c *Client) BestQuote(feeCategory, feeType string) (*FeeQuoteResponse, erro

// Loop the results of the channel
var testRate uint64
var quoteFound bool
var lastErr error
for result := range resultsChannel {

// Check for error?
if result.Response.Error != nil {
return nil, result.Response.Error
lastErr = result.Response.Error
continue
}

// Parse the response
quote, err := result.parseQuote()
if err != nil {
return nil, err
var quote FeeQuoteResponse
if quote, lastErr = result.parseQuote(); lastErr != nil {
continue
}

// Get a test rate
if testRate, err = quote.Quote.CalculateFee(feeCategory, feeType, 1000); err != nil {
return nil, err
if testRate, lastErr = quote.Quote.CalculateFee(feeCategory, feeType, 1000); lastErr != nil {
continue
}

// Never set (or better)
// (Never set) || (or better than previous rate)
quoteFound = true
if bestRate == 0 || testRate < bestRate {
bestRate = testRate
bestQuote = quote
}
}

// No quotes?
if !quoteFound && lastErr != nil {
return nil, lastErr
}

// Return the best quote found
return &bestQuote, nil
}
98 changes: 97 additions & 1 deletion best_quote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,83 @@ func (m *mockHTTPBadRate) Do(req *http.Request) (*http.Response, error) {
"publicKey": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087","encoding": "` + testEncoding + `","mimetype": "` + testMimeType + `"}`)))
}

if req.URL.String() == defaultProtocol+"www.ddpurse.com/openapi/mapi/feeQuote" {
resp.StatusCode = http.StatusBadRequest
resp.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(``)))
}

// Default is valid
return resp, nil
}

// mockHTTPBestQuoteTwoFailed for mocking requests
type mockHTTPBestQuoteTwoFailed struct{}

// Do is a mock http request
func (m *mockHTTPBestQuoteTwoFailed) Do(req *http.Request) (*http.Response, error) {
resp := new(http.Response)
resp.StatusCode = http.StatusBadRequest

// No req found
if req == nil {
return resp, fmt.Errorf("missing request")
}

// Valid response
if req.URL.String() == defaultProtocol+"merchantapi.taal.com/mapi/feeQuote" {
resp.StatusCode = http.StatusBadRequest
resp.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(``)))
}

if req.URL.String() == defaultProtocol+"merchantapi.matterpool.io/mapi/feeQuote" {
resp.StatusCode = http.StatusBadRequest
resp.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(``)))
}

if req.URL.String() == defaultProtocol+"www.ddpurse.com/openapi/mapi/feeQuote" {
resp.StatusCode = http.StatusOK
resp.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(`{
"payload": "{\"apiVersion\":\"` + testAPIVersion + `\",\"timestamp\":\"2020-10-09T22:09:04.433Z\",\"expiryTime\":\"2020-10-09T22:19:04.433Z\",\"minerId\":null,\"currentHighestBlockHash\":\"0000000000000000028285a9168c95457521a743765f499de389c094e883f42a\",\"currentHighestBlockHeight\":656171,\"minerReputation\":null,\"fees\":[{\"feeType\":\"standard\",\"miningFee\":{\"satoshis\":350,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}},{\"feeType\":\"data\",\"miningFee\":{\"satoshis\":430,\"bytes\":1000},\"relayFee\":{\"satoshis\":175,\"bytes\":1000}}]}",
"payload": "{\"apiVersion\":\"` + testAPIVersion + `\",\"timestamp\":\"2020-10-09T22:09:04.433Z\",\"expiryTime\":\"2020-10-09T22:19:04.433Z\",\"minerId\":null,\"currentHighestBlockHash\":\"0000000000000000028285a9168c95457521a743765f499de389c094e883f42a\",\"currentHighestBlockHeight\":656171,\"minerReputation\":null,\"fees\":[{\"feeType\":\"standard\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}},{\"feeType\":\"data\",\"miningFee\":{\"satoshis\":420,\"bytes\":1000},\"relayFee\":{\"satoshis\":150,\"bytes\":1000}}]}",
"signature": null,"publicKey": null,"encoding": "` + testEncoding + `","mimetype": "` + testMimeType + `"}`)))
}

// Default is valid
return resp, nil
}

// mockHTTPBestQuoteAllFailed for mocking requests
type mockHTTPBestQuoteAllFailed struct{}

// Do is a mock http request
func (m *mockHTTPBestQuoteAllFailed) Do(req *http.Request) (*http.Response, error) {
resp := new(http.Response)
resp.StatusCode = http.StatusBadRequest

// No req found
if req == nil {
return resp, fmt.Errorf("missing request")
}

// Valid response
if req.URL.String() == defaultProtocol+"merchantapi.taal.com/mapi/feeQuote" {
resp.StatusCode = http.StatusBadRequest
resp.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(``)))
}

if req.URL.String() == defaultProtocol+"merchantapi.matterpool.io/mapi/feeQuote" {
resp.StatusCode = http.StatusBadRequest
resp.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(``)))
}

if req.URL.String() == defaultProtocol+"www.ddpurse.com/openapi/mapi/feeQuote" {
resp.StatusCode = http.StatusBadRequest
resp.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(``)))
}

// Default is valid
return resp, nil
}

// TestClient_BestQuote tests the method BestQuote()
func TestClient_BestQuote(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -172,6 +238,36 @@ func TestClient_BestQuote(t *testing.T) {
assert.Error(t, err)
assert.Nil(t, response)
})

t.Run("best quote - two failed", func(t *testing.T) {

// Create a client
client := newTestClient(&mockHTTPBestQuoteTwoFailed{})

// Create a req
response, err := client.BestQuote(FeeCategoryMining, FeeTypeData)
assert.NoError(t, err)
assert.NotNil(t, response)

// Check returned values
assert.Equal(t, testEncoding, response.Encoding)
assert.Equal(t, testMimeType, response.MimeType)

// Check that we got fees
assert.Equal(t, 2, len(response.Quote.Fees))
assert.Equal(t, MinerMempool, response.Miner.Name)
})

t.Run("best quote - all failed", func(t *testing.T) {

// Create a client
client := newTestClient(&mockHTTPBestQuoteAllFailed{})

// Create a req
response, err := client.BestQuote(FeeCategoryMining, FeeTypeData)
assert.Error(t, err)
assert.Nil(t, response)
})
}

// ExampleClient_BestQuote example using BestQuote()
Expand Down
2 changes: 1 addition & 1 deletion fastest_quote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func TestClient_FastestQuote(t *testing.T) {

// Check that we got fees
assert.Equal(t, 2, len(response.Quote.Fees))
assert.Equal(t, response.Miner.Name, MinerMempool)
assert.Equal(t, MinerMempool, response.Miner.Name)
})

}
Expand Down

0 comments on commit ebd0130

Please sign in to comment.