Launching the Tableland engineering blog v4.1.2 with some updates on mainnet support, new features, and those released over the past month or so.
Engineering Updates | August 2022
Launching the Tableland engineering blog with some updates on mainnet support, new features, and those released over the past month or so.
TL;DR
- Mainnet support! Contracts are now live on Ethereum, Polygon, and Optimism.
- Optimism Kovan deprecation — and new testnet support was added for Optimism Goerli & Arbitrum Goerli.
- New package versions are out, so be sure to update to the latest release.
- New endpoints for
schema
&structure
discoverability. - Changes to parameters in some SDK methods, including
create
andwrite
. - New methods in the smart contracts for ACLs & controllers — also reflected in the SDK and CLI.
- Some new smart contract utilities for working with SQL.
- Validator updates, including multi-transaction support, increased testnet row limit, and moving to SQLite.
- Released a SQL parser as a WASM-based JavaScript library, using a custom SQL parser under the hood (written in Go).
- New SVGs for the TABLE token.
- New writeups that describe some of these features in more detail, including details on the Tableland Rigs.
- A bunch of new docs that walk through new and existing features / concepts.
Release Notes
General
- Contracts were deployed and are now live the following mainnets: Ethereum, Optimism, and Polygon!
- Note that while these are obviously mainnets; the Tableland testnet is still being used.
- Developers should ensure any contracts using Tableland are upgradeable if directly setting the
baseURI
as the testnet gateway (e.g., an NFT’s metadata). - New package versions released:
@tableland/[email protected]
@tableland/[email protected]
@tableland/[email protected]
@tableland/[email protected]
(new! pre-release)- Support was added for the Arbitrum Goerli and Optimism Goerli testnets.
- This is in part because Optimism is deprecating Optimism Kovan; as such, Tableland will also deprecate Optimism Kovan. Be sure to migrate any relevant tables ASAP!
- Additionally, support for Arbitrum Nitro Goerli has been added.
- Validator SQLite migration happened a few weeks ago, and a SQL spec parser has now been released.
- The transition was from PostgresQL to SQLite, which opened to door for a number of future protocol features. More details are included in the writeup at the bottom.
- The SQL parser uses the protocol’s custom SQL spec, which is tailored toward web3.
- Validator client was open sourced () a few weeks ago.
- As the network prepares to onboard validators over the coming months, the code has been made open to the public after 6+ months of development and years of prior work leading up to it.
- Images for TABLE ERC721 have been updated (previously, a static Tableland logo).
- This makes the registry’s TABLE token display a dynamically generated SVG image of relevant table details (name, chain, # rows, schema). Loot style.
Validator
- Increased Tableland testnet maximum number of rows to 500k (previously, set to 100k).
- Added mutli-transaction support.
- Prior to this release, table creates and writes for the same table was not possible in the same transaction. Developers had to use clunky post-deploy logic / helper functions to create a table and then write to it to avoid any errors.
- Now, multi-transactions are possible, removing the need for post-deploy smart contract logic. For example, an address can create a table and write to it in the same tx. See the writeup below for more details.
- For running a validator locally during development, check out the repo — under the hood, it uses the validator source code.
Smart Contracts
- Released
@tableland/[email protected]
. - Added
getController
— a helper to get the controller of a table, e.g., to get the controller after previously setting it withsetController
. - Also added
lockController
in addition to a new internal state variable that stores these locks. Use this method to permanently lock a table’s controller. - To use these methods, it’d look something like the following:
- Added new a SQL helpers library — such as generating table names, CREATE schemas, and INSERT/UPDATE/DELETE statements
- Updated with new Tableland deployment proxy contracts and their associated addresses.
/*
* Registry (TablelandTables) proxy contract addresses can always be found
* here: https://github.com/tablelandnetwork/evm-tableland#currently-supported-chains
*/
// A private storage variable
ITablelandTables private _tableland;
// An instance of the registry contract where `registry` is some `address`
_tableland = ITablelandTables(registry);
// And to leverage these new methods, it'd look something like the following
_tableland.getController(1);
_tableland.lockController(0x4D5286d81317E284Cd377cB98b478552Bbe641ae, 1);
import './SQLHelpers.sol';
// Somewhere in your contract's code
SQLHelpers.toCreateFromSchema("my_table", "id int");
// CREATE TABLE my_table_1 (id int)
SQLHelpers.toInsert("my_table", 123, "id", "1");
// INSERT INTO my_table_1_123 (id) VALUES (1)
SQLHelpers.toUpdate("my_table", 123, "set id = 2", "id = 1");
// UPDATE my_table_1_123 SET set id = 2 WHERE id = 1
SQLHelpers.toDelete("my_table", 123, "id = 1");
// DELETE FROM my_table_1_123 WHERE id = 1
REST API
- Added
schema
andstructure
REST APIs, which are now part of the SDK and will later be added to the CLI. schema
allows for table developers to query for a table’s schema. For example, callinghttps://testnet.tableland.network/schema/rigs_5_28
will return all of the columns, their SQL types, and associated constraints (e.g., primary key).structure
enables table discoverability. Use this to discover tables on the same chain with the same table structure hash, which indicates a matching schema. A matching schema indicates potential opportunities for table JOINs and composability — e.g.,https://testnet.tableland.network/chain/5/tables/structure/7d5cd636b3cb913155fe97a54af38383c2a7a94c98369616bdfe6409558cc57a
.
‣
// Get the matching tables from structure hash
curl https://testnet.tableland.network/chain/5/tables/structure/7d5cd636b3cb913155fe97a54af38383c2a7a94c98369616bdfe6409558cc57a
// [
// {
// "controller": "0x4D5286d81317E284Cd377cB98b478552Bbe641ae",
// "name": "rest_api_5_85",
// "structure": "7d5cd636b3cb913155fe97a54af38383c2a7a94c98369616bdfe6409558cc57a"
// },
// {
// "controller": "0x4D5286d81317E284Cd377cB98b478552Bbe641ae",
// "name": "matching_structure_5_296",
// "structure": "7d5cd636b3cb913155fe97a54af38383c2a7a94c98369616bdfe6409558cc57a"
// }
// ]
// Get the schema of a table
curl https://testnet.tableland.network/schema/rigs_holders_snapshot_1_2
// {
// "columns": [
// {
// "name": "holder",
// "type": "text",
// "constraints": [
// "PRIMARY KEY"
// ]
// },
// {
// "name": "quantity",
// "type": "integer",
// "constraints": []
// },
// ],
// "table_constraints": []
// }
SDK
- Released
@tableland/[email protected]
. - Added
schema
andstructure
methods to support using the endpoints described above. - Added new controller-related methods:
getController
,setController
, andlockController
. setController
method helps SDK users provision access control by specifying an address to control the table ACLs, which may be an EOA or contract address.getController
andlockController
methods are described in the smart contracts section.- Examples of these controller methods:
- Changes to the parameters in
create
. - The method no longer takes parameters
schema
andprefix
but now offers additional options, whereprefix
is a key instead of a standalone param. Thus, the parameters forcreate
are nowschema
and an optional object with a key calledprefix
, among others. write
andsetController
now allow forrpcRelay
as a method-level option to be passed, which is also set in theconnection
.rpcRelay
is a boolean identifier for whether or not a smart contract call should be relayed by the Tableland validator or not. It defaults totrue
for testnet chains, and it cannot betrue
for mainnet chains.write
now takes the parametersstatement
and an optional object (instance ofWriteOptions
) with keys calledrpcRelay
andskipConfirm
.- An example:
// Check the controller, and then lock it if it's "good to go" for an irreversible lock
let controller = await tableland.getController("my_sdk_table_5_311")
console.log(controller)
// 0x0000000000000000000000000000000000000000
// This likely means `setController` was never and defaults to 0x0
// Lock the controller....FOR-E-VER...FOR-E-VER...
let tx = await tableland.lockController("my_sdk_table_5_311")
console.log(tx)
// {
// hash: "0x084a15643927555e87d3889eaa145bbe382a3687b738b6a7c176d3e5e8fc1cce"
// }
// Runs a mutating query statement at the specified table
const insertRes = await tableland.write(
`INSERT INTO ${name} (id, name) VALUES (0, 'Bobby Tables');`,
{
rpcRelay: false,
skipConfirm: false
}
);
console.log(insertRes)
// {
// "hash": "0xbe8c14686af7c2c71c5a996923816d20e31d59a1a976962b443f93a96a031f2d"
// }
CLI
- Released
@tableland/[email protected]
. - Added a
controller
command, which enables calls to the aforementionedgetController
,setController
, andlockController
methods. - Each method has a dedicated subcommand for
get
,set
, andlock
. - Added a new global flag
rpcRelay
(boolean) for setting whether or not to relay a testnet write queries (write
andcontroller
commands). - Miscellaneous optimizations and error message improvements were also added.
> tableland controller get cli_demo_table_5_237
# "0x0000000000000000000000000000000000000000"
> tableland controller set 0x4D5286d81317E284Cd377cB98b478552Bbe641ae cli_demo_table_5_237
# {
# "hash": "0xca5efde91c461c1e272d9e7ac65bc50d31493dc9c4a530c678081defd3a6492f"
# }
> tableland controller lock cli_demo_table_5_237
# {
# "hash": "0x9b3979e9355a5ae32a2d34cae295e186a1aa60ae9522c3b0c9f1a5bbae8653e4"
# }
SQL Parser
- Released
@tableland/[email protected]
— a WASM-based JavaScript library that wraps Tableland's Go-based parser. - It was designed for the Tableland SQL specification, which slightly differs from typical SQLite and needs a custom parser.
- Simply import and use it in testing workflows:
- Read more in the writeup SQLite Migration & Parser.
import init from "@tableland/sqlparser";
// Initialize module (adds sqlparser object to global namespace)
await init();
// Parse sql statement
const [parsed] = await sqlparser.parse(
"select * FrOM fake_table_1 WHere something='nothing';"
);
Release Notes on GitHub
Check out the following links for release notes on GitHub:
Writeups
Exploring Rigs Tables
- Take a deep dive into the Tableland Rigs NFT and the technical details for metadata design and composing queries.
SQLite Migration & Parser
- An overview of the SQLite migration and SQL parser.
Affecting Tableland State
- An explainer on how the validator client processes transactions and design for the new multi-transaction support.
Value Layering across L1 & L2
- A brief on layering value across different chains, such as adopting the Tableland Rigs model where L1 NFTs use metadata tables deployed on L2.
Deploying an NFT on Polygon
- A tutorial that walks through how two set up a two table metadata schema and deploy the tables & NFT smart contract on Polygon.
Docs
- Split Limits & Deployed contracts into separate pages — Limits and a separate Deployed Contracts — to help with readability.
- Added more information to Limits, including limitations to be aware of with smart contracts, chains, tables, tx times, and table reads.
- Added information about Response Times, including introductory information on Tableland<>chain interactions.
- Created a page about Considerations & Tradeoffs. It reviews where people host data in web3 and what data belongs on Tableland.
- Made a page about Choosing a Chain, with details on L1 vs. L1 as well as chain-specific resources.
- Some docs on getting started with Polygon.
- Added a brief on incrementing values with an
INTEGER
type automatically, if it has thePRIMARY KEY
constraint. - Updated SDK, CLI, and REST API docs to reflect the changes mentioned throughout.