sui
sui copied to clipboard
RPC: Support calling Move function without sending a tx
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
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.
@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?
@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.
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.
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.
@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.
@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:
- it is seeing the latest data
- it has high availabilities
@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.
Emmm, but then we need to send N queries. Seems like more work is offloaded to the client side. 🤔
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
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.
@PaulFidika we have https://docs.sui.io/sui-jsonrpc#sui_dryRunTransaction for txn simulation already. another endpoint that I am adding is dryRunMoveCall, https://github.com/MystenLabs/sui/issues/4967
@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.)
@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 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.
by native txns, I meant txns other than move calls, like paySui for example
With devInspect live, this issue can be closed I believe