-
Notifications
You must be signed in to change notification settings - Fork 3
/
config.go
308 lines (284 loc) · 10.6 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
package rosetta
import (
"fmt"
"time"
"github.com/coinbase/rosetta-sdk-go/types"
url "github.com/goware/urlx"
"github.com/spf13/pflag"
clientflags "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
crgerrs "github.com/cosmos/rosetta/lib/errors"
crg "github.com/cosmos/rosetta/lib/server"
)
const (
HTTP = "http"
HTTPS = "https"
TCP = "tcp"
HTTPSPORT = "443"
)
// configuration defaults constants
const (
// DefaultBlockchain defines the default blockchain identifier name
DefaultBlockchain = "app"
// DefaultAddr defines the default rosetta binding address
DefaultAddr = ":8080"
// DefaultRetries is the default number of retries
DefaultRetries = 5
// DefaultCometEndpoint is the default value for the CometBFT endpoint
DefaultCometEndpoint = "localhost:26657"
// DefaultGRPCEndpoint is the default value for the gRPC endpoint
DefaultGRPCEndpoint = "localhost:9090"
// DefaultGRPCEndpoint is the default value for the gRPC endpoint
DefaultGRPCTypesServerEndpoint = ""
// DefaultNetwork defines the default network name
DefaultNetwork = "network"
// DefaultOffline defines the default offline value
DefaultOffline = false
// DefaultEnableFeeSuggestion indicates to use fee suggestion if `construction/metadata` is called without gas limit and price
DefaultEnableFeeSuggestion = false
// DenomToSuggest defines the default denom for fee suggestion
DenomToSuggest = "uatom"
// DefaultPrices defines the default list of prices to suggest
DefaultPrices = "1uatom,1stake"
)
// configuration flags
const (
FlagBlockchain = "blockchain"
FlagNetwork = "network"
FlagTendermintEndpoint = "tendermint"
FlagGRPCEndpoint = "grpc"
FlagGRPCTypesServerEndpoint = "grpc-types-server"
FlagAddr = "addr"
FlagRetries = "retries"
FlagOffline = "offline"
FlagEnableFeeSuggestion = "enable-fee-suggestion"
FlagGasToSuggest = "gas-to-suggest"
FlagDenomToSuggest = "denom-to-suggest"
FlagPricesToSuggest = "prices-to-suggest"
FlagPlugin = "plugin"
)
// Config defines the configuration of the rosetta server
type Config struct {
// Blockchain defines the blockchain name
// defaults to DefaultBlockchain
Blockchain string
// Network defines the network name
Network string
// TendermintRPC defines the endpoint to connect to
// CometBFT RPC, specifying 'tcp://' before is not
// required, usually it's at port 26657 of the
TendermintRPC string
// GRPCEndpoint defines the cosmos application gRPC endpoint
// usually it is located at 9090 port
GRPCEndpoint string
// Addr defines the default address to bind the rosetta server to
// defaults to DefaultAddr
Addr string
// Retries defines the maximum number of retries
// rosetta will do before quitting
Retries int
// Offline defines if the server must be run in offline mode
Offline bool
// EnableFeeSuggestion indicates to use fee suggestion when `construction/metadata` is called without gas limit and price
EnableFeeSuggestion bool
// GasToSuggest defines the gas limit for fee suggestion
GasToSuggest int
// DenomToSuggest defines the default denom for fee suggestion
DenomToSuggest string
// GasPrices defines the gas prices for fee suggestion
GasPrices sdk.DecCoins
// Codec overrides the default data and construction api client codecs
Codec *codec.ProtoCodec
// InterfaceRegistry overrides the default data and construction api interface registry
InterfaceRegistry codectypes.InterfaceRegistry
}
// NetworkIdentifier returns the network identifier given the configuration
func (c *Config) NetworkIdentifier() *types.NetworkIdentifier {
return &types.NetworkIdentifier{
Blockchain: c.Blockchain,
Network: c.Network,
}
}
// validate validates a configuration and sets
// its defaults in case they were not provided
func (c *Config) validate() error {
if (c.Codec == nil) != (c.InterfaceRegistry == nil) {
return crgerrs.WrapError(crgerrs.ErrConfig, "codec and interface registry must be both different from nil or nil")
}
if c.Addr == "" {
c.Addr = DefaultAddr
}
if c.Blockchain == "" {
c.Blockchain = DefaultBlockchain
}
if c.Retries == 0 {
c.Retries = DefaultRetries
}
// these are must
if c.Network == "" {
return crgerrs.WrapError(crgerrs.ErrConfig, "network not provided")
}
if c.GasToSuggest <= 0 {
return crgerrs.WrapError(crgerrs.ErrConfig, "gas to suggest must be positive")
}
if c.EnableFeeSuggestion {
found := false
for i := 0; i < c.GasPrices.Len(); i++ {
if c.GasPrices.GetDenomByIndex(i) == c.DenomToSuggest {
found = true
break
}
}
if !found {
return crgerrs.WrapError(crgerrs.ErrConfig, "default suggest denom is not found in prices to suggest")
}
}
// these are optional but it must be online
if c.GRPCEndpoint == "" {
return crgerrs.WrapError(crgerrs.ErrConfig, "grpc endpoint not provided")
}
if c.TendermintRPC == "" {
return crgerrs.WrapError(crgerrs.ErrConfig, "cometbft rpc not provided")
}
validatedURL, err := c.validateURL(c.TendermintRPC)
if err != nil {
return err
}
c.TendermintRPC = validatedURL
return nil
}
func (c *Config) validateURL(tendermintRPC string) (string, error) {
u, err := url.Parse(tendermintRPC)
if err != nil {
return "", crgerrs.WrapError(crgerrs.ErrConfig, err.Error())
}
if u.Port() == HTTPSPORT && u.Scheme != HTTPS {
u.Scheme = HTTPS
}
if u.Port() == "" {
switch u.Scheme {
case HTTP, TCP:
u.Host += ":80"
case HTTPS:
u.Host += ":443"
}
}
return u.String(), nil
}
// WithCodec extends the configuration with a predefined Codec
func (c *Config) WithCodec(ir codectypes.InterfaceRegistry, cdc *codec.ProtoCodec) {
c.Codec = cdc
c.InterfaceRegistry = ir
}
// FromFlags gets the configuration from flags
func FromFlags(flags *pflag.FlagSet) (*Config, error) {
blockchain, err := flags.GetString(FlagBlockchain)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting blockchain flag %s", err.Error()))
}
network, err := flags.GetString(FlagNetwork)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting network flag %s", err.Error()))
}
tendermintRPC, err := flags.GetString(FlagTendermintEndpoint)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting tendermintRPC flag %s", err.Error()))
}
gRPCEndpoint, err := flags.GetString(FlagGRPCEndpoint)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting gRPCEndpoint flag %s", err.Error()))
}
addr, err := flags.GetString(FlagAddr)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting addr flag %s", err.Error()))
}
retries, err := flags.GetInt(FlagRetries)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting retries flag %s", err.Error()))
}
offline, err := flags.GetBool(FlagOffline)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting offline flag %s", err.Error()))
}
enableDefaultFeeSuggestion, err := flags.GetBool(FlagEnableFeeSuggestion)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting enableDefaultFeeSuggestion flag %s", err.Error()))
}
gasToSuggest, err := flags.GetInt(FlagGasToSuggest)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting gasToSuggest flag %s", err.Error()))
}
denomToSuggest, err := flags.GetString(FlagDenomToSuggest)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting denomToSuggest flag %s", err.Error()))
}
var prices sdk.DecCoins
if enableDefaultFeeSuggestion {
pricesToSuggest, err := flags.GetString(FlagPricesToSuggest)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while getting pricesToSuggest flag %s", err.Error()))
}
prices, err = sdk.ParseDecCoins(pricesToSuggest)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while parcing prices from the sdk %s", err.Error()))
}
}
conf := &Config{
Blockchain: blockchain,
Network: network,
TendermintRPC: tendermintRPC,
GRPCEndpoint: gRPCEndpoint,
Addr: addr,
Retries: retries,
Offline: offline,
EnableFeeSuggestion: enableDefaultFeeSuggestion,
GasToSuggest: gasToSuggest,
DenomToSuggest: denomToSuggest,
GasPrices: prices,
}
err = conf.validate()
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while validating configs %s", err.Error()))
}
return conf, nil
}
func ServerFromConfig(conf *Config) (crg.Server, error) {
err := conf.validate()
if err != nil {
return crg.Server{}, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while validating configs %s", err.Error()))
}
client, err := NewClient(conf)
if err != nil {
return crg.Server{}, crgerrs.WrapError(crgerrs.ErrConfig, fmt.Sprintf("while creating a new client from configs %s", err.Error()))
}
return crg.NewServer(
crg.Settings{
Network: &types.NetworkIdentifier{
Blockchain: conf.Blockchain,
Network: conf.Network,
},
Client: client,
Listen: conf.Addr,
Offline: conf.Offline,
Retries: conf.Retries,
RetryWait: 15 * time.Second,
})
}
// SetFlags sets the configuration flags to the given flagset
func SetFlags(flags *pflag.FlagSet) {
flags.String(FlagBlockchain, DefaultBlockchain, "the blockchain type")
flags.String(FlagNetwork, DefaultNetwork, "the network name")
flags.String(FlagTendermintEndpoint, DefaultCometEndpoint, "the CometBFT rpc endpoint, without tcp://")
flags.String(FlagGRPCEndpoint, DefaultGRPCEndpoint, "the app gRPC endpoint")
flags.String(FlagGRPCTypesServerEndpoint, DefaultGRPCTypesServerEndpoint, "the app gRPC Server endpoint for proto messages types and reflection")
flags.String(FlagAddr, DefaultAddr, "the address rosetta will bind to")
flags.Int(FlagRetries, DefaultRetries, "the number of retries that will be done before quitting")
flags.Bool(FlagOffline, DefaultOffline, "run rosetta only with construction API")
flags.Bool(FlagEnableFeeSuggestion, DefaultEnableFeeSuggestion, "enable default fee suggestion")
flags.Int(FlagGasToSuggest, clientflags.DefaultGasLimit, "default gas for fee suggestion")
flags.String(FlagDenomToSuggest, DenomToSuggest, "default denom for fee suggestion")
flags.String(FlagPricesToSuggest, DefaultPrices, "default prices for fee suggestion")
flags.String(FlagPlugin, "", "plugin folder name")
}