-
Notifications
You must be signed in to change notification settings - Fork 266
Configure symbol groups by name #403
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
Conversation
@@ -1,5 +1,5 @@ | |||
#![deny(warnings)] | |||
#![allow(clippy::result_large_err)] | |||
#![allow(clippy::result_unit_err)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clippy changed this for some reason
@@ -402,8 +399,8 @@ pub fn gen_attest_tx( | |||
pub async fn crawl_pyth_mapping( | |||
rpc_client: &RpcClient, | |||
first_mapping_addr: &Pubkey, | |||
) -> Result<HashMap<Pubkey, HashSet<Pubkey>>, ErrBox> { | |||
let mut ret = HashMap::new(); | |||
) -> Result<Vec<P2WProductAccount>, ErrBox> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adding the name of each product to the result here (so we can match on it to make the batches)
third_party/pyth/p2w_autoattest.py
Outdated
default_attestation_conditions: | ||
min_interval_secs: 30 | ||
price_changed_bps: 500 | ||
name_groups: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hacked the existing tests to include name groups
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think leaving this empty is right. I think Tilt setup should be able to show that the name group settings are respected by default. Other than that, we should be able to confirm that this setting is respected in the log, ideally with warn!
on name groups that were never used.
pub min_rpc_interval_ms: u64, | ||
/// Attestation conditions that will be used for any symbols included in the mapping | ||
/// that aren't explicitly in one of the groups below. | ||
pub default_attestation_conditions: AttestationConditions, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the old code could use AttestationConditions::default()
for these symbols under some conditions (if the config file didn't have a "mapping" group). That old behavior is likely to lead to configuration bugs, so I fixed it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the comment is a bit misleading here. It also adds the condition to named groups.
I think it's even better to add this to the symbol groups as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The refactoring and the change set looks great! I left some minor comments about the code.
Just one big concern about testing the code, because afaik we do not add symbol in the pyth_publisher.py
and the returned name (that you used) is just a debug information. The e2e test is not failing because the current logic skips the symbols. To add symbol name to a product (and fix testing) you will need to call pyth_admin upd_price
like this test.
Second comment is that do you see any use case for keeping the symbol_groups approach? I am in favor of removing it entirely (to keep the code simple).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I value the use case but I am not sold on the scope of this changeset. IIUC the intent is to add the ability to say "Any symbol name containing "BTC" lands here" etc. I think this can be achieved without the need to create a whole new group type (one could slap a Vec<String>
member on the existing group type instead) and especially without messing with the utility methods on the attestation config type. I do not agree with the unidirectional flow idea because I don't think the new utility functions have a meaningful life outside AttestationConfig. I think that dragging a batch vector outside attestation_config obfuscates the source of truth about available batches. Ultimately, I do not believe this change is complete without unit-testing the new config merging logic, descriptive logging and a convincing reason to widen the scope beyond just sorting the batches into their matching buckets.
third_party/pyth/p2w_autoattest.py
Outdated
default_attestation_conditions: | ||
min_interval_secs: 30 | ||
price_changed_bps: 500 | ||
name_groups: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think leaving this empty is right. I think Tilt setup should be able to show that the name group settings are respected by default. Other than that, we should be able to confirm that this setting is respected in the log, ideally with warn!
on name groups that were never used.
@@ -137,6 +137,8 @@ | |||
mapping_reload_interval_mins: 1 # Very fast for testing purposes | |||
min_rpc_interval_ms: 0 # RIP RPC | |||
max_batch_jobs: 1000 # Where we're going there's no oomkiller | |||
default_attestation_conditions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@drozdziak1 and i agreed that i can update the integration tests in a follow-up, since we currently don't have a good way to validate that the things in the config are actually being attested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for addressing my comments. Looking forward to adding it to the tests. I like to revisit keeping the old configuration way after adding proper e2e tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! I like the new lookup/symbol merging separation. My remaining concerns are primarily naming, comments and some edge cases.
@@ -439,6 +435,13 @@ pub async fn crawl_pyth_mapping( | |||
} | |||
}; | |||
|
|||
let mut prod_name = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we default to "<unspecified>"
or similar? Extra credit for an Option<>. If our rules parsing grows, we may get a nasty edge case with something.contains("")
which is always true for any string
vec![] | ||
}; | ||
|
||
Ok(attestation_cfg.instantiate_batches(&products, max_batch_size)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! The mapping lookup/config merge divide is way more visible
@@ -510,22 +504,43 @@ async fn handle_attest_non_daemon_mode( | |||
Ok(()) | |||
} | |||
|
|||
async fn attestation_config_to_batches( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment about how this works? i.e. that we do an on-chain lookup and we merge results with attestation config and then collapse everything to a vec? The on-chain state lookup is not obvious at first glance. Ideally the function's name could conceive that, but I had no success coming up with anything less than 40 chars 😅
pub max_msg_accounts: u64, | ||
|
||
/// Optionally, we take a mapping account to add remaining symbols from a Pyth deployments. | ||
/// These symbols are processed under `default_attestation_conditions`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is no longer true (the group decides that, and the defaults only apply if no group matches the symbol)
} | ||
/// Instantiate the batches of symbols to attest by matching the config against the collection | ||
/// of on-chain product accounts. | ||
pub fn instantiate_batches( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the comment has to mention anything about on-chain. This just collapses the config into a vec and optionally merges in extra symbols
max_batch_size: usize, | ||
) -> Vec<SymbolBatch> { | ||
// Construct mapping from the name of each product account to its corresponding symbols | ||
let mut name_to_symbols: HashMap<String, Vec<P2WSymbol>> = HashMap::new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will cause duplicate-named products in the mapping behave in a very ambiguous way. Such edge case would cause two distinct P2WProductAccount
s. This is then obfuscated by putting symbols from both in the same bucket on the name_to_symbols
hashmap. This has no serious consequences right now, but I think it's confusing.
}, | ||
/// A symbol specified by its product and price account keys. | ||
Key { | ||
/// Optional human-readable name for the symbol (for logging purposes). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly the same as P2WSymbol
, have you considered Key(P2WSymbol)
?
/// Config entry for a symbol to attest. | ||
#[derive(Clone, Debug, Hash, Deserialize, Serialize, PartialEq, Eq)] | ||
#[serde(tag = "type", rename_all = "snake_case")] | ||
pub enum SymbolConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's more like a symbol reference than a config. You're not affecting symbol behavior here, only identifying them.
} | ||
|
||
#[derive(Clone, Debug, Hash, Deserialize, Serialize, PartialEq, Eq)] | ||
pub struct SymbolBatch { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain in a doc comment how the types are used? This one is easy to mistake with SymbolGroupConfig
mapping_reload_interval_mins: 42, | ||
symbol_groups: vec![], | ||
}; | ||
fn test_instantiate_batches() -> Result<(), ErrBox> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test does not assert desired behavior edge cases:
- Group already has the same symbol
- No name group matches this symbol (default group)
- brand new symbol is added to the right place
This PR adds the ability to configure which symbols are in each group using just the name of the symbol. This change will make it easier for us to maintain the configuration file as we customize the groups.
I refactored the code a little to simplify the change. Specifically, the previous code used to read
AttestationConfig
at startup, then mutate it over time to store any additional symbols read from the mapping account. I refactored the code so there's a unidirectional information flowAttestationConfig
-> merged with mapping data to create list of batches -> batches are published. I then extracted out the logic for merging the config with the mapping data into a function. Check out the first commit to see the general shape of the refactor.See inline comments for added details on changes.