Skip to content

Conversation

@Riateche
Copy link
Contributor

@Riateche Riateche commented Jul 16, 2025

Summary

This PR splits old content of FeedMetadata into two categories:

  1. Essential feed properties that are used for feed aggregation or other functions within Lazer core system (relayer, router, history service): name, exponent, min_publishers, min_rate, expiry_time, market_schedule, state. These are now properties of the Feed message.
  2. Extra metadata used for feed search, documentation, feed catalogs (symbol, description, asset_type, quote_currency), and for matching with external systems (cmc_id, hermes_id). These fields may be used by publishers and by history service (for feed search API), but are otherwise treated as opaque in the Lazer core system. They are now stored as a collection of dynamically typed key-value pairs. This gives the operations team more freedom to extend and change metadata.

Other relevant changes in this PR:

  • Rename is_activated to is_enabled_in_shard (same for other related fields) to clarify the meaning and intended usage, and to avoid confusion with Feed.state.
  • Add DynamicValue Rust type to deal with metadata without loss of information.

Rationale

For more flexible metadata.

How has this been tested?

  • Current tests cover my changes
  • Added new tests
  • Manually tested the code

@vercel
Copy link

vercel bot commented Jul 16, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
api-reference ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 21, 2025 10:46am
component-library ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 21, 2025 10:46am
developer-hub ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 21, 2025 10:46am
entropy-debugger ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 21, 2025 10:46am
entropy-explorer ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 21, 2025 10:46am
insights ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 21, 2025 10:46am
proposals ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 21, 2025 10:46am
staking ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 21, 2025 10:46am

optional FeedState state = 107;


// [required] Feed status in the current shard. Disabled feeds will not be visible in
Copy link
Collaborator

Choose a reason for hiding this comment

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

sorry i got a bit lost here with feedState. what cases does it cover that feed state is not :? is it like we add a same feed to all the shards that we need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Feed state is a consumer-facing and publisher-facing property that's also used to limit access to the feeds. is_enabled_in_shard is a purely internal thing for moving live feeds between shards.

Copy link
Collaborator

Choose a reason for hiding this comment

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

it kind of feels complex but got it. but how do you envision it? on my head i was like we do it as a new feed creation but i think the price feed state is replicated everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my view the sequence should be like this:

  1. We have a feed live in the old shard.
  2. We add a feed with the same feed ID and metadata to the new shard and set enabled_in_shard = false.
  3. Agent discovers the feed in the new shard and starts publishing the same data to it.
  4. We verify that the feed in the new shard is ready to go live (publisher data and aggregation are good).
  5. We schedule the switch using disable_in_shard_timestamp in the old shard and enable_in_shard_timestamp in the new shard.
  6. At this timestamp aggregators will stop producing updates for the feed in the old shard and start producing updates for it in the new shard. This makes the switch transparent to consumers, as long as both shards are available to the router that they're connected to.
  7. We delete the feed in the old shard.

COMING_SOON = 0;
// A fully available feed.
STABLE = 1;
// Inactive feeds are not available to consumers or publishers.
Copy link
Contributor

Choose a reason for hiding this comment

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

it is technically available to publishers now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean by "technically available"? Can you suggest a proper description of this state?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think he means publishers can publish to them regardless of the state of the feed? We should change this in the future though.

Perhaps you can specify they are feeds which can/can't be subscribed to?

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Inactive feeds are not available to consumers or publishers.
// Inactive feeds are not available to consumers.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the only difference in INACTIVE and COMING_SOON is to inform the end user that inactive feed will never become active.

Copy link
Collaborator

Choose a reason for hiding this comment

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

we might let some people consume comin_soon ones too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated comments.

optional string market_schedule = 106;
// [required] Feed state
optional FeedState state = 107;

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should add asset_type here too. Because we will be using asset_type to determine what kind of feed type is expected (e.g funding-rate vs regular price).

Copy link
Collaborator

Choose a reason for hiding this comment

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

