Skip to content

Commit 8ec9ba1

Browse files
authored
Added a generic function for retry mechanism (#1071)
* Added generic function to implement retry mechanism on top of a function * Used InvokeFunctionWithRetryAttempts() for retry mechanism * Moved GetStakerSRZRBalance() from stake.go to stakedToken.go * Fixed tests * Added alternate RPC support * Added alternateProvider as a config paramter * Added GetAlternateProvider() in GetConfig() * Fixed GetStringAlternateProvider() usage in setConfig() * Fixed tests * Used alternateProvider from config * Requested changes
1 parent 927d64f commit 8ec9ba1

26 files changed

+552
-680
lines changed

client/alternateClient.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package client
2+
3+
import (
4+
"github.com/ethereum/go-ethereum/ethclient"
5+
"razor/logger"
6+
"reflect"
7+
"time"
8+
)
9+
10+
var (
11+
log = logger.NewLogger()
12+
alternateClientStruct AlternateClientStruct
13+
)
14+
15+
type AlternateClientStruct struct {
16+
switchToAlternateClient bool
17+
alternateProvider string
18+
}
19+
20+
func StartTimerForAlternateClient(switchClientAfterTime uint64) {
21+
log.Infof("StartTimerForAlternateClient: Alternate client will be switched back to primary client in %v seconds!", switchClientAfterTime)
22+
time.Sleep(time.Duration(switchClientAfterTime) * time.Second)
23+
log.Info("Switching back to primary RPC..")
24+
SetSwitchToAlternateClientStatus(false)
25+
}
26+
27+
//ReplaceClientWithAlternateClient will replace the primary client(client from primary RPC) with secondary client which would be created using alternate RPC
28+
func ReplaceClientWithAlternateClient(arguments []reflect.Value) []reflect.Value {
29+
clientDataType := reflect.TypeOf((*ethclient.Client)(nil)).Elem()
30+
for i := range arguments {
31+
argument := arguments[i]
32+
argumentDataType := reflect.TypeOf(argument.Interface()).Elem()
33+
if argumentDataType != nil {
34+
if argumentDataType == clientDataType {
35+
alternateProvider := GetAlternateProvider()
36+
alternateClient, dialErr := ethclient.Dial(alternateProvider)
37+
if dialErr != nil {
38+
log.Errorf("Error in connecting using alternate RPC %v: %v", alternateProvider, dialErr)
39+
return arguments
40+
}
41+
arguments[i] = reflect.ValueOf(alternateClient)
42+
return arguments
43+
}
44+
}
45+
}
46+
return arguments
47+
}
48+
49+
func GetSwitchToAlternateClientStatus() bool {
50+
return alternateClientStruct.switchToAlternateClient
51+
}
52+
53+
func SetSwitchToAlternateClientStatus(status bool) {
54+
alternateClientStruct.switchToAlternateClient = status
55+
}
56+
57+
func GetAlternateProvider() string {
58+
return alternateClientStruct.alternateProvider
59+
}
60+
61+
func SetAlternateProvider(alternateProvider string) {
62+
alternateClientStruct.alternateProvider = alternateProvider
63+
}

cmd/config-utils.go

+28
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package cmd
33

44
import (
5+
"razor/client"
56
"razor/core"
67
"razor/core/types"
78
"razor/utils"
@@ -14,6 +15,7 @@ import (
1415
func (*UtilsStruct) GetConfigData() (types.Configurations, error) {
1516
config := types.Configurations{
1617
Provider: "",
18+
AlternateProvider: "",
1719
GasMultiplier: 0,
1820
BufferPercent: 0,
1921
WaitTime: 0,
@@ -30,6 +32,10 @@ func (*UtilsStruct) GetConfigData() (types.Configurations, error) {
3032
if err != nil {
3133
return config, err
3234
}
35+
alternateProvider, err := cmdUtils.GetAlternateProvider()
36+
if err != nil {
37+
return config, err
38+
}
3339
gasMultiplier, err := cmdUtils.GetMultiplier()
3440
if err != nil {
3541
return config, err
@@ -79,6 +85,8 @@ func (*UtilsStruct) GetConfigData() (types.Configurations, error) {
7985
return config, err
8086
}
8187
config.Provider = provider
88+
config.AlternateProvider = alternateProvider
89+
client.SetAlternateProvider(alternateProvider)
8290
config.GasMultiplier = gasMultiplier
8391
config.BufferPercent = bufferPercent
8492
config.WaitTime = waitTime
@@ -117,6 +125,26 @@ func (*UtilsStruct) GetProvider() (string, error) {
117125
return provider, nil
118126
}
119127

128+
//This function returns the alternate provider
129+
func (*UtilsStruct) GetAlternateProvider() (string, error) {
130+
alternateProvider, err := flagSetUtils.GetRootStringAlternateProvider()
131+
if err != nil {
132+
return core.DefaultAlternateProvider, err
133+
}
134+
if alternateProvider == "" {
135+
if viper.IsSet("alternateProvider") {
136+
alternateProvider = viper.GetString("alternateProvider")
137+
} else {
138+
alternateProvider = core.DefaultAlternateProvider
139+
log.Debug("alternate provider is not set, taking its default value ", alternateProvider)
140+
}
141+
}
142+
if !strings.HasPrefix(alternateProvider, "https") {
143+
log.Warn("You are not using a secure RPC URL. Switch to an https URL instead to be safe.")
144+
}
145+
return alternateProvider, nil
146+
}
147+
120148
//This function returns the multiplier
121149
func (*UtilsStruct) GetMultiplier() (float32, error) {
122150
gasMultiplier, err := flagSetUtils.GetRootFloat32GasMultiplier()

cmd/config-utils_test.go

+82
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
func TestGetConfigData(t *testing.T) {
1212
nilConfig := types.Configurations{
1313
Provider: "",
14+
AlternateProvider: "",
1415
GasMultiplier: 0,
1516
BufferPercent: 0,
1617
WaitTime: 0,
@@ -25,6 +26,7 @@ func TestGetConfigData(t *testing.T) {
2526

2627
configData := types.Configurations{
2728
Provider: "",
29+
AlternateProvider: "",
2830
GasMultiplier: 1,
2931
BufferPercent: 20,
3032
WaitTime: 1,
@@ -41,6 +43,8 @@ func TestGetConfigData(t *testing.T) {
4143
type args struct {
4244
provider string
4345
providerErr error
46+
alternateProvider string
47+
alternateProviderErr error
4448
gasMultiplier float32
4549
gasMultiplierErr error
4650
bufferPercent int32
@@ -76,6 +80,7 @@ func TestGetConfigData(t *testing.T) {
7680
name: "Test 1: When GetConfigData function executes successfully",
7781
args: args{
7882
provider: "",
83+
alternateProvider: "",
7984
gasMultiplier: 1,
8085
bufferPercent: 20,
8186
waitTime: 1,
@@ -163,12 +168,21 @@ func TestGetConfigData(t *testing.T) {
163168
want: nilConfig,
164169
wantErr: errors.New("httpTimeout error"),
165170
},
171+
{
172+
name: "Test 11: When there is an error in getting alternate provider",
173+
args: args{
174+
alternateProviderErr: errors.New("alternate provider error"),
175+
},
176+
want: nilConfig,
177+
wantErr: errors.New("alternate provider error"),
178+
},
166179
}
167180
for _, tt := range tests {
168181
t.Run(tt.name, func(t *testing.T) {
169182
SetUpMockInterfaces()
170183

171184
cmdUtilsMock.On("GetProvider").Return(tt.args.provider, tt.args.providerErr)
185+
cmdUtilsMock.On("GetAlternateProvider").Return(tt.args.alternateProvider, tt.args.alternateProviderErr)
172186
cmdUtilsMock.On("GetMultiplier").Return(tt.args.gasMultiplier, tt.args.gasMultiplierErr)
173187
cmdUtilsMock.On("GetWaitTime").Return(tt.args.waitTime, tt.args.waitTimeErr)
174188
cmdUtilsMock.On("GetGasPrice").Return(tt.args.gasPrice, tt.args.gasPriceErr)
@@ -630,6 +644,74 @@ func TestGetProvider(t *testing.T) {
630644
}
631645
}
632646

647+
func TestGetAlternateProvider(t *testing.T) {
648+
type args struct {
649+
alternateProvider string
650+
alternateProviderErr error
651+
}
652+
tests := []struct {
653+
name string
654+
args args
655+
want string
656+
wantErr error
657+
}{
658+
{
659+
name: "Test 1: When getAlternateProvider function execute successfully",
660+
args: args{
661+
alternateProvider: "https://polygon-mumbai.g.alchemy.com/v2/-Re1lE3oDIVTWchuKMfRIECn0I",
662+
},
663+
want: "https://polygon-mumbai.g.alchemy.com/v2/-Re1lE3oDIVTWchuKMfRIECn0I",
664+
wantErr: nil,
665+
},
666+
{
667+
name: "Test 2: When alternate provider has prefix https",
668+
args: args{
669+
alternateProvider: "127.0.0.1:8545",
670+
},
671+
want: "127.0.0.1:8545",
672+
wantErr: nil,
673+
},
674+
{
675+
name: "Test 3: When there is an error in getting alternate provider",
676+
args: args{
677+
alternateProviderErr: errors.New("alternateProvider error"),
678+
},
679+
want: "http://127.0.0.1:8545",
680+
wantErr: errors.New("alternateProvider error"),
681+
},
682+
{
683+
name: "Test 4: When alternate provider is nil",
684+
args: args{
685+
alternateProvider: "",
686+
},
687+
want: "http://127.0.0.1:8545",
688+
wantErr: nil,
689+
},
690+
}
691+
for _, tt := range tests {
692+
t.Run(tt.name, func(t *testing.T) {
693+
SetUpMockInterfaces()
694+
695+
flagSetMock.On("GetRootStringAlternateProvider").Return(tt.args.alternateProvider, tt.args.alternateProviderErr)
696+
utils := &UtilsStruct{}
697+
698+
got, err := utils.GetAlternateProvider()
699+
if got != tt.want {
700+
t.Errorf("getAlternateProvider() got = %v, want %v", got, tt.want)
701+
}
702+
if err == nil || tt.wantErr == nil {
703+
if err != tt.wantErr {
704+
t.Errorf("Error for getAlternateProvider function, got = %v, want = %v", err, tt.wantErr)
705+
}
706+
} else {
707+
if err.Error() != tt.wantErr.Error() {
708+
t.Errorf("Error for getAlternateProvider function, got = %v, want = %v", err, tt.wantErr)
709+
}
710+
}
711+
})
712+
}
713+
}
714+
633715
func TestGetWaitTime(t *testing.T) {
634716
type args struct {
635717
waitTime int32

cmd/interface.go

+3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ type AssetManagerInterface interface {
111111

112112
type FlagSetInterface interface {
113113
GetStringProvider(flagSet *pflag.FlagSet) (string, error)
114+
GetStringAlternateProvider(flagSet *pflag.FlagSet) (string, error)
114115
GetFloat32GasMultiplier(flagSet *pflag.FlagSet) (float32, error)
115116
GetInt32Buffer(flagSet *pflag.FlagSet) (int32, error)
116117
GetInt32Wait(flagSet *pflag.FlagSet) (int32, error)
@@ -122,6 +123,7 @@ type FlagSetInterface interface {
122123
GetInt64HTTPTimeout(flagSet *pflag.FlagSet) (int64, error)
123124
GetUint32BountyId(flagSet *pflag.FlagSet) (uint32, error)
124125
GetRootStringProvider() (string, error)
126+
GetRootStringAlternateProvider() (string, error)
125127
GetRootFloat32GasMultiplier() (float32, error)
126128
GetRootInt32Buffer() (int32, error)
127129
GetRootInt32Wait() (int32, error)
@@ -167,6 +169,7 @@ type FlagSetInterface interface {
167169
type UtilsCmdInterface interface {
168170
SetConfig(flagSet *pflag.FlagSet) error
169171
GetProvider() (string, error)
172+
GetAlternateProvider() (string, error)
170173
GetMultiplier() (float32, error)
171174
GetWaitTime() (int32, error)
172175
GetGasPrice() (int32, error)

cmd/mocks/flag_set_interface.go

+42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/mocks/utils_cmd_interface.go

+21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/root.go

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
var (
1717
Provider string
18+
AlternateProvider string
1819
GasMultiplier float32
1920
BufferPercent int32
2021
WaitTime int32
@@ -61,6 +62,7 @@ func init() {
6162
cobra.OnInitialize(initConfig)
6263

6364
rootCmd.PersistentFlags().StringVarP(&Provider, "provider", "p", "", "provider name")
65+
rootCmd.PersistentFlags().StringVarP(&AlternateProvider, "alternateProvider", "", "", "alternate provider name")
6466
rootCmd.PersistentFlags().Float32VarP(&GasMultiplier, "gasmultiplier", "g", -1, "gas multiplier value")
6567
rootCmd.PersistentFlags().Int32VarP(&BufferPercent, "buffer", "b", 0, "buffer percent")
6668
rootCmd.PersistentFlags().Int32VarP(&WaitTime, "wait", "w", -1, "wait time")
@@ -115,6 +117,7 @@ func setLogLevel() {
115117

116118
log.Debug("Config details: ")
117119
log.Debugf("Provider: %s", config.Provider)
120+
log.Debugf("Alternate Provider: %s", config.AlternateProvider)
118121
log.Debugf("Gas Multiplier: %.2f", config.GasMultiplier)
119122
log.Debugf("Buffer Percent: %d", config.BufferPercent)
120123
log.Debugf("Wait Time: %d", config.WaitTime)

0 commit comments

Comments
 (0)