-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Add get_processed_inner_instruction syscall #22515
Conversation
86b997e
to
07553d2
Compare
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.
For my part, looks good once CI is happy
Pull request has been modified.
programs/bpf_loader/src/syscalls.rs
Outdated
@@ -2636,6 +2659,8 @@ fn call<'a, 'b: 'a>( | |||
) | |||
.map_err(SyscallError::InstructionError)?; | |||
|
|||
invoke_context.add_sibling_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.
Two things:
- Can we use
CompiledInstruction
which has account indices, instead ofPubkey
s? (better for ABIv2). - How about referencing the recorded instructions by index / a range?
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.
Instructions aren't always recorded, are you thinking we should always turn on full instruction recording?
I'll take a look at using CompiledInstruction
, are you referring to what the syscall returns, or what is stored internally in the invoke_context?
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 refactoring should have made it cheap enough to always run it. And this PR here comes close to "always on" as well. So why not have them both use an unified underlying mechanism?
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.
Yeah, I'll take a look at that, this implementation is pretty cheap as is, but we can probably do better
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.
One thing to keep in mind is that the instruction recorder records instructions before they are invoked, so it includes instructions that haven't been fully processed yet which also results in a different order
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.
Recorded inner instructions are defined being invoked, not successfully processed:
https://docs.solana.com/developing/clients/jsonrpc-api#inner-instructions-structure
c2b15a0
to
1db88a8
Compare
Codecov Report
@@ Coverage Diff @@
## master #22515 +/- ##
=========================================
+ Coverage 81.1% 81.5% +0.4%
=========================================
Files 560 553 -7
Lines 151206 149771 -1435
=========================================
- Hits 122633 122127 -506
+ Misses 28573 27644 -929 |
1db88a8
to
b58222f
Compare
9f79099
to
6d7366c
Compare
72812a3
to
d3441b9
Compare
sdk/program/src/instruction.rs
Outdated
/// when calling the `sol_get_processed_inner_instruction` syscall. | ||
#[repr(C)] | ||
#[derive(Default, Debug, Clone, Copy)] | ||
pub struct InnerMeta { |
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: InnerMeta
seems a little too generic. ProcessedInnerInstructionMeta
?
@@ -197,6 +197,7 @@ pub struct InvokeContext<'a> { | |||
pub timings: ExecuteDetailsTimings, | |||
pub blockhash: Hash, | |||
pub lamports_per_signature: u64, | |||
pub processed_inner_instructions: Vec<(usize, 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.
This should go in TransactionContext
, because it is not runtime internal and should be exposed to ABIv2 programs as well. I am preparing a PR that moves the InstructionRecorder
there, on which you could rebase this PR.
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'm going to merge this today, feel free to move it after
), | ||
result | ||
); | ||
|
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.
Lets convert from CompiledInstruction
to Instruction
on demand 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.
As we discussed, we can make those changes after this pr lands.
Pull request has been modified.
right, i missed |
As I said, we should always include all instructions. It is easy to filter out the unfinished ones if a program does not want that. |
👍🏼 |
The future inner instructions are not known though, so the runtime could only return the unfinished transaction instructions and we already have the instructions sysvar for can be used for that purpose. |
I'm a little uneasy about |
🤔 yeah
At this call site, I think the result would currently be |
Current result would be |
Result would be empty if the syscall was called before A invoked X too? |
The current implementation yes, the proposed would return |
@mvines @CriesofCarrots , given:
If SPL token is Z, will returning |
0d1bbe5
to
b1aab0d
Compare
The case we'd need is when SPL Token is But for the sake of discussion, if SPL token was Z (or Y) then I'd expect it to see X since X has completed. I think what we're trying to determine is whether Z would also see Y and A since those instructions haven't completed yet. I'm leaning towards including Y and A, even though they are in progress, since this allows Z to figure out who's calling it and I think that enables some interesting use cases (programs changing their behaviour based on caller). But perhaps that's actually an anti-pattern/footgun that we shouldn't enable? |
The reason I ask is that X isn't a direct sibling of Z within Y. Seems like a separate syscall should be added, something like |
Got it. Yeah not opposed to deferring a more general solution to later. SPL Token just needs to inspect the previous sibling instruction at its depth. |
Hey, all. Sorry I was offline for most of this dialog. Is the PR up to date with the currently proposed implementation? If so, I'll catch up with a close read. |
@CriesofCarrots Yeah, I see the desire for this api to include top-level instructions and that becomes non-trivial to define the desired behavior. For example, if we include top-level instructions do we also include their inner instructions? Do we include all instructions a depth minus? Do we include instructions currently being processed and let the program figure out via depth if they are in-progress or not? A lot of info was shared in this thread, reading through that would be helpful. My current thinking is for this API to include all inner instructions of the current top-level and take a max depth. Then we could provide a separate syscall to get the call stack. I want to make sure we cover the use case for SPL but also provide a clear API for other use cases without clouding or returning the world. I think there is also an argument to include all instructions at depth or below that have been processed which would include processed top-level instructions. |
Okay, I've read through everything carefully now.
I think that ambiguity could be a big footgun.
That said, this ^ . It does appeal to me to implement the simpler approach now, and offer the more general utility later if needed. That simpler implementation being:
F sees: |
Maybe we need
"B sees" -> "G sees" right? Sounds good to me if so! But maybe we need a call with everybody on the PR to work out any remaining design discussion with our vocal folds? |
Oops, yep, edited in my comment
Happy to oscillate some vocal folds. I think Jack is unavailable the rest of this week, so maybe Monday? |
In the examples above I'm inclined to return |
The previously (successfully -- implicit) processed instructions at the caller's depth is what we're immediately after. |
Replaced by #22859 |
Replaced by #22859 |
Problem
There are scenarios where instructions (top-level or via CPI) would like to know what the last instruction processed was. Some examples are verification of assert instructions or to check for memo instructions. Programs can already check tx level instructions via the
Sysvar1nstructions1111111111111111111111111
but there is no way to get information about what inner instructions have been processed.Summary of Changes
Add a syscall that allows a program to query what inner instructions have been successfully processed.
Fixes #22437