Skip to content
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

Should the response of an RPC realm function call have the return value? #1100

Closed
jefft0 opened this issue Sep 6, 2023 · 4 comments
Closed
Assignees
Labels
❓ question Questions about Gno

Comments

@jefft0
Copy link
Contributor

jefft0 commented Sep 6, 2023

I'm following the guide to call the board "CreateReply" realm function from the command line using a local gnoland node. The return value of this Gno function is the PostID . Indeed, in the node's ApplyBlock function I inserted a print statement:

fmt.Println("Debug: abciResponses", string(abciResponses.DeliverTxs[0].ResponseBase.Data))

As expected, the gnoland log output shows "Debug: abciResponses (20 gno.land/r/demo/boards.PostID)". Now, in the command-line client I insert the print statement:

io.Println("DATA: ", len(bres.CheckTx.ResponseBase.Data))

The full output from calling "CreateReply" is:

GAS WANTED: 2000000
GAS USED:   1390915
DATA:  0

The Data field is empty, but I expect it to have the return value of the realm function call. My question: When the client uses BroadcastTxCommit to do an RPC realm function call, should the the result Data field have the return value of the realm function call?

@jefft0 jefft0 changed the title Should the response of an RPC realm function call have the realm function return value? Should the response of an RPC realm function call have the return value? Sep 6, 2023
@zivkovicmilos zivkovicmilos self-assigned this Sep 6, 2023
@zivkovicmilos zivkovicmilos added the ❓ question Questions about Gno label Sep 6, 2023
@zivkovicmilos
Copy link
Member

Hey @jefft0,

Thank you for opening the issue.

As far as I know, the Gno execution environment fills out the Data field of DeliverTx when the call is finished:

resstr := ""
resstr, err = vh.vm.Call(ctx, msg)
if err != nil {
return abciResult(err)
}
res.Data = []byte(resstr)

This is propagated out to the RPC layer, so you should be able to extract the response through the DeliverTx.ResponseBase.Data object. Keep in mind that if you're doing this parsing through the RPC layer, this ResponseBase.Data is base64 encoded, so you need to decode it on the client side.

I see that you are checking the CheckTx field, and not the DeliverTx field.
Try changing the print to this instead:
io.Println("DATA: ", len(bres.DeliverTx.ResponseBase.Data))

Calling Realm methods through RPC

Since we don't have this documented anywhere (yet!), I'm going to provide some more context on how an RPC client could handle Realm calls below:

Example: If you want to call a method BertyFunc() on a realm gno.land/r/berty, you can send the following RPC request:

id: // random value
jsonrpc: "2.0"
method: "abci_query"
params: [
    "vm/qeval",
    "Z25vLmxhbmQvci9iZXJ0eQpCZXJ0eUZ1bmMoKQ==",
    "0",
    false
]

You might be wondering what Z25vLmxhbmQvci9iZXJ0eQpCZXJ0eUZ1bmMoKQ== is.
It is the base64 encoding of the params for the vm/qeval call. Specifically, it is the base64 encoding of (notice the newline):

gno.land/r/berty
BertyFunc()

As I mentioned above, since you're doing this request through the RPC layer, the response you get from the RPC query will be in fact an ABCI response object, that contains the field response.ResponseBase.Data, which is base64 encoded.

Luckily, you don't have to handle this on your own -- we provide support for this exact functionality via the evaluateExpression in gno-js-client. Please note that this is for read-only methods (that don't modify the state).

I hope this answers several questions you might've had about this kind of Gno RPC shenanigans

@jefft0
Copy link
Contributor Author

jefft0 commented Sep 6, 2023

Thanks! As you suggest, I changed the print statement to:

io.Println("DATA: ", string(bres.DeliverTx.ResponseBase.Data))

Now it prints "(20 gno.land/r/demo/boards.PostID)" (with no need to decode base64). This format is created by the TypedValue String method. Are there utility functions or a recommended way to "unmarshal" this into a useable object?

@zivkovicmilos
Copy link
Member

Thanks! As you suggest, I changed the print statement to:

io.Println("DATA: ", string(bres.DeliverTx.ResponseBase.Data))

Now it prints "(20 gno.land/r/demo/boards.PostID)" (with no need to decode base64). This format is created by the TypedValue String method.

If you're calling it directly from Go (using the Gno client code we have), you don't need to do base64 juggling

Are there utility functions or a recommended way to "unmarshal" this into a useable object?

Sadly we don't have a standard for parsing these values, you'd need to write a custom parser for them at the moment.

It's part of the bigger issue I'm trying to tackle in the near future, and that's having Realms / Packages have a sort of ABI (if you're familiar with how Solidity contracts get compiled into a parsable format). I've noted it here, in under the "ABI Support for Realms" section, and we have a meta issue by @moul: #925

@jefft0
Copy link
Contributor Author

jefft0 commented Sep 6, 2023

Thanks again. Our immediate issue is solved since we can now get something for the return value of a function call. And it is a known issue that the client is currently at a loss for how to parse the value, but we can track the issues you mention. Closing this as answered.

@jefft0 jefft0 closed this as completed Sep 6, 2023
@moul moul added this to the 🚀 main.gno.land milestone Sep 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
❓ question Questions about Gno
Projects
Archived in project
Development

No branches or pull requests

3 participants