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

Conversation

Eric-Warehime
Copy link
Collaborator

This PR renames ./build/oracle => ./build/slinky.

It also refactors the marketmap provider factory to be more in line with the other factories (websocket and API). The idea being that once we remove the aggregator bit, we can get rid of all of the special casing for dYdX and rely on the factory to construct the proper marketmap provider for any chain we support.

I've pointed this PR at the eric/convert-everything-to-cobra branch since it made sense to change these in the context of the cobra refactor.

Copy link

codecov bot commented Mar 25, 2024

Codecov Report

Attention: Patch coverage is 14.70588% with 58 lines in your changes are missing coverage. Please review.

Project coverage is 62.34%. Comparing base (0787b25) to head (f4c871e).
Report is 2 commits behind head on main.

❗ Current head f4c871e differs from pull request most recent head db63e31. Consider uploading reports for the commit db63e31 to get more accurate results

Files Patch % Lines
cmd/slinky/main.go 0.00% 30 Missing ⚠️
cmd/slinky-config/main.go 0.00% 26 Missing ⚠️
providers/factories/oracle/marketmap.go 81.81% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #272      +/-   ##
==========================================
+ Coverage   62.11%   62.34%   +0.22%     
==========================================
  Files         215      215              
  Lines        9503     9475      -28     
==========================================
+ Hits         5903     5907       +4     
+ Misses       3055     3023      -32     
  Partials      545      545              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

apiDataHandler, err = dydx.NewAPIHandler(cfg.API)
ids = []types.Chain{{ChainID: dydx.ChainID}}
default:
return nil, fmt.Errorf("unknown provider: %s", cfg.Name)
Copy link
Contributor

Choose a reason for hiding this comment

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

This case should return the default marketmap API handler that hits x/marketemap right?

or is the idea that we'll fill this info out later after the refactor?

@@ -132,6 +132,10 @@ func runOracle() error {
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

Copy link
Contributor

@davidterpay davidterpay left a comment

Choose a reason for hiding this comment

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

given that the mm provider is only going to be utilized by dYdX for the time being, we need to move back into dYdXOptions

Base automatically changed from eric/convert-everything-to-cobra to main March 25, 2024 15:26
switch cfg.Name {
case dydx.Name:
apiDataHandler, err = dydx.NewAPIHandler(cfg.API)
ids = []types.Chain{{ChainID: dydx.ChainID}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm not sure how this is used right now, but it feels like we don't really need the chain-id as long as we point the mm provider at the correct node?

Copy link
Contributor

Choose a reason for hiding this comment

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

ya, how would our configs work if we have a market-map for multiple chains? Have we even resolved this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea this is currently hard coded based on the desired chain but it doesnt really matter since all you have to do is point it to the correct URL. The providers were purposfully designed to assume you have inputs when constructing URLs, but in the future we can probably make it allow static or no entries.

@Eric-Warehime
Copy link
Collaborator Author

Approach I ended up with:

  • Ignores aggregation type entirely. Run the full aggregation paths validation on all configs we get.
  • Update CLIs as follows:
    Config is pretty much as before.
slinky-config --chain "" -- node-http-url ""

Slinky requires a valid oracle.json path. Has optional flags, market-config-path or market-config-update-path which are mutually exclusive.
market-config-path is the path to the market.json to start the system with (same as we currently have)--though that will get updated if you have a market map provider present.
market-config-update-path is a place where we will write market updates in line with what the sidecar is doing. Sidecar initially bootstraps with an empty config and writes updates to this path.
Specifying neither of these will initialize with an empty market map and updates will never be written to disk.

slinky --oracle-config-path "./oracle.json"
slinky --oracle-config-path "./oracle.json" --market-config-path ./market.json
slinky --oracle-config-path "./oracle.json" --market-config-update-path ./new-file.json

@@ -132,6 +132,10 @@ func runOracle() error {
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.

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)

@@ -129,29 +123,33 @@ func runOracle() error {
}

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.

switch cfg.Name {
case dydx.Name:
apiDataHandler, err = dydx.NewAPIHandler(cfg.API)
ids = []types.Chain{{ChainID: dydx.ChainID}}
Copy link
Contributor

Choose a reason for hiding this comment

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

ya, how would our configs work if we have a market-map for multiple chains? Have we even resolved this?

tickersToPaths[tickerStr] = mmtypes.Paths{}
}
paths := tickersToPaths[tickerStr].Paths
paths = append(paths, mmtypes.Path{Operations: []mmtypes.Operation{
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.

)
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.",
)
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.

@@ -38,11 +38,6 @@ func NewMedianAggregator(
return nil, err
}

if cfg.AggregationType != mmtypes.AggregationType_INDEX_PRICE_AGGREGATION {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason we can't remove the agg-type from the config, now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I left it since we're rewriting all of the mm stuff and deleting all the proto and tests didn't seem worth it at this point.

Copy link
Contributor

Choose a reason for hiding this comment

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

What is the reason we need to remove this rn? From my perspective I put this in the case where operators accidentally use the wrong market.json file. this was an easy way to make sure things were configured correctly. the dYdX market params API constructs the market.json to include the field to be set correctly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Supporting multiple aggregation types seems like a really bad idea in general. It will make it even harder to reason about how a price was determined and introduce potential for multi-modal behavior in our on chain prices based on a bug in one place but not another.

I also removed it because it was the one stateful piece of validation that was preventing us from bootstrapping the oracle without a market.json config.

Copy link
Contributor

Choose a reason for hiding this comment

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

yea agree, multiple not gud. im fine making this change now

Copy link
Contributor

@davidterpay davidterpay left a comment

Choose a reason for hiding this comment

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

We're going to need to update the local market.json if we want to enforce that the single aggregation type is utilized otherwise any build is going to fail on start.

@Eric-Warehime
Copy link
Collaborator Author

We're going to need to update the local market.json

@davidterpay It's updated in this PR

)
rootCmd.Flags().DurationVarP(
&updateInterval,
"update-interval",
"",
500*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.",
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

@Eric-Warehime Eric-Warehime merged commit 2f64382 into main Mar 26, 2024
11 checks passed
@Eric-Warehime Eric-Warehime deleted the eric/rename-slinky-refactor-mmfactory branch March 26, 2024 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants