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 #521 from BuxOrg/feat/418-default-miners
Browse files Browse the repository at this point in the history
feat(BUX-418, BUX-166): use Arc with gorillapool as a default option
  • Loading branch information
wregulski authored Jan 5, 2024
2 parents d1114ad + 95ebcbd commit 3552dc1
Show file tree
Hide file tree
Showing 19 changed files with 196 additions and 421 deletions.
21 changes: 5 additions & 16 deletions chainstate/broadcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"strings"
"sync"
"time"

"github.com/BuxOrg/bux/utils"
)

var (
Expand Down Expand Up @@ -90,7 +88,8 @@ func (c *Client) broadcast(ctx context.Context, id, hex string, timeout time.Dur
func createActiveProviders(c *Client, txID, txHex string) []txBroadcastProvider {
providers := make([]txBroadcastProvider, 0, 10)

if shouldBroadcastWithMAPI(c) {
switch c.ActiveProvider() {
case ProviderMinercraft:
for _, miner := range c.options.config.minercraftConfig.broadcastMiners {
if miner == nil {
continue
Expand All @@ -99,26 +98,16 @@ func createActiveProviders(c *Client, txID, txHex string) []txBroadcastProvider
pvdr := mapiBroadcastProvider{miner: miner, txID: txID, txHex: txHex}
providers = append(providers, &pvdr)
}
}

if shouldBroadcastWithBroadcastClient(c) {
case ProviderBroadcastClient:
pvdr := broadcastClientProvider{txID: txID, txHex: txHex}
providers = append(providers, &pvdr)
default:
c.options.logger.Warn().Msg("no active provider for broadcast")
}

return providers
}

func shouldBroadcastWithMAPI(c *Client) bool {
return !utils.StringInSlice(ProviderMAPI, c.options.config.excludedProviders) &&
(c.Network() == MainNet || c.Network() == TestNet) // Only supported on main and test right now
}

func shouldBroadcastWithBroadcastClient(c *Client) bool {
return !utils.StringInSlice(ProviderBroadcastClient, c.options.config.excludedProviders) &&
c.BroadcastClient() != nil
}

func broadcastToProvider(ctx, fallbackCtx context.Context, provider txBroadcastProvider, txID string,
c *Client, fallbackTimeout time.Duration,
resultsChannel chan broadcastResult, status *broadcastStatus,
Expand Down
115 changes: 0 additions & 115 deletions chainstate/broadcast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"strings"
"testing"
"time"

broadcast_client_mock "github.com/bitcoin-sv/go-broadcast-client/broadcast/broadcast-client-mock"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -127,120 +126,6 @@ func TestClient_Broadcast_BroadcastClient(t *testing.T) {
})
}

// TestClient_Broadcast_MultipleClients will test the method Broadcast() with multiple clients
func TestClient_Broadcast_MultipleClients(t *testing.T) {
t.Parallel()

t.Run("broadcast - success from multiple clients", func(t *testing.T) {
// given
bc := broadcast_client_mock.Builder().
WithMockArc(broadcast_client_mock.MockSuccess).
Build()
c := NewTestClient(
context.Background(), t,
WithMinercraft(&minerCraftBroadcastSuccess{}),
WithBroadcastClient(bc),
)

// when
providers, err := c.Broadcast(
context.Background(), broadcastExample1TxID, broadcastExample1TxHex, defaultBroadcastTimeOut,
)

// then
require.NoError(t, err)
miners := strings.Split(providers, ",")
assert.GreaterOrEqual(t, len(miners), 1)
assert.True(t, containsAtLeastOneElement(miners,
ProviderBroadcastClient,
minercraft.MinerTaal,
minercraft.MinerMatterpool,
minercraft.MinerGorillaPool,
minercraft.MinerMempool,
))
})

t.Run("broadcast - success from broadcastClient (mAPI timeouts)", func(t *testing.T) {
// given
bc := broadcast_client_mock.Builder().
WithMockArc(broadcast_client_mock.MockSuccess).
Build()
c := NewTestClient(
context.Background(), t,
WithMinercraft(&minerCraftBroadcastTimeout{}), // Timeout
WithBroadcastClient(bc), // Success
)

// when
providers, err := c.Broadcast(
context.Background(), broadcastExample1TxID, broadcastExample1TxHex, defaultBroadcastTimeOut,
)

// then
require.NoError(t, err)
miners := strings.Split(providers, ",")
assert.GreaterOrEqual(t, len(miners), 1)
assert.True(t, containsAtLeastOneElement(miners, ProviderBroadcastClient))
assert.NotContains(t, miners, minercraft.MinerTaal)
assert.NotContains(t, miners, minercraft.MinerMempool)
assert.NotContains(t, miners, minercraft.MinerGorillaPool)
assert.NotContains(t, miners, minercraft.MinerMatterpool)
})

t.Run("broadcast - success from mAPI (broadcastClient timeouts)", func(t *testing.T) {
// given
bc := broadcast_client_mock.Builder().
WithMockArc(broadcast_client_mock.MockTimeout).
Build()
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
c := NewTestClient(
ctx, t,
WithBroadcastClient(bc), // Timeout
WithMinercraft(&minerCraftBroadcastSuccess{}), // Success
)

// when
providers, err := c.Broadcast(
context.Background(), broadcastExample1TxID, broadcastExample1TxHex, defaultBroadcastTimeOut,
)

// then
require.NoError(t, err)
miners := strings.Split(providers, ",")
assert.GreaterOrEqual(t, len(miners), 1)
assert.True(t, containsAtLeastOneElement(
miners,
minercraft.MinerTaal,
minercraft.MinerMempool,
minercraft.MinerGorillaPool,
minercraft.MinerMatterpool,
))
assert.NotContains(t, miners, ProviderBroadcastClient)
})

t.Run("broadcast - all providers fail", func(t *testing.T) {
// given
bc := broadcast_client_mock.Builder().
WithMockArc(broadcast_client_mock.MockFailure).
Build()
c := NewTestClient(
context.Background(), t,
WithMinercraft(&minerCraftTxNotFound{}),
WithBroadcastClient(bc),
)

// when
provider, err := c.Broadcast(
context.Background(), broadcastExample1TxID, broadcastExample1TxHex, defaultBroadcastTimeOut,
)

// then
require.Error(t, err)
assert.Equal(t, ProviderAll, provider)
})
}

func containsAtLeastOneElement(coll1 []string, coll2 ...string) bool {
m := make(map[string]bool)

Expand Down
19 changes: 16 additions & 3 deletions chainstate/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,10 @@ func NewClient(ctx context.Context, opts ...ClientOps) (ClientInterface, error)
client.options.logger = logging.GetDefaultLogger()
}

// Start Minercraft
if err := client.startMinerCraft(ctx); err != nil {
return nil, err
if client.ActiveProvider() == ProviderMinercraft {
if err := client.startMinerCraft(ctx); err != nil {
return nil, err
}
}

// Return the client
Expand Down Expand Up @@ -275,3 +276,15 @@ func (c *Client) DeleteUnreacheableMiners() {
}
c.options.config.minercraftConfig.broadcastMiners = c.options.config.minercraftConfig.broadcastMiners[:validMinerIndex]
}

// ActiveProvider returns a name of a provider based on config.
func (c *Client) ActiveProvider() string {
excluded := c.options.config.excludedProviders
if !utils.StringInSlice(ProviderBroadcastClient, excluded) && c.BroadcastClient() != nil {
return ProviderBroadcastClient
}
if !utils.StringInSlice(ProviderMinercraft, excluded) && (c.Network() == MainNet || c.Network() == TestNet) {
return ProviderMinercraft
}
return ProviderNone
}
6 changes: 2 additions & 4 deletions chainstate/client_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (

// TestWithNewRelic will test the method WithNewRelic()
func TestWithNewRelic(t *testing.T) {

t.Run("get opts", func(t *testing.T) {
opt := WithNewRelic()
assert.IsType(t, *new(ClientOps), opt)
Expand All @@ -35,7 +34,6 @@ func TestWithNewRelic(t *testing.T) {

// TestWithDebugging will test the method WithDebugging()
func TestWithDebugging(t *testing.T) {

t.Run("get opts", func(t *testing.T) {
opt := WithDebugging()
assert.IsType(t, *new(ClientOps), opt)
Expand Down Expand Up @@ -334,9 +332,9 @@ func TestWithExcludedProviders(t *testing.T) {
options := &clientOptions{
config: &syncConfig{},
}
opt := WithExcludedProviders([]string{ProviderWhatsOnChain})
opt := WithExcludedProviders([]string{ProviderBroadcastClient})
opt(options)
assert.Equal(t, 1, len(options.config.excludedProviders))
assert.Equal(t, ProviderWhatsOnChain, options.config.excludedProviders[0])
assert.Equal(t, ProviderBroadcastClient, options.config.excludedProviders[0])
})
}
4 changes: 3 additions & 1 deletion chainstate/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

broadcast_client "github.com/bitcoin-sv/go-broadcast-client/broadcast/broadcast-client"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tonicpow/go-minercraft/v2"
Expand Down Expand Up @@ -47,7 +48,8 @@ func TestNewClient(t *testing.T) {
Token: "",
APIUrl: "https://tapi.taal.com/arc",
}
customClient := broadcast_client.Builder().WithArc(arcConfig).Build()
logger := zerolog.Nop()
customClient := broadcast_client.Builder().WithArc(arcConfig, &logger).Build()
require.NotNil(t, customClient)
c, err := NewClient(
context.Background(),
Expand Down
5 changes: 2 additions & 3 deletions chainstate/definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ const (
// List of providers
const (
ProviderAll = "all" // All providers (used for errors etc)
ProviderMAPI = "mapi" // Query & broadcast provider for mAPI (using given miners)
ProviderWhatsOnChain = "whatsonchain" // Query & broadcast provider for WhatsOnChain
ProviderMinercraft = "minercraft" // Query & broadcast provider for mAPI (using given miners)
ProviderBroadcastClient = "broadcastclient" // Query & broadcast provider for configured miners
ProviderPulse = "pulse" // MerkleProof provider
ProviderNone = "none" // No providers (used to indicate no providers)
)

// DefaultFee is used when a fee has not been set by the user
Expand Down
1 change: 1 addition & 0 deletions chainstate/mock_const.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
onChainExample1Confirmations = int64(314)
onChainExample1TxHex = "01000000025b7439a0c9effa3f19d0e441d2eea596e44a8c49240b6e389c29498285f92ad3010000006a4730440220482c1c896678d7307e1de35cef2aae4907f2684617a26d8abd24c444d527c80d02204c550f8f9d69b9cf65780e2e066041750261702639d02605a2eb694ade4ca1d64121029ce7958b2aa3c627334f50bb810c678e2b284db0ef6f7d067f7fccfa05d0f095ffffffff1998b0e4955e1d8ba976d943c43f32e143ba90e805f0e882d3b8edc0f7473b77020000006a47304402204beb486e5d99a15d4d2267e328abb5466a05fdc20d64903d0ace1c4fabb71a34022024803ae9e18b3c11683b2ff2b5fb4ca973a22fdd390f6ab1f99396604a3f06af4121038ea0f258fb838b5193e9739ddd808bb97aaab52a60ba8a83958b13109ab183ccffffffff030000000000000000fd8901006a0372756e0105004d7d017b22696e223a312c22726566223a5b22653864393134303764643461646164363366333739353032303861383532653562306334383037333563656235346133653334333539346163313839616331625f6f31222c22376135346462326162303030306161303035316134383230343162336135653761636239386333363135363863623334393063666564623066653161356438385f6f33225d2c226f7574223a5b2233356463303036313539393333623438353433343565663663633363366261663165666462353263343837313933386632366539313034343632313562343036225d2c2264656c223a5b5d2c22637265223a5b5d2c2265786563223a5b7b226f70223a2243414c4c222c2264617461223a5b7b22246a6967223a307d2c22757064617465222c5b7b22246a6967223a317d2c7b2267726164756174696f6e506f736974696f6e223a6e756c6c2c226c6576656c223a382c226e616d65223a22e38395e383abe38380222c227870223a373030307d5d5d7d5d7d11010000000000001976a914058cae340a2ef8fd2b43a074b75fb6b38cb2765788acd4020000000000001976a914160381a3811b474ff77f31f64f4e57a5bb5ebf1788ac00000000"
onChainExample1TxID = "908c26f8227fa99f1b26f99a19648653a1382fb3b37b03870e9c138894d29b3b"
onChainExampleArcTxID = "a11b9e1ee08e264f9add02e4afa40dad3c00a23f250ac04449face095c68fab7"

// API key
// testDummyKey = "test-dummy-api-key-value" //nolint:gosec // this is a dummy key
Expand Down
25 changes: 17 additions & 8 deletions chainstate/requirements.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,23 @@ func (c *Client) validRequirement(requirement RequiredIn) bool {
return requirement == RequiredOnChain || requirement == RequiredInMempool
}

// checkRequirement will check to see if the requirement has been met
func checkRequirement(requirement RequiredIn, id string, txInfo *TransactionInfo) bool {
if requirement == RequiredInMempool { // Good response, and only has TX
func checkRequirement(requirement RequiredIn, id string, txInfo *TransactionInfo, onChainCondition bool) bool {
switch requirement {
case RequiredInMempool:
return txInfo.ID == id
} else if requirement == RequiredOnChain { // Good response, found block hash
if len(txInfo.BlockHash) > 0 && txInfo.Confirmations > 0 {
return true
}
case RequiredOnChain:
return onChainCondition
default:
return false
}
return false
}

func checkRequirementArc(requirement RequiredIn, id string, txInfo *TransactionInfo) bool {
isConfirmedOnChain := len(txInfo.BlockHash) > 0 && txInfo.TxStatus != ""
return checkRequirement(requirement, id, txInfo, isConfirmedOnChain)
}

func checkRequirementMapi(requirement RequiredIn, id string, txInfo *TransactionInfo) bool {
isConfirmedOnChain := len(txInfo.BlockHash) > 0 && txInfo.Confirmations > 0
return checkRequirement(requirement, id, txInfo, isConfirmedOnChain)
}
12 changes: 6 additions & 6 deletions chainstate/requirements_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func Test_checkRequirement(t *testing.T) {
t.Parallel()

t.Run("found in mempool - mAPI", func(t *testing.T) {
success := checkRequirement(requiredInMempool, onChainExample1TxID, &TransactionInfo{
success := checkRequirementMapi(requiredInMempool, onChainExample1TxID, &TransactionInfo{
BlockHash: "",
BlockHeight: 0,
Confirmations: 0,
Expand All @@ -22,7 +22,7 @@ func Test_checkRequirement(t *testing.T) {
})

t.Run("found in mempool - on-chain - mAPI", func(t *testing.T) {
success := checkRequirement(requiredInMempool, onChainExample1TxID, &TransactionInfo{
success := checkRequirementMapi(requiredInMempool, onChainExample1TxID, &TransactionInfo{
BlockHash: onChainExample1BlockHash,
BlockHeight: onChainExample1BlockHeight,
Confirmations: 1,
Expand All @@ -34,7 +34,7 @@ func Test_checkRequirement(t *testing.T) {
})

t.Run("found in mempool - whatsonchain", func(t *testing.T) {
success := checkRequirement(requiredInMempool, onChainExample1TxID, &TransactionInfo{
success := checkRequirementMapi(requiredInMempool, onChainExample1TxID, &TransactionInfo{
BlockHash: "",
BlockHeight: 0,
Confirmations: 0,
Expand All @@ -46,7 +46,7 @@ func Test_checkRequirement(t *testing.T) {
})

t.Run("not in mempool - mAPI", func(t *testing.T) {
success := checkRequirement(requiredInMempool, onChainExample1TxID, &TransactionInfo{
success := checkRequirementMapi(requiredInMempool, onChainExample1TxID, &TransactionInfo{
BlockHash: "",
BlockHeight: 0,
Confirmations: 0,
Expand All @@ -58,7 +58,7 @@ func Test_checkRequirement(t *testing.T) {
})

t.Run("found on chain - mAPI", func(t *testing.T) {
success := checkRequirement(requiredOnChain, onChainExample1TxID, &TransactionInfo{
success := checkRequirementMapi(requiredOnChain, onChainExample1TxID, &TransactionInfo{
BlockHash: onChainExample1BlockHash,
BlockHeight: onChainExample1BlockHeight,
Confirmations: 1,
Expand All @@ -70,7 +70,7 @@ func Test_checkRequirement(t *testing.T) {
})

t.Run("not on chain - mAPI", func(t *testing.T) {
success := checkRequirement(requiredOnChain, onChainExample1TxID, &TransactionInfo{
success := checkRequirementMapi(requiredOnChain, onChainExample1TxID, &TransactionInfo{
BlockHash: "",
BlockHeight: 0,
Confirmations: 0,
Expand Down
Loading

0 comments on commit 3552dc1

Please sign in to comment.