From f06b5dbff466c699f0084f8fc7481120d46c67e6 Mon Sep 17 00:00:00 2001 From: wregulski <48433067+wregulski@users.noreply.github.com> Date: Thu, 17 Aug 2023 09:22:06 +0200 Subject: [PATCH] feat(BUX-162): moves headers opts out of tx struct (#14) * feat: moves headers opts out of tx struct * fix: moves .With methods to exposed broadcast packages --- broadcast/interface.go | 4 +- broadcast/internal/arc/arc_submit_tx.go | 44 +++++++++++------ broadcast/internal/arc/arc_submit_tx_test.go | 4 +- broadcast/internal/composite/broadcaster.go | 2 + broadcast/transaction.go | 52 ++++++++++++++------ 5 files changed, 72 insertions(+), 34 deletions(-) diff --git a/broadcast/interface.go b/broadcast/interface.go index 9e02e23..8f1d38d 100644 --- a/broadcast/interface.go +++ b/broadcast/interface.go @@ -24,14 +24,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) (*SubmitTxResponse, error) + 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 slice of SubmitTxResponse objects. type TransactionsSubmitter interface { - SubmitBatchTransactions(ctx context.Context, tx []*Transaction) ([]*SubmitTxResponse, error) + SubmitBatchTransactions(ctx context.Context, tx []*Transaction, opts ...TransactionOptFunc) ([]*SubmitTxResponse, error) } // Client is a grouping interface that represents the entire exposed functionality of the broadcast client. diff --git a/broadcast/internal/arc/arc_submit_tx.go b/broadcast/internal/arc/arc_submit_tx.go index 1071de2..71f17bc 100644 --- a/broadcast/internal/arc/arc_submit_tx.go +++ b/broadcast/internal/arc/arc_submit_tx.go @@ -17,12 +17,17 @@ type SubmitTxRequest struct { var ErrSubmitTxMarshal = errors.New("error while marshalling submit tx body") -func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction) (*broadcast.SubmitTxResponse, error) { +func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transaction, opts ...broadcast.TransactionOptFunc) (*broadcast.SubmitTxResponse, error) { if a == nil { return nil, broadcast.ErrClientUndefined } - result, err := submitTransaction(ctx, a, tx) + options := &broadcast.TransactionOpts{} + for _, opt := range opts { + opt(options) + } + + result, err := submitTransaction(ctx, a, tx, options) if err != nil { return nil, err } @@ -34,7 +39,7 @@ func (a *ArcClient) SubmitTransaction(ctx context.Context, tx *broadcast.Transac return result, nil } -func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction) ([]*broadcast.SubmitTxResponse, error) { +func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcast.Transaction, opts ...broadcast.TransactionOptFunc) ([]*broadcast.SubmitTxResponse, error) { if a == nil { return nil, broadcast.ErrClientUndefined } @@ -43,7 +48,12 @@ func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcas return nil, errors.New("invalid request, no transactions to submit") } - result, err := submitBatchTransactions(ctx, a, txs) + options := &broadcast.TransactionOpts{} + for _, opt := range opts { + opt(options) + } + + result, err := submitBatchTransactions(ctx, a, txs, options) if err != nil { return nil, err } @@ -55,7 +65,7 @@ func (a *ArcClient) SubmitBatchTransactions(ctx context.Context, txs []*broadcas return result, nil } -func submitTransaction(ctx context.Context, arc *ArcClient, tx *broadcast.Transaction) (*broadcast.SubmitTxResponse, error) { +func submitTransaction(ctx context.Context, arc *ArcClient, tx *broadcast.Transaction, opts *broadcast.TransactionOpts) (*broadcast.SubmitTxResponse, error) { url := arc.apiURL + arcSubmitTxRoute data, err := createSubmitTxBody(tx) if err != nil { @@ -68,7 +78,7 @@ func submitTransaction(ctx context.Context, arc *ArcClient, tx *broadcast.Transa arc.token, data, ) - appendSubmitTxHeaders(&pld, tx) + appendSubmitTxHeaders(&pld, opts) resp, err := arc.HTTPClient.DoRequest( ctx, @@ -87,7 +97,7 @@ func submitTransaction(ctx context.Context, arc *ArcClient, tx *broadcast.Transa return &model, nil } -func submitBatchTransactions(ctx context.Context, arc *ArcClient, txs []*broadcast.Transaction) ([]*broadcast.SubmitTxResponse, error) { +func submitBatchTransactions(ctx context.Context, arc *ArcClient, txs []*broadcast.Transaction, opts *broadcast.TransactionOpts) ([]*broadcast.SubmitTxResponse, error) { url := arc.apiURL + arcSubmitBatchTxsRoute data, err := createSubmitBatchTxsBody(txs) if err != nil { @@ -100,7 +110,7 @@ func submitBatchTransactions(ctx context.Context, arc *ArcClient, txs []*broadca arc.token, data, ) - appendSubmitTxHeaders(&pld, txs[0]) + appendSubmitTxHeaders(&pld, opts) resp, err := arc.HTTPClient.DoRequest( ctx, @@ -144,20 +154,24 @@ func createSubmitBatchTxsBody(txs []*broadcast.Transaction) ([]byte, error) { return data, nil } -func appendSubmitTxHeaders(pld *httpclient.HTTPRequest, tx *broadcast.Transaction) { - if tx.MerkleProof { +func appendSubmitTxHeaders(pld *httpclient.HTTPRequest, opts *broadcast.TransactionOpts) { + if opts == nil { + return + } + + if opts.MerkleProof { pld.AddHeader("X-MerkleProof", "true") } - if tx.CallBackURL != "" { - pld.AddHeader("X-CallbackUrl", tx.CallBackURL) + if opts.CallbackURL != "" { + pld.AddHeader("X-CallbackUrl", opts.CallbackURL) } - if tx.CallBackToken != "" { - pld.AddHeader("X-CallbackToken", tx.CallBackToken) + if opts.CallbackToken != "" { + pld.AddHeader("X-CallbackToken", opts.CallbackToken) } - if statusCode, ok := broadcast.MapTxStatusToInt(tx.WaitForStatus); ok { + if statusCode, ok := broadcast.MapTxStatusToInt(opts.WaitForStatus); ok { pld.AddHeader("X-WaitForStatus", strconv.Itoa(statusCode)) } } diff --git a/broadcast/internal/arc/arc_submit_tx_test.go b/broadcast/internal/arc/arc_submit_tx_test.go index c7bd4bb..729d793 100644 --- a/broadcast/internal/arc/arc_submit_tx_test.go +++ b/broadcast/internal/arc/arc_submit_tx_test.go @@ -70,7 +70,7 @@ func TestSubmitTransaction(t *testing.T) { body, _ := createSubmitTxBody(tc.transaction) expectedPayload := httpclient.NewPayload(httpclient.POST, "http://example.com"+arcSubmitTxRoute, "someToken", body) - appendSubmitTxHeaders(&expectedPayload, tc.transaction) + appendSubmitTxHeaders(&expectedPayload, nil) mockHttpClient.On("DoRequest", context.Background(), expectedPayload). Return(tc.httpResponse, tc.httpError).Once() @@ -163,7 +163,7 @@ func TestSubmitBatchTransactions(t *testing.T) { body, _ := createSubmitBatchTxsBody(tc.transactions) expectedPayload := httpclient.NewPayload(httpclient.POST, "http://example.com"+arcSubmitBatchTxsRoute, "someToken", body) - appendSubmitTxHeaders(&expectedPayload, tc.transactions[0]) + appendSubmitTxHeaders(&expectedPayload, nil) mockHttpClient.On("DoRequest", context.Background(), expectedPayload). Return(tc.httpResponse, tc.httpError).Once() diff --git a/broadcast/internal/composite/broadcaster.go b/broadcast/internal/composite/broadcaster.go index 624c4f0..105910e 100644 --- a/broadcast/internal/composite/broadcaster.go +++ b/broadcast/internal/composite/broadcaster.go @@ -94,6 +94,7 @@ func (c *compositeBroadcaster) QueryTransaction( func (c *compositeBroadcaster) SubmitTransaction( ctx context.Context, tx *broadcast.Transaction, + opts ...broadcast.TransactionOptFunc, ) (*broadcast.SubmitTxResponse, error) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { @@ -118,6 +119,7 @@ func (c *compositeBroadcaster) SubmitTransaction( func (c *compositeBroadcaster) SubmitBatchTransactions( ctx context.Context, txs []*broadcast.Transaction, + opts ...broadcast.TransactionOptFunc, ) ([]*broadcast.SubmitTxResponse, error) { executionFuncs := make([]executionFunc, len(c.broadcasters)) for i, broadcaster := range c.broadcasters { diff --git a/broadcast/transaction.go b/broadcast/transaction.go index c69df69..f74804b 100644 --- a/broadcast/transaction.go +++ b/broadcast/transaction.go @@ -2,20 +2,42 @@ package broadcast // Transaction is the body contents in the "submit transaction" request type Transaction struct { - // CallbackEncryption is the encryption method used for the callback (to set in the callback header). - CallBackEncryption string `json:"callBackEncryption,omitempty"` - // CallbackToken is the token used for the callback (to set in the callback header). - CallBackToken string `json:"callBackToken,omitempty"` - // CallbackURL is the URL used for the callback (to set in the callback header). - CallBackURL string `json:"callBackUrl,omitempty"` - // DsCheck is the double spend check flag. - DsCheck bool `json:"dsCheck,omitempty"` - // MerkleFormat is the requested merkle format (to set in the merkle format header). - MerkleFormat string `json:"merkleFormat,omitempty"` - // MerkleProof is the merkle proof flag - if merkle proof should be included in the response (to set in the merkle proof header). - MerkleProof bool `json:"merkleProof,omitempty"` - // RawTx is the raw transaction string -> required. + // RawTx is the raw transaction hex string. RawTx string `json:"rawtx"` - // WaitForStatus is the status to wait for with the callback (to set in the wait for status header). - WaitForStatus TxStatus `json:"waitForStatus,omitempty"` +} + +// TransactionOptFunc defines an optional arguments that can be passed to the SubmitTransaction method. +type TransactionOptFunc func(o *TransactionOpts) + +// TransactionOpts is a struct that holds optional arguments that can be passed to the SubmitTransaction method. +type TransactionOpts struct { + // CallbackURL is the URL that will be called when the transaction status changes. + CallbackURL string + // CallbackToken is the token that will be sent in the callback request. + CallbackToken string + // MerkleProof is a flag that indicates if the merkle proof should be returned in the submit transaction response. + MerkleProof bool + // WaitForStatus is the status that the callback request will wait for. + WaitForStatus TxStatus +} + +func WithCallback(callbackURL string, callbackToken ...string) TransactionOptFunc { + return func(o *TransactionOpts) { + o.CallbackToken = callbackURL + if len(callbackToken) > 0 { + o.CallbackToken = callbackToken[0] + } + } +} + +func WithMerkleProof() TransactionOptFunc { + return func(o *TransactionOpts) { + o.MerkleProof = true + } +} + +func WithWaitForStatus(status TxStatus) TransactionOptFunc { + return func(o *TransactionOpts) { + o.WaitForStatus = status + } }