From 0012c852750aa8d3a6c52e2ca3d5ac6dfe522672 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Thu, 18 Jul 2024 11:20:25 -0700 Subject: [PATCH 01/13] Add coin gecko pro API usage for the governor --- node/cmd/guardiand/node.go | 8 +- node/pkg/adminrpc/adminserver_test.go | 2 +- node/pkg/governor/governor.go | 4 + node/pkg/governor/governor_monitoring_test.go | 2 +- node/pkg/governor/governor_prices.go | 25 +++-- node/pkg/governor/governor_test.go | 102 +++++++++++++++++- node/pkg/node/adminServiceRunnable.go | 2 +- node/pkg/node/options.go | 8 +- 8 files changed, 136 insertions(+), 17 deletions(-) diff --git a/node/cmd/guardiand/node.go b/node/cmd/guardiand/node.go index 3900b4a71a..44ca8d23b2 100644 --- a/node/cmd/guardiand/node.go +++ b/node/cmd/guardiand/node.go @@ -233,6 +233,7 @@ var ( chainGovernorEnabled *bool governorFlowCancelEnabled *bool + coinGeckoApiKey *string ccqEnabled *bool ccqAllowedRequesters *string @@ -439,6 +440,7 @@ func init() { chainGovernorEnabled = NodeCmd.Flags().Bool("chainGovernorEnabled", false, "Run the chain governor") governorFlowCancelEnabled = NodeCmd.Flags().Bool("governorFlowCancelEnabled", false, "Enable flow cancel on the governor") + coinGeckoApiKey = NodeCmd.Flags().String("coinGeckoApiKey", "", "Coin gecko pro API key. Defaults to off via no API key") ccqEnabled = NodeCmd.Flags().Bool("ccqEnabled", false, "Enable cross chain query support") ccqAllowedRequesters = NodeCmd.Flags().String("ccqAllowedRequesters", "", "Comma separated list of signers allowed to submit cross chain queries") @@ -828,6 +830,10 @@ func runNode(cmd *cobra.Command, args []string) { logger.Fatal("Either --gatewayContract, --gatewayWS and --gatewayLCD must all be set or all unset") } + if !*chainGovernorEnabled && *coinGeckoApiKey != "" { + logger.Fatal("If coinGeckoApiKey is set, then chainGovernorEnabled must be set") + } + var publicRpcLogDetail common.GrpcLogDetail switch *publicRpcLogDetailStr { case "none": @@ -1583,7 +1589,7 @@ func runNode(cmd *cobra.Command, args []string) { node.GuardianOptionDatabase(db), node.GuardianOptionWatchers(watcherConfigs, ibcWatcherConfig), node.GuardianOptionAccountant(*accountantWS, *accountantContract, *accountantCheckEnabled, accountantWormchainConn, *accountantNttContract, accountantNttWormchainConn), - node.GuardianOptionGovernor(*chainGovernorEnabled, *governorFlowCancelEnabled), + node.GuardianOptionGovernor(*chainGovernorEnabled, *governorFlowCancelEnabled, *coinGeckoApiKey), node.GuardianOptionGatewayRelayer(*gatewayRelayerContract, gatewayRelayerWormchainConn), node.GuardianOptionQueryHandler(*ccqEnabled, *ccqAllowedRequesters), node.GuardianOptionAdminService(*adminSocketPath, ethRPC, ethContract, rpcMap), diff --git a/node/pkg/adminrpc/adminserver_test.go b/node/pkg/adminrpc/adminserver_test.go index f1167f71c1..a7e8742177 100644 --- a/node/pkg/adminrpc/adminserver_test.go +++ b/node/pkg/adminrpc/adminserver_test.go @@ -322,7 +322,7 @@ func Test_adminCommands(t *testing.T) { } func newNodePrivilegedServiceForGovernorTests() *nodePrivilegedService { - gov := governor.NewChainGovernor(zap.NewNop(), &db.MockGovernorDB{}, wh_common.GoTest, false) + gov := governor.NewChainGovernor(zap.NewNop(), &db.MockGovernorDB{}, wh_common.GoTest, false, "") return &nodePrivilegedService{ db: nil, diff --git a/node/pkg/governor/governor.go b/node/pkg/governor/governor.go index fbea430def..26d40f68e4 100644 --- a/node/pkg/governor/governor.go +++ b/node/pkg/governor/governor.go @@ -201,6 +201,7 @@ type ChainGovernor struct { statusPublishCounter int64 configPublishCounter int64 flowCancelEnabled bool + coinGeckoApiKey string } func NewChainGovernor( @@ -208,7 +209,9 @@ func NewChainGovernor( db db.GovernorDB, env common.Environment, flowCancelEnabled bool, + coinGeckoApiKey string, ) *ChainGovernor { + return &ChainGovernor{ db: db, logger: logger.With(zap.String("component", "cgov")), @@ -218,6 +221,7 @@ func NewChainGovernor( msgsSeen: make(map[string]bool), env: env, flowCancelEnabled: flowCancelEnabled, + coinGeckoApiKey: coinGeckoApiKey, } } diff --git a/node/pkg/governor/governor_monitoring_test.go b/node/pkg/governor/governor_monitoring_test.go index 5683e17429..2cbd08c815 100644 --- a/node/pkg/governor/governor_monitoring_test.go +++ b/node/pkg/governor/governor_monitoring_test.go @@ -11,7 +11,7 @@ import ( func TestIsVAAEnqueuedNilMessageID(t *testing.T) { logger, _ := zap.NewProduction() - gov := NewChainGovernor(logger, nil, common.GoTest, true) + gov := NewChainGovernor(logger, nil, common.GoTest, true, "") enqueued, err := gov.IsVAAEnqueued(nil) require.EqualError(t, err, "no message ID specified") assert.Equal(t, false, enqueued) diff --git a/node/pkg/governor/governor_prices.go b/node/pkg/governor/governor_prices.go index f3ebe8fded..01d88c5681 100644 --- a/node/pkg/governor/governor_prices.go +++ b/node/pkg/governor/governor_prices.go @@ -44,7 +44,7 @@ func (gov *ChainGovernor) initCoinGecko(ctx context.Context, run bool) error { } // Create the set of queries, breaking the IDs into the appropriate size chunks. - gov.coinGeckoQueries = createCoinGeckoQueries(ids, tokensPerCoinGeckoQuery) + gov.coinGeckoQueries = createCoinGeckoQueries(ids, tokensPerCoinGeckoQuery, gov.coinGeckoApiKey) for queryIdx, query := range gov.coinGeckoQueries { gov.logger.Info("coingecko query: ", zap.Int("queryIdx", queryIdx), zap.String("query", query)) } @@ -64,7 +64,7 @@ func (gov *ChainGovernor) initCoinGecko(ctx context.Context, run bool) error { } // createCoinGeckoQueries creates the set of CoinGecko queries, breaking the set of IDs into the appropriate size chunks. -func createCoinGeckoQueries(idList []string, tokensPerQuery int) []string { +func createCoinGeckoQueries(idList []string, tokensPerQuery int, coinGeckoApiKey string) []string { var queries []string queryIdx := 0 tokenIdx := 0 @@ -72,7 +72,7 @@ func createCoinGeckoQueries(idList []string, tokensPerQuery int) []string { first := true for _, coinGeckoId := range idList { if tokenIdx%tokensPerQuery == 0 && tokenIdx != 0 { - queries = append(queries, createCoinGeckoQuery(ids)) + queries = append(queries, createCoinGeckoQuery(ids, coinGeckoApiKey)) ids = "" first = true queryIdx += 1 @@ -88,19 +88,30 @@ func createCoinGeckoQueries(idList []string, tokensPerQuery int) []string { } if ids != "" { - queries = append(queries, createCoinGeckoQuery(ids)) + queries = append(queries, createCoinGeckoQuery(ids, coinGeckoApiKey)) } return queries } // createCoinGeckoQuery creates a CoinGecko query for the specified set of IDs. -func createCoinGeckoQuery(ids string) string { +func createCoinGeckoQuery(ids string, coinGeckoApiKey string) string { params := url.Values{} params.Add("ids", ids) params.Add("vs_currencies", "usd") - query := "https://api.coingecko.com/api/v3/simple/price?" + params.Encode() + // If modifying this code, ensure that the test 'TestCoinGeckoPriceChecks' passes when adding a pro API key to it. + // Since the code is requires an API key (which we don't want to publish to git), this + // part of the test is normally skipped but mods to sensitive places should still be checked + query := "" + if coinGeckoApiKey == "" { + query = "https://api.coingecko.com/api/v3/simple/price?" + params.Encode() + } else { // Pro version API key path + query = "https://pro-api.coingecko.com/api/v3/simple/price?" + params.Add("x_cg_pro_api_key", coinGeckoApiKey) + query += "&" + params.Encode() + } + return query } @@ -309,7 +320,7 @@ func CheckQuery(logger *zap.Logger) error { logger.Info("Instantiating governor.") ctx := context.Background() var db db.MockGovernorDB - gov := NewChainGovernor(logger, &db, common.MainNet, true) + gov := NewChainGovernor(logger, &db, common.MainNet, true, "") if err := gov.initConfig(); err != nil { return err diff --git a/node/pkg/governor/governor_test.go b/node/pkg/governor/governor_test.go index 388af53d37..7a0e5bde4d 100644 --- a/node/pkg/governor/governor_test.go +++ b/node/pkg/governor/governor_test.go @@ -666,7 +666,7 @@ func newChainGovernorForTestWithLogger(ctx context.Context, logger *zap.Logger) } var db db.MockGovernorDB - gov := NewChainGovernor(logger, &db, common.GoTest, true) + gov := NewChainGovernor(logger, &db, common.GoTest, true, "") err := gov.Run(ctx) if err != nil { @@ -2183,7 +2183,7 @@ func TestSmallerPendingTransfersAfterBigOneShouldGetReleased(t *testing.T) { func TestMainnetConfigIsValid(t *testing.T) { logger := zap.NewNop() var db db.MockGovernorDB - gov := NewChainGovernor(logger, &db, common.GoTest, true) + gov := NewChainGovernor(logger, &db, common.GoTest, true, "") gov.env = common.TestNet err := gov.initConfig() @@ -2193,7 +2193,7 @@ func TestMainnetConfigIsValid(t *testing.T) { func TestTestnetConfigIsValid(t *testing.T) { logger := zap.NewNop() var db db.MockGovernorDB - gov := NewChainGovernor(logger, &db, common.GoTest, true) + gov := NewChainGovernor(logger, &db, common.GoTest, true, "") gov.env = common.TestNet err := gov.initConfig() @@ -3187,7 +3187,7 @@ func TestCoinGeckoQueries(t *testing.T) { ids[idx] = fmt.Sprintf("id%d", idx) } - queries := createCoinGeckoQueries(ids, tc.chunkSize) + queries := createCoinGeckoQueries(ids, tc.chunkSize, "") require.Equal(t, tc.expectedQueries, len(queries)) results := make(map[string]string) @@ -3216,6 +3216,100 @@ func TestCoinGeckoQueries(t *testing.T) { } } +// Test the URL of CoinGecko queries to be correct +func TestCoinGeckoQueryFormat(t *testing.T) { + id_amount := 10 + ids := make([]string, id_amount) + for idx := 0; idx < id_amount; idx++ { + ids[idx] = fmt.Sprintf("id%d", idx) + } + + // Create and parse the query + queries := createCoinGeckoQueries(ids, 100, "") // Not API key + require.Equal(t, len(queries), 1) + query_url, err := url.Parse(queries[0]) + require.Equal(t, err, nil) + params, err := url.ParseQuery(query_url.RawQuery) + require.Equal(t, err, nil) + + // Test the portions of the URL for the non-pro version of the API + require.Equal(t, query_url.Scheme, "https") + require.Equal(t, query_url.Host, "api.coingecko.com") + require.Equal(t, query_url.Path, "/api/v3/simple/price") + require.Equal(t, params.Has("x_cg_pro_api_key"), false) + require.Equal(t, params.Has("vs_currencies"), true) + require.Equal(t, params["vs_currencies"][0], "usd") + require.Equal(t, params.Has("ids"), true) + + // Create and parse the query with an API key + queries = createCoinGeckoQueries(ids, 100, "FAKE_KEY") // With API key + require.Equal(t, len(queries), 1) + query_url, err = url.Parse(queries[0]) + require.Equal(t, err, nil) + params, err = url.ParseQuery(query_url.RawQuery) + require.Equal(t, err, nil) + + // Test the portions of the URL actually provided + require.Equal(t, query_url.Scheme, "https") + require.Equal(t, query_url.Host, "pro-api.coingecko.com") + require.Equal(t, query_url.Path, "/api/v3/simple/price") + require.Equal(t, params.Has("x_cg_pro_api_key"), true) + require.Equal(t, params["x_cg_pro_api_key"][0], "FAKE_KEY") + require.Equal(t, params.Has("vs_currencies"), true) + require.Equal(t, params["vs_currencies"][0], "usd") + require.Equal(t, params.Has("ids"), true) + +} + +// Test that the prices are gathering from the CoinGecko API +func TestCoinGeckoPriceChecks(t *testing.T) { + coinGeckoApiKey := "" // Add API key to test the pro API endpoint. Remove before commit + ids := []string{"usd-coin"} + + ctx := context.Background() + gov, err := newChainGovernorForTest(ctx) + require.Equal(t, err, nil) + + /* + The standard governor doesn't have the test suite initiated. Even if it did, + the amount of time this takes is too high So, instead of doing that, we're + testing at a lower level to ensure that the queries are actually made successfully + from the URLs given directly + */ + coinGeckoQueries := createCoinGeckoQueries(ids, 1, "") + require.Equal(t, len(coinGeckoQueries), 1) + + token_map, err := gov.queryCoinGeckoChunk(coinGeckoQueries[0]) + require.Equal(t, err, nil) + token_entry, ok := token_map[ids[0]].(map[string]interface{}) + require.Equal(t, ok, true) + + token_price, ok := token_entry["usd"] + require.Equal(t, ok, true) + require.LessOrEqual(t, token_price, 1.5) + require.GreaterOrEqual(t, token_price, 0.5) + + // Only run if the key is specified + if coinGeckoApiKey != "" { + // Pro API key tests + coinGeckoQueries = createCoinGeckoQueries(ids, 1, coinGeckoApiKey) + require.Equal(t, len(coinGeckoQueries), 1) + + token_map, err = gov.queryCoinGeckoChunk(coinGeckoQueries[0]) + require.Equal(t, err, nil) + + // Check the price information. Make sure it succeeded. + token_entry, ok = token_map[ids[0]].(map[string]interface{}) + require.Equal(t, ok, true) + token_price, ok = token_entry["usd"] + require.Equal(t, ok, true) + require.LessOrEqual(t, token_price, 1.5) + require.GreaterOrEqual(t, token_price, 0.5) + + fmt.Println(coinGeckoQueries) + } +} + // setupLogsCapture is a helper function for making a zap logger/observer combination for testing that certain logs have been made func setupLogsCapture(t testing.TB, options ...zap.Option) (*zap.Logger, *observer.ObservedLogs) { t.Helper() diff --git a/node/pkg/node/adminServiceRunnable.go b/node/pkg/node/adminServiceRunnable.go index 44e1e79bc8..d892333238 100644 --- a/node/pkg/node/adminServiceRunnable.go +++ b/node/pkg/node/adminServiceRunnable.go @@ -77,7 +77,7 @@ func adminServiceRunnable( contract := ethcommon.HexToAddress(*ethContract) evmConnector, err = connectors.NewEthereumBaseConnector(ctx, "eth", *ethRpc, contract, logger) if err != nil { - return nil, fmt.Errorf("failed to connecto to ethereum") + return nil, fmt.Errorf("failed to connect to ethereum") } } diff --git a/node/pkg/node/options.go b/node/pkg/node/options.go index 48f2e8c5af..5103148c69 100644 --- a/node/pkg/node/options.go +++ b/node/pkg/node/options.go @@ -218,7 +218,7 @@ func GuardianOptionAccountant( // GuardianOptionGovernor enables or disables the governor. // Dependencies: db -func GuardianOptionGovernor(governorEnabled bool, flowCancelEnabled bool) *GuardianOption { +func GuardianOptionGovernor(governorEnabled bool, flowCancelEnabled bool, coinGeckoApiKey string) *GuardianOption { return &GuardianOption{ name: "governor", dependencies: []string{"db"}, @@ -227,9 +227,13 @@ func GuardianOptionGovernor(governorEnabled bool, flowCancelEnabled bool) *Guard if flowCancelEnabled { logger.Info("chain governor is enabled with flow cancel enabled") } else { + logger.Info("chain governor is enabled without flow cancel") } - g.gov = governor.NewChainGovernor(logger, g.db, g.env, flowCancelEnabled) + if coinGeckoApiKey != "" { + logger.Info("coingecko pro API key in use") + } + g.gov = governor.NewChainGovernor(logger, g.db, g.env, flowCancelEnabled, coinGeckoApiKey) } else { logger.Info("chain governor is disabled") } From 7f44428094c5ec560d509aee903947da0279fbf6 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Thu, 18 Jul 2024 12:11:08 -0700 Subject: [PATCH 02/13] Add in missing parameter for node test --- node/pkg/node/node_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/pkg/node/node_test.go b/node/pkg/node/node_test.go index 9c74be7af4..38929c3209 100644 --- a/node/pkg/node/node_test.go +++ b/node/pkg/node/node_test.go @@ -188,7 +188,7 @@ func mockGuardianRunnable(t testing.TB, gs []*mockGuardian, mockGuardianIndex ui GuardianOptionDatabase(db), GuardianOptionWatchers(watcherConfigs, nil), GuardianOptionNoAccountant(), // disable accountant - GuardianOptionGovernor(true, false), + GuardianOptionGovernor(true, false, ""), GuardianOptionGatewayRelayer("", nil), // disable gateway relayer GuardianOptionP2P(gs[mockGuardianIndex].p2pKey, networkID, bootstrapPeers, nodeName, false, false, cfg.p2pPort, "", 0, "", "", func() string { return "" }), GuardianOptionPublicRpcSocket(cfg.publicSocket, publicRpcLogDetail), From c8de38579ee23592d1c57b7c0c3991cb0e56e05a Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Thu, 18 Jul 2024 12:28:22 -0700 Subject: [PATCH 03/13] Fix missing parameter in publicrpcserver_test.go --- node/pkg/publicrpc/publicrpcserver_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/pkg/publicrpc/publicrpcserver_test.go b/node/pkg/publicrpc/publicrpcserver_test.go index a6b9dad416..8e2446df0c 100644 --- a/node/pkg/publicrpc/publicrpcserver_test.go +++ b/node/pkg/publicrpc/publicrpcserver_test.go @@ -69,7 +69,7 @@ func TestGetSignedVAABadAddress(t *testing.T) { func TestGovernorIsVAAEnqueuedNoMessage(t *testing.T) { ctx := context.Background() logger, _ := zap.NewProduction() - gov := governor.NewChainGovernor(logger, nil, common.GoTest, false) + gov := governor.NewChainGovernor(logger, nil, common.GoTest, false, "") server := &PublicrpcServer{logger: logger, gov: gov} // A message without the messageId set should not panic but return an error instead. From b96fdfa585059176e41b6c1e66e206ffd425fe32 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Fri, 19 Jul 2024 08:52:23 -0700 Subject: [PATCH 04/13] Add in NIT fixes --- node/pkg/governor/governor.go | 1 - node/pkg/governor/governor_prices.go | 2 +- node/pkg/governor/governor_test.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/node/pkg/governor/governor.go b/node/pkg/governor/governor.go index 26d40f68e4..8f6137b1c8 100644 --- a/node/pkg/governor/governor.go +++ b/node/pkg/governor/governor.go @@ -211,7 +211,6 @@ func NewChainGovernor( flowCancelEnabled bool, coinGeckoApiKey string, ) *ChainGovernor { - return &ChainGovernor{ db: db, logger: logger.With(zap.String("component", "cgov")), diff --git a/node/pkg/governor/governor_prices.go b/node/pkg/governor/governor_prices.go index 01d88c5681..95aa32eacc 100644 --- a/node/pkg/governor/governor_prices.go +++ b/node/pkg/governor/governor_prices.go @@ -101,7 +101,7 @@ func createCoinGeckoQuery(ids string, coinGeckoApiKey string) string { params.Add("vs_currencies", "usd") // If modifying this code, ensure that the test 'TestCoinGeckoPriceChecks' passes when adding a pro API key to it. - // Since the code is requires an API key (which we don't want to publish to git), this + // Since the code requires an API key (which we don't want to publish to git), this // part of the test is normally skipped but mods to sensitive places should still be checked query := "" if coinGeckoApiKey == "" { diff --git a/node/pkg/governor/governor_test.go b/node/pkg/governor/governor_test.go index 7a0e5bde4d..c3caab8911 100644 --- a/node/pkg/governor/governor_test.go +++ b/node/pkg/governor/governor_test.go @@ -3225,7 +3225,7 @@ func TestCoinGeckoQueryFormat(t *testing.T) { } // Create and parse the query - queries := createCoinGeckoQueries(ids, 100, "") // Not API key + queries := createCoinGeckoQueries(ids, 100, "") // No API key require.Equal(t, len(queries), 1) query_url, err := url.Parse(queries[0]) require.Equal(t, err, nil) From f22f58aaaf1d96de2befe6c7f94c0a1629e87bcc Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Fri, 19 Jul 2024 08:54:30 -0700 Subject: [PATCH 05/13] Change CLI description --- node/cmd/guardiand/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/cmd/guardiand/node.go b/node/cmd/guardiand/node.go index 44ca8d23b2..f7a3ed180d 100644 --- a/node/cmd/guardiand/node.go +++ b/node/cmd/guardiand/node.go @@ -440,7 +440,7 @@ func init() { chainGovernorEnabled = NodeCmd.Flags().Bool("chainGovernorEnabled", false, "Run the chain governor") governorFlowCancelEnabled = NodeCmd.Flags().Bool("governorFlowCancelEnabled", false, "Enable flow cancel on the governor") - coinGeckoApiKey = NodeCmd.Flags().String("coinGeckoApiKey", "", "Coin gecko pro API key. Defaults to off via no API key") + coinGeckoApiKey = NodeCmd.Flags().String("coinGeckoApiKey", "", "CoinGecko Pro API key. If no API key is provided, CoinGecko requests may be throttled or blocked.") ccqEnabled = NodeCmd.Flags().Bool("ccqEnabled", false, "Enable cross chain query support") ccqAllowedRequesters = NodeCmd.Flags().String("ccqAllowedRequesters", "", "Comma separated list of signers allowed to submit cross chain queries") From ba177693b8c19affef77da7df56ca8a063061db0 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Tue, 23 Jul 2024 12:45:01 -0700 Subject: [PATCH 06/13] Reorder error message so that the important part is not truncated in the logs --- node/pkg/governor/governor_prices.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/pkg/governor/governor_prices.go b/node/pkg/governor/governor_prices.go index 95aa32eacc..10879f22ea 100644 --- a/node/pkg/governor/governor_prices.go +++ b/node/pkg/governor/governor_prices.go @@ -171,7 +171,7 @@ func (gov *ChainGovernor) queryCoinGecko(ctx context.Context) error { query := query + "&" + params.Encode() thisResult, err := gov.queryCoinGeckoChunk(query) if err != nil { - gov.logger.Error("CoinGecko query failed", zap.Int("queryIdx", queryIdx), zap.String("query", query), zap.Error(err)) + gov.logger.Error("CoinGecko query failed", zap.Error(err), zap.Int("queryIdx", queryIdx), zap.String("query", query)) gov.revertAllPrices() return err } From f593041dbc9e430a9db37913d42b2e1d228fa0f4 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Tue, 23 Jul 2024 12:48:43 -0700 Subject: [PATCH 07/13] Remove network test from unit test. Plan on creating a Github action cron action for this instead --- node/pkg/governor/governor_test.go | 50 ------------------------------ 1 file changed, 50 deletions(-) diff --git a/node/pkg/governor/governor_test.go b/node/pkg/governor/governor_test.go index c3caab8911..3ce25645a5 100644 --- a/node/pkg/governor/governor_test.go +++ b/node/pkg/governor/governor_test.go @@ -3258,56 +3258,6 @@ func TestCoinGeckoQueryFormat(t *testing.T) { require.Equal(t, params.Has("vs_currencies"), true) require.Equal(t, params["vs_currencies"][0], "usd") require.Equal(t, params.Has("ids"), true) - -} - -// Test that the prices are gathering from the CoinGecko API -func TestCoinGeckoPriceChecks(t *testing.T) { - coinGeckoApiKey := "" // Add API key to test the pro API endpoint. Remove before commit - ids := []string{"usd-coin"} - - ctx := context.Background() - gov, err := newChainGovernorForTest(ctx) - require.Equal(t, err, nil) - - /* - The standard governor doesn't have the test suite initiated. Even if it did, - the amount of time this takes is too high So, instead of doing that, we're - testing at a lower level to ensure that the queries are actually made successfully - from the URLs given directly - */ - coinGeckoQueries := createCoinGeckoQueries(ids, 1, "") - require.Equal(t, len(coinGeckoQueries), 1) - - token_map, err := gov.queryCoinGeckoChunk(coinGeckoQueries[0]) - require.Equal(t, err, nil) - token_entry, ok := token_map[ids[0]].(map[string]interface{}) - require.Equal(t, ok, true) - - token_price, ok := token_entry["usd"] - require.Equal(t, ok, true) - require.LessOrEqual(t, token_price, 1.5) - require.GreaterOrEqual(t, token_price, 0.5) - - // Only run if the key is specified - if coinGeckoApiKey != "" { - // Pro API key tests - coinGeckoQueries = createCoinGeckoQueries(ids, 1, coinGeckoApiKey) - require.Equal(t, len(coinGeckoQueries), 1) - - token_map, err = gov.queryCoinGeckoChunk(coinGeckoQueries[0]) - require.Equal(t, err, nil) - - // Check the price information. Make sure it succeeded. - token_entry, ok = token_map[ids[0]].(map[string]interface{}) - require.Equal(t, ok, true) - token_price, ok = token_entry["usd"] - require.Equal(t, ok, true) - require.LessOrEqual(t, token_price, 1.5) - require.GreaterOrEqual(t, token_price, 0.5) - - fmt.Println(coinGeckoQueries) - } } // setupLogsCapture is a helper function for making a zap logger/observer combination for testing that certain logs have been made From aed07e4536d329168cb008db5d79793695d46fb7 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Tue, 6 Aug 2024 10:11:12 -0700 Subject: [PATCH 08/13] Remove unnecessary '&' from URL path --- node/pkg/governor/governor_prices.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/pkg/governor/governor_prices.go b/node/pkg/governor/governor_prices.go index 10879f22ea..59d61bc068 100644 --- a/node/pkg/governor/governor_prices.go +++ b/node/pkg/governor/governor_prices.go @@ -109,7 +109,7 @@ func createCoinGeckoQuery(ids string, coinGeckoApiKey string) string { } else { // Pro version API key path query = "https://pro-api.coingecko.com/api/v3/simple/price?" params.Add("x_cg_pro_api_key", coinGeckoApiKey) - query += "&" + params.Encode() + query += params.Encode() } return query From 85f29eacebea5dbf3981748dea0d507fb640aedb Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Tue, 6 Aug 2024 10:43:05 -0700 Subject: [PATCH 09/13] Add in new parameters for gov from rebase --- node/pkg/governor/governor_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/pkg/governor/governor_test.go b/node/pkg/governor/governor_test.go index 3ce25645a5..d44168c5d7 100644 --- a/node/pkg/governor/governor_test.go +++ b/node/pkg/governor/governor_test.go @@ -302,7 +302,7 @@ func TestFlowCancelFeatureFlag(t *testing.T) { ctx := context.Background() var db db.MockGovernorDB - gov := NewChainGovernor(zap.NewNop(), &db, common.GoTest, true) + gov := NewChainGovernor(zap.NewNop(), &db, common.GoTest, true, "") // Trigger the evaluation of the flow cancelling config err := gov.Run(ctx) @@ -322,7 +322,7 @@ func TestFlowCancelFeatureFlag(t *testing.T) { assert.NotZero(t, numFlowCancelling) // Disable flow cancelling - gov = NewChainGovernor(zap.NewNop(), &db, common.GoTest, false) + gov = NewChainGovernor(zap.NewNop(), &db, common.GoTest, false, "") // Trigger the evaluation of the flow cancelling config err = gov.Run(ctx) From ad83a2a0750e0a4bd5bef2b8307684c04bfb2de2 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Thu, 22 Aug 2024 10:09:41 -0700 Subject: [PATCH 10/13] Fix regression on query creation --- node/pkg/governor/governor_prices.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/node/pkg/governor/governor_prices.go b/node/pkg/governor/governor_prices.go index 59d61bc068..88e02417a4 100644 --- a/node/pkg/governor/governor_prices.go +++ b/node/pkg/governor/governor_prices.go @@ -107,9 +107,8 @@ func createCoinGeckoQuery(ids string, coinGeckoApiKey string) string { if coinGeckoApiKey == "" { query = "https://api.coingecko.com/api/v3/simple/price?" + params.Encode() } else { // Pro version API key path - query = "https://pro-api.coingecko.com/api/v3/simple/price?" params.Add("x_cg_pro_api_key", coinGeckoApiKey) - query += params.Encode() + query = "https://pro-api.coingecko.com/api/v3/simple/price?" + params.Encode() } return query From 4c7772e40bc39af1fcb165e51d426a3332d2d3d3 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Thu, 18 Jul 2024 11:20:25 -0700 Subject: [PATCH 11/13] Add coin gecko pro API usage for the governor --- node/pkg/governor/governor.go | 1 + node/pkg/governor/governor_test.go | 50 ++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/node/pkg/governor/governor.go b/node/pkg/governor/governor.go index 8f6137b1c8..26d40f68e4 100644 --- a/node/pkg/governor/governor.go +++ b/node/pkg/governor/governor.go @@ -211,6 +211,7 @@ func NewChainGovernor( flowCancelEnabled bool, coinGeckoApiKey string, ) *ChainGovernor { + return &ChainGovernor{ db: db, logger: logger.With(zap.String("component", "cgov")), diff --git a/node/pkg/governor/governor_test.go b/node/pkg/governor/governor_test.go index d44168c5d7..4360db1e91 100644 --- a/node/pkg/governor/governor_test.go +++ b/node/pkg/governor/governor_test.go @@ -3258,6 +3258,56 @@ func TestCoinGeckoQueryFormat(t *testing.T) { require.Equal(t, params.Has("vs_currencies"), true) require.Equal(t, params["vs_currencies"][0], "usd") require.Equal(t, params.Has("ids"), true) + +} + +// Test that the prices are gathering from the CoinGecko API +func TestCoinGeckoPriceChecks(t *testing.T) { + coinGeckoApiKey := "" // Add API key to test the pro API endpoint. Remove before commit + ids := []string{"usd-coin"} + + ctx := context.Background() + gov, err := newChainGovernorForTest(ctx) + require.Equal(t, err, nil) + + /* + The standard governor doesn't have the test suite initiated. Even if it did, + the amount of time this takes is too high So, instead of doing that, we're + testing at a lower level to ensure that the queries are actually made successfully + from the URLs given directly + */ + coinGeckoQueries := createCoinGeckoQueries(ids, 1, "") + require.Equal(t, len(coinGeckoQueries), 1) + + token_map, err := gov.queryCoinGeckoChunk(coinGeckoQueries[0]) + require.Equal(t, err, nil) + token_entry, ok := token_map[ids[0]].(map[string]interface{}) + require.Equal(t, ok, true) + + token_price, ok := token_entry["usd"] + require.Equal(t, ok, true) + require.LessOrEqual(t, token_price, 1.5) + require.GreaterOrEqual(t, token_price, 0.5) + + // Only run if the key is specified + if coinGeckoApiKey != "" { + // Pro API key tests + coinGeckoQueries = createCoinGeckoQueries(ids, 1, coinGeckoApiKey) + require.Equal(t, len(coinGeckoQueries), 1) + + token_map, err = gov.queryCoinGeckoChunk(coinGeckoQueries[0]) + require.Equal(t, err, nil) + + // Check the price information. Make sure it succeeded. + token_entry, ok = token_map[ids[0]].(map[string]interface{}) + require.Equal(t, ok, true) + token_price, ok = token_entry["usd"] + require.Equal(t, ok, true) + require.LessOrEqual(t, token_price, 1.5) + require.GreaterOrEqual(t, token_price, 0.5) + + fmt.Println(coinGeckoQueries) + } } // setupLogsCapture is a helper function for making a zap logger/observer combination for testing that certain logs have been made From 4d443f806717a3a6ca1ebff8fea862ab3f8dbb14 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Fri, 19 Jul 2024 08:52:23 -0700 Subject: [PATCH 12/13] Add in NIT fixes --- node/pkg/governor/governor.go | 1 - 1 file changed, 1 deletion(-) diff --git a/node/pkg/governor/governor.go b/node/pkg/governor/governor.go index 26d40f68e4..8f6137b1c8 100644 --- a/node/pkg/governor/governor.go +++ b/node/pkg/governor/governor.go @@ -211,7 +211,6 @@ func NewChainGovernor( flowCancelEnabled bool, coinGeckoApiKey string, ) *ChainGovernor { - return &ChainGovernor{ db: db, logger: logger.With(zap.String("component", "cgov")), From 2fdfcde4a0fd4251bf17f35fcad58c36830bd8a1 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Tue, 23 Jul 2024 12:48:43 -0700 Subject: [PATCH 13/13] Remove network test from unit test. Plan on creating a Github action cron action for this instead --- node/pkg/governor/governor_test.go | 50 ------------------------------ 1 file changed, 50 deletions(-) diff --git a/node/pkg/governor/governor_test.go b/node/pkg/governor/governor_test.go index 4360db1e91..d44168c5d7 100644 --- a/node/pkg/governor/governor_test.go +++ b/node/pkg/governor/governor_test.go @@ -3258,56 +3258,6 @@ func TestCoinGeckoQueryFormat(t *testing.T) { require.Equal(t, params.Has("vs_currencies"), true) require.Equal(t, params["vs_currencies"][0], "usd") require.Equal(t, params.Has("ids"), true) - -} - -// Test that the prices are gathering from the CoinGecko API -func TestCoinGeckoPriceChecks(t *testing.T) { - coinGeckoApiKey := "" // Add API key to test the pro API endpoint. Remove before commit - ids := []string{"usd-coin"} - - ctx := context.Background() - gov, err := newChainGovernorForTest(ctx) - require.Equal(t, err, nil) - - /* - The standard governor doesn't have the test suite initiated. Even if it did, - the amount of time this takes is too high So, instead of doing that, we're - testing at a lower level to ensure that the queries are actually made successfully - from the URLs given directly - */ - coinGeckoQueries := createCoinGeckoQueries(ids, 1, "") - require.Equal(t, len(coinGeckoQueries), 1) - - token_map, err := gov.queryCoinGeckoChunk(coinGeckoQueries[0]) - require.Equal(t, err, nil) - token_entry, ok := token_map[ids[0]].(map[string]interface{}) - require.Equal(t, ok, true) - - token_price, ok := token_entry["usd"] - require.Equal(t, ok, true) - require.LessOrEqual(t, token_price, 1.5) - require.GreaterOrEqual(t, token_price, 0.5) - - // Only run if the key is specified - if coinGeckoApiKey != "" { - // Pro API key tests - coinGeckoQueries = createCoinGeckoQueries(ids, 1, coinGeckoApiKey) - require.Equal(t, len(coinGeckoQueries), 1) - - token_map, err = gov.queryCoinGeckoChunk(coinGeckoQueries[0]) - require.Equal(t, err, nil) - - // Check the price information. Make sure it succeeded. - token_entry, ok = token_map[ids[0]].(map[string]interface{}) - require.Equal(t, ok, true) - token_price, ok = token_entry["usd"] - require.Equal(t, ok, true) - require.LessOrEqual(t, token_price, 1.5) - require.GreaterOrEqual(t, token_price, 0.5) - - fmt.Println(coinGeckoQueries) - } } // setupLogsCapture is a helper function for making a zap logger/observer combination for testing that certain logs have been made