#View functions

29 messages · Page 1 of 1 (latest)

tender warren
#

I'm looking into adding view function capability to the sdk.

(The video posted by @red basalt at https://discord.com/channels/897514728459468821/1110323110277828639 where he commented on it being difficult to identify view functions spawned my interest in this, and I think it might be doable with Rust in a nice way, so have time boxed an effort to ship it.)

I'm thinking through some issues to do with it, that I'm posting in this thread.

#

RE:

that would be great to have actually! do note though, that the sets of read-only and read-write functions and sets of auth-required and no auth required fns are not equivalent

there can be RO functions that require auth (e.g. consider an oracle that only works for 'subscribers' - I've seen an idea like that around) and there are RW functions that don't require auth
#1110323110277828639 message

#

@spice orchid I thought require_auth always writes data, because nonces are always written. Therefore, Soroban's Auth provides no way to do auth and the auth be read-only to the ledger. Is that correct?

spice orchid
#

no, nonces are not used for invoker auth (importantly for when contract is invoker)

#

even when the nonce is modified, it's technically not the contract state, but the account state (i.e. the annotation can only tell precisely if the current contract state is mutated or not)

#

in any case, I think it would be just useful to provide some way of annotating the view functions for the sake of documentation/tooling

#

there are also stateless functions that call into mutating functions (like the swap example) and it's not really obvious as to whether it should be annotated or not.

tender warren
#

Ok got it, so if contract A calls B, and B does A.require_auth(), then that doesn't write any data, and that is supported by Soroban?

#

It might write data if A implements __check_auth, but assuming it doesn't, no data is written?

spice orchid
#

yeah, why not? footprint and auth are orthogonal

#

nonce may or may not be modified and that's really out of scope of the contract control (e.g. in case of just calling transfer nonce would be modified during the transfer call, but if swap calls transfer, then nonce will be modified during swap etc.).

tender warren
#

Been thinking through this a bit:

#

View functions is doable within a single contract, because we can change the Env parameter to be a &Env on view functions, and &mut Env on non-view functions, and we can change the Env and other functions so that the storage interface doesn't have a set function if you created it with a &Env. And the nice thing about all that is that it is guaranteed by the compiler.

#

However, there's no way to guarantee that a call to another function doesn't mutate storage.

#

So either view functions can't call other contracts, which is absurd.

#

Or view functions can call other functions that mutate state, which is surprising.

#

Or, we make it possible to do a read-only invoke of another contract which panics or errors if it tries to write state, which is getting somewhere, but is no longer a guarantee by the compiler.

#

@fast thorn Is it reasonable to add a host function that does a call, but panics if the call, or any subsequent call in that path, tries to write any state?

fast thorn
#

I guess? I mean if you invoke with a footprint that doesn't cover the LE in question .. I believe it will already

#

(I'm nervous about @spice orchid saying "footprint and auth are orthogonal", if there are writes-to-nonces or anything else that's not captured by the footprint that's a problem)

tender warren
#

o0o0o0o footprints.

#

If there was a host function I could call like, panic_on_footprint_with_writes(), I could inject that into view functions 👀.

#

Although that doesn't help in tests where there is not footprint.

spice orchid
#

auth framework uses footprints correctly. however certain auth code paths don't need to touch storage at all:

  • invoker account - seq num modification happens outside of the host
  • invoker contract - there are no nonces or storage modifications
  • subcontract calls - nonce is only modified once at the top-most level, as the signature spans the whole call tree
#

gjven that the view functions seem mostly useful for stuff that is called from other contracts (as view functions on-chain are pretty much pointless and we even considered invalidating txs with empty RW footprint), wouldn't it be sufficient that the generated clients would just use &Env/&mut Env correctly?

#

i.e. you can't call a &mut Env function subocontract function given just &Env

tender warren
#

That's a possibility. We could generate two clients, one for read-only, and one for read-write. I don't think it could be done with the existing client's design without there being two clients.

spice orchid
#

maybe we still can consider passing &self/&mut self into contract calls/clients instead of Env? that would make things much more natural. I believe there has been discussion regarding that topic at some point

red basalt
#

view functions on-chain are pretty much pointless
This reminds me that CosmWasm allows contracts to directly read the storage of other contracts, without needing to load those separate contracts out of memory and execute them.