Fat Contract provides high consistency on-chain storage, but it’s only writable by commands. So it has very high costs and doesn’t scale with the size of the worker network. In the contrast, queries have high scalability, low latency, and rich off-chain functions, but they are stateless – there’s no access to the on-chain storage in a query. This makes queries in Fat Contracts hard to use. After all, most of the applications require some kind of state.
The first trail: STF
How can we turn queries to stateful functions? Probably the simplest way is to make the function a STF (state transition function):
- Isolate the state in the service (function)
- Pass the state to the service alongside the input of the query
- Return the update to the state alongside the output of the query
For example, here’s a simple counter program:
var a = 0;
function incBy(x) {
a += x;
return a;
}
To make it a stateless function, we simply pass the state to the function:
function incBy(state, x) {
state.a += x;
return [state, state.a];
}
Then it’s the caller’s duty to maintain the state outside the function. Each time the caller send the current state and the argument to the function, and receive the new state and the return value of the function. Next time, the caller should call the function with the new state.
Theoretically the STF model can work if the caller is honest. However it brings up a few concerns.
State meability and privacy
In the naive model, the caller can feed whatever state to the function. They can also potentially manipulate the state. This is definitely not what we want. We can fix it pretty quick by adding a layer of encryption on the state.
To do that, we can seal the state and only decrypt it within the Fat Contract:
function incBy(sealedState, x) {
let state = decrypt(sealedState);
state.a += x;
sealedState = encrypt(state);
return [sealed, state.a];
}
Encryption is only possible if the runtime can securely keep the state encryption keys. Fortunately, Fat Contract is such a confidential preserving runtime environment.
Usually the we should use authentication encryption to ensure the integrity of the state (thus the caller cannot manipulate the state). By sealing the state, we also address the confidentiality problem at the same time.
Data availability
Since the state is encrypted and authenticated, we can save the state data wherever the app developer feel secure. For a highly decentralized and long term project, it makes sense to store the data on a permanent storage protocol like Arweave. However for the applications that only keep the state in a short period (e.g. chat, personal pasteboard, auction, etc), a cheaper centralized storage like AWS S3 may be good enough, given we are not concerning about data integrity and privacy.
In fact, S3 might be nicer than it looks like. S3 is an object storage service offering HTTP API to read and write the data. From the Fat Contract’s point of view, S3 can be used as a key-value store. We can either save the entire state as a data blob in a kv entry directly, or potentially break the state into a few segments and save them separately (with the caution about data integrity and consistency).
Since S3 offers HTTP API, and Fat Contract also allow a query to send out HTTP requests, we can load and save the state within the contract. So there’s no need to ask the caller to fetch and update the state outside the contract. The contract just need to manage the credential to access the S3 (which is easy!).
After applying the S3 trick, the code will look like:
function incBy(x) {
let state = getAndDecrypt(s3Url);
state.a += x;
sealedState = encryptAndPut(s3Url);
return state.a;
}
There’s another advantage. S3 has already become the de facto of distributed storage. Once there’s a S3 client SDK implemented in Fat Contract, any service compatible with S3 can be used as the storage backend. So far, S3 is supported by almost all the cloud providers and on-prem open sources projects (minio), and even some decentralized storage (storj).
Data freshness and replay attack
(WIP)
- order of state version
- S3 and ETag
- state channel (lighting network)