-
Notifications
You must be signed in to change notification settings - Fork 56
New crate: mollusk-svm-on-demand
#171
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
base: main
Are you sure you want to change the base?
Conversation
buffalojoec
left a comment
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 pretty nifty!
My biggest concern is that it reimplements a lot of the harness's API. I would rather figure out how we can get this to play nice with the AccountStore trait and then it can be supported by the generic framework. I left a comment about it.
Thanks for putting this up, though! Seems very useful.
| @@ -0,0 +1,20 @@ | |||
| [package] | |||
| name = "mollusk-svm-on-demand" | |||
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 we need to bikeshed the name. 😅
This library tends to use more descriptive (sometimes verbose) naming conventions, so it's clear what a given crate does. "On demand" is pretty vague in my opinion.
What about something like one of these?
mollusk-account-store-on-demandmollusk-account-store-rpc-on-demandmollusk-account-store-rpc
| @@ -0,0 +1,20 @@ | |||
| [package] | |||
| name = "mollusk-svm-on-demand" | |||
| description = "Automatically fetch and use mainnet accounts with the Mollusk SVM harness." | |||
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.
Is it only mainnet-beta?
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.
Good catch, it's not. Fixing
| //! RPC account store for fetching accounts from Solana RPC endpoints. | ||
| //! | ||
| //! This module provides the `RpcAccountStore` type for automatically fetching | ||
| //! accounts from mainnet and managing them for use with Mollusk testing. |
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.
It doesn't appear the tool is limited to mainnet. Why should it be, anyway?
| self.fetch_accounts(&pubkeys.into_iter().collect::<Vec<_>>()) | ||
| .await?; |
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.
Since fetch_accounts is internal, you could just make it accept a pubkey iterator (impl Iterator<Item = Pubkey>). You're also deduping in the fetch_accounts as well, so no need for the hash map above this. Just pipe the mapped iterator over the instruction accounts directly into fetch_accounts!
| return Ok(()); | ||
| } | ||
|
|
||
| let accounts = self.client.get_multiple_accounts(&missing_pubkeys).await?; |
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.
Eh, I suppose you maybe do have to do one allocation, but perhaps you can filter by cache.contains_key and collect that into a vec, then pass to the RPC call?
| pub async fn process_instruction_with_context( | ||
| rpc_url: &str, | ||
| mut mollusk: Mollusk, | ||
| instruction: &Instruction, | ||
| accounts: &[(Pubkey, Account)], | ||
| ) -> Result<InstructionResult> { | ||
| let cache = RpcAccountStore::new(rpc_url) | ||
| .allow_missing_accounts() | ||
| .skip_program_validation() | ||
| .with_accounts(accounts) | ||
| .from_instruction(instruction) | ||
| .await? | ||
| .add_programs(&mut mollusk) | ||
| .await? | ||
| .cache; | ||
|
|
||
| let context = mollusk.with_context(cache); | ||
| Ok(context.process_instruction(instruction)) | ||
| } |
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.
Why not just let developers create an RpcAccountStore and then do this?
let store = RpcAccountStore::new(rpc_url)
.allow_missing_accounts()
.skip_program_validation();
let mollusk = Mollusk::default().with_context(&store);
mollusk.process_instruction(
&instruction,
&accounts,
);You just need to implement AccountStore for RpcAccountStore.
mollusk/harness/src/account_store.rs
Line 7 in fc77245
| pub trait AccountStore { |
Is it because your fetcher is async? Can you use the blocking RPC client instead?
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.
Yes I maybe should have made it more clear but this is currently possible.
You just need to add an .await() at the end of the store implementation and you can then blast it in the normal harness
| /// This function fetches the program data accounts for all programs that are | ||
| /// stored in the cache and adds them to the Mollusk environment. | ||
| /// | ||
| /// Note: This is needed because mollusk-svm doesn't load the programs for CPIs directly from the accounts. |
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.
Hm, maybe it should (?)
Agree, I don't love that as well. Tbh all current methods works without having to reimplement the harness, I added that after just to make it easier to use for people that don't really know how to do so. But probably it's just more confusing and just midcurved the entire implementation. I'm down to nuke the reimplementation of the harness |
|
@L0STE what do you think about something like this? I just went with the blocking RPC client and implemented What you could do it configure it to either |
This crate simplifies testing by fetching and storing mainnet accounts directly in the
AccountStore.Key Features
The new
RpcAccountStoreallows you to:with_accountsmethodfrom_instructionmethod to automatically dump all accounts referenced in an instructionallow_missing_accountsmethod, which stores them with default valuesadd_programsmethod, which fetches program data from the account store and loads it viamollusk.add_program_with_elf_and_loader(supports both loader V2 and V3)with_synced_slotfor oracles that require the current mainnet slot to function correctlyNew Harness
Added a new test harness variant with
*_with_contextmethods that implement all the above helpers. These methods support both strict and non-strict modes depending on how they're called, while maintaining the same interface as the original harness.