diff --git a/broadcast/internal/arc/arc_fee_quote.go b/broadcast/internal/arc/arc_fee_quote.go index 8796fb0..938060f 100644 --- a/broadcast/internal/arc/arc_fee_quote.go +++ b/broadcast/internal/arc/arc_fee_quote.go @@ -2,15 +2,16 @@ 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) { policyQuotes, err := a.GetPolicyQuote(ctx) if err != nil { - a.Logger.Error().Msgf("Failed to get policy quote: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("GetFeeQuote: request failed"), err) } feeQuote := &broadcast.FeeQuote{ diff --git a/broadcast/internal/arc/arc_fee_quote_test.go b/broadcast/internal/arc/arc_fee_quote_test.go index 73c04ad..3802797 100644 --- a/broadcast/internal/arc/arc_fee_quote_test.go +++ b/broadcast/internal/arc/arc_fee_quote_test.go @@ -4,11 +4,13 @@ import ( "bytes" "context" "errors" - "github.com/rs/zerolog" "io" "net/http" + "strings" "testing" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -81,8 +83,9 @@ func TestFeeQuote(t *testing.T) { // then assert.Equal(t, tc.expectedResult, result) - assert.Equal(t, tc.expectedError, err) - + if err != nil { + assert.True(t, strings.Contains(err.Error(), tc.expectedError.Error())) + } // assert Expectations on the mock mockHttpClient.AssertExpectations(t) }) diff --git a/broadcast/internal/arc/arc_policy_quote.go b/broadcast/internal/arc/arc_policy_quote.go index caad250..4cf0622 100644 --- a/broadcast/internal/arc/arc_policy_quote.go +++ b/broadcast/internal/arc/arc_policy_quote.go @@ -2,6 +2,7 @@ package arc import ( "context" + "errors" "net/http" "github.com/bitcoin-sv/go-broadcast-client/broadcast" @@ -16,8 +17,7 @@ func (a *ArcClient) GetPolicyQuote(ctx context.Context) ([]*broadcast.PolicyQuot model, err := getPolicyQuote(ctx, a) if err != nil { - a.Logger.Error().Msgf("Failed to get policy quote: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("GetPolicyQuote: request failed"), err) } model.Miner = a.apiURL diff --git a/broadcast/internal/arc/arc_policy_quote_test.go b/broadcast/internal/arc/arc_policy_quote_test.go index fb7a7c2..0990437 100644 --- a/broadcast/internal/arc/arc_policy_quote_test.go +++ b/broadcast/internal/arc/arc_policy_quote_test.go @@ -4,11 +4,13 @@ import ( "bytes" "context" "errors" - "github.com/rs/zerolog" "io" "net/http" + "strings" "testing" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -86,8 +88,9 @@ func TestPolicyQuote(t *testing.T) { // then assert.Equal(t, tc.expectedResult, result) - assert.Equal(t, tc.expectedError, err) - + if err != nil { + assert.True(t, strings.Contains(err.Error(), tc.expectedError.Error())) + } // assert Expectations on the mock mockHttpClient.AssertExpectations(t) }) diff --git a/broadcast/internal/arc/arc_query_tx.go b/broadcast/internal/arc/arc_query_tx.go index ce787ca..fefb435 100644 --- a/broadcast/internal/arc/arc_query_tx.go +++ b/broadcast/internal/arc/arc_query_tx.go @@ -6,7 +6,7 @@ import ( "net/http" "github.com/bitcoin-sv/go-broadcast-client/broadcast" - arcutils "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/arc/utils" + arc_utils "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/arc/utils" "github.com/bitcoin-sv/go-broadcast-client/httpclient" ) @@ -14,20 +14,17 @@ var ErrMissingTxID = errors.New("missing tx id") func (a *ArcClient) QueryTransaction(ctx context.Context, txID string) (*broadcast.QueryTxResponse, error) { if a == nil { - a.Logger.Error().Msgf("Failed to query tx: %s", broadcast.ErrClientUndefined.Error()) return nil, broadcast.ErrClientUndefined } result, err := queryTransaction(ctx, a, txID) if err != nil { - a.Logger.Error().Msgf("Failed to query tx: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("QueryTransaction: querying failed"), err) } err = validateQueryTxResponse(result) if err != nil { - a.Logger.Error().Msgf("Failed to validate query tx response: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("QueryTransaction: validation of query tx response failed"), err) } a.Logger.Debug().Msgf("Got query tx response from miner: %s", result.Miner) @@ -62,7 +59,7 @@ func queryTransaction(ctx context.Context, arc *ArcClient, txHash string) (*broa func decodeQueryResponseBody(resp *http.Response, arc *ArcClient) (*broadcast.QueryTxResponse, error) { base := broadcast.BaseTxResponse{} - err := arcutils.DecodeResponseBody(resp.Body, &base) + err := arc_utils.DecodeResponseBody(resp.Body, &base) if err != nil { return nil, err } diff --git a/broadcast/internal/arc/arc_query_tx_test.go b/broadcast/internal/arc/arc_query_tx_test.go index 1836bd9..288b32f 100644 --- a/broadcast/internal/arc/arc_query_tx_test.go +++ b/broadcast/internal/arc/arc_query_tx_test.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net/http" + "strings" "testing" "github.com/rs/zerolog" @@ -86,7 +87,10 @@ func TestQueryTransaction(t *testing.T) { // then assert.Equal(t, tc.expectedResult, result) - assert.Equal(t, tc.expectedError, err) + + if err != nil { + assert.True(t, strings.Contains(err.Error(), tc.expectedError.Error())) + } // assert Expectations on the mock mockHttpClient.AssertExpectations(t) diff --git a/broadcast/internal/arc/arc_submit_tx.go b/broadcast/internal/arc/arc_submit_tx.go index f50a04d..b3c1c91 100644 --- a/broadcast/internal/arc/arc_submit_tx.go +++ b/broadcast/internal/arc/arc_submit_tx.go @@ -23,7 +23,6 @@ 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) { if a == nil { - a.Logger.Error().Msgf("Failed to submit tx: %s", broadcast.ErrClientUndefined.Error()) return nil, broadcast.ErrClientUndefined } @@ -34,13 +33,11 @@ func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transac result, err := submitTransaction(ctx, a, tx, options) if err != nil { - a.Logger.Error().Msgf("Failed to submit tx: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("SubmitTransaction: submitting failed"), err) } if err := validateSubmitTxResponse(result); err != nil { - a.Logger.Error().Msgf("Failed to validate submit tx response: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("SubmitTransaction: validation of submit tx response failed"), err) } response := &broadcast.SubmitTxResponse{ @@ -49,20 +46,17 @@ func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transac } a.Logger.Debug().Msgf("Got submit tx response from miner: %s", response.Miner) - return response, nil } func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitBatchTxResponse, error) { if a == nil { - a.Logger.Error().Msgf("Failed to submit batch txs: %s", broadcast.ErrClientUndefined.Error()) return nil, broadcast.ErrClientUndefined } if len(txs) == 0 { err := errors.New("invalid request, no transactions to submit") - a.Logger.Error().Msgf("Failed to submit batch txs: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("SubmitBatchTransactions: bad request"), err) } options := &broadcast.TransactionOpts{} @@ -72,13 +66,11 @@ func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcas result, err := submitBatchTransactions(ctx, a, txs, options) if err != nil { - a.Logger.Error().Msgf("Failed to submit batch txs: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("SubmitBatchTransactions: submitting failed"), err) } if err := validateBatchResponse(result); err != nil { - a.Logger.Error().Msgf("Failed to validate batch txs response: %s", err.Error()) - return nil, err + return nil, arc_utils.WithCause(errors.New("SubmitBatchTransactions: validation of batch submit tx response failed"), err) } response := &broadcast.SubmitBatchTxResponse{ @@ -276,18 +268,18 @@ func efTxRequest(rawTx string) (*SubmitTxRequest, error) { } func beefTxRequest(rawTx string) (*SubmitTxRequest, error) { - return nil, fmt.Errorf("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, err + return nil, arc_utils.WithCause(errors.New("rawTxRequest: bt.NewTxFromString failed"), err) } for _, input := range transaction.Inputs { if err = updateUtxoWithMissingData(arc, input); err != nil { - return nil, err + return nil, arc_utils.WithCause(errors.New("rawTxRequest: updateUtxoWithMissingData() failed"), err) } } @@ -297,19 +289,8 @@ func rawTxRequest(arc *ArcClient, rawTx string) (*SubmitTxRequest, error) { return request, nil } -func decodeJunblebusTransaction(resp *http.Response) (*junglebusTransaction, error) { - tx := &junglebusTransaction{} - err := arc_utils.DecodeResponseBody(resp.Body, &tx) - if err != nil { - return nil, err - } - - return tx, nil -} - func updateUtxoWithMissingData(arc *ArcClient, input *bt.Input) error { txid := input.PreviousTxIDStr() - pld := httpclient.NewPayload( httpclient.GET, fmt.Sprintf("https://junglebus.gorillapool.io/v1/transaction/get/%s", txid), @@ -322,16 +303,20 @@ func updateUtxoWithMissingData(arc *ArcClient, input *bt.Input) error { arc.HTTPClient.DoRequest, pld, decodeJunblebusTransaction, - parseArcError, + nil, ) if err != nil { - return err + return fmt.Errorf("junglebus request failed: %w", err) + } + + if len(tx.Transaction) == 0 { + return errors.New("junglebus responded with empty tx.Transaction[]") } actualTx, err := bt.NewTxFromBytes(tx.Transaction) if err != nil { - return err + return arc_utils.WithCause(errors.New("converting junglebusTransaction.Transaction to bt.Tx failed"), err) } o := actualTx.Outputs[input.PreviousTxOutIndex] @@ -340,6 +325,17 @@ func updateUtxoWithMissingData(arc *ArcClient, input *bt.Input) error { return nil } +func decodeJunblebusTransaction(resp *http.Response) (*junglebusTransaction, error) { + tx := &junglebusTransaction{} + err := arc_utils.DecodeResponseBody(resp.Body, &tx) + if err != nil { + return nil, fmt.Errorf("decodeJunblebusTransaction: %w", err) + } + + fmt.Println(tx) + return tx, nil +} + type junglebusTransaction struct { ID string `json:"id"` Transaction []byte `json:"transaction"` diff --git a/broadcast/internal/arc/arc_submit_tx_test.go b/broadcast/internal/arc/arc_submit_tx_test.go index e18749d..80376f5 100644 --- a/broadcast/internal/arc/arc_submit_tx_test.go +++ b/broadcast/internal/arc/arc_submit_tx_test.go @@ -6,6 +6,7 @@ import ( "errors" "io" "net/http" + "strings" "testing" "github.com/rs/zerolog" @@ -103,8 +104,10 @@ func TestSubmitTransaction(t *testing.T) { // then assert.Equal(t, tc.expectedResult, result) - assert.Equal(t, tc.expectedError, err) + if err != nil { + assert.True(t, strings.Contains(err.Error(), tc.expectedError.Error())) + } // assert Expectations on the mock mockHttpClient.AssertExpectations(t) }) diff --git a/broadcast/internal/arc/utils/arc_utils.go b/broadcast/internal/arc/utils/arc_utils.go index c497a6a..a7f35a2 100644 --- a/broadcast/internal/arc/utils/arc_utils.go +++ b/broadcast/internal/arc/utils/arc_utils.go @@ -2,6 +2,8 @@ package arcutils import ( "encoding/json" + "errors" + "fmt" "io" "github.com/bitcoin-sv/go-broadcast-client/broadcast" @@ -15,3 +17,7 @@ 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)) +}