-
Notifications
You must be signed in to change notification settings - Fork 6
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
tests: Use mollusk on process instruction #18
Conversation
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.
Just tiny things, this looks really good!
I had to look at only the second commit because for some reason the first commit still has everything from #17
*EXPECTED_DATA.write().unwrap() = expected_data; | ||
} | ||
|
||
struct SyscallStubs {} |
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.
Totally separate, but I just realized, with this change, we can remove the solana-program
dependency from spl-token
and make it much easier for downstream users
program/tests/processor.rs
Outdated
} | ||
solana_program::entrypoint::SUCCESS | ||
// Update accounts after the instruction is processed. | ||
for (original, (_, updated)) in accounts.iter_mut().zip(result.resulting_accounts.iter()) { |
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.
nit: can the second be an into_iter()
to avoid the clone in the next line?
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.
Mollusk will vend you back the exact same accounts in the same order, but with any post-processing changes. So you can just do something like this:
accounts = result.resulting_accounts.into_iter().unzip().1;
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.
But they will be a "copy" of the input, right? In this case we have Vec<&mut SolanaAccount>
, so we need to update those references, not the whole Vec
.
We are giving mollusk a copy of the input here:
let instruction_accounts: Vec<(Pubkey, AccountSharedData)> = instruction
.accounts
.iter()
.zip(&accounts)
.map(|(account_meta, account)| {
(
account_meta.pubkey,
AccountSharedData::from((*account).clone()),
)
})
.collect();
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, they're a copy of the input but with any changes from the instruction(s) applied. So basically the same as what you are doing already.
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 loop is updating the original references:
for (original, (_, updated)) in accounts
.iter_mut()
.zip(result.resulting_accounts.into_iter())
{
original.data = updated.data().to_vec();
original.lamports = updated.lamports();
original.owner = *updated.owner();
}
I think I need to keep this loop, since those references are used in the caller test code.
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.
Looking good!
This is a completely separate note, but going through this and thinking about p-token, I just realized you can write a pretty nifty benchmark that:
- Clones down SPL-Token from mainnet-beta
- Runs all fixtures on both programs using
process_fixture
(no validation) - Collects each program's compute unit usage from the results.
- Compares them.
// Dedup accounts for mollusk. | ||
account_infos.iter().for_each(|account_info| { | ||
if !cached_accounts.contains_key(account_info.key) { | ||
let account = SolanaAccount { | ||
lamports: account_info.lamports(), | ||
data: account_info.try_borrow_data().unwrap().to_vec(), | ||
owner: *account_info.owner, | ||
executable: account_info.executable, | ||
rent_epoch: account_info.rent_epoch, | ||
}; | ||
dedup_accounts.push((*account_info.key, AccountSharedData::from(account))); | ||
cached_accounts.insert(account_info.key, account_info); | ||
} | ||
}); |
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, interesting. This is required since if the user provides duplicate transaction accounts, the TransactionContext
doesn't pilfer the duplicates out? I wonder if there's an elegant way to handle this within the Mollusk harness somehow.
Works for me if not, though.
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 main reason for it is that the function takes an AccountInfo
and Mollusk expects an AccountSharedData
for each account. Then during this conversion, we only convert one "copy" of each account.
Oooh, that is nice! We can do that once we get everything merged. |
9b284cb
to
b8d47b7
Compare
I think I was missing a rebase - now it looks fine. |
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.
Looks good to me!
@@ -4,7 +4,6 @@ on: | |||
push: | |||
branches: [main] | |||
pull_request: | |||
branches: [main] |
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 want this in here still, right?
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.
Not sure, if we don't restrict the branches, we can have CI run in stacked PRs.
* Use mollusk on process instruction * Enable workflow * Use non-chain process instruction * Address review comments
Problem
PR #17 moved processors tests to the
tests
folder but instructions are executed directly against the programProcessor
.Solution
Reimplement both
do_process_instruction
anddo_process_instruction_dups
to usemollusk
to execute instructions.While the intention was not to introduce any changes to existing tests, there were a couple of changes required:
Processor
directly were updated to usedo_process_instruction_dups
test_close_account