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

RPC: Support calling Move function without sending a tx #3815

Closed
sblackshear opened this issue Aug 6, 2022 · 16 comments
Closed

RPC: Support calling Move function without sending a tx #3815

sblackshear opened this issue Aug 6, 2022 · 16 comments
Assignees
Milestone

Comments

@sblackshear
Copy link
Collaborator

This is useful for exposing the results of on-chain logic implemented in Move (e.g., price calculations), or just generally executing code without needing a local VM.

Basically, this is equivalent of view functions in Eth. But because Sui Move is pure, we don't (I think) have to worry about view functions that can be called in this way and non-view functions that cannot--everything is basically a view function. We could consider not allowing invocation of functions that do transfers and emit events, but it is harmless to support this if we want to...

More context in Discord: https://discord.com/channels/916379725201563759/925108748551323649/1005595327291731989

@jamescarter-le
Copy link

jamescarter-le commented Aug 7, 2022

Note that it's not just view functions in Solidity that can be called, any function can be called, and the result is returned.

The difference is the use of the eth_call RPC method which just executes the transaction but then reverts the state on return.

By doing the check this way, you ensure that if operating on two Move objects, they are both at the same point in time, whereas if you get both objects via RPC and reimplement the function outside, you could get different objects when asking for each, and have to maintain a mirrored test suite, which is not good practice.

@666lcz 666lcz added this to the [C] Wave 2 milestone Aug 8, 2022
@gegaowp gegaowp self-assigned this Aug 12, 2022
@gegaowp
Copy link
Contributor

gegaowp commented Aug 12, 2022

@sblackshear I saw that eth_call does not cost gas, and presumably sui_call will be executed on fullnodes without any gas cost either, is it a concern that sui_call would be abused somehow and take too many resources on full-nodes?

@jamescarter-le
Copy link

@sblackshear I saw that eth_call does not cost gas, and presumably sui_call will be executed on fullnodes without any gas cost either, is it a concern that sui_call would be abused somehow and take too many resources on full-nodes?

The cost is inherent to running a node, normally JSON RPC are not exposed running an Eth node, and there are many 3rd party services such as Infura and Alchemy who's niche is providing high availability and throughput RPC services.

@leofisG
Copy link
Contributor

leofisG commented Sep 12, 2022

Will this API have any instruction bounds?

One use case that can be quite helpful in the context of Defi borrow and lending is to fetch all of the user objects underwater for liquidation. However, this operation might become costly when there are tens of thousands of users' objects to fetch and perform calculations.

An example in terms of Aptos Move can be found here. Although this is not Sui Move, it illustrates the ideas.

@jamescarter-le
Copy link

Normally the RPC service providing access to this kind of data either provides a timeout on the request call, so long running calls are cancelled after 10000ms for example.

@gegaowp
Copy link
Contributor

gegaowp commented Sep 12, 2022

@leofisG

fetch all of the user objects

this looks like just data fetch, if so can https://docs.sui.io/sui-jsonrpc#sui_getObjectsOwnedByAddress work instead? also is this info used for txn construction (otherwise maybe a simple local indexing would also work) ?

per the question, yes we will have bound on this call either time or instruction, so super costly calls probably will fail or timeout.

@leofisG
Copy link
Contributor

leofisG commented Sep 12, 2022

@gegaowp the getObjectsOwnedByAddress won't work since we want to know global all users' margin accounts to see which one is under water. It is more similar to the getProgramAccounts API from Solana if you're familiar.

For the indexer, it will work. But need to ensure that:

  1. it is seeing the latest data
  2. it has high availabilities

@gegaowp
Copy link
Contributor

gegaowp commented Sep 12, 2022

@leofisG we chatted briefly in an internal thread and the code pointer will very likely hit the txn execution limit, maybe also the limit of Sui Move object.

I am also copying Sam's recommendation here:

The design pattern I would recommend based on the example code is based on events:

  • Emit an event inside Move code each time a user is created or deleted
  • Expose a Move function get_user_info that encapsulates the logic of the loop body from 371 - 381 inside the get_all_users function.

Getting an answer to "who are all the users of the lending protocol" is then just an event query on (1). If there are N users, you can then send N full node queries calling the function in (2).
An alternative to (2) is to emit on-chain events each time a user borrows, deposits, etc. Then, do an event query to find the most recent such event for each user in (1). This is a useful pattern in many cases, but I would not recommend it here because finding the most recent event for infrequent users may require going pretty far back in the event stream history. Something like (e.g.) a leaderboard is much more amenable to this sort of pattern--just emit an event every time there's a new high score, and you can get the 100 highest by looking at the last 100 events.

@leofisG
Copy link
Contributor

leofisG commented Sep 13, 2022

Emmm, but then we need to send N queries. Seems like more work is offloaded to the client side. 🤔

@PaulFidika
Copy link
Contributor

Is the intention for this to do transaction simulation? Like:

let output_coin = swap_coin(input_coin);
return sui::balance::value(&output_coin.balance)

this would call some swap_coin function with an input_coin, and then return to us the balance of the newly outputted coin. We can then present this to users to be like "oh, this is the price you will get in return".

Another possible use for this could be like data-formatting, like:

let nft_traits: simple_map<string, string> = parse_vec_to_traits(vec, language);
return nft_traits

where we take a vector of bytes describing the metadata of an nft, something like [0, 15, 255, 32...] and turn it into a map that is like:

key: hat, value: fedora
key: glasses, value: null,
key: hair-color, value: blue

and then that could be returned and displayed to users. This would allow NFTs to convert their compact data-encodings into human readable formats in a modular way.

@gegaowp
Copy link
Contributor

gegaowp commented Oct 4, 2022

@PaulFidika we have https://docs.sui.io/sui-jsonrpc#sui_dryRunTransaction for txn simulation already.
another endpoint that I am adding is dryRunMoveCall, #4967

@PaulFidika
Copy link
Contributor

@PaulFidika we have https://docs.sui.io/sui-jsonrpc#sui_dryRunTransaction for txn simulation already. another endpoint that I am adding is dryRunMoveCall, #4967

Oh okay, so dryRunTransaction is for transaction simulation, and these 'view function' calls will be for data-formatting then? Or what is the intended use for them? (Assuming they're still going to be developed.)

@gegaowp
Copy link
Contributor

gegaowp commented Oct 4, 2022

@PaulFidika with dryRunTransaction, ppl can simulate txn runs, which can be move Move function or native function like TransferSui, but it needs to be a signed txn, and requires a gas object and also checks ownership, thus it must be from the owner themselves;
on the other hand, dryRunMoveCall bypasses ownership checks and gas payment, it will it Move VM directly and thus cannot simulate native functions; DApp can probably simulate this for users when needed.

@PaulFidika
Copy link
Contributor

@PaulFidika with dryRunTransaction, ppl can simulate txn runs, which can be move Move function or native function like TransferSui, but it needs to be a signed txn, and requires a gas object and also checks ownership, thus it must be from the owner themselves; on the other hand, dryRunMoveCall bypasses ownership checks and gas payment, it will it Move VM directly and thus cannot simulate native functions; DApp can probably simulate this for users when needed.

When you say it cannot simulate native functions, what does that mean? None of the functions marked as 'native' in Move will work? That would really limit the usefulness of this if true, because almost everything in Sui Move relies on a native function.

@gegaowp
Copy link
Contributor

gegaowp commented Dec 7, 2022

by native txns, I meant txns other than move calls, like paySui for example

@PaulFidika
Copy link
Contributor

PaulFidika commented Jan 6, 2023

With devInspect live, this issue can be closed I believe

@gegaowp gegaowp closed this as completed Jan 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants