Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Rename oracle to slinky, refactor mm provider factory #272

Merged
merged 23 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7d8d191
Convert all commands to cobra
Eric-Warehime Mar 22, 2024
0b0e899
Fix lint
Eric-Warehime Mar 25, 2024
adb39d8
Merge branch 'main' into eric/convert-everything-to-cobra
Eric-Warehime Mar 25, 2024
0fcc9dd
Rename oracle to slinky, refactor mm provider factory
Eric-Warehime Mar 25, 2024
c50a833
Merge remote-tracking branch 'origin' into eric/rename-slinky-refacto…
Eric-Warehime Mar 25, 2024
c1cd3ee
Update aggregation stuff
Eric-Warehime Mar 25, 2024
5960108
Merge remote-tracking branch 'origin' into eric/rename-slinky-refacto…
Eric-Warehime Mar 25, 2024
ebdb2aa
Fix metrics stuff I broke in merge
Eric-Warehime Mar 25, 2024
6d8b7fb
Remove chain arg from slinky
Eric-Warehime Mar 25, 2024
adeecd2
Change names, flags
Eric-Warehime Mar 25, 2024
279db59
Do validate
Eric-Warehime Mar 25, 2024
d5e7d3d
Fix path tests
Eric-Warehime Mar 25, 2024
7c2230f
Fix keeper tests
Eric-Warehime Mar 25, 2024
7a8f3b9
Fix integ tests
Eric-Warehime Mar 25, 2024
0da58f2
Generate paths for default configs
Eric-Warehime Mar 26, 2024
a752c03
Fix lint fumpt
Eric-Warehime Mar 26, 2024
77faa08
Fix integ tests
Eric-Warehime Mar 26, 2024
67614b2
Provide paths everywhere
Eric-Warehime Mar 26, 2024
a62d7d6
Fix slashing tests
Eric-Warehime Mar 26, 2024
f19b85e
update
Eric-Warehime Mar 26, 2024
ea8f03b
Update oracle/constants/chains.go
Eric-Warehime Mar 26, 2024
f4c871e
Merge remote-tracking branch 'origin' into eric/rename-slinky-refacto…
Eric-Warehime Mar 26, 2024
db63e31
Merge branch 'main' into eric/rename-slinky-refactor-mmfactory
Eric-Warehime Mar 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ release:
prerelease: true

builds:
- main: 'cmd/oracle/main.go'
- main: 'cmd/slinky/main.go'
goos:
- 'linux'
- 'darwin'
Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ build: tidy
@go build -o ./build/ ./...

run-oracle-server: build
@./build/oracle --oracle-config-path ${ORACLE_CONFIG_FILE} --market-config-path ${MARKET_CONFIG_FILE}
@./build/slinky --oracle-config-path ${ORACLE_CONFIG_FILE} --market-config-path ${MARKET_CONFIG_FILE}

run-oracle-client: build
@./build/client --host localhost --port 8080
Expand All @@ -43,7 +43,7 @@ run-prom-client:

update-local-configs: build
@echo "Updating local config..."
@./build/config --oracle-config-path ${ORACLE_CONFIG_FILE} --market-config-path ${MARKET_CONFIG_FILE}
@./build/slinky-config --oracle-config-path ${ORACLE_CONFIG_FILE} --market-config-path ${MARKET_CONFIG_FILE}

start-oracle:
@echo "Starting oracle side-car, blockchain, and prometheus dashboard..."
Expand All @@ -54,7 +54,8 @@ stop-oracle:
@$(DOCKER_COMPOSE) -f docker-compose.yml down

install: tidy
@go install -mod=readonly $(BUILD_FLAGS) ./cmd/oracle
@go install -mod=readonly $(BUILD_FLAGS) ./cmd/slinky
@go install -mod=readonly $(BUILD_FLAGS) ./cmd/slinky-config

.PHONY: build run-oracle-server install

Expand Down
46 changes: 31 additions & 15 deletions cmd/config/main.go → cmd/slinky-config/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"encoding/json"
"fmt"
"os"
"strings"
"time"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -34,7 +35,7 @@

var (
rootCmd = &cobra.Command{
Use: "config",
Use: "slinky-config",
Short: "Create configuration required for running slinky.",
Args: cobra.NoArgs,
Run: func(_ *cobra.Command, _ []string) {
Expand Down Expand Up @@ -222,77 +223,77 @@
"oracle-config-path",
"",
"oracle.json",
"path to write the oracle config file to. this file is required to run the oracle.",
"Path to write the oracle config file to. This file is required to run the oracle.",

Check warning on line 226 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L226

Added line #L226 was not covered by tests
)
rootCmd.Flags().StringVarP(
&marketCfgPath,
"market-config-path",
"",
"market.json",
"path to write the market config file to. this file is required to run the oracle.",
"Path to write the market config file to. This file is required to run the oracle.",

Check warning on line 233 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L233

Added line #L233 was not covered by tests
)
rootCmd.Flags().StringVarP(
&chain,
"chain-id",
"chain",

Check warning on line 237 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L237

Added line #L237 was not covered by tests
"",
"",
"chain-id that we expect the oracle to be running on. ex dydx-mainnet-1, dydx-testnet-4. this should only be specified if required by the chain.",
"Chain that we expect the oracle to be running on {dydx, \"\"}. This should only be specified if required by the chain.",

Check warning on line 240 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L240

Added line #L240 was not covered by tests
)
rootCmd.Flags().StringVarP(
&nodeURL,
"node-http-url",
"",
"",
"http endpoint of the cosmos sdk node corresponding to the chain id (typically something like localhost:1317). this should only be specified if required by the chain.",
"Http endpoint of the cosmos sdk node corresponding to the chain (typically localhost:1317 or a remote API). This should only be specified if required by the chain.",

Check warning on line 247 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L247

Added line #L247 was not covered by tests
)
rootCmd.Flags().StringVarP(
&host,
"host",
"",
"0.0.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we checking that the default value isn't used if no chain is given here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable is only used if dydx chain is specified otherwise it's ignored at the moment.

"host is the oracle / prometheus server host.",
"Host is the oracle / prometheus server host.",

Check warning on line 254 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L254

Added line #L254 was not covered by tests
)
rootCmd.Flags().StringVarP(
&pricesPort,
"port",
"",
"8080",
"port that the oracle will make prices available on. to query prices after starting the oracle, use the following command: curl http://<host>:<port>/slinky/oracle/v1/prices",
"Port that the oracle will make prices available on. To query prices after starting the oracle, use the following command: curl http://<host>:<port>/slinky/oracle/v1/prices",

Check warning on line 261 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L261

Added line #L261 was not covered by tests
)
rootCmd.Flags().StringVarP(
&prometheusPort,
"prometheus-port",
"",
"8002",
"port that the prometheus server will listen on. to query prometheus metrics after starting the oracle, use the following command: curl http://<host>:<port>/metrics",
"Port that the prometheus server will listen on. To query prometheus metrics after starting the oracle, use the following command: curl http://<host>:<port>/metrics",

Check warning on line 268 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L268

Added line #L268 was not covered by tests
)
rootCmd.Flags().BoolVarP(
&disabledMetrics,
"disable-metrics",
"",
false,
"flag that disables the prometheus server. if this is enabled the prometheus port must be specified. to query prometheus metrics after starting the oracle, use the following command: curl http://<host>:<port>/metrics",
"Flag that disables the prometheus server. If this is enabled the prometheus port must be specified. To query prometheus metrics after starting the oracle, use the following command: curl http://<host>:<port>/metrics",

Check warning on line 275 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L275

Added line #L275 was not covered by tests
)
rootCmd.Flags().BoolVarP(
&debug,
"debug-mode",
"",
false,
"flag that enables debug mode. specifically the side-car will run in debug mode. this is useful for local development / debugging.",
"Flag that enables debug mode for the side-car. This is useful for local development / debugging.",

Check warning on line 282 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L282

Added line #L282 was not covered by tests
)
rootCmd.Flags().DurationVarP(
&updateInterval,
"update-interval",
"",
1500*time.Millisecond,
"interval at which the oracle will update the prices. this should be set to the interval desired by the chain.",
"Interval at which the oracle will update the prices. This should be set to the interval desired by the chain.",

Check warning on line 289 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L289

Added line #L289 was not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make sure that this is set to 500 milliseconds

)
rootCmd.Flags().DurationVarP(
&maxPriceAge,
"max-price-age",
"",
2*time.Minute,
"maximum age of a price that the oracle will accept. this should be set to the maximum age desired by the chain.",
"Maximum age of a price that the oracle will accept. This should be set to the maximum age desired by the chain.",

Check warning on line 296 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L296

Added line #L296 was not covered by tests
)
}

Expand All @@ -306,7 +307,7 @@
func createOracleConfig() error {
// If the providers is not empty, filter the providers to include only the
// providers that are specified.
if chain == constants.DYDXMainnet.ID || chain == constants.DYDXTestnet.ID {
if strings.ToLower(chain) == constants.Dydx {

Check warning on line 310 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L310

Added line #L310 was not covered by tests
// Filter out the providers that are not supported by the dYdX chain.
validProviders := make(map[string]struct{})
for _, providers := range dydx.ProviderMapping {
Expand Down Expand Up @@ -382,7 +383,7 @@
// oracle is always started using the market map that is expected to be stored by the
// market map module.
func createMarketMap() error {
if chain == constants.DYDXMainnet.ID || chain == constants.DYDXTestnet.ID {
if strings.ToLower(chain) == constants.Dydx {

Check warning on line 386 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L386

Added line #L386 was not covered by tests
fmt.Fprintf(
os.Stderr,
"dYdX chain requires the use of a predetermined market map. please use the market map provided by the Skip/dYdX team or the default market map provided in /config/dydx/market.json",
Expand All @@ -397,6 +398,7 @@
// TickersToProviders defines a map of tickers to their respective providers. This
// contains all of the providers that are supported per ticker.
tickersToProviders = make(map[string]mmtypes.Providers)
tickersToPaths = make(map[string]mmtypes.Paths)

Check warning on line 401 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L401

Added line #L401 was not covered by tests
)

// Iterate through all of the provider ticker configurations and update the
Expand All @@ -422,13 +424,27 @@
providers := tickersToProviders[tickerStr].Providers
providers = append(providers, config)
tickersToProviders[tickerStr] = mmtypes.Providers{Providers: providers}

if _, ok := tickersToPaths[tickerStr]; !ok {
tickersToPaths[tickerStr] = mmtypes.Paths{}

Check warning on line 429 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L428-L429

Added lines #L428 - L429 were not covered by tests
}
paths := tickersToPaths[tickerStr].Paths
paths = append(paths, mmtypes.Path{Operations: []mmtypes.Operation{

Check warning on line 432 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L431-L432

Added lines #L431 - L432 were not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're medianizing over all paths, no? This would give extra weight to the raw feed if it alr existed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just a pure median over all feeds with optional 1 hop inversion.

{
CurrencyPair: ticker.CurrencyPair,
Invert: false,
Provider: config.Name,
},
}})
tickersToPaths[tickerStr] = mmtypes.Paths{Paths: paths}

Check warning on line 439 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L434-L439

Added lines #L434 - L439 were not covered by tests
}
}

// Create a new market map from the provider to market map.
marketMap := mmtypes.MarketMap{
Tickers: tickers,
Providers: tickersToProviders,
Paths: tickersToPaths,

Check warning on line 447 in cmd/slinky-config/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky-config/main.go#L447

Added line #L447 was not covered by tests
}

// Validate the market map.
Expand Down
110 changes: 38 additions & 72 deletions cmd/oracle/main.go → cmd/slinky/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

"github.com/skip-mev/slinky/oracle"
"github.com/skip-mev/slinky/oracle/config"
"github.com/skip-mev/slinky/oracle/constants"
oraclemetrics "github.com/skip-mev/slinky/oracle/metrics"
"github.com/skip-mev/slinky/oracle/orchestrator"
"github.com/skip-mev/slinky/oracle/types"
Expand All @@ -36,12 +35,11 @@
},
}

oracleCfgPath string
marketCfgPath string
runPprof bool
profilePort string
chain string
updateLocalConfig bool
oracleCfgPath string
marketCfgPath string
updateMarketCfgPath string
runPprof bool
profilePort string
)

func init() {
Expand All @@ -50,43 +48,37 @@
"oracle-config-path",
"",
"oracle.json",
"path to the oracle config file",
"Path to the oracle config file.",

Check warning on line 51 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L51

Added line #L51 was not covered by tests
)
rootCmd.Flags().StringVarP(
&marketCfgPath,
"market-config-path",
"",
"market.json",
"path to the market config file",
"",
"Path to the market config file. If you supplied a node URL in your config, this will not be required.",
)
rootCmd.Flags().StringVarP(
&updateMarketCfgPath,
"update-market-config-path",
"",
"",
"Path where the current market config will be written. Overwrites any pre-existing file. Requires an http-node-url/marketmap provider in your oracle.json config.",

Check warning on line 65 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L57-L65

Added lines #L57 - L65 were not covered by tests
)
rootCmd.Flags().BoolVarP(
&runPprof,
"run-pprof",
"",
false,
"run pprof server",
"Run pprof server.",

Check warning on line 72 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L72

Added line #L72 was not covered by tests
)
rootCmd.Flags().StringVarP(
&profilePort,
"pprof-port",
"",
"6060",
"port for the pprof server to listen on",
)
rootCmd.Flags().StringVarP(
&chain,
"chain-id",
"",
"",
"the chain id for which the side car should run for (ex. dydx-mainnet-1)",
)
rootCmd.Flags().BoolVarP(
&updateLocalConfig,
"update-local-market-config",
"",
true,
"update the market map config when a new one is received; this will overwrite the existing config file.",
"Port for the pprof server to listen on.",

Check warning on line 79 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L79

Added line #L79 was not covered by tests
)
rootCmd.MarkFlagsMutuallyExclusive("update-market-config-path", "market-config-path")

Check warning on line 81 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L81

Added line #L81 was not covered by tests
}

// start the oracle-grpc server + oracle process, cancel on interrupt or terminate.
Expand All @@ -110,9 +102,12 @@
return fmt.Errorf("failed to read oracle config file: %s", err.Error())
}

marketCfg, err := types.ReadMarketConfigFromFile(marketCfgPath)
if err != nil {
return fmt.Errorf("failed to read market config file: %s", err.Error())
var marketCfg mmtypes.MarketMap
if marketCfgPath != "" {
marketCfg, err = types.ReadMarketConfigFromFile(marketCfgPath)
if err != nil {
return fmt.Errorf("failed to read market config file: %s", err.Error())

Check warning on line 109 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L105-L109

Added lines #L105 - L109 were not covered by tests
}
}

var logger *zap.Logger
Expand All @@ -129,29 +124,33 @@
}

metrics := oraclemetrics.NewMetricsFromConfig(cfg.Metrics)
aggregator, err := oraclemath.NewMedianAggregator(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we agreed to have a single aggregation strat in the oracle (the dydx one)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the dydx aggregation.

logger,
marketCfg,
metrics,
)
if err != nil {
return fmt.Errorf("failed to create data aggregator: %w", err)

Check warning on line 133 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L127-L133

Added lines #L127 - L133 were not covered by tests
}

// Define the orchestrator and oracle options. These determine how the orchestrator and oracle are created & executed.
orchestratorOpts := []orchestrator.Option{
orchestrator.WithLogger(logger),
orchestrator.WithMarketMap(marketCfg),
orchestrator.WithPriceAPIQueryHandlerFactory(oraclefactory.APIQueryHandlerFactory), // Replace with custom API query handler factory.
orchestrator.WithPriceWebSocketQueryHandlerFactory(oraclefactory.WebSocketQueryHandlerFactory), // Replace with custom websocket query handler factory.
orchestrator.WithMarketMapperFactory(oraclefactory.MarketMapProviderFactory),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the marketmap provider factory to only be included in the dYdX options because it will either run the mm provider and update based on what is on dYdX main-net or it will fail to be constructed if the market map provider is not included in the oracle config. There is probably a cleaner way with dealing how to run this based per chain and whether the mm provider is desired. But I'm assuming this isnt desired behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused why this even needs to be an option? Shouldn't we be able to have casing logic like websocket / api, and have the default be a nop updater (no mm-provider? Or a mm provider that never updates)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an option that lets the orchestrator know how to construct a market map provider if one is included in the oracle.json. Reading through this again I think this looks good.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The factories take care of casing based on the API/Websocket implementation

orchestrator.WithAggregator(aggregator),

Check warning on line 143 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L142-L143

Added lines #L142 - L143 were not covered by tests
}
if updateMarketCfgPath != "" {
orchestratorOpts = append(orchestratorOpts, orchestrator.WithWriteTo(updateMarketCfgPath))

Check warning on line 146 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L145-L146

Added lines #L145 - L146 were not covered by tests
}
oracleOpts := []oracle.Option{
oracle.WithLogger(logger),
oracle.WithUpdateInterval(cfg.UpdateInterval),
oracle.WithMetrics(metrics),
oracle.WithMaxCacheAge(cfg.MaxPriceAge),
}

if chain == constants.DYDXMainnet.ID || chain == constants.DYDXTestnet.ID {
customOrchestratorOps, customOracleOpts, err := dydxOptions(logger, marketCfg, metrics)
if err != nil {
return fmt.Errorf("failed to create dydx orchestrator and oracle options: %w", err)
}

orchestratorOpts = append(orchestratorOpts, customOrchestratorOps...)
oracleOpts = append(oracleOpts, customOracleOpts...)
oracle.WithDataAggregator(aggregator),

Check warning on line 153 in cmd/slinky/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/slinky/main.go#L153

Added line #L153 was not covered by tests
}

// Create the orchestrator and start the orchestrator.
Expand Down Expand Up @@ -219,36 +218,3 @@
}
return nil
}

// dydxOptions specifies the custom orchestrator and oracle options for dYdX.
func dydxOptions(
logger *zap.Logger,
marketCfg mmtypes.MarketMap,
metrics oraclemetrics.Metrics,
) ([]orchestrator.Option, []oracle.Option, error) {
// dYdX uses the median index price aggregation strategy.
aggregator, err := oraclemath.NewMedianAggregator(
logger,
marketCfg,
metrics,
)
if err != nil {
return nil, nil, err
}

// The oracle must be configured with the median index price aggregator.
customOracleOpts := []oracle.Option{
oracle.WithDataAggregator(aggregator),
}

// Additionally, dYdX requires a custom market map provider that fetches market params from the chain.
customOrchestratorOps := []orchestrator.Option{
orchestrator.WithMarketMapperFactory(oraclefactory.DefaultDYDXMarketMapProvider),
orchestrator.WithAggregator(aggregator),
}
if updateLocalConfig {
customOrchestratorOps = append(customOrchestratorOps, orchestrator.WithWriteTo(marketCfgPath))
}

return customOrchestratorOps, customOracleOpts, nil
}
Loading
Loading