From 72eaf401c40055a158950b8e6606937bf5f0918d Mon Sep 17 00:00:00 2001 From: arkadiuszos4chain Date: Thu, 18 Apr 2024 02:43:01 +0200 Subject: [PATCH 1/7] fix: return failure object --- .../broadcast-client-mock/mock_client_test.go | 8 +-- broadcast/errors.go | 30 ++++++++++++ broadcast/interface.go | 10 ++-- .../acceptance_tests/arc_fee_quote_test.go | 6 +-- .../acceptance_tests/arc_policy_quote_test.go | 6 +-- .../acceptance_tests/arc_query_tx_test.go | 10 ++-- .../acceptance_tests/arc_submit_tx_test.go | 6 +-- broadcast/internal/arc/arc_error.go | 2 +- broadcast/internal/arc/arc_fee_quote.go | 10 ++-- broadcast/internal/arc/arc_policy_quote.go | 8 +-- broadcast/internal/arc/arc_query_tx.go | 9 ++-- broadcast/internal/arc/arc_submit_tx.go | 49 +++++++------------ broadcast/internal/arc/arc_submit_tx_test.go | 6 +-- .../arc/mocks/arc_client_mock_no_response.go | 20 ++++---- .../arc/mocks/arc_client_mock_success.go | 10 ++-- .../arc/mocks/arc_client_mock_timeout.go | 10 ++-- broadcast/internal/arc/mocks/consts.go | 44 ++++++++--------- broadcast/internal/arc/utils/arc_utils.go | 6 --- broadcast/internal/composite/broadcaster.go | 26 +++++----- broadcast/internal/composite/strategy.go | 10 ++-- broadcast/internal/composite/strategy_test.go | 15 ++++-- broadcast/internal/utils/utils.go | 10 ++++ broadcast/transaction.go | 9 +--- 23 files changed, 172 insertions(+), 148 deletions(-) create mode 100644 broadcast/internal/utils/utils.go diff --git a/broadcast/broadcast-client-mock/mock_client_test.go b/broadcast/broadcast-client-mock/mock_client_test.go index 628b711..011603d 100644 --- a/broadcast/broadcast-client-mock/mock_client_test.go +++ b/broadcast/broadcast-client-mock/mock_client_test.go @@ -74,7 +74,7 @@ func TestMockClientSuccess(t *testing.T) { result, err := broadcaster.SubmitTransaction(context.Background(), &broadcast.Transaction{Hex: "test-rawtx"}) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, result.Miner, fixtures.ProviderMain) assert.Equal(t, result.BlockHash, fixtures.TxBlockHash) @@ -101,7 +101,7 @@ func TestMockClientSuccess(t *testing.T) { result, err := broadcaster.SubmitBatchTransactions(context.Background(), []*broadcast.Transaction{{Hex: "test-rawtx"}, {Hex: "test2-rawtx"}}) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, expectedResult, result) }) @@ -263,7 +263,7 @@ func TestMockClientTimeout(t *testing.T) { result, err := broadcaster.SubmitTransaction(ctx, &broadcast.Transaction{Hex: "test-rawtx"}) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Greater(t, time.Since(startTime), defaultTestTime) assert.Equal(t, result.Miner, fixtures.ProviderMain) @@ -294,7 +294,7 @@ func TestMockClientTimeout(t *testing.T) { result, err := broadcaster.SubmitBatchTransactions(ctx, []*broadcast.Transaction{{Hex: "test-rawtx"}, {Hex: "test2-rawtx"}}) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Greater(t, time.Since(startTime), defaultTestTime) assert.Equal(t, expectedResult, result) diff --git a/broadcast/errors.go b/broadcast/errors.go index de56d0b..792f50e 100644 --- a/broadcast/errors.go +++ b/broadcast/errors.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "strings" + + "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/utils" ) // ErrClientUndefined is returned when the client is undefined. @@ -77,3 +79,31 @@ func (err ArcError) Error() string { sb.WriteString("}") return sb.String() } + +type SubmitFailure struct { + Description string + ArcErrorResponse *ArcError +} + +func (failure SubmitFailure) Error() string { + sb := strings.Builder{} + sb.WriteString(failure.Description) + + if failure.ArcErrorResponse != nil { + sb.WriteString(", ") + sb.WriteString(failure.ArcErrorResponse.Error()) + } + + return sb.String() +} + +func Failure(description string, err error) *SubmitFailure { + if arcErr, ok := err.(ArcError); ok { + return &SubmitFailure{ + Description: description, + ArcErrorResponse: &arcErr, + } + } + + return &SubmitFailure{Description: utils.WithCause(errors.New(description), err).Error()} +} diff --git a/broadcast/interface.go b/broadcast/interface.go index e8df92d..4d92d01 100644 --- a/broadcast/interface.go +++ b/broadcast/interface.go @@ -7,20 +7,20 @@ import ( // FeeQuoter it the interface that wraps GetFeeQuote method. // It retrieves the Fee Quote from the configured miners. type FeeQuoter interface { - GetFeeQuote(ctx context.Context) ([]*FeeQuote, error) + GetFeeQuote(ctx context.Context) ([]*FeeQuote, *SubmitFailure) } // PolicyQuoter it the interface that wraps GetPolicyQuote method. // It retrieves the Policy Quote from the configured miners. type PolicyQuoter interface { - GetPolicyQuote(ctx context.Context) ([]*PolicyQuoteResponse, error) + GetPolicyQuote(ctx context.Context) ([]*PolicyQuoteResponse, *SubmitFailure) } // TransactionQuerier is the interface that wraps the QueryTransaction method. // It takes a transaction ID and returns the transaction details, like it's status, hash, height etc. // Everything is wrapped in the QueryTxResponse struct. type TransactionQuerier interface { - QueryTransaction(ctx context.Context, txID string) (*QueryTxResponse, error) + QueryTransaction(ctx context.Context, txID string) (*QueryTxResponse, *SubmitFailure) } // TransactionSubmitter is the interface that wraps the SubmitTransaction method. @@ -28,14 +28,14 @@ type TransactionQuerier interface { // Transaction object needs RawTx to be set. All other fields are optional and used to append headers related to status callbacks. // As a result it returns a SubmitTxResponse object. type TransactionSubmitter interface { - SubmitTransaction(ctx context.Context, tx *Transaction, opts ...TransactionOptFunc) (*SubmitTxResponse, error) + SubmitTransaction(ctx context.Context, tx *Transaction, opts ...TransactionOptFunc) (*SubmitTxResponse, *SubmitFailure) } // TransactionsSubmitter is the interface that wraps the SubmitBatchTransactions method. // It is the same as TransactionSubmitter but it takes a slice of transactions and tries to broadcast them to the P2P network. // As a result it returns a SubmitBatchTxResponse, which includes a slice of SubmitTxResponse objects. type TransactionsSubmitter interface { - SubmitBatchTransactions(ctx context.Context, tx []*Transaction, opts ...TransactionOptFunc) (*SubmitBatchTxResponse, error) + SubmitBatchTransactions(ctx context.Context, tx []*Transaction, opts ...TransactionOptFunc) (*SubmitBatchTxResponse, *SubmitFailure) } // Client is a grouping interface that represents the entire exposed functionality of the broadcast client. diff --git a/broadcast/internal/acceptance_tests/arc_fee_quote_test.go b/broadcast/internal/acceptance_tests/arc_fee_quote_test.go index 290d284..a6098ee 100644 --- a/broadcast/internal/acceptance_tests/arc_fee_quote_test.go +++ b/broadcast/internal/acceptance_tests/arc_fee_quote_test.go @@ -37,7 +37,7 @@ func TestFeeQuote(t *testing.T) { result, err := broadcaster.GetFeeQuote(context.Background()) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 2, httpmock.GetTotalCallCount()) assert.Equal(t, int64(1), result[0].MiningFee.Satoshis) @@ -66,7 +66,7 @@ func TestFeeQuote(t *testing.T) { assert.Error(t, err) assert.Nil(t, result) assert.Equal(t, 2, httpmock.GetTotalCallCount()) - assert.EqualError(t, err, broadcast.ErrNoMinerResponse.Error()) + assert.Contains(t, err.Error(), broadcast.ErrNoMinerResponse.Error()) }) t.Run("Should successfully query from single ArcClient", func(t *testing.T) { @@ -82,7 +82,7 @@ func TestFeeQuote(t *testing.T) { result, err := broadcaster.GetFeeQuote(context.Background()) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 1, httpmock.GetTotalCallCount()) assert.Equal(t, int64(1), result[0].MiningFee.Satoshis) diff --git a/broadcast/internal/acceptance_tests/arc_policy_quote_test.go b/broadcast/internal/acceptance_tests/arc_policy_quote_test.go index 2767244..6b94630 100644 --- a/broadcast/internal/acceptance_tests/arc_policy_quote_test.go +++ b/broadcast/internal/acceptance_tests/arc_policy_quote_test.go @@ -78,7 +78,7 @@ func TestPolicyQuote(t *testing.T) { result, err := broadcaster.GetPolicyQuote(context.Background()) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) }) @@ -102,7 +102,7 @@ func TestPolicyQuote(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrNoMinerResponse.Error()) + assert.Contains(t, err.Error(), broadcast.ErrNoMinerResponse.Error()) }) t.Run("Should successfully query from single ArcClient", func(t *testing.T) { @@ -125,7 +125,7 @@ func TestPolicyQuote(t *testing.T) { result, err := broadcaster.GetPolicyQuote(context.Background()) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) }) diff --git a/broadcast/internal/acceptance_tests/arc_query_tx_test.go b/broadcast/internal/acceptance_tests/arc_query_tx_test.go index dd1a9c2..88459c4 100644 --- a/broadcast/internal/acceptance_tests/arc_query_tx_test.go +++ b/broadcast/internal/acceptance_tests/arc_query_tx_test.go @@ -54,7 +54,7 @@ func TestQueryTransaction(t *testing.T) { result, err := broadcaster.QueryTransaction(context.Background(), mockTxID) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 1, httpmock.GetTotalCallCount()) assert.Equal(t, "MINED", string(result.TxStatus)) @@ -77,7 +77,7 @@ func TestQueryTransaction(t *testing.T) { result, err := broadcaster.QueryTransaction(context.Background(), mockTxID) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 1, httpmock.GetTotalCallCount()) assert.Equal(t, "MINED", string(result.TxStatus)) @@ -100,7 +100,7 @@ func TestQueryTransaction(t *testing.T) { result, err := broadcaster.QueryTransaction(context.Background(), mockTxID) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 2, httpmock.GetTotalCallCount()) assert.Equal(t, "CONFIRMED", string(result.TxStatus)) @@ -125,7 +125,7 @@ func TestQueryTransaction(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrAllBroadcastersFailed.Error()) + assert.Contains(t, err.Error(), broadcast.ErrAllBroadcastersFailed.Error()) assert.Equal(t, 2, httpmock.GetTotalCallCount()) }) @@ -142,7 +142,7 @@ func TestQueryTransaction(t *testing.T) { result, err := broadcaster.QueryTransaction(context.Background(), mockTxID) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) }) diff --git a/broadcast/internal/acceptance_tests/arc_submit_tx_test.go b/broadcast/internal/acceptance_tests/arc_submit_tx_test.go index 51299d3..b0c5566 100644 --- a/broadcast/internal/acceptance_tests/arc_submit_tx_test.go +++ b/broadcast/internal/acceptance_tests/arc_submit_tx_test.go @@ -72,7 +72,7 @@ func TestSubmitTransaction(t *testing.T) { result, err := broadcaster.SubmitTransaction(context.Background(), &broadcast.Transaction{Hex: "transaction-data"}) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 1, httpmock.GetTotalCallCount()) @@ -99,7 +99,7 @@ func TestSubmitTransaction(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrAllBroadcastersFailed.Error()) + assert.EqualError(t, err, broadcast.Failure("SubmitBatchTransactions", broadcast.ErrAllBroadcastersFailed).Error()) assert.Equal(t, 2, httpmock.GetTotalCallCount()) assert.Equal(t, 1, callCount(submitUrl(urls[0]))) assert.Equal(t, 1, callCount(submitUrl(urls[1]))) @@ -144,7 +144,7 @@ func TestSubmitTransaction(t *testing.T) { result, err := broadcaster.SubmitTransaction(context.Background(), &broadcast.Transaction{Hex: mockHex}) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 2, httpmock.GetTotalCallCount()) assert.Equal(t, urls[1], result.Miner) diff --git a/broadcast/internal/arc/arc_error.go b/broadcast/internal/arc/arc_error.go index 59454ac..0590d24 100644 --- a/broadcast/internal/arc/arc_error.go +++ b/broadcast/internal/arc/arc_error.go @@ -31,7 +31,7 @@ func parseArcError(statusCode int, body []byte) error { } if resultError.Title != "" { - return resultError + return &resultError } return nil diff --git a/broadcast/internal/arc/arc_fee_quote.go b/broadcast/internal/arc/arc_fee_quote.go index 938060f..cd98156 100644 --- a/broadcast/internal/arc/arc_fee_quote.go +++ b/broadcast/internal/arc/arc_fee_quote.go @@ -2,16 +2,18 @@ package arc import ( "context" - "errors" "github.com/bitcoin-sv/go-broadcast-client/broadcast" - arc_utils "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/arc/utils" ) -func (a *ArcClient) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, error) { +func (a *ArcClient) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, *broadcast.SubmitFailure) { + if a == nil { + return nil, broadcast.Failure("GetFeeQuote:", broadcast.ErrClientUndefined) + } + policyQuotes, err := a.GetPolicyQuote(ctx) if err != nil { - return nil, arc_utils.WithCause(errors.New("GetFeeQuote: request failed"), err) + return nil, broadcast.Failure("GetFeeQuote: request failed", err) } feeQuote := &broadcast.FeeQuote{ diff --git a/broadcast/internal/arc/arc_policy_quote.go b/broadcast/internal/arc/arc_policy_quote.go index 4cf0622..2129936 100644 --- a/broadcast/internal/arc/arc_policy_quote.go +++ b/broadcast/internal/arc/arc_policy_quote.go @@ -2,22 +2,22 @@ package arc import ( "context" - "errors" "net/http" "github.com/bitcoin-sv/go-broadcast-client/broadcast" arc_utils "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/arc/utils" + "github.com/bitcoin-sv/go-broadcast-client/httpclient" ) -func (a *ArcClient) GetPolicyQuote(ctx context.Context) ([]*broadcast.PolicyQuoteResponse, error) { +func (a *ArcClient) GetPolicyQuote(ctx context.Context) ([]*broadcast.PolicyQuoteResponse, *broadcast.SubmitFailure) { if a == nil { - return nil, broadcast.ErrClientUndefined + return nil, broadcast.Failure("GetPolicyQuote:", broadcast.ErrClientUndefined) } model, err := getPolicyQuote(ctx, a) if err != nil { - return nil, arc_utils.WithCause(errors.New("GetPolicyQuote: request failed"), err) + return nil, broadcast.Failure("GetPolicyQuote: request failed", err) } model.Miner = a.apiURL diff --git a/broadcast/internal/arc/arc_query_tx.go b/broadcast/internal/arc/arc_query_tx.go index fefb435..a79d353 100644 --- a/broadcast/internal/arc/arc_query_tx.go +++ b/broadcast/internal/arc/arc_query_tx.go @@ -7,24 +7,25 @@ import ( "github.com/bitcoin-sv/go-broadcast-client/broadcast" arc_utils "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/arc/utils" + "github.com/bitcoin-sv/go-broadcast-client/httpclient" ) var ErrMissingTxID = errors.New("missing tx id") -func (a *ArcClient) QueryTransaction(ctx context.Context, txID string) (*broadcast.QueryTxResponse, error) { +func (a *ArcClient) QueryTransaction(ctx context.Context, txID string) (*broadcast.QueryTxResponse, *broadcast.SubmitFailure) { if a == nil { - return nil, broadcast.ErrClientUndefined + return nil, broadcast.Failure("QueryTransaction:", broadcast.ErrClientUndefined) } result, err := queryTransaction(ctx, a, txID) if err != nil { - return nil, arc_utils.WithCause(errors.New("QueryTransaction: querying failed"), err) + return nil, broadcast.Failure("QueryTransaction: querying failed", err) } err = validateQueryTxResponse(result) if err != nil { - return nil, arc_utils.WithCause(errors.New("QueryTransaction: validation of query tx response failed"), err) + return nil, broadcast.Failure("QueryTransaction: validation of query tx response failed", err) } a.Logger.Debug().Msgf("Got query tx response from miner: %s", result.Miner) diff --git a/broadcast/internal/arc/arc_submit_tx.go b/broadcast/internal/arc/arc_submit_tx.go index b3c1c91..dcd4895 100644 --- a/broadcast/internal/arc/arc_submit_tx.go +++ b/broadcast/internal/arc/arc_submit_tx.go @@ -11,6 +11,7 @@ import ( "github.com/bitcoin-sv/go-broadcast-client/broadcast" arc_utils "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/arc/utils" + "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/utils" "github.com/bitcoin-sv/go-broadcast-client/httpclient" "github.com/libsv/go-bt/v2" ) @@ -21,9 +22,9 @@ type SubmitTxRequest struct { var ErrSubmitTxMarshal = errors.New("error while marshalling submit tx body") -func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitTxResponse, error) { +func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitTxResponse, *broadcast.SubmitFailure) { if a == nil { - return nil, broadcast.ErrClientUndefined + return nil, broadcast.Failure("SubmitTransaction:", broadcast.ErrClientUndefined) } options := &broadcast.TransactionOpts{} @@ -33,11 +34,11 @@ func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transac result, err := submitTransaction(ctx, a, tx, options) if err != nil { - return nil, arc_utils.WithCause(errors.New("SubmitTransaction: submitting failed"), err) + return nil, broadcast.Failure("SubmitTransaction: submitting failed", err) } if err := validateSubmitTxResponse(result); err != nil { - return nil, arc_utils.WithCause(errors.New("SubmitTransaction: validation of submit tx response failed"), err) + return nil, broadcast.Failure("SubmitTransaction: validation of submit tx response failed", err) } response := &broadcast.SubmitTxResponse{ @@ -49,14 +50,13 @@ func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transac return response, nil } -func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitBatchTxResponse, error) { +func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitBatchTxResponse, *broadcast.SubmitFailure) { if a == nil { - return nil, broadcast.ErrClientUndefined + return nil, broadcast.Failure("SubmitBatchTransactions:", broadcast.ErrClientUndefined) } if len(txs) == 0 { - err := errors.New("invalid request, no transactions to submit") - return nil, arc_utils.WithCause(errors.New("SubmitBatchTransactions: bad request"), err) + return nil, broadcast.Failure("SubmitBatchTransactions: bad request", errors.New("invalid request, no transactions to submit")) } options := &broadcast.TransactionOpts{} @@ -66,11 +66,11 @@ func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcas result, err := submitBatchTransactions(ctx, a, txs, options) if err != nil { - return nil, arc_utils.WithCause(errors.New("SubmitBatchTransactions: submitting failed"), err) + return nil, broadcast.Failure("SubmitBatchTransactions: submitting failed", err) } if err := validateBatchResponse(result); err != nil { - return nil, arc_utils.WithCause(errors.New("SubmitBatchTransactions: validation of batch submit tx response failed"), err) + return nil, broadcast.Failure("SubmitBatchTransactions: validation of batch submit tx response failed", err) } response := &broadcast.SubmitBatchTxResponse{ @@ -189,33 +189,22 @@ func appendSubmitTxHeaders(pld *httpclient.HTTPRequest, opts *broadcast.Transact } func decodeSubmitResponseBody(resp *http.Response) (*broadcast.SubmittedTx, error) { - base := broadcast.BaseSubmitTxResponse{} - err := arc_utils.DecodeResponseBody(resp.Body, &base) + model := &broadcast.SubmittedTx{} + err := arc_utils.DecodeResponseBody(resp.Body, &model) if err != nil { - return nil, broadcast.ErrUnableToDecodeMerklePath - } - - model := &broadcast.SubmittedTx{ - BaseSubmitTxResponse: base, + return nil, err } return model, nil } func decodeSubmitBatchResponseBody(resp *http.Response) ([]*broadcast.SubmittedTx, error) { - base := make([]broadcast.BaseSubmitTxResponse, 0) - err := arc_utils.DecodeResponseBody(resp.Body, &base) + model := make([]*broadcast.SubmittedTx, 0) + err := arc_utils.DecodeResponseBody(resp.Body, &model) if err != nil { return nil, err } - model := make([]*broadcast.SubmittedTx, 0) - for _, tx := range base { - model = append(model, &broadcast.SubmittedTx{ - BaseSubmitTxResponse: tx, - }) - } - return model, nil } @@ -268,18 +257,18 @@ func efTxRequest(rawTx string) (*SubmitTxRequest, error) { } func beefTxRequest(rawTx string) (*SubmitTxRequest, error) { - return nil, errors.New("submitting transactions in BEEF format is unimplemented yet...") + return nil, errors.New("submitting transactions in BEEF format is unimplemented yet") } func rawTxRequest(arc *ArcClient, rawTx string) (*SubmitTxRequest, error) { transaction, err := bt.NewTxFromString(rawTx) if err != nil { - return nil, arc_utils.WithCause(errors.New("rawTxRequest: bt.NewTxFromString failed"), err) + return nil, utils.WithCause(errors.New("rawTxRequest: bt.NewTxFromString failed"), err) } for _, input := range transaction.Inputs { if err = updateUtxoWithMissingData(arc, input); err != nil { - return nil, arc_utils.WithCause(errors.New("rawTxRequest: updateUtxoWithMissingData() failed"), err) + return nil, utils.WithCause(errors.New("rawTxRequest: updateUtxoWithMissingData() failed"), err) } } @@ -316,7 +305,7 @@ func updateUtxoWithMissingData(arc *ArcClient, input *bt.Input) error { actualTx, err := bt.NewTxFromBytes(tx.Transaction) if err != nil { - return arc_utils.WithCause(errors.New("converting junglebusTransaction.Transaction to bt.Tx failed"), err) + return utils.WithCause(errors.New("converting junglebusTransaction.Transaction to bt.Tx failed"), err) } o := actualTx.Outputs[input.PreviousTxOutIndex] diff --git a/broadcast/internal/arc/arc_submit_tx_test.go b/broadcast/internal/arc/arc_submit_tx_test.go index 80376f5..0262a29 100644 --- a/broadcast/internal/arc/arc_submit_tx_test.go +++ b/broadcast/internal/arc/arc_submit_tx_test.go @@ -42,10 +42,8 @@ func TestSubmitTransaction(t *testing.T) { expectedResult: &broadcast.SubmitTxResponse{ BaseResponse: broadcast.BaseResponse{Miner: "http://example.com"}, SubmittedTx: &broadcast.SubmittedTx{ - BaseSubmitTxResponse: broadcast.BaseSubmitTxResponse{ - BaseTxResponse: broadcast.BaseTxResponse{ - TxStatus: broadcast.Confirmed, - }, + BaseTxResponse: broadcast.BaseTxResponse{ + TxStatus: broadcast.Confirmed, }, }, }, diff --git a/broadcast/internal/arc/mocks/arc_client_mock_no_response.go b/broadcast/internal/arc/mocks/arc_client_mock_no_response.go index c9ea8b8..91a7425 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_no_response.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_no_response.go @@ -10,28 +10,28 @@ import ( type ArcClientMockFailure struct{} // GetFeeQuote returns an error. -func (*ArcClientMockFailure) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, error) { - return nil, broadcast.ErrNoMinerResponse +func (*ArcClientMockFailure) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.SubmitFailure) { + return nil, broadcast.Failure("", broadcast.ErrNoMinerResponse) } // GetPolicyQuote returns an error. -func (*ArcClientMockFailure) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, error) { - return nil, broadcast.ErrNoMinerResponse +func (*ArcClientMockFailure) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.SubmitFailure) { + return nil, broadcast.Failure("", broadcast.ErrNoMinerResponse) } // QueryTransaction returns an error. -func (*ArcClientMockFailure) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, error) { - return nil, broadcast.ErrAllBroadcastersFailed +func (*ArcClientMockFailure) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.SubmitFailure) { + return nil, broadcast.Failure("", broadcast.ErrNoMinerResponse) } // SubmitBatchTransactions returns an error. -func (*ArcClientMockFailure) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, error) { - return nil, broadcast.ErrAllBroadcastersFailed +func (*ArcClientMockFailure) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.SubmitFailure) { + return nil, broadcast.Failure("", broadcast.ErrAllBroadcastersFailed) } // SubmitTransaction returns an error. -func (*ArcClientMockFailure) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, error) { - return nil, broadcast.ErrAllBroadcastersFailed +func (*ArcClientMockFailure) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.SubmitFailure) { + return nil, broadcast.Failure("", broadcast.ErrAllBroadcastersFailed) } // NewArcClientMockFailure creates a new mock arc client that returns an error from all its methods. diff --git a/broadcast/internal/arc/mocks/arc_client_mock_success.go b/broadcast/internal/arc/mocks/arc_client_mock_success.go index 4c8fe1d..44cea01 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_success.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_success.go @@ -10,7 +10,7 @@ import ( type ArcClientMock struct{} // GetFeeQuote returns a successful FeeQuote response. -func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, error) { +func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.SubmitFailure) { quotes := make([]*broadcast_api.FeeQuote, 0) quotes = append(quotes, Fee1) quotes = append(quotes, Fee2) @@ -19,7 +19,7 @@ func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuot } // GetPolicyQuote return a successful PolicyQuoteResponse. -func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, error) { +func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.SubmitFailure) { policies := make([]*broadcast_api.PolicyQuoteResponse, 0) policies = append(policies, Policy1) policies = append(policies, Policy2) @@ -28,12 +28,12 @@ func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.Poli } // QueryTransaction returns a successful QueryTxResponse. -func (*ArcClientMock) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, error) { +func (*ArcClientMock) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.SubmitFailure) { return QueryTx(txID), nil } // SubmitTransaction returns a successful SubmitTxResponse. -func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, error) { +func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.SubmitFailure) { return &broadcast_api.SubmitTxResponse{ BaseResponse: broadcast_api.BaseResponse{Miner: fixtures.ProviderMain}, SubmittedTx: SubmittedTx, @@ -41,7 +41,7 @@ func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.T } // SubmitBatchTransactions returns a successful SubmitBatchTxResponse. -func (*ArcClientMock) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, error) { +func (*ArcClientMock) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.SubmitFailure) { return &broadcast_api.SubmitBatchTxResponse{ BaseResponse: broadcast_api.BaseResponse{Miner: fixtures.ProviderMain}, Transactions: []*broadcast_api.SubmittedTx{ diff --git a/broadcast/internal/arc/mocks/arc_client_mock_timeout.go b/broadcast/internal/arc/mocks/arc_client_mock_timeout.go index 3cd95da..f1eae3c 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_timeout.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_timeout.go @@ -11,7 +11,7 @@ import ( type ArcClientMockTimeout struct{} // GetFeeQuote returns a successful FeeQuote response. -func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, error) { +func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.SubmitFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -24,7 +24,7 @@ func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api. } // GetPolicyQuote return a successful PolicyQuoteResponse. -func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, error) { +func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.SubmitFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -37,7 +37,7 @@ func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_a } // QueryTransaction returns a successful QueryTxResponse. -func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, error) { +func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.SubmitFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -46,7 +46,7 @@ func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) } // SubmitTransaction returns a successful SubmitTxResponse. -func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, error) { +func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.SubmitFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -58,7 +58,7 @@ func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcas } // SubmitBatchTransactions returns a successful SubmitBatchTxResponse. -func (*ArcClientMockTimeout) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, error) { +func (*ArcClientMockTimeout) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.SubmitFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } diff --git a/broadcast/internal/arc/mocks/consts.go b/broadcast/internal/arc/mocks/consts.go index 1d9a078..718443e 100644 --- a/broadcast/internal/arc/mocks/consts.go +++ b/broadcast/internal/arc/mocks/consts.go @@ -47,34 +47,30 @@ var ( } SubmittedTx = &broadcast_api.SubmittedTx{ - BaseSubmitTxResponse: broadcast_api.BaseSubmitTxResponse{ - Status: fixtures.TxResponseStatus, - Title: fixtures.TxResponseTitle, - BaseTxResponse: broadcast_api.BaseTxResponse{ - BlockHash: fixtures.TxBlockHash, - BlockHeight: fixtures.TxBlockHeight, - ExtraInfo: fixtures.TxExtraInfo, - MerklePath: fixtures.TxMerklePath, - Timestamp: fixtures.Timestamp, - TxStatus: fixtures.TxStatus, - TxID: fixtures.TxId, - }, + Status: fixtures.TxResponseStatus, + Title: fixtures.TxResponseTitle, + BaseTxResponse: broadcast_api.BaseTxResponse{ + BlockHash: fixtures.TxBlockHash, + BlockHeight: fixtures.TxBlockHeight, + ExtraInfo: fixtures.TxExtraInfo, + MerklePath: fixtures.TxMerklePath, + Timestamp: fixtures.Timestamp, + TxStatus: fixtures.TxStatus, + TxID: fixtures.TxId, }, } SubmittedTxSecondary = &broadcast_api.SubmittedTx{ - BaseSubmitTxResponse: broadcast_api.BaseSubmitTxResponse{ - Status: fixtures.TxResponseStatus, - Title: fixtures.TxResponseTitle, - BaseTxResponse: broadcast_api.BaseTxResponse{ - BlockHash: fixtures.TxBlockHashSecondary, - BlockHeight: fixtures.TxBlockHeightSecondary, - ExtraInfo: fixtures.TxExtraInfo, - MerklePath: fixtures.TxMerklePath, - Timestamp: fixtures.Timestamp, - TxStatus: fixtures.TxStatus, - TxID: fixtures.TxIdSecondary, - }, + Status: fixtures.TxResponseStatus, + Title: fixtures.TxResponseTitle, + BaseTxResponse: broadcast_api.BaseTxResponse{ + BlockHash: fixtures.TxBlockHashSecondary, + BlockHeight: fixtures.TxBlockHeightSecondary, + ExtraInfo: fixtures.TxExtraInfo, + MerklePath: fixtures.TxMerklePath, + Timestamp: fixtures.Timestamp, + TxStatus: fixtures.TxStatus, + TxID: fixtures.TxIdSecondary, }, } ) diff --git a/broadcast/internal/arc/utils/arc_utils.go b/broadcast/internal/arc/utils/arc_utils.go index a7f35a2..c497a6a 100644 --- a/broadcast/internal/arc/utils/arc_utils.go +++ b/broadcast/internal/arc/utils/arc_utils.go @@ -2,8 +2,6 @@ package arcutils import ( "encoding/json" - "errors" - "fmt" "io" "github.com/bitcoin-sv/go-broadcast-client/broadcast" @@ -17,7 +15,3 @@ func DecodeResponseBody(body io.ReadCloser, resultOutput any) error { return nil } - -func WithCause(err error, cause error) error { - return errors.Join(err, fmt.Errorf("\tcaused by: %w\t", cause)) -} diff --git a/broadcast/internal/composite/broadcaster.go b/broadcast/internal/composite/broadcaster.go index dc07892..529a4d8 100644 --- a/broadcast/internal/composite/broadcaster.go +++ b/broadcast/internal/composite/broadcaster.go @@ -33,7 +33,7 @@ func NewBroadcaster(strategy Strategy, factories ...BroadcastFactory) broadcast. func (c *compositeBroadcaster) GetPolicyQuote( ctx context.Context, -) ([]*broadcast.PolicyQuoteResponse, error) { +) ([]*broadcast.PolicyQuoteResponse, *broadcast.SubmitFailure) { var policyQuotes []*broadcast.PolicyQuoteResponse for _, broadcaster := range c.broadcasters { @@ -44,13 +44,13 @@ func (c *compositeBroadcaster) GetPolicyQuote( } if policyQuotes == nil { - return nil, broadcast.ErrNoMinerResponse + return nil, broadcast.Failure("GetPolicyQuote: ", broadcast.ErrNoMinerResponse) } return policyQuotes, nil } -func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, error) { +func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, *broadcast.SubmitFailure) { var feeQuotes []*broadcast.FeeQuote for _, broadcaster := range c.broadcasters { @@ -61,7 +61,7 @@ func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.Fe } if feeQuotes == nil { - return nil, broadcast.ErrNoMinerResponse + return nil, broadcast.Failure("GetFeeQuote: ", broadcast.ErrNoMinerResponse) } return feeQuotes, nil @@ -70,11 +70,11 @@ func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.Fe func (c *compositeBroadcaster) QueryTransaction( ctx context.Context, txID string, -) (*broadcast.QueryTxResponse, error) { +) (*broadcast.QueryTxResponse, *broadcast.SubmitFailure) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, error) { + executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.SubmitFailure) { return currentBroadcaster.QueryTransaction(ctx, txID) } } @@ -86,7 +86,7 @@ func (c *compositeBroadcaster) QueryTransaction( // Convert result to QueryTxResponse queryTxResponse, ok := result.(*broadcast.QueryTxResponse) if !ok { - return nil, fmt.Errorf("unexpected result type: %T", result) + return nil, broadcast.Failure(fmt.Sprintf("unexpected result type: %T", result), nil) } return queryTxResponse, nil @@ -96,11 +96,11 @@ func (c *compositeBroadcaster) SubmitTransaction( ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc, -) (*broadcast.SubmitTxResponse, error) { +) (*broadcast.SubmitTxResponse, *broadcast.SubmitFailure) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, error) { + executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.SubmitFailure) { return currentBroadcaster.SubmitTransaction(ctx, tx) } } @@ -112,7 +112,7 @@ func (c *compositeBroadcaster) SubmitTransaction( // Convert result to SubmitTxResponse submitTxResponse, ok := result.(*broadcast.SubmitTxResponse) if !ok { - return nil, fmt.Errorf("unexpected result type: %T", result) + return nil, broadcast.Failure(fmt.Sprintf("unexpected result type: %T", result), nil) } return submitTxResponse, nil @@ -122,11 +122,11 @@ func (c *compositeBroadcaster) SubmitBatchTransactions( ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc, -) (*broadcast.SubmitBatchTxResponse, error) { +) (*broadcast.SubmitBatchTxResponse, *broadcast.SubmitFailure) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, error) { + executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.SubmitFailure) { return currentBroadcaster.SubmitBatchTransactions(ctx, txs) } } @@ -139,7 +139,7 @@ func (c *compositeBroadcaster) SubmitBatchTransactions( // Convert result to []SubmitTxResponse submitTxResponse, ok := result.(*broadcast.SubmitBatchTxResponse) if !ok { - return nil, fmt.Errorf("unexpected result type: %T", result) + return nil, broadcast.Failure(fmt.Sprintf("unexpected result type: %T", result), nil) } return submitTxResponse, nil diff --git a/broadcast/internal/composite/strategy.go b/broadcast/internal/composite/strategy.go index 6099a9a..9ab342e 100644 --- a/broadcast/internal/composite/strategy.go +++ b/broadcast/internal/composite/strategy.go @@ -17,9 +17,9 @@ const ( type Result interface{} -type executionFunc func(context.Context) (Result, error) +type executionFunc func(context.Context) (Result, *broadcast.SubmitFailure) -type StrategyExecutionFunc func(context.Context, []executionFunc) (Result, error) +type StrategyExecutionFunc func(context.Context, []executionFunc) (Result, *broadcast.SubmitFailure) // Strategy is a component designed to offer flexibility in selecting a communication approach // for interacting with multiple broadcasting services, such as multiple Arc services. @@ -37,12 +37,12 @@ func New(name StrategyName) (*Strategy, error) { } } -func (s *Strategy) Execute(ctx context.Context, executionFuncs []executionFunc) (Result, error) { +func (s *Strategy) Execute(ctx context.Context, executionFuncs []executionFunc) (Result, *broadcast.SubmitFailure) { return s.executionFunc(ctx, executionFuncs) } var ( - OneByOne = &Strategy{name: OneByOneStrategy, executionFunc: func(ctx context.Context, executionFuncs []executionFunc) (Result, error) { + OneByOne = &Strategy{name: OneByOneStrategy, executionFunc: func(ctx context.Context, executionFuncs []executionFunc) (Result, *broadcast.SubmitFailure) { for _, executionFunc := range executionFuncs { result, err := executionFunc(ctx) if err != nil { @@ -50,6 +50,6 @@ var ( } return result, nil } - return nil, broadcast.ErrAllBroadcastersFailed + return nil, broadcast.Failure("", broadcast.ErrAllBroadcastersFailed) }} ) diff --git a/broadcast/internal/composite/strategy_test.go b/broadcast/internal/composite/strategy_test.go index 310e61e..e1ae45a 100644 --- a/broadcast/internal/composite/strategy_test.go +++ b/broadcast/internal/composite/strategy_test.go @@ -14,8 +14,12 @@ type mockExecutionFunc struct { err error } -func (m mockExecutionFunc) Execute(_ context.Context) (Result, error) { - return m.result, m.err +func (m mockExecutionFunc) Execute(_ context.Context) (Result, *broadcast.SubmitFailure) { + if m.err != nil { + return m.result, broadcast.Failure("", m.err) + } + + return m.result, nil } func TestStrategy_Execute(t *testing.T) { @@ -63,7 +67,12 @@ func TestStrategy_Execute(t *testing.T) { result, err := strategy.Execute(context.Background(), tc.funcs) // then - assert.Equal(t, tc.err, err) + if tc.err == nil { + assert.Nil(t, err) + } else { + assert.NotNil(t, err) + assert.Contains(t, err.Error(), tc.err.Error()) + } assert.Equal(t, tc.expected, result) }) } diff --git a/broadcast/internal/utils/utils.go b/broadcast/internal/utils/utils.go new file mode 100644 index 0000000..d818a55 --- /dev/null +++ b/broadcast/internal/utils/utils.go @@ -0,0 +1,10 @@ +package utils + +import ( + "errors" + "fmt" +) + +func WithCause(err error, cause error) error { + return errors.Join(err, fmt.Errorf("\tcaused by: %w\t", cause)) +} diff --git a/broadcast/transaction.go b/broadcast/transaction.go index 65d97d5..4bd2105 100644 --- a/broadcast/transaction.go +++ b/broadcast/transaction.go @@ -30,8 +30,8 @@ type QueryTxResponse struct { BaseTxResponse } -// BaseSubmitTxResponse is the internal response returned by the miner from submitting transaction(s). -type BaseSubmitTxResponse struct { +// SubmittedTx is the submit response. +type SubmittedTx struct { BaseTxResponse // Status is the status of the response. Status int `json:"status,omitempty"` @@ -39,11 +39,6 @@ type BaseSubmitTxResponse struct { Title string `json:"title,omitempty"` } -// SubmittedTx is the submit response with decoded Merkl Path. -type SubmittedTx struct { - BaseSubmitTxResponse -} - // SubmitTxResponse is the response returned by the SubmitTransaction method. type SubmitTxResponse struct { BaseResponse From 1e0b0824d95246cf2e5e04005d933b68faac8dfe Mon Sep 17 00:00:00 2001 From: arkadiuszos4chain Date: Fri, 19 Apr 2024 08:37:39 +0200 Subject: [PATCH 2/7] fix(spv-642): return failure object --- .../mock_client_builder.go | 2 +- broadcast/errors.go | 10 ++++----- broadcast/interface.go | 10 ++++----- broadcast/internal/arc/arc_fee_quote.go | 2 +- broadcast/internal/arc/arc_policy_quote.go | 2 +- broadcast/internal/arc/arc_query_tx.go | 2 +- broadcast/internal/arc/arc_submit_tx.go | 4 ++-- .../arc/mocks/arc_client_mock_no_response.go | 21 +++++++++---------- .../arc/mocks/arc_client_mock_success.go | 10 ++++----- .../arc/mocks/arc_client_mock_timeout.go | 10 ++++----- broadcast/internal/composite/broadcaster.go | 16 +++++++------- broadcast/internal/composite/strategy.go | 8 +++---- broadcast/internal/composite/strategy_test.go | 2 +- 13 files changed, 49 insertions(+), 50 deletions(-) diff --git a/broadcast/broadcast-client-mock/mock_client_builder.go b/broadcast/broadcast-client-mock/mock_client_builder.go index bfe384f..2c2a8c5 100644 --- a/broadcast/broadcast-client-mock/mock_client_builder.go +++ b/broadcast/broadcast-client-mock/mock_client_builder.go @@ -20,7 +20,7 @@ type builder struct { factories []composite.BroadcastFactory } -// Builder is used to prepare the mock broadcast client. It is recommended +// Builder is used to prepare the mock broadcast client. It is recommended // to use that builder for creating the mock broadcast client. func Builder() *builder { return &builder{} diff --git a/broadcast/errors.go b/broadcast/errors.go index 792f50e..95bdcd4 100644 --- a/broadcast/errors.go +++ b/broadcast/errors.go @@ -80,12 +80,12 @@ func (err ArcError) Error() string { return sb.String() } -type SubmitFailure struct { +type FailureResponse struct { Description string ArcErrorResponse *ArcError } -func (failure SubmitFailure) Error() string { +func (failure FailureResponse) Error() string { sb := strings.Builder{} sb.WriteString(failure.Description) @@ -97,13 +97,13 @@ func (failure SubmitFailure) Error() string { return sb.String() } -func Failure(description string, err error) *SubmitFailure { +func Failure(description string, err error) *FailureResponse { if arcErr, ok := err.(ArcError); ok { - return &SubmitFailure{ + return &FailureResponse{ Description: description, ArcErrorResponse: &arcErr, } } - return &SubmitFailure{Description: utils.WithCause(errors.New(description), err).Error()} + return &FailureResponse{Description: utils.WithCause(errors.New(description), err).Error()} } diff --git a/broadcast/interface.go b/broadcast/interface.go index 4d92d01..bd32e11 100644 --- a/broadcast/interface.go +++ b/broadcast/interface.go @@ -7,20 +7,20 @@ import ( // FeeQuoter it the interface that wraps GetFeeQuote method. // It retrieves the Fee Quote from the configured miners. type FeeQuoter interface { - GetFeeQuote(ctx context.Context) ([]*FeeQuote, *SubmitFailure) + GetFeeQuote(ctx context.Context) ([]*FeeQuote, *FailureResponse) } // PolicyQuoter it the interface that wraps GetPolicyQuote method. // It retrieves the Policy Quote from the configured miners. type PolicyQuoter interface { - GetPolicyQuote(ctx context.Context) ([]*PolicyQuoteResponse, *SubmitFailure) + GetPolicyQuote(ctx context.Context) ([]*PolicyQuoteResponse, *FailureResponse) } // TransactionQuerier is the interface that wraps the QueryTransaction method. // It takes a transaction ID and returns the transaction details, like it's status, hash, height etc. // Everything is wrapped in the QueryTxResponse struct. type TransactionQuerier interface { - QueryTransaction(ctx context.Context, txID string) (*QueryTxResponse, *SubmitFailure) + QueryTransaction(ctx context.Context, txID string) (*QueryTxResponse, *FailureResponse) } // TransactionSubmitter is the interface that wraps the SubmitTransaction method. @@ -28,14 +28,14 @@ type TransactionQuerier interface { // Transaction object needs RawTx to be set. All other fields are optional and used to append headers related to status callbacks. // As a result it returns a SubmitTxResponse object. type TransactionSubmitter interface { - SubmitTransaction(ctx context.Context, tx *Transaction, opts ...TransactionOptFunc) (*SubmitTxResponse, *SubmitFailure) + SubmitTransaction(ctx context.Context, tx *Transaction, opts ...TransactionOptFunc) (*SubmitTxResponse, *FailureResponse) } // TransactionsSubmitter is the interface that wraps the SubmitBatchTransactions method. // It is the same as TransactionSubmitter but it takes a slice of transactions and tries to broadcast them to the P2P network. // As a result it returns a SubmitBatchTxResponse, which includes a slice of SubmitTxResponse objects. type TransactionsSubmitter interface { - SubmitBatchTransactions(ctx context.Context, tx []*Transaction, opts ...TransactionOptFunc) (*SubmitBatchTxResponse, *SubmitFailure) + SubmitBatchTransactions(ctx context.Context, tx []*Transaction, opts ...TransactionOptFunc) (*SubmitBatchTxResponse, *FailureResponse) } // Client is a grouping interface that represents the entire exposed functionality of the broadcast client. diff --git a/broadcast/internal/arc/arc_fee_quote.go b/broadcast/internal/arc/arc_fee_quote.go index cd98156..a753751 100644 --- a/broadcast/internal/arc/arc_fee_quote.go +++ b/broadcast/internal/arc/arc_fee_quote.go @@ -6,7 +6,7 @@ import ( "github.com/bitcoin-sv/go-broadcast-client/broadcast" ) -func (a *ArcClient) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, *broadcast.SubmitFailure) { +func (a *ArcClient) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, *broadcast.FailureResponse) { if a == nil { return nil, broadcast.Failure("GetFeeQuote:", broadcast.ErrClientUndefined) } diff --git a/broadcast/internal/arc/arc_policy_quote.go b/broadcast/internal/arc/arc_policy_quote.go index 2129936..a9f5616 100644 --- a/broadcast/internal/arc/arc_policy_quote.go +++ b/broadcast/internal/arc/arc_policy_quote.go @@ -10,7 +10,7 @@ import ( "github.com/bitcoin-sv/go-broadcast-client/httpclient" ) -func (a *ArcClient) GetPolicyQuote(ctx context.Context) ([]*broadcast.PolicyQuoteResponse, *broadcast.SubmitFailure) { +func (a *ArcClient) GetPolicyQuote(ctx context.Context) ([]*broadcast.PolicyQuoteResponse, *broadcast.FailureResponse) { if a == nil { return nil, broadcast.Failure("GetPolicyQuote:", broadcast.ErrClientUndefined) } diff --git a/broadcast/internal/arc/arc_query_tx.go b/broadcast/internal/arc/arc_query_tx.go index a79d353..1892485 100644 --- a/broadcast/internal/arc/arc_query_tx.go +++ b/broadcast/internal/arc/arc_query_tx.go @@ -13,7 +13,7 @@ import ( var ErrMissingTxID = errors.New("missing tx id") -func (a *ArcClient) QueryTransaction(ctx context.Context, txID string) (*broadcast.QueryTxResponse, *broadcast.SubmitFailure) { +func (a *ArcClient) QueryTransaction(ctx context.Context, txID string) (*broadcast.QueryTxResponse, *broadcast.FailureResponse) { if a == nil { return nil, broadcast.Failure("QueryTransaction:", broadcast.ErrClientUndefined) } diff --git a/broadcast/internal/arc/arc_submit_tx.go b/broadcast/internal/arc/arc_submit_tx.go index dcd4895..746e7d4 100644 --- a/broadcast/internal/arc/arc_submit_tx.go +++ b/broadcast/internal/arc/arc_submit_tx.go @@ -22,7 +22,7 @@ type SubmitTxRequest struct { var ErrSubmitTxMarshal = errors.New("error while marshalling submit tx body") -func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitTxResponse, *broadcast.SubmitFailure) { +func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitTxResponse, *broadcast.FailureResponse) { if a == nil { return nil, broadcast.Failure("SubmitTransaction:", broadcast.ErrClientUndefined) } @@ -50,7 +50,7 @@ func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transac return response, nil } -func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitBatchTxResponse, *broadcast.SubmitFailure) { +func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitBatchTxResponse, *broadcast.FailureResponse) { if a == nil { return nil, broadcast.Failure("SubmitBatchTransactions:", broadcast.ErrClientUndefined) } diff --git a/broadcast/internal/arc/mocks/arc_client_mock_no_response.go b/broadcast/internal/arc/mocks/arc_client_mock_no_response.go index 91a7425..55a3de6 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_no_response.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_no_response.go @@ -3,35 +3,34 @@ package mocks import ( "context" - "github.com/bitcoin-sv/go-broadcast-client/broadcast" broadcast_api "github.com/bitcoin-sv/go-broadcast-client/broadcast" ) type ArcClientMockFailure struct{} // GetFeeQuote returns an error. -func (*ArcClientMockFailure) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.SubmitFailure) { - return nil, broadcast.Failure("", broadcast.ErrNoMinerResponse) +func (*ArcClientMockFailure) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.FailureResponse) { + return nil, broadcast_api.Failure("", broadcast_api.ErrNoMinerResponse) } // GetPolicyQuote returns an error. -func (*ArcClientMockFailure) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.SubmitFailure) { - return nil, broadcast.Failure("", broadcast.ErrNoMinerResponse) +func (*ArcClientMockFailure) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.FailureResponse) { + return nil, broadcast_api.Failure("", broadcast_api.ErrNoMinerResponse) } // QueryTransaction returns an error. -func (*ArcClientMockFailure) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.SubmitFailure) { - return nil, broadcast.Failure("", broadcast.ErrNoMinerResponse) +func (*ArcClientMockFailure) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.FailureResponse) { + return nil, broadcast_api.Failure("", broadcast_api.ErrNoMinerResponse) } // SubmitBatchTransactions returns an error. -func (*ArcClientMockFailure) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.SubmitFailure) { - return nil, broadcast.Failure("", broadcast.ErrAllBroadcastersFailed) +func (*ArcClientMockFailure) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.FailureResponse) { + return nil, broadcast_api.Failure("", broadcast_api.ErrAllBroadcastersFailed) } // SubmitTransaction returns an error. -func (*ArcClientMockFailure) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.SubmitFailure) { - return nil, broadcast.Failure("", broadcast.ErrAllBroadcastersFailed) +func (*ArcClientMockFailure) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.FailureResponse) { + return nil, broadcast_api.Failure("", broadcast_api.ErrAllBroadcastersFailed) } // NewArcClientMockFailure creates a new mock arc client that returns an error from all its methods. diff --git a/broadcast/internal/arc/mocks/arc_client_mock_success.go b/broadcast/internal/arc/mocks/arc_client_mock_success.go index 44cea01..2167ec7 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_success.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_success.go @@ -10,7 +10,7 @@ import ( type ArcClientMock struct{} // GetFeeQuote returns a successful FeeQuote response. -func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.SubmitFailure) { +func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.FailureResponse) { quotes := make([]*broadcast_api.FeeQuote, 0) quotes = append(quotes, Fee1) quotes = append(quotes, Fee2) @@ -19,7 +19,7 @@ func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuot } // GetPolicyQuote return a successful PolicyQuoteResponse. -func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.SubmitFailure) { +func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.FailureResponse) { policies := make([]*broadcast_api.PolicyQuoteResponse, 0) policies = append(policies, Policy1) policies = append(policies, Policy2) @@ -28,12 +28,12 @@ func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.Poli } // QueryTransaction returns a successful QueryTxResponse. -func (*ArcClientMock) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.SubmitFailure) { +func (*ArcClientMock) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.FailureResponse) { return QueryTx(txID), nil } // SubmitTransaction returns a successful SubmitTxResponse. -func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.SubmitFailure) { +func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.FailureResponse) { return &broadcast_api.SubmitTxResponse{ BaseResponse: broadcast_api.BaseResponse{Miner: fixtures.ProviderMain}, SubmittedTx: SubmittedTx, @@ -41,7 +41,7 @@ func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.T } // SubmitBatchTransactions returns a successful SubmitBatchTxResponse. -func (*ArcClientMock) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.SubmitFailure) { +func (*ArcClientMock) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.FailureResponse) { return &broadcast_api.SubmitBatchTxResponse{ BaseResponse: broadcast_api.BaseResponse{Miner: fixtures.ProviderMain}, Transactions: []*broadcast_api.SubmittedTx{ diff --git a/broadcast/internal/arc/mocks/arc_client_mock_timeout.go b/broadcast/internal/arc/mocks/arc_client_mock_timeout.go index f1eae3c..722ab19 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_timeout.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_timeout.go @@ -11,7 +11,7 @@ import ( type ArcClientMockTimeout struct{} // GetFeeQuote returns a successful FeeQuote response. -func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.SubmitFailure) { +func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.FailureResponse) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -24,7 +24,7 @@ func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api. } // GetPolicyQuote return a successful PolicyQuoteResponse. -func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.SubmitFailure) { +func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.FailureResponse) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -37,7 +37,7 @@ func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_a } // QueryTransaction returns a successful QueryTxResponse. -func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.SubmitFailure) { +func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.FailureResponse) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -46,7 +46,7 @@ func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) } // SubmitTransaction returns a successful SubmitTxResponse. -func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.SubmitFailure) { +func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.FailureResponse) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -58,7 +58,7 @@ func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcas } // SubmitBatchTransactions returns a successful SubmitBatchTxResponse. -func (*ArcClientMockTimeout) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.SubmitFailure) { +func (*ArcClientMockTimeout) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.FailureResponse) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } diff --git a/broadcast/internal/composite/broadcaster.go b/broadcast/internal/composite/broadcaster.go index 529a4d8..642a18f 100644 --- a/broadcast/internal/composite/broadcaster.go +++ b/broadcast/internal/composite/broadcaster.go @@ -33,7 +33,7 @@ func NewBroadcaster(strategy Strategy, factories ...BroadcastFactory) broadcast. func (c *compositeBroadcaster) GetPolicyQuote( ctx context.Context, -) ([]*broadcast.PolicyQuoteResponse, *broadcast.SubmitFailure) { +) ([]*broadcast.PolicyQuoteResponse, *broadcast.FailureResponse) { var policyQuotes []*broadcast.PolicyQuoteResponse for _, broadcaster := range c.broadcasters { @@ -50,7 +50,7 @@ func (c *compositeBroadcaster) GetPolicyQuote( return policyQuotes, nil } -func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, *broadcast.SubmitFailure) { +func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, *broadcast.FailureResponse) { var feeQuotes []*broadcast.FeeQuote for _, broadcaster := range c.broadcasters { @@ -70,11 +70,11 @@ func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.Fe func (c *compositeBroadcaster) QueryTransaction( ctx context.Context, txID string, -) (*broadcast.QueryTxResponse, *broadcast.SubmitFailure) { +) (*broadcast.QueryTxResponse, *broadcast.FailureResponse) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.SubmitFailure) { + executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.FailureResponse) { return currentBroadcaster.QueryTransaction(ctx, txID) } } @@ -96,11 +96,11 @@ func (c *compositeBroadcaster) SubmitTransaction( ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc, -) (*broadcast.SubmitTxResponse, *broadcast.SubmitFailure) { +) (*broadcast.SubmitTxResponse, *broadcast.FailureResponse) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.SubmitFailure) { + executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.FailureResponse) { return currentBroadcaster.SubmitTransaction(ctx, tx) } } @@ -122,11 +122,11 @@ func (c *compositeBroadcaster) SubmitBatchTransactions( ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc, -) (*broadcast.SubmitBatchTxResponse, *broadcast.SubmitFailure) { +) (*broadcast.SubmitBatchTxResponse, *broadcast.FailureResponse) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.SubmitFailure) { + executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.FailureResponse) { return currentBroadcaster.SubmitBatchTransactions(ctx, txs) } } diff --git a/broadcast/internal/composite/strategy.go b/broadcast/internal/composite/strategy.go index 9ab342e..3fc56d0 100644 --- a/broadcast/internal/composite/strategy.go +++ b/broadcast/internal/composite/strategy.go @@ -17,9 +17,9 @@ const ( type Result interface{} -type executionFunc func(context.Context) (Result, *broadcast.SubmitFailure) +type executionFunc func(context.Context) (Result, *broadcast.FailureResponse) -type StrategyExecutionFunc func(context.Context, []executionFunc) (Result, *broadcast.SubmitFailure) +type StrategyExecutionFunc func(context.Context, []executionFunc) (Result, *broadcast.FailureResponse) // Strategy is a component designed to offer flexibility in selecting a communication approach // for interacting with multiple broadcasting services, such as multiple Arc services. @@ -37,12 +37,12 @@ func New(name StrategyName) (*Strategy, error) { } } -func (s *Strategy) Execute(ctx context.Context, executionFuncs []executionFunc) (Result, *broadcast.SubmitFailure) { +func (s *Strategy) Execute(ctx context.Context, executionFuncs []executionFunc) (Result, *broadcast.FailureResponse) { return s.executionFunc(ctx, executionFuncs) } var ( - OneByOne = &Strategy{name: OneByOneStrategy, executionFunc: func(ctx context.Context, executionFuncs []executionFunc) (Result, *broadcast.SubmitFailure) { + OneByOne = &Strategy{name: OneByOneStrategy, executionFunc: func(ctx context.Context, executionFuncs []executionFunc) (Result, *broadcast.FailureResponse) { for _, executionFunc := range executionFuncs { result, err := executionFunc(ctx) if err != nil { diff --git a/broadcast/internal/composite/strategy_test.go b/broadcast/internal/composite/strategy_test.go index e1ae45a..58b1424 100644 --- a/broadcast/internal/composite/strategy_test.go +++ b/broadcast/internal/composite/strategy_test.go @@ -14,7 +14,7 @@ type mockExecutionFunc struct { err error } -func (m mockExecutionFunc) Execute(_ context.Context) (Result, *broadcast.SubmitFailure) { +func (m mockExecutionFunc) Execute(_ context.Context) (Result, *broadcast.FailureResponse) { if m.err != nil { return m.result, broadcast.Failure("", m.err) } From dd0cf42f3707b17ff77c523f891c0d212e07c178 Mon Sep 17 00:00:00 2001 From: arkadiuszos4chain Date: Fri, 19 Apr 2024 09:19:51 +0200 Subject: [PATCH 3/7] feat(spv-642): fix tests --- .../broadcast-client-mock/mock_client_test.go | 38 +++++++++---------- .../acceptance_tests/arc_submit_tx_test.go | 8 ++-- broadcast/internal/composite/broadcaster.go | 12 +++--- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/broadcast/broadcast-client-mock/mock_client_test.go b/broadcast/broadcast-client-mock/mock_client_test.go index 011603d..c447877 100644 --- a/broadcast/broadcast-client-mock/mock_client_test.go +++ b/broadcast/broadcast-client-mock/mock_client_test.go @@ -21,10 +21,10 @@ func TestMockClientSuccess(t *testing.T) { expectedResult := []*broadcast.PolicyQuoteResponse{mocks.Policy1, mocks.Policy2} // when - result, err := broadcaster.GetPolicyQuote(context.Background()) + result, fail := broadcaster.GetPolicyQuote(context.Background()) // then - assert.NoError(t, err) + assert.Nil(t, fail) assert.NotNil(t, result) assert.Equal(t, result, expectedResult) }) @@ -37,10 +37,10 @@ func TestMockClientSuccess(t *testing.T) { expectedResult := []*broadcast.FeeQuote{mocks.Fee1, mocks.Fee2} // when - result, err := broadcaster.GetFeeQuote(context.Background()) + result, fail := broadcaster.GetFeeQuote(context.Background()) // then - assert.NoError(t, err) + assert.Nil(t, fail) assert.NotNil(t, result) assert.Equal(t, expectedResult, result) }) @@ -56,7 +56,7 @@ func TestMockClientSuccess(t *testing.T) { result, err := broadcaster.QueryTransaction(context.Background(), testTxId) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, result.Miner, fixtures.ProviderMain) assert.Equal(t, result.TxID, testTxId) @@ -71,10 +71,10 @@ func TestMockClientSuccess(t *testing.T) { Build() // when - result, err := broadcaster.SubmitTransaction(context.Background(), &broadcast.Transaction{Hex: "test-rawtx"}) + result, fail := broadcaster.SubmitTransaction(context.Background(), &broadcast.Transaction{Hex: "test-rawtx"}) // then - assert.Nil(t, err) + assert.Nil(t, fail) assert.NotNil(t, result) assert.Equal(t, result.Miner, fixtures.ProviderMain) assert.Equal(t, result.BlockHash, fixtures.TxBlockHash) @@ -98,10 +98,10 @@ func TestMockClientSuccess(t *testing.T) { } // when - result, err := broadcaster.SubmitBatchTransactions(context.Background(), []*broadcast.Transaction{{Hex: "test-rawtx"}, {Hex: "test2-rawtx"}}) + result, fail := broadcaster.SubmitBatchTransactions(context.Background(), []*broadcast.Transaction{{Hex: "test-rawtx"}, {Hex: "test2-rawtx"}}) // then - assert.Nil(t, err) + assert.Nil(t, fail) assert.NotNil(t, result) assert.Equal(t, expectedResult, result) }) @@ -115,12 +115,12 @@ func TestMockClientFailure(t *testing.T) { Build() // when - result, err := broadcaster.GetPolicyQuote(context.Background()) + result, fail := broadcaster.GetPolicyQuote(context.Background()) // then - assert.Error(t, err) + assert.Error(t, fail) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrNoMinerResponse.Error()) + assert.ErrorContains(t, fail, broadcast.ErrNoMinerResponse.Error()) }) t.Run("Should return error from GetFeeQuote method of mock Arc Client with Failure Mock Type", func(t *testing.T) { @@ -135,7 +135,7 @@ func TestMockClientFailure(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrNoMinerResponse.Error()) + assert.ErrorContains(t, err, broadcast.ErrNoMinerResponse.Error()) }) t.Run("Should return error from QueryTransaction method of mock Arc Client with Failure Mock Type", func(t *testing.T) { @@ -150,7 +150,7 @@ func TestMockClientFailure(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrAllBroadcastersFailed.Error()) + assert.ErrorContains(t, err, broadcast.ErrNoMinerResponse.Error()) }) t.Run("Should return error from SubmitTransaction method of mock Arc Client with Failure Mock Type", func(t *testing.T) { @@ -165,7 +165,7 @@ func TestMockClientFailure(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrAllBroadcastersFailed.Error()) + assert.ErrorContains(t, err, broadcast.ErrAllBroadcastersFailed.Error()) }) t.Run("Should return error from SubmitBatchTransaction method of mock Arc Client with Failure Mock Type", func(t *testing.T) { @@ -180,7 +180,7 @@ func TestMockClientFailure(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrAllBroadcastersFailed.Error()) + assert.ErrorContains(t, err, broadcast.ErrAllBroadcastersFailed.Error()) }) } @@ -201,7 +201,7 @@ func TestMockClientTimeout(t *testing.T) { result, err := broadcaster.GetPolicyQuote(ctx) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Greater(t, time.Since(startTime), defaultTestTime) assert.Equal(t, expectedResult, result) @@ -221,7 +221,7 @@ func TestMockClientTimeout(t *testing.T) { result, err := broadcaster.GetFeeQuote(ctx) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Greater(t, time.Since(startTime), defaultTestTime) assert.Equal(t, expectedResult, result) @@ -241,7 +241,7 @@ func TestMockClientTimeout(t *testing.T) { result, err := broadcaster.QueryTransaction(ctx, testTxId) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Greater(t, time.Since(startTime), defaultTestTime) assert.Equal(t, result.Miner, fixtures.ProviderMain) diff --git a/broadcast/internal/acceptance_tests/arc_submit_tx_test.go b/broadcast/internal/acceptance_tests/arc_submit_tx_test.go index b0c5566..5cda57c 100644 --- a/broadcast/internal/acceptance_tests/arc_submit_tx_test.go +++ b/broadcast/internal/acceptance_tests/arc_submit_tx_test.go @@ -99,7 +99,7 @@ func TestSubmitTransaction(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.Failure("SubmitBatchTransactions", broadcast.ErrAllBroadcastersFailed).Error()) + assert.ErrorContains(t, err, broadcast.ErrAllBroadcastersFailed.Error()) assert.Equal(t, 2, httpmock.GetTotalCallCount()) assert.Equal(t, 1, callCount(submitUrl(urls[0]))) assert.Equal(t, 1, callCount(submitUrl(urls[1]))) @@ -174,7 +174,7 @@ func TestSubmitBatchTransactions(t *testing.T) { result, err := broadcaster.SubmitBatchTransactions(context.Background(), batch) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 1, httpmock.GetTotalCallCount()) assert.Equal(t, 1, callCount(submitBatchUrl(urls[0]))) @@ -199,7 +199,7 @@ func TestSubmitBatchTransactions(t *testing.T) { result, err := broadcaster.SubmitBatchTransactions(context.Background(), batch) // then - assert.NoError(t, err) + assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, 2, httpmock.GetTotalCallCount()) assert.Equal(t, 1, callCount(submitBatchUrl(urls[1]))) @@ -227,7 +227,7 @@ func TestSubmitBatchTransactions(t *testing.T) { // then assert.Error(t, err) assert.Nil(t, result) - assert.EqualError(t, err, broadcast.ErrAllBroadcastersFailed.Error()) + assert.ErrorContains(t, err, broadcast.ErrAllBroadcastersFailed.Error()) assert.Equal(t, 2, httpmock.GetTotalCallCount()) }) diff --git a/broadcast/internal/composite/broadcaster.go b/broadcast/internal/composite/broadcaster.go index 642a18f..5ae2240 100644 --- a/broadcast/internal/composite/broadcaster.go +++ b/broadcast/internal/composite/broadcaster.go @@ -104,9 +104,9 @@ func (c *compositeBroadcaster) SubmitTransaction( return currentBroadcaster.SubmitTransaction(ctx, tx) } } - result, err := c.strategy.Execute(ctx, executionFuncs) - if err != nil { - return nil, err + result, fail := c.strategy.Execute(ctx, executionFuncs) + if fail != nil { + return nil, fail } // Convert result to SubmitTxResponse @@ -131,9 +131,9 @@ func (c *compositeBroadcaster) SubmitBatchTransactions( } } - result, err := c.strategy.Execute(ctx, executionFuncs) - if err != nil { - return nil, err + result, fail := c.strategy.Execute(ctx, executionFuncs) + if fail != nil { + return nil, fail } // Convert result to []SubmitTxResponse From 08704a1ca1e68f64538b8de82c5dfdb58bb55644 Mon Sep 17 00:00:00 2001 From: arkadiuszos4chain Date: Fri, 19 Apr 2024 10:48:51 +0200 Subject: [PATCH 4/7] feat(spv-642): fix after review --- broadcast/internal/arc/arc_submit_tx.go | 2 +- broadcast/internal/arc/utils/arc_utils.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/broadcast/internal/arc/arc_submit_tx.go b/broadcast/internal/arc/arc_submit_tx.go index 746e7d4..da53d99 100644 --- a/broadcast/internal/arc/arc_submit_tx.go +++ b/broadcast/internal/arc/arc_submit_tx.go @@ -190,7 +190,7 @@ func appendSubmitTxHeaders(pld *httpclient.HTTPRequest, opts *broadcast.Transact func decodeSubmitResponseBody(resp *http.Response) (*broadcast.SubmittedTx, error) { model := &broadcast.SubmittedTx{} - err := arc_utils.DecodeResponseBody(resp.Body, &model) + err := arc_utils.DecodeResponseBody(resp.Body, model) if err != nil { return nil, err } diff --git a/broadcast/internal/arc/utils/arc_utils.go b/broadcast/internal/arc/utils/arc_utils.go index c497a6a..db6380a 100644 --- a/broadcast/internal/arc/utils/arc_utils.go +++ b/broadcast/internal/arc/utils/arc_utils.go @@ -7,7 +7,7 @@ import ( "github.com/bitcoin-sv/go-broadcast-client/broadcast" ) -func DecodeResponseBody(body io.ReadCloser, resultOutput any) error { +func DecodeResponseBody[T any](body io.ReadCloser, resultOutput *T) error { err := json.NewDecoder(body).Decode(resultOutput) if err != nil { return broadcast.ErrUnableToDecodeResponse From 3b9c5fd3cc3d049f87e10b71a71b017c50ca610c Mon Sep 17 00:00:00 2001 From: wregulski Date: Tue, 14 May 2024 11:30:38 +0200 Subject: [PATCH 5/7] fix(SPV-642): change error type by wrapping it in interface --- broadcast/errors.go | 21 ++++++++++++++----- broadcast/interface.go | 10 ++++----- broadcast/internal/arc/arc_fee_quote.go | 6 +++--- broadcast/internal/arc/arc_policy_quote.go | 2 +- broadcast/internal/arc/arc_query_tx.go | 2 +- broadcast/internal/arc/arc_submit_tx.go | 4 ++-- .../arc/mocks/arc_client_mock_no_response.go | 10 ++++----- .../arc/mocks/arc_client_mock_success.go | 10 ++++----- .../arc/mocks/arc_client_mock_timeout.go | 10 ++++----- broadcast/internal/composite/broadcaster.go | 16 +++++++------- broadcast/internal/composite/strategy.go | 8 +++---- broadcast/internal/composite/strategy_test.go | 2 +- 12 files changed, 56 insertions(+), 45 deletions(-) diff --git a/broadcast/errors.go b/broadcast/errors.go index 95bdcd4..544c3d3 100644 --- a/broadcast/errors.go +++ b/broadcast/errors.go @@ -4,9 +4,8 @@ package broadcast import ( "errors" "fmt" - "strings" - "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/utils" + "strings" ) // ErrClientUndefined is returned when the client is undefined. @@ -23,7 +22,7 @@ var ErrClientUndefined = errors.New("client is undefined") // ErrAllBroadcastersFailed is returned when all configured broadcasters failed to query or broadcast the transaction. var ErrAllBroadcastersFailed = errors.New("all broadcasters failed") -// ErrBroadcastFailed is returned when the broadcast failed. +// ErrBroadcasterFailed is returned when the broadcast failed. var ErrBroadcasterFailed = errors.New("broadcaster failed") // ErrUnableToDecodeResponse is returned when the http response cannot be decoded. @@ -45,6 +44,12 @@ var ErrStrategyUnkown = errors.New("unknown strategy") // ErrNoMinerResponse is returned when no response is received from any miner. var ErrNoMinerResponse = errors.New("failed to get reponse from any miner") +// ArcFailure is the interface for the error returned by the ArcClient. +type ArcFailure interface { + error + Details() *FailureResponse +} + // ArcError is general type for the error returned by the ArcClient. type ArcError struct { Type string `json:"type"` @@ -56,6 +61,11 @@ type ArcError struct { ExtraInfo string `json:"extraInfo,omitempty"` } +// Details returns the details of the error it's the implementation of the ArcFailure interface. +func (failure *FailureResponse) Details() *FailureResponse { + return failure +} + // Error returns the error string it's the implementation of the error interface. func (err ArcError) Error() string { sb := strings.Builder{} @@ -85,7 +95,7 @@ type FailureResponse struct { ArcErrorResponse *ArcError } -func (failure FailureResponse) Error() string { +func (failure *FailureResponse) Error() string { sb := strings.Builder{} sb.WriteString(failure.Description) @@ -98,7 +108,8 @@ func (failure FailureResponse) Error() string { } func Failure(description string, err error) *FailureResponse { - if arcErr, ok := err.(ArcError); ok { + var arcErr ArcError + if errors.As(err, &arcErr) { return &FailureResponse{ Description: description, ArcErrorResponse: &arcErr, diff --git a/broadcast/interface.go b/broadcast/interface.go index bd32e11..7a8c9e5 100644 --- a/broadcast/interface.go +++ b/broadcast/interface.go @@ -7,20 +7,20 @@ import ( // FeeQuoter it the interface that wraps GetFeeQuote method. // It retrieves the Fee Quote from the configured miners. type FeeQuoter interface { - GetFeeQuote(ctx context.Context) ([]*FeeQuote, *FailureResponse) + GetFeeQuote(ctx context.Context) ([]*FeeQuote, ArcFailure) } // PolicyQuoter it the interface that wraps GetPolicyQuote method. // It retrieves the Policy Quote from the configured miners. type PolicyQuoter interface { - GetPolicyQuote(ctx context.Context) ([]*PolicyQuoteResponse, *FailureResponse) + GetPolicyQuote(ctx context.Context) ([]*PolicyQuoteResponse, ArcFailure) } // TransactionQuerier is the interface that wraps the QueryTransaction method. // It takes a transaction ID and returns the transaction details, like it's status, hash, height etc. // Everything is wrapped in the QueryTxResponse struct. type TransactionQuerier interface { - QueryTransaction(ctx context.Context, txID string) (*QueryTxResponse, *FailureResponse) + QueryTransaction(ctx context.Context, txID string) (*QueryTxResponse, ArcFailure) } // TransactionSubmitter is the interface that wraps the SubmitTransaction method. @@ -28,14 +28,14 @@ type TransactionQuerier interface { // Transaction object needs RawTx to be set. All other fields are optional and used to append headers related to status callbacks. // As a result it returns a SubmitTxResponse object. type TransactionSubmitter interface { - SubmitTransaction(ctx context.Context, tx *Transaction, opts ...TransactionOptFunc) (*SubmitTxResponse, *FailureResponse) + SubmitTransaction(ctx context.Context, tx *Transaction, opts ...TransactionOptFunc) (*SubmitTxResponse, ArcFailure) } // TransactionsSubmitter is the interface that wraps the SubmitBatchTransactions method. // It is the same as TransactionSubmitter but it takes a slice of transactions and tries to broadcast them to the P2P network. // As a result it returns a SubmitBatchTxResponse, which includes a slice of SubmitTxResponse objects. type TransactionsSubmitter interface { - SubmitBatchTransactions(ctx context.Context, tx []*Transaction, opts ...TransactionOptFunc) (*SubmitBatchTxResponse, *FailureResponse) + SubmitBatchTransactions(ctx context.Context, tx []*Transaction, opts ...TransactionOptFunc) (*SubmitBatchTxResponse, ArcFailure) } // Client is a grouping interface that represents the entire exposed functionality of the broadcast client. diff --git a/broadcast/internal/arc/arc_fee_quote.go b/broadcast/internal/arc/arc_fee_quote.go index a753751..7b1b5de 100644 --- a/broadcast/internal/arc/arc_fee_quote.go +++ b/broadcast/internal/arc/arc_fee_quote.go @@ -6,14 +6,14 @@ import ( "github.com/bitcoin-sv/go-broadcast-client/broadcast" ) -func (a *ArcClient) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, *broadcast.FailureResponse) { +func (a *ArcClient) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, broadcast.ArcFailure) { if a == nil { - return nil, broadcast.Failure("GetFeeQuote:", broadcast.ErrClientUndefined) + return nil, broadcast.Failure("GetFeeQuote: arc client is nil", nil) } policyQuotes, err := a.GetPolicyQuote(ctx) if err != nil { - return nil, broadcast.Failure("GetFeeQuote: request failed", err) + return nil, err } feeQuote := &broadcast.FeeQuote{ diff --git a/broadcast/internal/arc/arc_policy_quote.go b/broadcast/internal/arc/arc_policy_quote.go index a9f5616..852df41 100644 --- a/broadcast/internal/arc/arc_policy_quote.go +++ b/broadcast/internal/arc/arc_policy_quote.go @@ -10,7 +10,7 @@ import ( "github.com/bitcoin-sv/go-broadcast-client/httpclient" ) -func (a *ArcClient) GetPolicyQuote(ctx context.Context) ([]*broadcast.PolicyQuoteResponse, *broadcast.FailureResponse) { +func (a *ArcClient) GetPolicyQuote(ctx context.Context) ([]*broadcast.PolicyQuoteResponse, broadcast.ArcFailure) { if a == nil { return nil, broadcast.Failure("GetPolicyQuote:", broadcast.ErrClientUndefined) } diff --git a/broadcast/internal/arc/arc_query_tx.go b/broadcast/internal/arc/arc_query_tx.go index 1892485..e348e6e 100644 --- a/broadcast/internal/arc/arc_query_tx.go +++ b/broadcast/internal/arc/arc_query_tx.go @@ -13,7 +13,7 @@ import ( var ErrMissingTxID = errors.New("missing tx id") -func (a *ArcClient) QueryTransaction(ctx context.Context, txID string) (*broadcast.QueryTxResponse, *broadcast.FailureResponse) { +func (a *ArcClient) QueryTransaction(ctx context.Context, txID string) (*broadcast.QueryTxResponse, broadcast.ArcFailure) { if a == nil { return nil, broadcast.Failure("QueryTransaction:", broadcast.ErrClientUndefined) } diff --git a/broadcast/internal/arc/arc_submit_tx.go b/broadcast/internal/arc/arc_submit_tx.go index da53d99..add3099 100644 --- a/broadcast/internal/arc/arc_submit_tx.go +++ b/broadcast/internal/arc/arc_submit_tx.go @@ -22,7 +22,7 @@ type SubmitTxRequest struct { var ErrSubmitTxMarshal = errors.New("error while marshalling submit tx body") -func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitTxResponse, *broadcast.FailureResponse) { +func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitTxResponse, broadcast.ArcFailure) { if a == nil { return nil, broadcast.Failure("SubmitTransaction:", broadcast.ErrClientUndefined) } @@ -50,7 +50,7 @@ func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transac return response, nil } -func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitBatchTxResponse, *broadcast.FailureResponse) { +func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitBatchTxResponse, broadcast.ArcFailure) { if a == nil { return nil, broadcast.Failure("SubmitBatchTransactions:", broadcast.ErrClientUndefined) } diff --git a/broadcast/internal/arc/mocks/arc_client_mock_no_response.go b/broadcast/internal/arc/mocks/arc_client_mock_no_response.go index 55a3de6..0b318af 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_no_response.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_no_response.go @@ -9,27 +9,27 @@ import ( type ArcClientMockFailure struct{} // GetFeeQuote returns an error. -func (*ArcClientMockFailure) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.FailureResponse) { +func (*ArcClientMockFailure) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, broadcast_api.ArcFailure) { return nil, broadcast_api.Failure("", broadcast_api.ErrNoMinerResponse) } // GetPolicyQuote returns an error. -func (*ArcClientMockFailure) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMockFailure) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, broadcast_api.ArcFailure) { return nil, broadcast_api.Failure("", broadcast_api.ErrNoMinerResponse) } // QueryTransaction returns an error. -func (*ArcClientMockFailure) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMockFailure) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, broadcast_api.ArcFailure) { return nil, broadcast_api.Failure("", broadcast_api.ErrNoMinerResponse) } // SubmitBatchTransactions returns an error. -func (*ArcClientMockFailure) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMockFailure) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, broadcast_api.ArcFailure) { return nil, broadcast_api.Failure("", broadcast_api.ErrAllBroadcastersFailed) } // SubmitTransaction returns an error. -func (*ArcClientMockFailure) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMockFailure) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, broadcast_api.ArcFailure) { return nil, broadcast_api.Failure("", broadcast_api.ErrAllBroadcastersFailed) } diff --git a/broadcast/internal/arc/mocks/arc_client_mock_success.go b/broadcast/internal/arc/mocks/arc_client_mock_success.go index 2167ec7..0a9dae4 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_success.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_success.go @@ -10,7 +10,7 @@ import ( type ArcClientMock struct{} // GetFeeQuote returns a successful FeeQuote response. -func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.FailureResponse) { +func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, broadcast_api.ArcFailure) { quotes := make([]*broadcast_api.FeeQuote, 0) quotes = append(quotes, Fee1) quotes = append(quotes, Fee2) @@ -19,7 +19,7 @@ func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuot } // GetPolicyQuote return a successful PolicyQuoteResponse. -func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, broadcast_api.ArcFailure) { policies := make([]*broadcast_api.PolicyQuoteResponse, 0) policies = append(policies, Policy1) policies = append(policies, Policy2) @@ -28,12 +28,12 @@ func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.Poli } // QueryTransaction returns a successful QueryTxResponse. -func (*ArcClientMock) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMock) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, broadcast_api.ArcFailure) { return QueryTx(txID), nil } // SubmitTransaction returns a successful SubmitTxResponse. -func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, broadcast_api.ArcFailure) { return &broadcast_api.SubmitTxResponse{ BaseResponse: broadcast_api.BaseResponse{Miner: fixtures.ProviderMain}, SubmittedTx: SubmittedTx, @@ -41,7 +41,7 @@ func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.T } // SubmitBatchTransactions returns a successful SubmitBatchTxResponse. -func (*ArcClientMock) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMock) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, broadcast_api.ArcFailure) { return &broadcast_api.SubmitBatchTxResponse{ BaseResponse: broadcast_api.BaseResponse{Miner: fixtures.ProviderMain}, Transactions: []*broadcast_api.SubmittedTx{ diff --git a/broadcast/internal/arc/mocks/arc_client_mock_timeout.go b/broadcast/internal/arc/mocks/arc_client_mock_timeout.go index 722ab19..9b2e34d 100644 --- a/broadcast/internal/arc/mocks/arc_client_mock_timeout.go +++ b/broadcast/internal/arc/mocks/arc_client_mock_timeout.go @@ -11,7 +11,7 @@ import ( type ArcClientMockTimeout struct{} // GetFeeQuote returns a successful FeeQuote response. -func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, *broadcast_api.FailureResponse) { +func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, broadcast_api.ArcFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -24,7 +24,7 @@ func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api. } // GetPolicyQuote return a successful PolicyQuoteResponse. -func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, broadcast_api.ArcFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -37,7 +37,7 @@ func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_a } // QueryTransaction returns a successful QueryTxResponse. -func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, broadcast_api.ArcFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -46,7 +46,7 @@ func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) } // SubmitTransaction returns a successful SubmitTxResponse. -func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, broadcast_api.ArcFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } @@ -58,7 +58,7 @@ func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcas } // SubmitBatchTransactions returns a successful SubmitBatchTxResponse. -func (*ArcClientMockTimeout) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, *broadcast_api.FailureResponse) { +func (*ArcClientMockTimeout) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, broadcast_api.ArcFailure) { if deadline, ok := ctx.Deadline(); ok { time.Sleep(time.Until(deadline) + 10*time.Millisecond) } diff --git a/broadcast/internal/composite/broadcaster.go b/broadcast/internal/composite/broadcaster.go index 5ae2240..48f84eb 100644 --- a/broadcast/internal/composite/broadcaster.go +++ b/broadcast/internal/composite/broadcaster.go @@ -33,7 +33,7 @@ func NewBroadcaster(strategy Strategy, factories ...BroadcastFactory) broadcast. func (c *compositeBroadcaster) GetPolicyQuote( ctx context.Context, -) ([]*broadcast.PolicyQuoteResponse, *broadcast.FailureResponse) { +) ([]*broadcast.PolicyQuoteResponse, broadcast.ArcFailure) { var policyQuotes []*broadcast.PolicyQuoteResponse for _, broadcaster := range c.broadcasters { @@ -50,7 +50,7 @@ func (c *compositeBroadcaster) GetPolicyQuote( return policyQuotes, nil } -func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, *broadcast.FailureResponse) { +func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, broadcast.ArcFailure) { var feeQuotes []*broadcast.FeeQuote for _, broadcaster := range c.broadcasters { @@ -70,11 +70,11 @@ func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.Fe func (c *compositeBroadcaster) QueryTransaction( ctx context.Context, txID string, -) (*broadcast.QueryTxResponse, *broadcast.FailureResponse) { +) (*broadcast.QueryTxResponse, broadcast.ArcFailure) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.FailureResponse) { + executionFuncs[i] = func(ctx context.Context) (Result, broadcast.ArcFailure) { return currentBroadcaster.QueryTransaction(ctx, txID) } } @@ -96,11 +96,11 @@ func (c *compositeBroadcaster) SubmitTransaction( ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc, -) (*broadcast.SubmitTxResponse, *broadcast.FailureResponse) { +) (*broadcast.SubmitTxResponse, broadcast.ArcFailure) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.FailureResponse) { + executionFuncs[i] = func(ctx context.Context) (Result, broadcast.ArcFailure) { return currentBroadcaster.SubmitTransaction(ctx, tx) } } @@ -122,11 +122,11 @@ func (c *compositeBroadcaster) SubmitBatchTransactions( ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc, -) (*broadcast.SubmitBatchTxResponse, *broadcast.FailureResponse) { +) (*broadcast.SubmitBatchTxResponse, broadcast.ArcFailure) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, *broadcast.FailureResponse) { + executionFuncs[i] = func(ctx context.Context) (Result, broadcast.ArcFailure) { return currentBroadcaster.SubmitBatchTransactions(ctx, txs) } } diff --git a/broadcast/internal/composite/strategy.go b/broadcast/internal/composite/strategy.go index 3fc56d0..da99263 100644 --- a/broadcast/internal/composite/strategy.go +++ b/broadcast/internal/composite/strategy.go @@ -17,9 +17,9 @@ const ( type Result interface{} -type executionFunc func(context.Context) (Result, *broadcast.FailureResponse) +type executionFunc func(context.Context) (Result, broadcast.ArcFailure) -type StrategyExecutionFunc func(context.Context, []executionFunc) (Result, *broadcast.FailureResponse) +type StrategyExecutionFunc func(context.Context, []executionFunc) (Result, broadcast.ArcFailure) // Strategy is a component designed to offer flexibility in selecting a communication approach // for interacting with multiple broadcasting services, such as multiple Arc services. @@ -37,12 +37,12 @@ func New(name StrategyName) (*Strategy, error) { } } -func (s *Strategy) Execute(ctx context.Context, executionFuncs []executionFunc) (Result, *broadcast.FailureResponse) { +func (s *Strategy) Execute(ctx context.Context, executionFuncs []executionFunc) (Result, broadcast.ArcFailure) { return s.executionFunc(ctx, executionFuncs) } var ( - OneByOne = &Strategy{name: OneByOneStrategy, executionFunc: func(ctx context.Context, executionFuncs []executionFunc) (Result, *broadcast.FailureResponse) { + OneByOne = &Strategy{name: OneByOneStrategy, executionFunc: func(ctx context.Context, executionFuncs []executionFunc) (Result, broadcast.ArcFailure) { for _, executionFunc := range executionFuncs { result, err := executionFunc(ctx) if err != nil { diff --git a/broadcast/internal/composite/strategy_test.go b/broadcast/internal/composite/strategy_test.go index 58b1424..4df11e5 100644 --- a/broadcast/internal/composite/strategy_test.go +++ b/broadcast/internal/composite/strategy_test.go @@ -14,7 +14,7 @@ type mockExecutionFunc struct { err error } -func (m mockExecutionFunc) Execute(_ context.Context) (Result, *broadcast.FailureResponse) { +func (m mockExecutionFunc) Execute(_ context.Context) (Result, broadcast.ArcFailure) { if m.err != nil { return m.result, broadcast.Failure("", m.err) } From 1fb2e9c81fe1f29d0398649d4f463ea77719a65b Mon Sep 17 00:00:00 2001 From: wregulski Date: Tue, 14 May 2024 11:56:08 +0200 Subject: [PATCH 6/7] fix(SPV-642): revert assert.NoError in Tests --- broadcast/broadcast-client-mock/mock_client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/broadcast/broadcast-client-mock/mock_client_test.go b/broadcast/broadcast-client-mock/mock_client_test.go index c447877..923b19a 100644 --- a/broadcast/broadcast-client-mock/mock_client_test.go +++ b/broadcast/broadcast-client-mock/mock_client_test.go @@ -24,7 +24,7 @@ func TestMockClientSuccess(t *testing.T) { result, fail := broadcaster.GetPolicyQuote(context.Background()) // then - assert.Nil(t, fail) + assert.NoError(t, fail) assert.NotNil(t, result) assert.Equal(t, result, expectedResult) }) From 2ed9af6e04323536804c033eec21f9fd4004df19 Mon Sep 17 00:00:00 2001 From: wregulski Date: Tue, 14 May 2024 11:58:50 +0200 Subject: [PATCH 7/7] chore(SPV-642): add missing comments and remove unused references --- broadcast/errors.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/broadcast/errors.go b/broadcast/errors.go index 544c3d3..e91c124 100644 --- a/broadcast/errors.go +++ b/broadcast/errors.go @@ -22,15 +22,9 @@ var ErrClientUndefined = errors.New("client is undefined") // ErrAllBroadcastersFailed is returned when all configured broadcasters failed to query or broadcast the transaction. var ErrAllBroadcastersFailed = errors.New("all broadcasters failed") -// ErrBroadcasterFailed is returned when the broadcast failed. -var ErrBroadcasterFailed = errors.New("broadcaster failed") - // ErrUnableToDecodeResponse is returned when the http response cannot be decoded. var ErrUnableToDecodeResponse = errors.New("unable to decode response") -// ErrUnableToDecodeMerklePath is returned when merkle path from transaction response cannot be decoded. -var ErrUnableToDecodeMerklePath = errors.New("unable to decode merkle path from response") - // ErrMissingStatus is returned when the tx status is missing. var ErrMissingStatus = errors.New("missing tx status") @@ -90,11 +84,13 @@ func (err ArcError) Error() string { return sb.String() } +// FailureResponse is the response returned by the ArcClient when the request fails. type FailureResponse struct { Description string ArcErrorResponse *ArcError } +// Error returns the error string it's the implementation of the error interface. func (failure *FailureResponse) Error() string { sb := strings.Builder{} sb.WriteString(failure.Description) @@ -107,6 +103,7 @@ func (failure *FailureResponse) Error() string { return sb.String() } +// Failure returns a new FailureResponse with the description and the error. func Failure(description string, err error) *FailureResponse { var arcErr ArcError if errors.As(err, &arcErr) {