let's call it feed type.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ali-behjati are you saying it's different from asset_type and we have both? Because I was thinking we could infer feed type based on asset_type. and multiple asset_types can have the same feed type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I also prefer to have feed type (Price/FundingRate) because those options are what we care about in the implementation. (It's already like this in the transaction protobuf). Asset type has a lot of options and I think it's better to leave it in the dynamic metadata.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I called it FeedKind because type is annoying to use in Rust 😅

Copy link
Contributor

@darunrs darunrs left a comment

Choose a reason for hiding this comment

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

LGTM but will let Keyvan/Ali give final approval since they left their own comments already. Just a handful of small questions.

// Add a new feed. Refer to `Feed` message fields documentation.
message AddFeed {
// [required] ID of the feed. Must be unique (within the shard).
// [required]
Copy link
Contributor

Choose a reason for hiding this comment

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

Why was this description removed? Is it no longer accurate?

Copy link
Contributor

Choose a reason for hiding this comment

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

If a feed ID needs to change as a result of moving to another shard which already has that ID (further, how do we prevent this from happening?), how would that impact subscribing to the feed? Is this ID separate from the customer/publisher facing feed ID?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed all field comments here because I don't want them to be duplicated with comments on the same fields in Feed. Otherwise they could go out of sync.

Feed IDs have to be globally unique. We don't have a way to enforce it in a shard, but we can check it in xc-admin I guess. If a feed is moved to another shard then it will always have the same ID. If the ID is not the same then it's not really the same feed anymore.

// IDs of publishers enabled for this feed.
repeated uint32 permissioned_publishers = 3;
// [required]
optional DynamicValue.Map metadata = 3;
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason we skip field ID 2 if this is not in use yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I use the same IDs here as in Feed, and 2 is occupied there by per_publisher field. However, none of that really matters.

COMING_SOON = 0;
// A fully available feed.
STABLE = 1;
// Inactive feeds are not available to consumers or publishers.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think he means publishers can publish to them regardless of the state of the feed? We should change this in the future though.

Perhaps you can specify they are feeds which can/can't be subscribed to?

// Feed kind determines the set of data fields available in the feed.
// It also determines the kind of data accepted from publishers for this feed
// (`PriceUpdate` or `FundingRateUpdate`).
enum FeedKind {
Copy link
Contributor

Choose a reason for hiding this comment

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

I intended to introduce this in some form. I will use the state enum to guard rail what updates a feed is able to accept.

Copy link
Contributor

Choose a reason for hiding this comment

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

we should use this for guard railing updates

// If a feed is present in
// multiple shards, it must only be active in one of them at each time.
// To enforce this, `pending_activation` and `pending_deactivation` fields
// To enforce this, `enable_in_shard_timestamp` and `disable_in_shard_timestamp` fields
Copy link
Contributor

Choose a reason for hiding this comment

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

To confirm my understanding, Aggregator pulls all shards. So, it is able to handle this switch in logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not possible to do that deterministically without timestamps because shards have separate transaction queues. Aggregator is only able to achieve deterministic results within a shard because the inputs are always arriving in the same order.

@keyvankhademi
Copy link
Contributor

Does this break the current agent transactions?
cc: @bplatak

UpdateFeedMetadata update_feed_metadata = 102;
EnableFeedInShard enable_feed_in_shard = 103;
DisableFeedInShard disable_feed_in_shard = 104;
google.protobuf.Empty remove_feed = 199;
Copy link
Contributor

Choose a reason for hiding this comment

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

we probably don't need this, since we will make feeds inactive instead of deleting.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prefer to have the option to delete them. Having lots of inactive feeds in state could become too costly.

Copy link
Collaborator

@ali-behjati ali-behjati left a comment

Choose a reason for hiding this comment

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

LGTM.

I don't see it breaking transaction sending part but it might affect the metadata read part but if it does it's fine as we haven't released it completely yet. @bplatak to say.

@Riateche
Copy link
Contributor Author

Does this break the current agent transactions?

I believe it doesn't. I only changed the package name in the transaction protos.

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.

5 participants