Right now, we more or less have two execution environments for Cadence (on the live network, not counting playground/emulator). We have the smart contract and transaction environment used to update the chain, and we have the scripting environment used for querying the chain. Currently, the differences between those two environments are minimal; and basically come down to “can you update the execution state?”
I have a couple of ideas for additional differences that could make the scripting environment more useful.
First: The “normal rules” of Cadence access control could be suspended in the scripting environment. This would allow any script to read any state in any account. Because there’s no way for that code to make changes to the on-chain state, there’s no reason why we should block access to any data, since all of that state is knowable off-chain anyway. This wouldn’t be a trivial change, since it would ideally “break” the normal rules of Cadence against down-casting, and accessing non-public variables, and would also let a script access any AuthAccount. (I know! It sounds scary at first. But think it through, it’s not as crazy at it might seem!)
Second: There is an approach for building dapps in a very “pure” way. The idea is that your dapp can be implemented as an entirely stateless web app. The only code is the smart contracts that live on chain and all client code is a bunch of static JS/HTML files on a server somewhere (or something like IPFS). We’re seeing this approach being used with some defi projects, for example.
The problem with this “pure dapp” vision is that there are certain read-only access patterns that are hard to implement efficiently this way. Consider a simple CryptoKitties gene-browser dapp; it just lets you look at the genes of any Kitty in existence. If you wanted to give the user the ability to search for cats by trait combinations, you’d either have to build some kind of search index on-chain (OOF!), or query and compare the search attributes against every single one of the 2M cats in existence from JS code running in a browser. (Double OOF!!)
So, here is the second idea. What if code running in the scripting environment could have some off-chain state to which it had both read and write access to? Give the scripting environment the ability to store data, but data that ONLY lives on the Access Node. And not all Access Nodes, just the ones that had been asked to run that script.
This should give developers the ability to build something that is deployed as static code (“a pure dapp”), while still allowing efficient data access capabilities. Obviously, the ANs would need to charge for the computational and storage costs of running scripts and storing the off-chain state, but those costs are likely to be a fraction of the cost of on-chain storage and computation. And, of course, a dapp developer could run their own AN, or get a contract with some company that provides monthly access to ANs as a service.
An open question is whether or not it makes sense to use these “stateful scripts” to store data that can’t be regenerated from on-chain data. In my example above, the Kitty index could be many times bigger (in terms of raw data storage) than the baseline Kitty data on chain, but it could always be recreated as a new projection if the AN went down or if the dapp developer/user switched to a different AN. I think that use case is really powerful.
But storing data that can’t be derived from on-chain information might also be useful. Imagine a dapp that let you choose between different interface skins (like a “dark mode”). Storing the selected skin on-chain seems potentially like overkill, but asking the user to chose their skin each time they log in (or the AN gets rebooted) seems unfortunate also.