Affecting Tableland State
⚙️

Affecting Tableland State

This article explains at a high level how affecting Tableland state works, both in the mechanics and semantics.

Affecting Tableland State

This article explains at a high level how affecting Tableland state works, both in the mechanics and semantics.

The journey of mutating state

To fully understand the potential and correct usage of the protocol, it’s helpful to know how the state is mutated in Tableland.

How does everything start?

Any activity affecting the state in the Tableland network starts with sending an EVM transaction to the blockchain.

This transaction can be classified into two buckets:

  • The transaction is directly sent to the Registry smart contract (e.g., minting a table, sending a write-query, setting a controller for ACL, transferring a table)
  • The transaction is sent to an arbitrary smart contract that might call the Registry smart contract as part of some flow.

In any of these cases, there will be one or multiple calls to the Registry smart contract methods. These methods emit EVM events that signal that something important has happened in the protocol.

These events have a type and data that Tableland validators watch and apply in the Tableland state. For example, for a runSQL(...) method call, an event of type RunSQL with data being the SQL write-query is emitted that validators will execute to mutate the table state.

Note that these EVM events are part of the transaction execution receipt in the underlying blockchain. For example, you can see here the events produced as a result of transaction execution.

Transaction execution by validators

Any EVM transaction execution can have two results: Success or Failure. For example, if you try to send some funds from your wallet address but you don’t have enough balance, that transaction will fail. Similarly, if you call a smart-contract method and run out of gas in the middle of the execution, all the pending affected states are rollbacked.

Tableland works in the same way. Tableland validators watch for successful transaction executions and apply those changes in the Tableland state. This explains some apparent fact: failed transactions don’t affect the state. This means there won’t be dangling changes in the Tableland network compared to the rollbacked on-chain state that this transaction tried to change; both commit or rollback decisions will be aligned.

Recall that in the previous section, we mentioned that we could have one or more events emitted in a single EVM transaction. The following are some examples of how this can happen:

  • If you send an EVM transaction to the runSQL(…) smart contract, this method only emits one event. This is precisely the example shown before.
  • Suppose you created a smart contract with a method mintTwoTables(...) where the implementation calls twice the createTable(...) method of the Registry smart contract. In that case, this transaction receipt will have two events emitted.

A validator will take this successful EVM transaction packed with N events and execute all of them atomically in the Tableland state. But what does this mean?

Atomicity and failure of EVM transactions execution

Let’s dive deeper into what atomicity means, what can go wrong in executing events, and how this affects the Tableland state.

Let’s start with an imaginary successful EVM transaction T with their events: E1, E2, and E3. These events can be anything, like create table or write-queries, but these details aren’t relevant to understanding the mechanics.

Executing these transaction T events can have two results:

  • Success: generating a Tableland receipt for this transaction with success status.
  • Failed: generating a Tableland receipt for this transaction with a failed status and auxiliary information of why.
💡
You can get the Tableland transaction receipt with the tableland_getReceipt RPC call.

A Tableland transaction execution is successful if executing all the events emitted in that transaction is succeeded. On the contrary, a Tableland transaction execution has failed if any event execution fails. You can relate this behavior exactly as SQL transactions work: the transaction is usually committed if all the queries succeed or rollbacked if any fail.

💡
Some simple reasons why executing an event can fail: - The write-query has invalid SQL syntax. - You don’t have enough permissions to do the operation.

Taking our transaction T as an example, if the execution of E1 succeeds but E2 fails, that will immediately roll back all the changes that E1 or E2 have done in Tableland. The event E3 is not even executed since E2 failing already caused a rollback.

A Tableland transaction success or failure is directly correlated to affecting Tableland state. If it is successful, all the expected events changes will permanently affect the state and can be seen by anyone doing read-queries. If it has failed, none of the events' changes will have affected the state, just as if the transaction never existed.

Note how we have three possible results of your original EVM transaction:

On-chain execution status
Tableland execution status
Affected Tableland state?
Success
Success
Success
Failure
Failure
Not executed

Now it’s pretty clear why checking your Tableland transaction receipt is essential. Even if the EVM transaction succeeded, the tableland execution could fail to leave the state as the EVM transaction never existed. (e.g., sending an invalid syntax write-query is fine for on-chain checks but is invalid when executing it in validators).

Let the mind fly…

With all this knowledge, it’s time to get creative and develop new ways to solve problems!

Each transaction has many events that open the door for multiple interesting use-cases and invariants you can enforce in your data; here’re some quick ideas:

  • Mint more than one table in the same transaction.
  • Mint a table and immediately insert data.
    • This allows having new invariants in the protocol:
      • Mint tables that can never result in an empty read.
      • Single-shot immutable tables. (CREATE+INSERT+FREEZE)
  • Allow transactional data mutation in more than one table.
    • If you have permissions, you can mutate the state of multiple tables having multi-table transactions.
  • Make smart contract Controllers more powerful. Every time the ACL controller authorizes a write-query, it could generate an INSERT statement to a separate table to have an independent audit log.

We’re pretty excited to see how you can leverage all this power!