Skip to content

lang: Allow CPI return values#1598

Merged
paul-schaaf merged 38 commits into
otter-sec:masterfrom
tomlinton:tomlinton/cpi-returns
Mar 24, 2022
Merged

lang: Allow CPI return values#1598
paul-schaaf merged 38 commits into
otter-sec:masterfrom
tomlinton:tomlinton/cpi-returns

Conversation

@tomlinton

Copy link
Copy Markdown
Contributor

If an instruction returns a type then write the result with the Solana set_return_data syscall. If the CPI client determines an instruction returns something it'll read it with get_return_data.

This shouldn't change anything for standard Result<()> returns from instructions, but specifying a Result with a type will result in a set_return_data call regardless of whether the call is made via CPI. I haven't figured out whether that is a good thing or a bad thing.

Closes #20

@tomlinton tomlinton marked this pull request as ready for review March 11, 2022 20:23

@paul-schaaf paul-schaaf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the generated idl should also include the return type of the instruction

Comment thread tests/cpi-returns/yarn.lock Outdated
Comment thread lang/syn/src/codegen/program/handlers.rs Outdated
Comment thread tests/cpi-returns/programs/caller/src/lib.rs Outdated
Comment thread tests/cpi-returns/programs/callee/src/lib.rs
Comment thread lang/syn/src/codegen/program/handlers.rs Outdated
Comment thread tests/cpi-returns/programs/callee/src/lib.rs
@paul-schaaf

Copy link
Copy Markdown
Contributor

specifying a Result with a type will result in a set_return_data call regardless of whether the call is made via CPI

seems like a general problem with set_return_data though, not a problem with your implementation. Or am I misunderstanding you?

Comment thread lang/syn/src/codegen/program/cpi.rs
Comment thread lang/syn/src/codegen/program/handlers.rs Outdated
@tomlinton

Copy link
Copy Markdown
Contributor Author

the generated idl should also include the return type of the instruction

Added this.

seems like a general problem with set_return_data though, not a problem with your implementation. Or am I misunderstanding you?

Yea I think this is OK.

Comment thread lang/syn/src/codegen/program/cpi.rs Outdated
"()" => (quote! {anchor_lang::Result<()> }, quote! { Ok(()) }),
_ => (
quote! { anchor_lang::Result<Return::<#ret_type>> },
quote! { Ok(Return::<#ret_type> { phantom: PhantomData }) }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

use full path for Return and PhantomData to avoid naming clashes (in the line above there's a Return too)


pub fn parse_return(method: &syn::ItemFn) -> ParseResult<IxReturn> {
match method.sig.output {
syn::ReturnType::Type(_, ref ty) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

an error here would be nice that hardcodes (with .to_string) that the return type must be of the form Result<()> or Result<T>

the return code (and possibly even other code) depends on this exact return type and you can't use aliases like type MyResult = Result<()>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There is still some tests returning ProgramResult, this handles return types that don't confirm to Result<()> or Result<T> by defaulting to assuming it returns the unit type, these might break I think? I can commit it anyway and let CI figure it out

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yea I cant think of anything that can actually go wrong with your code defaulting to no return type. so no need for that extra check i think

Comment thread lang/syn/src/codegen/program/cpi.rs Outdated
pub fn get(&self) -> Result<T> {
let (_key, data) = anchor_lang::solana_program::program::get_return_data().unwrap();
let value = T::try_from_slice(&data).unwrap();
Ok(value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks like this could just return T instead of Result<T>

@@ -0,0 +1,13 @@
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the way it works / what worked for me is that you dont have to specify the dependencies here. The package.json file in the tests dir already has them and this folder can pull them as long as its defined as a npm workspace member in the package.json in tests

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yea that is right

@paul-schaaf

Copy link
Copy Markdown
Contributor

LGTM! Is there anything left you want to add or can I merge?

@tomlinton

Copy link
Copy Markdown
Contributor Author

All good from my end, thanks! 🚀

@paul-schaaf paul-schaaf merged commit 1cb7429 into otter-sec:master Mar 24, 2022
@paul-schaaf

Copy link
Copy Markdown
Contributor

thank you for the contribution!

@tomlinton tomlinton mentioned this pull request Mar 28, 2022
Otter-0x4ka5h pushed a commit to Otter-0x4ka5h/anchor that referenced this pull request Mar 25, 2026
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.

CPI client with return values

2 participants