From 4f464e022ac5264ed65ab2ac89d7c6e399486473 Mon Sep 17 00:00:00 2001 From: wregulski Date: Sun, 19 May 2024 21:16:16 +0200 Subject: [PATCH 1/6] feat: add two helper methods on ArcError --- broadcast/errors.go | 20 ++++++++++++++++---- broadcast/internal/composite/strategy.go | 2 +- examples/submit_transaction/submit_tx.go | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/broadcast/errors.go b/broadcast/errors.go index e91c124..f188a5b 100644 --- a/broadcast/errors.go +++ b/broadcast/errors.go @@ -28,12 +28,12 @@ var ErrUnableToDecodeResponse = errors.New("unable to decode response") // ErrMissingStatus is returned when the tx status is missing. var ErrMissingStatus = errors.New("missing tx status") -// ErrStrategyUnkown is returned when the strategy provided is unknown. +// ErrStrategyUnknown is returned when the strategy provided is unknown. // Example: // // func NewBroadcaster(strategy Strategy, factories ...BroadcastFactory) broadcast.Client -// Calling NewBroadcaster we need to provide a strategy, if the strategy is unknown (we don't have an implementation for that) we return ErrStrategyUnkown. -var ErrStrategyUnkown = errors.New("unknown strategy") +// Calling NewBroadcaster we need to provide a strategy, if the strategy is unknown (we don't have an implementation for that) we return ErrStrategyUnknown. +var ErrStrategyUnknown = 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") @@ -55,13 +55,25 @@ type ArcError struct { ExtraInfo string `json:"extraInfo,omitempty"` } +// IsRejectedTransaction returns true if the transaction is in rejected status. +func (err *ArcError) IsRejectedTransaction() bool { + const RejectedStatus = 109 + return err.Status == RejectedStatus +} + +// Is returns true if the target is an ArcError. +func (err *ArcError) Is(target error) bool { + var arcError *ArcError + return errors.As(target, &arcError) +} + // 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 { +func (err *ArcError) Error() string { sb := strings.Builder{} sb.WriteString("arc error: {") diff --git a/broadcast/internal/composite/strategy.go b/broadcast/internal/composite/strategy.go index da99263..1cba534 100644 --- a/broadcast/internal/composite/strategy.go +++ b/broadcast/internal/composite/strategy.go @@ -33,7 +33,7 @@ func New(name StrategyName) (*Strategy, error) { case OneByOneStrategy: return &Strategy{name: name, executionFunc: OneByOne.executionFunc}, nil default: - return nil, broadcast.ErrStrategyUnkown + return nil, broadcast.ErrStrategyUnknown } } diff --git a/examples/submit_transaction/submit_tx.go b/examples/submit_transaction/submit_tx.go index 1e0aa8c..9b84ed1 100644 --- a/examples/submit_transaction/submit_tx.go +++ b/examples/submit_transaction/submit_tx.go @@ -16,7 +16,7 @@ func main() { token := "mainnet_06770f425eb00298839a24a49cbdc02c" deploymentID := "broadcast-client-example" apiURL := "https://arc.taal.com" - tx := broadcast.Transaction{Hex: "01000000026d9a56036235bb5b5e39b04b6f188c74bc45189a9122f235cad5f0c4b668817d000000006b483045022100ae4c9b06376c42bf82f7910de20bb025d8b43daf33eb2db1966f0f1fd361d499022063594799502920ceceb17e3301e44066431a5ae1e221ce1bd89b446e602adf62412102dd2063cc1d4fbc5a770b156f8cd9f5c80cc586df4c7d148444d6bb66c81a10daffffffff6e574c52ebc1c724a13d0afd525adbcfe0b134d9666ab9004240d9d072a7906b000000006a4730440220191c938793953f931c9297a27a651b07e5cb60432fd5750a3f53488ed23fae8702204c503822986ef959af741609dfe98a51004e36596ca52a865c5e029fdbcfb3d641210253085022df5ebbdc71f9e8f555443660cda4a3d36d732685be317d7e11b9eda4ffffffff0214000000000000001976a914553236189ff9fed552837b952e404e09f78c03fa88ac01000000000000001976a914d8f00ced3f960ffa6f0516b4e352e0a9feccc3af88ac00000000"} + tx := broadcast.Transaction{Hex: "0100000001f58d6ead84eadf358f85db9347e687ec5ed15559330e6b0929e967054ff5dbc4000000006a47304402207831d6ee02ebda30ff306946a1e63654d8234a99e217eb5ddb122fec10b9ea0a02204d18c24990df7fd4efe6805869389172921b473e34a31e35b336c402085f9b964121038989293fb3a740c239977c42edc679831b7f6cb1005545b608034a85f114baf3ffffffff020100000000000000084c0105954c01198807270000000000001976a914e9e47358fc4244d146161527c1ae870bcc179b3488ac00000000"} cfg := broadcast_client.ArcClientConfig{ Token: token, From 35097ca463f5485696124299289ff0aa344d2d35 Mon Sep 17 00:00:00 2001 From: wregulski Date: Sun, 19 May 2024 21:32:17 +0200 Subject: [PATCH 2/6] feat(SPV-642): revert basic error as return type of broadcaster methods --- 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 | 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 +- 11 files changed, 38 insertions(+), 38 deletions(-) diff --git a/broadcast/interface.go b/broadcast/interface.go index 7a8c9e5..e8df92d 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, ArcFailure) + GetFeeQuote(ctx context.Context) ([]*FeeQuote, error) } // 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, ArcFailure) + GetPolicyQuote(ctx context.Context) ([]*PolicyQuoteResponse, error) } // 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, ArcFailure) + QueryTransaction(ctx context.Context, txID string) (*QueryTxResponse, error) } // 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, ArcFailure) + SubmitTransaction(ctx context.Context, tx *Transaction, opts ...TransactionOptFunc) (*SubmitTxResponse, error) } // 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, ArcFailure) + SubmitBatchTransactions(ctx context.Context, tx []*Transaction, opts ...TransactionOptFunc) (*SubmitBatchTxResponse, error) } // 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 7b1b5de..4ef89d1 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.ArcFailure) { +func (a *ArcClient) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, error) { if a == nil { return nil, broadcast.Failure("GetFeeQuote: arc client is nil", nil) } diff --git a/broadcast/internal/arc/arc_policy_quote.go b/broadcast/internal/arc/arc_policy_quote.go index 852df41..666f578 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.ArcFailure) { +func (a *ArcClient) GetPolicyQuote(ctx context.Context) ([]*broadcast.PolicyQuoteResponse, error) { 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 e348e6e..627f435 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.ArcFailure) { +func (a *ArcClient) QueryTransaction(ctx context.Context, txID string) (*broadcast.QueryTxResponse, error) { 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 add3099..255c6fb 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.ArcFailure) { +func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitTxResponse, error) { 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.ArcFailure) { +func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitBatchTxResponse, error) { 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 0b318af..49920b4 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.ArcFailure) { +func (*ArcClientMockFailure) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, error) { return nil, broadcast_api.Failure("", broadcast_api.ErrNoMinerResponse) } // GetPolicyQuote returns an error. -func (*ArcClientMockFailure) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, broadcast_api.ArcFailure) { +func (*ArcClientMockFailure) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, error) { 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.ArcFailure) { +func (*ArcClientMockFailure) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, error) { 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.ArcFailure) { +func (*ArcClientMockFailure) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, error) { 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.ArcFailure) { +func (*ArcClientMockFailure) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, error) { 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 0a9dae4..4c8fe1d 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.ArcFailure) { +func (*ArcClientMock) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, error) { 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.ArcFailure) { +func (*ArcClientMock) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, error) { 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.ArcFailure) { +func (*ArcClientMock) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, error) { 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.ArcFailure) { +func (*ArcClientMock) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, error) { 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.ArcFailure) { +func (*ArcClientMock) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, error) { 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 9b2e34d..3cd95da 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.ArcFailure) { +func (*ArcClientMockTimeout) GetFeeQuote(ctx context.Context) ([]*broadcast_api.FeeQuote, error) { 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.ArcFailure) { +func (*ArcClientMockTimeout) GetPolicyQuote(ctx context.Context) ([]*broadcast_api.PolicyQuoteResponse, error) { 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.ArcFailure) { +func (*ArcClientMockTimeout) QueryTransaction(ctx context.Context, txID string) (*broadcast_api.QueryTxResponse, error) { 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.ArcFailure) { +func (*ArcClientMockTimeout) SubmitTransaction(ctx context.Context, tx *broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitTxResponse, error) { 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.ArcFailure) { +func (*ArcClientMockTimeout) SubmitBatchTransactions(ctx context.Context, tx []*broadcast_api.Transaction, opts ...broadcast_api.TransactionOptFunc) (*broadcast_api.SubmitBatchTxResponse, error) { 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 48f84eb..705916d 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.ArcFailure) { +) ([]*broadcast.PolicyQuoteResponse, error) { 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.ArcFailure) { +func (c *compositeBroadcaster) GetFeeQuote(ctx context.Context) ([]*broadcast.FeeQuote, error) { 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.ArcFailure) { +) (*broadcast.QueryTxResponse, error) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, broadcast.ArcFailure) { + executionFuncs[i] = func(ctx context.Context) (Result, error) { 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.ArcFailure) { +) (*broadcast.SubmitTxResponse, error) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, broadcast.ArcFailure) { + executionFuncs[i] = func(ctx context.Context) (Result, error) { 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.ArcFailure) { +) (*broadcast.SubmitBatchTxResponse, error) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { currentBroadcaster := broadcaster - executionFuncs[i] = func(ctx context.Context) (Result, broadcast.ArcFailure) { + executionFuncs[i] = func(ctx context.Context) (Result, error) { return currentBroadcaster.SubmitBatchTransactions(ctx, txs) } } diff --git a/broadcast/internal/composite/strategy.go b/broadcast/internal/composite/strategy.go index 1cba534..a8d4858 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.ArcFailure) +type executionFunc func(context.Context) (Result, error) -type StrategyExecutionFunc func(context.Context, []executionFunc) (Result, broadcast.ArcFailure) +type StrategyExecutionFunc func(context.Context, []executionFunc) (Result, error) // 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.ArcFailure) { +func (s *Strategy) Execute(ctx context.Context, executionFuncs []executionFunc) (Result, error) { return s.executionFunc(ctx, executionFuncs) } var ( - OneByOne = &Strategy{name: OneByOneStrategy, executionFunc: func(ctx context.Context, executionFuncs []executionFunc) (Result, broadcast.ArcFailure) { + OneByOne = &Strategy{name: OneByOneStrategy, executionFunc: func(ctx context.Context, executionFuncs []executionFunc) (Result, error) { 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 4df11e5..26acdc1 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.ArcFailure) { +func (m mockExecutionFunc) Execute(_ context.Context) (Result, error) { if m.err != nil { return m.result, broadcast.Failure("", m.err) } From 586295f99695ffed159442d915f000b844dfaec8 Mon Sep 17 00:00:00 2001 From: wregulski Date: Sun, 19 May 2024 21:38:49 +0200 Subject: [PATCH 3/6] fix(SPV-642): proper implementation of failure function - use pointer instead of value --- broadcast/errors.go | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/broadcast/errors.go b/broadcast/errors.go index f188a5b..c123903 100644 --- a/broadcast/errors.go +++ b/broadcast/errors.go @@ -38,12 +38,6 @@ var ErrStrategyUnknown = 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"` @@ -67,11 +61,6 @@ func (err *ArcError) Is(target error) bool { return errors.As(target, &arcError) } -// 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{} @@ -117,11 +106,11 @@ func (failure *FailureResponse) Error() string { // Failure returns a new FailureResponse with the description and the error. func Failure(description string, err error) *FailureResponse { - var arcErr ArcError + var arcErr *ArcError if errors.As(err, &arcErr) { return &FailureResponse{ Description: description, - ArcErrorResponse: &arcErr, + ArcErrorResponse: arcErr, } } From 20246f7265ed83d92a569796cb818b69cd3dea60 Mon Sep 17 00:00:00 2001 From: wregulski Date: Sun, 19 May 2024 21:53:13 +0200 Subject: [PATCH 4/6] chore(SPV-642): remove unused is method --- broadcast/errors.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/broadcast/errors.go b/broadcast/errors.go index c123903..7f922f8 100644 --- a/broadcast/errors.go +++ b/broadcast/errors.go @@ -55,12 +55,6 @@ func (err *ArcError) IsRejectedTransaction() bool { return err.Status == RejectedStatus } -// Is returns true if the target is an ArcError. -func (err *ArcError) Is(target error) bool { - var arcError *ArcError - return errors.As(target, &arcError) -} - // Error returns the error string it's the implementation of the error interface. func (err *ArcError) Error() string { sb := strings.Builder{} From 84aab36c0fb32c5fc084e5ebc620a601b897d07d Mon Sep 17 00:00:00 2001 From: Damian Orzepowski Date: Tue, 21 May 2024 14:40:52 +0200 Subject: [PATCH 5/6] feat(SPV-642): return wrapped errors instead of structs (#98) --- broadcast/errors.go | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/broadcast/errors.go b/broadcast/errors.go index 7f922f8..77ffe77 100644 --- a/broadcast/errors.go +++ b/broadcast/errors.go @@ -4,8 +4,9 @@ package broadcast import ( "errors" "fmt" - "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/utils" "strings" + + "github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/utils" ) // ErrClientUndefined is returned when the client is undefined. @@ -79,34 +80,12 @@ 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) - - if failure.ArcErrorResponse != nil { - sb.WriteString(", ") - sb.WriteString(failure.ArcErrorResponse.Error()) - } - - return sb.String() +func (err *ArcError) Is(target error) bool { + var arcError *ArcError + return errors.As(target, &arcError) } // 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) { - return &FailureResponse{ - Description: description, - ArcErrorResponse: arcErr, - } - } - - return &FailureResponse{Description: utils.WithCause(errors.New(description), err).Error()} +func Failure(description string, err error) error { + return utils.WithCause(errors.New(description), err) } From 0af7f8692c078487bc9a4083beb7a5b855937d9e Mon Sep 17 00:00:00 2001 From: wregulski Date: Tue, 21 May 2024 15:29:13 +0200 Subject: [PATCH 6/6] chore(SPV-642): revert previous hex in submit tx example --- examples/submit_transaction/submit_tx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/submit_transaction/submit_tx.go b/examples/submit_transaction/submit_tx.go index 9b84ed1..1e0aa8c 100644 --- a/examples/submit_transaction/submit_tx.go +++ b/examples/submit_transaction/submit_tx.go @@ -16,7 +16,7 @@ func main() { token := "mainnet_06770f425eb00298839a24a49cbdc02c" deploymentID := "broadcast-client-example" apiURL := "https://arc.taal.com" - tx := broadcast.Transaction{Hex: "0100000001f58d6ead84eadf358f85db9347e687ec5ed15559330e6b0929e967054ff5dbc4000000006a47304402207831d6ee02ebda30ff306946a1e63654d8234a99e217eb5ddb122fec10b9ea0a02204d18c24990df7fd4efe6805869389172921b473e34a31e35b336c402085f9b964121038989293fb3a740c239977c42edc679831b7f6cb1005545b608034a85f114baf3ffffffff020100000000000000084c0105954c01198807270000000000001976a914e9e47358fc4244d146161527c1ae870bcc179b3488ac00000000"} + tx := broadcast.Transaction{Hex: "01000000026d9a56036235bb5b5e39b04b6f188c74bc45189a9122f235cad5f0c4b668817d000000006b483045022100ae4c9b06376c42bf82f7910de20bb025d8b43daf33eb2db1966f0f1fd361d499022063594799502920ceceb17e3301e44066431a5ae1e221ce1bd89b446e602adf62412102dd2063cc1d4fbc5a770b156f8cd9f5c80cc586df4c7d148444d6bb66c81a10daffffffff6e574c52ebc1c724a13d0afd525adbcfe0b134d9666ab9004240d9d072a7906b000000006a4730440220191c938793953f931c9297a27a651b07e5cb60432fd5750a3f53488ed23fae8702204c503822986ef959af741609dfe98a51004e36596ca52a865c5e029fdbcfb3d641210253085022df5ebbdc71f9e8f555443660cda4a3d36d732685be317d7e11b9eda4ffffffff0214000000000000001976a914553236189ff9fed552837b952e404e09f78c03fa88ac01000000000000001976a914d8f00ced3f960ffa6f0516b4e352e0a9feccc3af88ac00000000"} cfg := broadcast_client.ArcClientConfig{ Token: token,