Skip to content
This repository has been archived by the owner on Apr 2, 2024. It is now read-only.

Commit

Permalink
Merge pull request #372 from 4chain-ag/feat-integrate-broadcast-client
Browse files Browse the repository at this point in the history
feat(BUX-147): integrate go-broadcast-client
  • Loading branch information
mergify[bot] authored Aug 23, 2023
2 parents 4a8442f + d86329f commit 31ba65a
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 20 deletions.
10 changes: 10 additions & 0 deletions chainstate/broadcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ func createActiveProviders(c *Client, txID, txHex string) []txBroadcastProvider
providers = append(providers, &pvdr)
}

if shouldBroadcastWithBroadcastClient(c) {
pvdr := broadcastClientProvider{txID: txID, txHex: txHex}
providers = append(providers, &pvdr)
}

return providers
}

Expand All @@ -128,6 +133,11 @@ func shouldBroadcastToNowNodes(c *Client) bool {
c.NowNodes() != nil // Only if NowNodes is loaded (requires API key)
}

func shouldBroadcastWithBroadcastClient(c *Client) bool {
return !utils.StringInSlice(ProviderBroadcastClient, c.options.config.excludedProviders) &&
c.BroadcastClient() != nil // Only if NowNodes is loaded (requires API key)
}

func broadcastToProvider(ctx, fallbackCtx context.Context, provider txBroadcastProvider, txID string,
c *Client, fallbackTimeout time.Duration,
resultsChannel chan broadcastResult, status *broadcastStatus,
Expand Down
35 changes: 35 additions & 0 deletions chainstate/broadcast_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
"strings"

"github.com/mrz1836/go-nownodes"
Expand Down Expand Up @@ -149,3 +150,37 @@ func broadcastNowNodes(ctx context.Context, client ClientInterface, uniqueID, tx
func incorrectTxIDReturnedErr(actualTxID, expectedTxID string) error {
return fmt.Errorf("returned tx id [%s] does not match given tx id [%s]", actualTxID, expectedTxID)
}

////

// BroadcastClient provider
type broadcastClientProvider struct {
txID, txHex string
}

func (provider broadcastClientProvider) getName() string {
return ProviderBroadcastClient
}

// Broadcast using BroadcastClient
func (provider broadcastClientProvider) broadcast(ctx context.Context, c *Client) error {
return broadcastWithBroadcastClient(ctx, c, provider.txID, provider.txHex)
}

func broadcastWithBroadcastClient(ctx context.Context, client ClientInterface, txID, hex string) error {
debugLog(client, txID, "executing broadcast request for "+ProviderBroadcastClient)

tx := broadcast.Transaction{
RawTx: hex,
}

result, err := client.BroadcastClient().SubmitTransaction(ctx, &tx)
if err != nil {
debugLog(client, txID, "error broadcast request for "+ProviderBroadcastClient+" failed: "+err.Error())
return nil
}

debugLog(client, txID, "result broadcast request for "+ProviderBroadcastClient+" blockhash: "+result.BlockHash+" status: "+result.TxStatus.String())

return nil
}
34 changes: 24 additions & 10 deletions chainstate/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package chainstate
import (
"context"
"fmt"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
broadcastClient "github.com/bitcoin-sv/go-broadcast-client/broadcast/broadcast-client"
"sync"
"time"

Expand Down Expand Up @@ -35,16 +37,18 @@ type (

// syncConfig holds all the configuration about the different sync processes
syncConfig struct {
excludedProviders []string // List of provider names
httpClient HTTPInterface // Custom HTTP client (Minercraft, WOC)
minercraftConfig *minercraftConfig // minercraftConfig configuration
minercraft minercraft.ClientInterface // Minercraft client
network Network // Current network (mainnet, testnet, stn)
nowNodes nownodes.ClientInterface // NOWNodes client
nowNodesAPIKey string // If set, use this key
queryTimeout time.Duration // Timeout for transaction query
whatsOnChain whatsonchain.ClientInterface // WhatsOnChain client
whatsOnChainAPIKey string // If set, use this key
excludedProviders []string // List of provider names
httpClient HTTPInterface // Custom HTTP client (Minercraft, WOC)
minercraftConfig *minercraftConfig // minercraftConfig configuration
minercraft minercraft.ClientInterface // Minercraft client
network Network // Current network (mainnet, testnet, stn)
nowNodes nownodes.ClientInterface // NOWNodes client
nowNodesAPIKey string // If set, use this key
queryTimeout time.Duration // Timeout for transaction query
whatsOnChain whatsonchain.ClientInterface // WhatsOnChain client
whatsOnChainAPIKey string // If set, use this key
broadcastClient broadcast.Client // Broadcast client
broadcastClientConfig *broadcastClientConfig // Broadcast client config
}

// minercraftConfig is specific for minercraft configuration
Expand All @@ -63,6 +67,11 @@ type (
FeeUnit *utils.FeeUnit `json:"fee_unit"` // The fee unit returned from Policy request
Miner *minercraft.Miner `json:"miner"` // The minercraft miner
}

// broadcastClientConfig is specific for broadcast client configuration
broadcastClientConfig struct {
BroadcastClientApis []broadcastClient.ArcClientConfig `json:"broadcast_client_apis"` // List of broadcast client apis
}
)

// NewClient creates a new client for all on-chain functionality
Expand Down Expand Up @@ -184,6 +193,11 @@ func (c *Client) NowNodes() nownodes.ClientInterface {
return c.options.config.nowNodes
}

// BroadcastClient will return the BroadcastClient client
func (c *Client) BroadcastClient() broadcast.Client {
return c.options.config.broadcastClient
}

// QueryTimeout will return the query timeout
func (c *Client) QueryTimeout() time.Duration {
return c.options.config.queryTimeout
Expand Down
28 changes: 24 additions & 4 deletions chainstate/client_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package chainstate

import (
"context"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
broadcastClient "github.com/bitcoin-sv/go-broadcast-client/broadcast/broadcast-client"
"time"

zLogger "github.com/mrz1836/go-logger"
Expand Down Expand Up @@ -35,10 +37,14 @@ func defaultClientOptions() *clientOptions {
minercraftFeeQuotes: true,
feeUnit: DefaultFee,
},
minercraft: nil,
network: MainNet,
queryTimeout: defaultQueryTimeOut,
whatsOnChain: nil,
minercraft: nil,
network: MainNet,
queryTimeout: defaultQueryTimeOut,
whatsOnChain: nil,
broadcastClient: nil,
broadcastClientConfig: &broadcastClientConfig{
BroadcastClientApis: nil,
},
},
debug: false,
newRelicEnabled: false,
Expand Down Expand Up @@ -260,3 +266,17 @@ func WithMinercraftAPIs(apis []*minercraft.MinerAPIs) ClientOps {
c.config.minercraftConfig.minerAPIs = apis
}
}

// WithBroadcastClient will set broadcast client APIs
func WithBroadcastClient(client broadcast.Client) ClientOps {
return func(c *clientOptions) {
c.config.broadcastClient = client
}
}

// WithBroadcastClientAPIs will set broadcast client APIs
func WithBroadcastClientAPIs(apis []broadcastClient.ArcClientConfig) ClientOps {
return func(c *clientOptions) {
c.config.broadcastClientConfig.BroadcastClientApis = apis
}
}
9 changes: 5 additions & 4 deletions chainstate/definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ const (

// List of providers
const (
ProviderAll = "all" // All providers (used for errors etc)
ProviderMAPI = "mapi" // Query & broadcast provider for mAPI (using given miners)
ProviderNowNodes = "nownodes" // Query & broadcast provider for NowNodes
ProviderWhatsOnChain = "whatsonchain" // Query & broadcast provider for WhatsOnChain
ProviderAll = "all" // All providers (used for errors etc)
ProviderMAPI = "mapi" // Query & broadcast provider for mAPI (using given miners)
ProviderNowNodes = "nownodes" // Query & broadcast provider for NowNodes
ProviderWhatsOnChain = "whatsonchain" // Query & broadcast provider for WhatsOnChain
ProviderBroadcastClient = "broadcastclient" // Query & broadcast provider for configured miners
)

// TransactionInfo is the universal information about the transaction found from a chain provider
Expand Down
2 changes: 2 additions & 0 deletions chainstate/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package chainstate

import (
"context"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
"net/http"
"time"

Expand Down Expand Up @@ -40,6 +41,7 @@ type ProviderServices interface {
Minercraft() minercraft.ClientInterface
NowNodes() nownodes.ClientInterface
WhatsOnChain() whatsonchain.ClientInterface
BroadcastClient() broadcast.Client
}

// MinercraftServices is the minercraft services interface
Expand Down
42 changes: 42 additions & 0 deletions chainstate/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ func (c *Client) query(ctx context.Context, id string, requiredIn RequiredIn,
}
}

// Next: try with BroadcastClient (if loaded)
if !utils.StringInSlice(ProviderBroadcastClient, c.options.config.excludedProviders) {
if c.BroadcastClient() != nil {
if resp, err := queryBroadcastClient(
ctxWithCancel, c, id,
); err == nil && checkRequirement(requiredIn, id, resp) {
return resp
}
}
}

// No transaction information found
return nil
}
Expand Down Expand Up @@ -122,6 +133,20 @@ func (c *Client) fastestQuery(ctx context.Context, id string, requiredIn Require
}
}

if !utils.StringInSlice(ProviderBroadcastClient, c.options.config.excludedProviders) {
if c.BroadcastClient() != nil {
wg.Add(1)
go func(ctx context.Context, client *Client, id string, requiredIn RequiredIn) {
defer wg.Done()
if resp, err := queryBroadcastClient(
ctx, client, id,
); err == nil && checkRequirement(requiredIn, id, resp) {
resultsChannel <- resp
}
}(ctxWithCancel, c, id, requiredIn)
}
}

// Waiting for all requests to finish
go func() {
wg.Wait()
Expand Down Expand Up @@ -187,3 +212,20 @@ func queryNowNodes(ctx context.Context, client ClientInterface, id string) (*Tra
}
return nil, ErrTransactionIDMismatch
}

// queryBroadcastClient will submit a query transaction request to a go-broadcast-client
func queryBroadcastClient(ctx context.Context, client ClientInterface, id string) (*TransactionInfo, error) {
client.DebugLog("executing request in minercraft using " + ProviderBroadcastClient)
if resp, err := client.BroadcastClient().QueryTransaction(ctx, id); err != nil {
client.DebugLog("error executing request in " + ProviderBroadcastClient + " failed: " + err.Error())
return nil, err
} else if resp != nil && strings.EqualFold(resp.TxID, id) {
return &TransactionInfo{
BlockHash: resp.BlockHash,
BlockHeight: resp.BlockHeight,
ID: resp.TxID,
Provider: resp.Miner,
}, nil
}
return nil, ErrTransactionIDMismatch
}
16 changes: 16 additions & 0 deletions client_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package bux
import (
"context"
"database/sql"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
broadcast_client "github.com/bitcoin-sv/go-broadcast-client/broadcast/broadcast-client"
"net/http"
"strings"
"time"
Expand Down Expand Up @@ -744,3 +746,17 @@ func WithMinercraftAPIs(miners []*minercraft.MinerAPIs) ClientOps {
c.chainstate.options = append(c.chainstate.options, chainstate.WithMinercraftAPIs(miners))
}
}

// WithBroadcastClient will set broadcast client
func WithBroadcastClient(broadcastClient broadcast.Client) ClientOps {
return func(c *clientOptions) {
c.chainstate.options = append(c.chainstate.options, chainstate.WithBroadcastClient(broadcastClient))
}
}

// WithBroadcastClientAPIs will set broadcast client APIs
func WithBroadcastClientAPIs(apis []broadcast_client.ArcClientConfig) ClientOps {
return func(c *clientOptions) {
c.chainstate.options = append(c.chainstate.options, chainstate.WithBroadcastClientAPIs(apis))
}
}
1 change: 1 addition & 0 deletions go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions mock_chainstate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bux

import (
"context"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
"time"

"github.com/BuxOrg/bux/chainstate"
Expand Down Expand Up @@ -125,6 +126,10 @@ func (c *chainStateEverythingOnChain) Monitor() chainstate.MonitorService {
return nil
}

func (c *chainStateEverythingOnChain) BroadcastClient() broadcast.Client {
return nil
}

func (c *chainStateEverythingOnChain) QueryTransaction(_ context.Context, id string,
_ chainstate.RequiredIn, _ time.Duration) (*chainstate.TransactionInfo, error) {

Expand Down
4 changes: 2 additions & 2 deletions model_sync_transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ func processSyncTransaction(ctx context.Context, syncTx *SyncTransaction, transa
transaction.BlockHeight = uint64(txInfo.BlockHeight)

// Create status message
message := "transaction was found on-chain by " + txInfo.Provider
message := "transaction was found on-chain by " + chainstate.ProviderBroadcastClient

// Save the transaction (should NOT error)
if err = transaction.Save(ctx); err != nil {
Expand All @@ -688,7 +688,7 @@ func processSyncTransaction(ctx context.Context, syncTx *SyncTransaction, transa
syncTx.Results.Results = append(syncTx.Results.Results, &SyncResult{
Action: syncActionSync,
ExecutedAt: time.Now().UTC(),
Provider: txInfo.Provider,
Provider: chainstate.ProviderBroadcastClient,
StatusMessage: message,
})

Expand Down

0 comments on commit 31ba65a

Please sign in to comment.