diff --git a/README.md b/README.md index 2f4507a8..4d7d4c86 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ There are two prerequisites for running a validator: Tableland has two separate networks: - `mainnet`: this network syncs mainnet EVM chains (e.g., Ethereum mainnet, Arbitrum mainnet, etc.). -- `testnet`: this network is syncing testnet EVM chains (e.g., Ethereum Sepolia, Arbitrum Goerli, etc.). +- `testnet`: this network is syncing testnet EVM chains (e.g., Ethereum Sepolia, Arbitrum Sepolia, etc.). This guide will focus on running the validator in the `mainnet` network. @@ -298,7 +298,7 @@ The validator configuration is done via a JSON file located at `deployed/mainnet This file contains general and chain-specific configuration, such as desired listening ports, gateway configuration, log level configuration, and chain-specific configuration, including name, chain ID, contract address, wallet private keys, and EVM node API endpoints. -The provided configurations in each `deployed/` already have everything needed for the environment and other recommended values. The environment variable expansion parts of the `config.json` file, such as secrets and other attributes in the `.env_validator` file, were explained in the [secret configuration section](2-configure-your-secrets-in-env-files) above. For example, the `VALIDATOR_ALCHEMY_ETHEREUM_MAINNET_API_KEY` variable configured in `.env_validator` expands a `${VALIDATOR_ALCHEMY_ETHEREUM_MAINNET_API_KEY}` present in the `config.json` file. If you want to use a self-hosted Ethereum mainnet node API or another provider, you can edit the `config.json` file in the `EthEndpoint` endpoint. This same logic applies to every possible configuration in the validator. +The provided configurations in each `deployed/` already have everything needed for the environment and other recommended values. The environment variable expansion parts of the `config.json` file, such as secrets and other attributes in the `.env_validator` file, were explained in the [secret configuration section](#2-configure-your-secrets-in-env-files) above. For example, the `VALIDATOR_ALCHEMY_ETHEREUM_MAINNET_API_KEY` variable configured in `.env_validator` expands a `${VALIDATOR_ALCHEMY_ETHEREUM_MAINNET_API_KEY}` present in the `config.json` file. If you want to use a self-hosted Ethereum mainnet node API or another provider, you can edit the `config.json` file in the `EthEndpoint` endpoint. This same logic applies to every possible configuration in the validator. #### Observability stack @@ -336,18 +336,16 @@ CREATE TABLE healthbot_{chainID} (counter INTEGER); This would result in having four tables—one per chain: - `healthbot_11155111_{tableID}` (Ethereum Sepolia) -- `healthbot_420_{tableID}` (Optimism Goerli) -- `healthbot_421613_{tableID}` (Arbitrum Goerli) -- `healthbot_80001_{tableID}` (Polygon Mumbai) +- `healthbot_11155420_{tableID}` (Optimism Sepolia) +- `healthbot_421614_{tableID}` (Arbitrum Sepolia) - `healthbot_314159_{tableID}` (Filecoin Calibration) You should create a file `.env_healthbot` in the `docker/deployed/testnet/healthbot` folder with the following content (an example is provided with `.env_healthbot.example`): ```txt HEALTHBOT_ETHEREUM_SEPOLIA_TABLE=healthbot_11155111_{tableID} -HEALTHBOT_OPTIMISM_GOERLI_TABLE=healthbot_420_{tableID} -HEALTHBOT_ARBITRUM_GOERLI_TABLE=healthbot_421613_{tableID} -HEALTHBOT_POLYGON_MUMBAI_TABLE=healthbot_80001_{tableID} +HEALTHBOT_OPTIMISM_SEPOLIA_TABLE=healthbot_11155420_{tableID} +HEALTHBOT_ARBITRUM_SEPOLIA_TABLE=healthbot_421614_{tableID} HEALTHBOT_FILECOIN_CALIBRATION_TABLE=healthbot_314159_{tableID} ``` @@ -473,4 +471,4 @@ Small note: If editing the README, please conform to the ## License -MIT AND Apache-2.0, © 2021-2023 Tableland Network Contributors +MIT AND Apache-2.0, © 2021-2024 Tableland Network Contributors diff --git a/cmd/api/main.go b/cmd/api/main.go index 611ac712..62480ab8 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -474,7 +474,7 @@ func createAPIServer( server := &http.Server{ Addr: ":" + httpConfig.Port, ReadTimeout: 10 * time.Second, - WriteTimeout: 20 * time.Second, + WriteTimeout: 60 * time.Second, IdleTimeout: 120 * time.Second, TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){}, Handler: router.Handler(), diff --git a/docker/deployed/staging/api/.env_validator.example b/docker/deployed/staging/api/.env_validator.example index c38fc499..c9a4e7fa 100644 --- a/docker/deployed/staging/api/.env_validator.example +++ b/docker/deployed/staging/api/.env_validator.example @@ -1,3 +1,2 @@ -VALIDATOR_ALCHEMY_OPTIMISM_GOERLI_API_KEY= -VALIDATOR_OPTIMISM_GOERLI_SIGNER_PRIVATE_KEY= +VALIDATOR_ALCHEMY_OPTIMISM_SEPOLIA_API_KEY= METRICS_HUB_API_KEY= \ No newline at end of file diff --git a/docker/deployed/staging/api/config.json b/docker/deployed/staging/api/config.json index d516576d..76d49c63 100644 --- a/docker/deployed/staging/api/config.json +++ b/docker/deployed/staging/api/config.json @@ -52,11 +52,11 @@ }, "Chains": [ { - "Name": "Optimism Goerli", - "ChainID": 420, + "Name": "Optimism Sepolia", + "ChainID": 11155420, "Registry": { - "EthEndpoint": "wss://opt-goerli.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_OPTIMISM_GOERLI_API_KEY}", - "ContractAddress": "0xfe79824f6E5894a3DD86908e637B7B4AF57eEE28" + "EthEndpoint": "wss://eth-sepolia.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_OPTIMISM_SEPOLIA_API_KEY}", + "ContractAddress": "0xd39a346e8299F4e3685f3D44215e0c9328e73439" }, "EventFeed": { "ChainAPIBackoff": "15s", diff --git a/docker/deployed/staging/healthbot/.env_healthbot.example b/docker/deployed/staging/healthbot/.env_healthbot.example index 74618d74..9939b7cf 100644 --- a/docker/deployed/staging/healthbot/.env_healthbot.example +++ b/docker/deployed/staging/healthbot/.env_healthbot.example @@ -1,4 +1,4 @@ -HEALTHBOT_OPTIMISM_GOERLI_PRIVATE_KEY= -HEALTHBOT_OPTIMISM_GOERLI_API_KEY= -HEALTHBOT_OPTIMISM_GOERLI_TABLE= +HEALTHBOT_OPTIMISM_SEPOLIA_PRIVATE_KEY= +HEALTHBOT_OPTIMISM_SEPOLIA_API_KEY= +HEALTHBOT_OPTIMISM_SEPOLIA_TABLE= diff --git a/docker/deployed/staging/healthbot/config.json b/docker/deployed/staging/healthbot/config.json index e4dbbfb6..1a335556 100644 --- a/docker/deployed/staging/healthbot/config.json +++ b/docker/deployed/staging/healthbot/config.json @@ -9,12 +9,12 @@ "Chains": [ { "ChainID": 420, - "WalletPrivateKey": "${HEALTHBOT_OPTIMISM_GOERLI_PRIVATE_KEY}", - "AlchemyAPIKey": "${HEALTHBOT_OPTIMISM_GOERLI_API_KEY}", + "WalletPrivateKey": "${HEALTHBOT_OPTIMISM_SEPOLIA_PRIVATE_KEY}", + "AlchemyAPIKey": "${HEALTHBOT_OPTIMISM_SEPOLIA_API_KEY}", "Probe": { "CheckInterval": "360s", "ReceiptTimeout": "20s", - "Tablename": "${HEALTHBOT_OPTIMISM_GOERLI_TABLE}" + "Tablename": "${HEALTHBOT_OPTIMISM_SEPOLIA_TABLE}" }, "OverrideClient" : { "GatewayEndpoint": "https://staging.tableland.network", diff --git a/docker/deployed/testnet/api/.env_validator.example b/docker/deployed/testnet/api/.env_validator.example index 4ca70005..3db2d265 100644 --- a/docker/deployed/testnet/api/.env_validator.example +++ b/docker/deployed/testnet/api/.env_validator.example @@ -1,7 +1,6 @@ VALIDATOR_ALCHEMY_ETHEREUM_SEPOLIA_API_KEY= VALIDATOR_GLIF_FILECOIN_CALIBRATION_API_KEY= -VALIDATOR_ALCHEMY_POLYGON_MUMBAI_API_KEY= -VALIDATOR_ALCHEMY_ETHEREUM_GOERLI_API_KEY= -VALIDATOR_ALCHEMY_ARBITRUM_GOERLI_API_KEY= -VALIDATOR_ALCHEMY_OPTIMISM_GOERLI_API_KEY= +VALIDATOR_ALCHEMY_POLYGON_AMOY_API_KEY= +VALIDATOR_ALCHEMY_ARBITRUM_SEPOLIA_API_KEY= +VALIDATOR_ALCHEMY_OPTIMISM_SEPOLIA_API_KEY= METRICS_HUB_API_KEY= diff --git a/docker/deployed/testnet/api/config.json b/docker/deployed/testnet/api/config.json index 82b88f0d..cde855dd 100644 --- a/docker/deployed/testnet/api/config.json +++ b/docker/deployed/testnet/api/config.json @@ -52,25 +52,6 @@ "ChainStackCollectFrequency": "15m" }, "Chains": [ - { - "Name": "Ethereum Goerli", - "ChainID": 5, - "Registry": { - "EthEndpoint": "wss://eth-goerli.alchemyapi.io/v2/${VALIDATOR_ALCHEMY_ETHEREUM_GOERLI_API_KEY}", - "ContractAddress": "0xDA8EA22d092307874f30A1F277D1388dca0BA97a" - }, - "EventFeed": { - "ChainAPIBackoff": "15s", - "NewBlockPollFreq": "10s", - "MinBlockDepth": 1, - "PersistEvents": true - }, - "EventProcessor": { - "BlockFailedExecutionBackoff": "10s", - "DedupExecutedTxns": true - }, - "HashCalculationStep": 150 - }, { "Name": "Ethereum Sepolia", "ChainID": 11155111, @@ -91,11 +72,11 @@ "HashCalculationStep": 150 }, { - "Name": "Polygon Mumbai", - "ChainID": 80001, + "Name": "Polygon Amoy", + "ChainID": 80002, "Registry": { - "EthEndpoint": "wss://polygon-mumbai.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_POLYGON_MUMBAI_API_KEY}", - "ContractAddress": "0x4b48841d4b32C4650E4ABc117A03FE8B51f38F68" + "EthEndpoint": "wss://polygon-amoy.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_POLYGON_AMOY_API_KEY}", + "ContractAddress": "0x170fb206132b693e38adFc8727dCfa303546Cec1" }, "EventFeed": { "ChainAPIBackoff": "15s", @@ -110,11 +91,11 @@ "HashCalculationStep": 360 }, { - "Name": "Arbitrum Goerli", - "ChainID": 421613, + "Name": "Arbitrum Sepolia", + "ChainID": 421614, "Registry": { - "EthEndpoint": "wss://arb-goerli.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_ARBITRUM_GOERLI_API_KEY}", - "ContractAddress": "0x033f69e8d119205089Ab15D340F5b797732f646b" + "EthEndpoint": "wss://arb-sepolia.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_ARBITRUM_SEPOLIA_API_KEY}", + "ContractAddress": "0x223A74B8323914afDC3ff1e5005564dC17231d6e" }, "EventFeed": { "ChainAPIBackoff": "15s", @@ -129,11 +110,11 @@ "HashCalculationStep": 360 }, { - "Name": "Optimism Goerli", - "ChainID": 420, + "Name": "Optimism Sepolia", + "ChainID": 11155420, "Registry": { - "EthEndpoint": "wss://opt-goerli.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_OPTIMISM_GOERLI_API_KEY}", - "ContractAddress": "0xC72E8a7Be04f2469f8C2dB3F1BdF69A7D516aBbA" + "EthEndpoint": "wss://opt-sepolia.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_OPTIMISM_SEPOLIA_API_KEY}", + "ContractAddress": "0x68A2f4423ad3bf5139Db563CF3bC80aA09ed7079" }, "EventFeed": { "ChainAPIBackoff": "15s", diff --git a/docker/deployed/testnet/healthbot/.env_healthbot.example b/docker/deployed/testnet/healthbot/.env_healthbot.example index d3b1fb6c..8dccf636 100644 --- a/docker/deployed/testnet/healthbot/.env_healthbot.example +++ b/docker/deployed/testnet/healthbot/.env_healthbot.example @@ -7,9 +7,6 @@ HEALTHBOT_FILECOIN_HYPERSPACE_TABLE= HEALTHBOT_ETHEREUM_GOERLI_PRIVATE_KEY= HEALTHBOT_ALCHEMY_ETHEREUM_GOERLI_API_KEY= HEALTHBOT_ETHEREUM_GOERLI_TABLE= -HEALTHBOT_POLYGON_MUMBAI_PRIVATE_KEY= -HEALTHBOT_ALCHEMY_POLYGON_MUMBAI_API_KEY= -HEALTHBOT_POLYGON_MUMBAI_TABLE= HEALTHBOT_ARBITRUM_GOERLI_PRIVATE_KEY= HEALTHBOT_ALCHEMY_ARBITRUM_GOERLI_API_KEY= HEALTHBOT_ARBITRUM_GOERLI_TABLE= diff --git a/docker/deployed/testnet/healthbot/config.json b/docker/deployed/testnet/healthbot/config.json index 088f3a61..d7faaff1 100644 --- a/docker/deployed/testnet/healthbot/config.json +++ b/docker/deployed/testnet/healthbot/config.json @@ -21,16 +21,6 @@ "EstimatedGasLimitMultiplier": 1.1 } }, - { - "ChainID": 80001, - "WalletPrivateKey": "${HEALTHBOT_POLYGON_MUMBAI_PRIVATE_KEY}", - "AlchemyAPIKey": "${HEALTHBOT_ALCHEMY_POLYGON_MUMBAI_API_KEY}", - "Probe": { - "CheckInterval": "240s", - "ReceiptTimeout": "40s", - "Tablename": "${HEALTHBOT_POLYGON_MUMBAI_TABLE}" - } - }, { "ChainID": 314159, "WalletPrivateKey": "${HEALTHBOT_FILECOIN_CALIBRATION_PRIVATE_KEY}", diff --git a/internal/router/controllers/apiv1/api_health.go b/internal/router/controllers/apiv1/api_health.go index c1a4e465..c060b02b 100644 --- a/internal/router/controllers/apiv1/api_health.go +++ b/internal/router/controllers/apiv1/api_health.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/api_query.go b/internal/router/controllers/apiv1/api_query.go index 0d2ccd80..3fd7d41f 100644 --- a/internal/router/controllers/apiv1/api_query.go +++ b/internal/router/controllers/apiv1/api_query.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ @@ -17,3 +17,8 @@ func QueryByStatement(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) } + +func QueryByStatementPost(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} diff --git a/internal/router/controllers/apiv1/api_receipt.go b/internal/router/controllers/apiv1/api_receipt.go index 81177b33..9baf8b23 100644 --- a/internal/router/controllers/apiv1/api_receipt.go +++ b/internal/router/controllers/apiv1/api_receipt.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/api_tables.go b/internal/router/controllers/apiv1/api_tables.go index fced67cc..855adf0a 100644 --- a/internal/router/controllers/apiv1/api_tables.go +++ b/internal/router/controllers/apiv1/api_tables.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/api_version.go b/internal/router/controllers/apiv1/api_version.go index 3f4aa476..8bb58d92 100644 --- a/internal/router/controllers/apiv1/api_version.go +++ b/internal/router/controllers/apiv1/api_version.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/logger.go b/internal/router/controllers/apiv1/logger.go index ed473ba0..d404d512 100644 --- a/internal/router/controllers/apiv1/logger.go +++ b/internal/router/controllers/apiv1/logger.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/model_column.go b/internal/router/controllers/apiv1/model_column.go index 56b9e071..f105c6ac 100644 --- a/internal/router/controllers/apiv1/model_column.go +++ b/internal/router/controllers/apiv1/model_column.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go b/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go index b0bf2f62..477f613b 100644 --- a/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go +++ b/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/model_query.go b/internal/router/controllers/apiv1/model_query.go new file mode 100644 index 00000000..339834e7 --- /dev/null +++ b/internal/router/controllers/apiv1/model_query.go @@ -0,0 +1,21 @@ +/* + * Tableland Validator - OpenAPI 3.0 + * + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. + * + * API version: 1.1.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type Query struct { + // The SQL read query statement + Statement string `json:"statement,omitempty"` + // The requested response format: * `objects` - Returns the query results as a JSON array of JSON objects. * `table` - Return the query results as a JSON object with columns and rows properties. + Format string `json:"format,omitempty"` + // Whether to extract the JSON object from the single property of the surrounding JSON object. + Extract bool `json:"extract,omitempty"` + // Whether to unwrap the returned JSON objects from their surrounding array. + Unwrap bool `json:"unwrap,omitempty"` +} diff --git a/internal/router/controllers/apiv1/model_schema.go b/internal/router/controllers/apiv1/model_schema.go index 83060b06..6f3fe078 100644 --- a/internal/router/controllers/apiv1/model_schema.go +++ b/internal/router/controllers/apiv1/model_schema.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/model_table.go b/internal/router/controllers/apiv1/model_table.go index 08a21d59..6dcd7f7b 100644 --- a/internal/router/controllers/apiv1/model_table.go +++ b/internal/router/controllers/apiv1/model_table.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/model_table_attributes.go b/internal/router/controllers/apiv1/model_table_attributes.go index e519d6b6..f079b750 100644 --- a/internal/router/controllers/apiv1/model_table_attributes.go +++ b/internal/router/controllers/apiv1/model_table_attributes.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ diff --git a/internal/router/controllers/apiv1/model_transaction_receipt.go b/internal/router/controllers/apiv1/model_transaction_receipt.go index 6b3c7e8b..b79011f6 100644 --- a/internal/router/controllers/apiv1/model_transaction_receipt.go +++ b/internal/router/controllers/apiv1/model_transaction_receipt.go @@ -1,16 +1,16 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ package apiv1 type TransactionReceipt struct { - + // This field is deprecated TableId string `json:"table_id,omitempty"` TableIds []string `json:"table_ids,omitempty"` diff --git a/internal/router/controllers/apiv1/model_version_info.go b/internal/router/controllers/apiv1/model_version_info.go index d460bc98..fbd9deed 100644 --- a/internal/router/controllers/apiv1/model_version_info.go +++ b/internal/router/controllers/apiv1/model_version_info.go @@ -1,16 +1,15 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ package apiv1 type VersionInfo struct { - Version int32 `json:"version,omitempty"` GitCommit string `json:"git_commit,omitempty"` diff --git a/internal/router/controllers/apiv1/routers.go b/internal/router/controllers/apiv1/routers.go index f61e6894..598aefd8 100644 --- a/internal/router/controllers/apiv1/routers.go +++ b/internal/router/controllers/apiv1/routers.go @@ -1,9 +1,9 @@ /* * Tableland Validator - OpenAPI 3.0 * - * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world. In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information. * - * API version: 1.0.0 + * API version: 1.1.0 * Contact: carson@textile.io * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ @@ -69,6 +69,13 @@ var routes = Routes{ QueryByStatement, }, + Route{ + "QueryByStatementPost", + strings.ToUpper("Post"), + "/api/v1/query", + QueryByStatementPost, + }, + Route{ "ReceiptByTransactionHash", strings.ToUpper("Get"), diff --git a/internal/router/controllers/controller.go b/internal/router/controllers/controller.go index 073d256a..699befdf 100644 --- a/internal/router/controllers/controller.go +++ b/internal/router/controllers/controller.go @@ -150,7 +150,7 @@ func (c *Controller) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http _ = json.NewEncoder(rw).Encode(receiptResponse) } -// GetTable handles the GET /chain/{chainID}/tables/{tableId} call. +// GetTable handles the GET /tables/{chainID}/{tableId} call. func (c *Controller) GetTable(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := mux.Vars(r) @@ -256,6 +256,11 @@ func (c *Controller) GetTableQuery(rw http.ResponseWriter, r *http.Request) { return } + if len(formatted) == 0 { + rw.WriteHeader(http.StatusNotFound) + return + } + collectReadQueryMetric(r.Context(), stm, config, took) rw.WriteHeader(http.StatusOK) @@ -265,6 +270,65 @@ func (c *Controller) GetTableQuery(rw http.ResponseWriter, r *http.Request) { _, _ = rw.Write(formatted) } +// PostTableQuery handles the POST /query call. +func (c *Controller) PostTableQuery(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + + // setting a default body because these options could be missing from JSON + body := &apiv1.Query{ + Format: string(formatter.Objects), + Extract: false, + Unwrap: false, + } + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + rw.WriteHeader(http.StatusBadRequest) + msg := fmt.Sprintf("Error parsing the body request: %v", err) + log.Ctx(r.Context()).Error().Err(err).Msg(msg) + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: msg}) + return + } + _ = r.Body.Close() + + start := time.Now() + res, ok := c.runReadRequest(r.Context(), body.Statement, rw) + if !ok { + return + } + took := time.Since(start) + + var opts []formatter.FormatOption + output, ok := formatter.OutputFromString(body.Format) + if !ok { + log.Ctx(r.Context()).Error().Msg("bad output query parameter") + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "bad output query parameter"}) + } + opts = append(opts, formatter.WithOutput(output)) + opts = append(opts, formatter.WithExtract(body.Extract)) + opts = append(opts, formatter.WithUnwrap(body.Unwrap)) + + formatted, config, err := formatter.Format(res, opts...) + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + msg := fmt.Sprintf("Error formatting data: %v", err) + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: msg}) + log.Ctx(r.Context()).Error().Err(err).Msg(msg) + return + } + + if len(formatted) == 0 { + rw.WriteHeader(http.StatusNotFound) + return + } + + collectReadQueryMetric(r.Context(), body.Statement, config, took) + + rw.WriteHeader(http.StatusOK) + if config.Unwrap && len(res.Rows) > 1 { + rw.Header().Set("Content-Type", "application/jsonl+json") + } + _, _ = rw.Write(formatted) +} + func (c *Controller) runReadRequest( ctx context.Context, stm string, diff --git a/internal/router/controllers/controller_test.go b/internal/router/controllers/controller_test.go index 1a2cce68..5cd20b79 100644 --- a/internal/router/controllers/controller_test.go +++ b/internal/router/controllers/controller_test.go @@ -1,7 +1,9 @@ package controllers import ( + "bytes" "context" + "encoding/json" "errors" "fmt" "math/big" @@ -90,6 +92,105 @@ func TestQuery(t *testing.T) { } } +func TestPostQuery(t *testing.T) { + r := mocks.NewGateway(t) + r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return( + &gateway.TableData{ + Columns: []gateway.Column{ + {Name: "id"}, + {Name: "eyes"}, + {Name: "mouth"}, + }, + Rows: [][]*gateway.ColumnValue{ + { + gateway.OtherColValue(1), + gateway.OtherColValue("Big"), + gateway.OtherColValue("Surprised"), + }, + { + gateway.OtherColValue(2), + gateway.OtherColValue("Medium"), + gateway.OtherColValue("Sad"), + }, + { + gateway.OtherColValue(3), + gateway.OtherColValue("Small"), + gateway.OtherColValue("Happy"), + }, + }, + }, + nil, + ) + + ctrl := NewController(r) + + router := mux.NewRouter() + router.HandleFunc("/query", ctrl.PostTableQuery) + + ctx := context.WithValue(context.Background(), middlewares.ContextIPAddress, strconv.Itoa(1)) + + // Table format + body, err := json.Marshal(struct { + Statement string + Format string + }{ + Statement: "select * from foo", + Format: "table", + }) + require.NoError(t, err) + + req, err := http.NewRequestWithContext(ctx, "POST", "/query", bytes.NewReader(body)) + require.NoError(t, err) + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + exp := `{"columns":[{"name":"id"},{"name":"eyes"},{"name":"mouth"}],"rows":[[1,"Big","Surprised"],[2,"Medium","Sad"],[3,"Small","Happy"]]}` // nolint + require.JSONEq(t, exp, rr.Body.String()) + + // Object format + body, err = json.Marshal(struct { + Statement string + Format string + }{ + Statement: "select * from foo", + Format: "objects", + }) + require.NoError(t, err) + + req, err = http.NewRequestWithContext(ctx, "POST", "/query", bytes.NewReader(body)) + require.NoError(t, err) + rr = httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + exp = `[{"eyes":"Big","id":1,"mouth":"Surprised"},{"eyes":"Medium","id":2,"mouth":"Sad"},{"eyes":"Small","id":3,"mouth":"Happy"}]` // nolint + require.JSONEq(t, exp, rr.Body.String()) + + // Unwrapped object format + body, err = json.Marshal(struct { + Statement string + Format string + Unwrap bool + }{ + Statement: "select * from foo", + Format: "objects", + Unwrap: true, + }) + require.NoError(t, err) + + req, err = http.NewRequestWithContext(ctx, "POST", "/query", bytes.NewReader(body)) + require.NoError(t, err) + rr = httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + exp = "{\"eyes\":\"Big\",\"id\":1,\"mouth\":\"Surprised\"}\n{\"eyes\":\"Medium\",\"id\":2,\"mouth\":\"Sad\"}\n{\"eyes\":\"Small\",\"id\":3,\"mouth\":\"Happy\"}\n" // nolint + wantStrings := parseJSONLString(exp) + gotStrings := parseJSONLString(rr.Body.String()) + require.Equal(t, len(wantStrings), len(gotStrings)) + for i, wantString := range wantStrings { + require.JSONEq(t, wantString, gotStrings[i]) + } +} + func TestQueryEmptyTable(t *testing.T) { r := mocks.NewGateway(t) r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return( @@ -123,11 +224,7 @@ func TestQueryEmptyTable(t *testing.T) { require.NoError(t, err) rr = httptest.NewRecorder() router.ServeHTTP(rr, req) - require.Equal(t, http.StatusOK, rr.Code) - exp = "" - wantString := parseJSONLString(exp) - gotString := parseJSONLString(rr.Body.String()) - require.Equal(t, wantString, gotString) + require.Equal(t, http.StatusNotFound, rr.Code) } func TestQueryExtracted(t *testing.T) { @@ -177,6 +274,73 @@ func TestQueryExtracted(t *testing.T) { } } +func TestPostQueryExtracted(t *testing.T) { + r := mocks.NewGateway(t) + r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return( + &gateway.TableData{ + Columns: []gateway.Column{{Name: "name"}}, + Rows: [][]*gateway.ColumnValue{ + {gateway.OtherColValue("bob")}, + {gateway.OtherColValue("jane")}, + {gateway.OtherColValue("alex")}, + }, + }, + nil, + ) + + ctrl := NewController(r) + + router := mux.NewRouter() + router.HandleFunc("/query", ctrl.PostTableQuery) + + // Extracted object format + body, err := json.Marshal(struct { + Statement string + Format string + Extract bool + }{ + Statement: "select * from foo", + Format: "objects", + Extract: true, + }) + require.NoError(t, err) + + req, err := http.NewRequestWithContext(context.Background(), "POST", "/query", bytes.NewReader(body)) + require.NoError(t, err) + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + exp := `["bob","jane","alex"]` + require.JSONEq(t, exp, rr.Body.String()) + + // Extracted unwrapped object format + body, err = json.Marshal(struct { + Statement string + Format string + Extract bool + Unwrap bool + }{ + Statement: "select * from foo", + Format: "objects", + Extract: true, + Unwrap: true, + }) + require.NoError(t, err) + + req, err = http.NewRequestWithContext(context.Background(), "POST", "/query", bytes.NewReader(body)) + require.NoError(t, err) + rr = httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + exp = "\"bob\"\n\"jane\"\n\"alex\"\n" + wantStrings := parseJSONLString(exp) + gotStrings := parseJSONLString(rr.Body.String()) + require.Equal(t, len(wantStrings), len(gotStrings)) + for i, wantString := range wantStrings { + require.JSONEq(t, wantString, gotStrings[i]) + } +} + func TestGetTablesByMocked(t *testing.T) { t.Parallel() diff --git a/internal/router/router.go b/internal/router/router.go index 17546c21..13cd109b 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -61,6 +61,10 @@ func configureAPIV1Routes( userCtrl.GetTableQuery, []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, }, + "QueryByStatementPost": { + userCtrl.PostTableQuery, + []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, + }, "ReceiptByTransactionHash": { userCtrl.GetReceiptByTransactionHash, []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim}, @@ -97,11 +101,30 @@ func configureAPIV1Routes( return fmt.Errorf("get path template: %s", err) } - router.get( - pathTemplate, - endpoint.handler, - append([]mux.MiddlewareFunc{middlewares.OtelHTTP(routeName)}, endpoint.middlewares...)..., - ) + methods, err := route.GetMethods() + if err != nil { + return fmt.Errorf("get method: %s", err) + } + + for _, method := range methods { + switch method { + case "GET": + router.get( + pathTemplate, + endpoint.handler, + append([]mux.MiddlewareFunc{middlewares.OtelHTTP(routeName)}, endpoint.middlewares...)..., + ) + case "POST": + router.post( + pathTemplate, + endpoint.handler, + append([]mux.MiddlewareFunc{middlewares.OtelHTTP(routeName)}, endpoint.middlewares...)..., + ) + default: + return fmt.Errorf("unknown method") + } + } + return nil }); err != nil { return fmt.Errorf("configuring api v1 router: %s", err) @@ -132,6 +155,13 @@ func (r *Router) get(uri string, f http.HandlerFunc, mid ...mux.MiddlewareFunc) sub.Use(mid...) } +// post creates a subroute on the specified URI that only accepts POST. You can provide specific middlewares. +func (r *Router) post(uri string, f http.HandlerFunc, mid ...mux.MiddlewareFunc) { + sub := r.r.Path(uri).Subrouter() + sub.HandleFunc("", f).Methods(http.MethodPost) + sub.Use(mid...) +} + // use adds middlewares to all routes. Should be used when a middleware should be execute all all routes (e.g. CORS). func (r *Router) use(mid ...mux.MiddlewareFunc) { r.r.Use(mid...) diff --git a/pkg/client/chains.go b/pkg/client/chains.go index aebbfb33..4cf0abd7 100644 --- a/pkg/client/chains.go +++ b/pkg/client/chains.go @@ -21,12 +21,11 @@ var ChainIDs = struct { Arbitrum ChainID ArbitrumNova ChainID Filecoin ChainID - EthereumGoerli ChainID EthereumSepolia ChainID - OptimismGoerli ChainID - ArbitrumGoerli ChainID + OptimismSepolia ChainID + ArbitrumSepolia ChainID FilecoinCalibration ChainID - PolygonMumbai ChainID + PolygonAmoy ChainID Local ChainID }{ Ethereum: 1, @@ -35,12 +34,11 @@ var ChainIDs = struct { Arbitrum: 42161, ArbitrumNova: 42170, Filecoin: 314, - EthereumGoerli: 5, EthereumSepolia: 11155111, - OptimismGoerli: 420, - ArbitrumGoerli: 421613, + OptimismSepolia: 11155420, + ArbitrumSepolia: 421614, FilecoinCalibration: 314159, - PolygonMumbai: 80001, + PolygonAmoy: 80002, Local: 31337, } @@ -90,29 +88,23 @@ var Chains = map[ChainID]Chain{ Name: "Filecoin", ContractAddr: common.HexToAddress("0x59EF8Bf2d6c102B4c42AEf9189e1a9F0ABfD652d"), }, - ChainIDs.EthereumGoerli: { - Endpoint: testnetURL, - ID: ChainIDs.EthereumGoerli, - Name: "Ethereum Goerli", - ContractAddr: common.HexToAddress("0xDA8EA22d092307874f30A1F277D1388dca0BA97a"), - }, ChainIDs.EthereumSepolia: { Endpoint: testnetURL, ID: ChainIDs.EthereumSepolia, Name: "Ethereum Sepolia", ContractAddr: common.HexToAddress("0xc50C62498448ACc8dBdE43DA77f8D5D2E2c7597D"), }, - ChainIDs.OptimismGoerli: { + ChainIDs.OptimismSepolia: { Endpoint: testnetURL, - ID: ChainIDs.OptimismGoerli, - Name: "Optimism Goerli", - ContractAddr: common.HexToAddress("0xC72E8a7Be04f2469f8C2dB3F1BdF69A7D516aBbA"), + ID: ChainIDs.OptimismSepolia, + Name: "Optimism Sepolia", + ContractAddr: common.HexToAddress("0x68A2f4423ad3bf5139Db563CF3bC80aA09ed7079"), }, - ChainIDs.ArbitrumGoerli: { + ChainIDs.ArbitrumSepolia: { Endpoint: testnetURL, - ID: ChainIDs.ArbitrumGoerli, - Name: "Arbitrum Goerli", - ContractAddr: common.HexToAddress("0x033f69e8d119205089Ab15D340F5b797732f646b"), + ID: ChainIDs.ArbitrumSepolia, + Name: "Arbitrum Sepolia", + ContractAddr: common.HexToAddress("0x223A74B8323914afDC3ff1e5005564dC17231d6e"), }, ChainIDs.FilecoinCalibration: { Endpoint: testnetURL, @@ -120,11 +112,11 @@ var Chains = map[ChainID]Chain{ Name: "Filecoin Calibration", ContractAddr: common.HexToAddress("0x030BCf3D50cad04c2e57391B12740982A9308621"), }, - ChainIDs.PolygonMumbai: { + ChainIDs.PolygonAmoy: { Endpoint: testnetURL, - ID: ChainIDs.PolygonMumbai, - Name: "Polygon Mumbai", - ContractAddr: common.HexToAddress("0x4b48841d4b32C4650E4ABc117A03FE8B51f38F68"), + ID: ChainIDs.PolygonAmoy, + Name: "Polygon Amoy", + ContractAddr: common.HexToAddress("0x170fb206132b693e38adFc8727dCfa303546Cec1"), }, ChainIDs.Local: { Endpoint: localURL, @@ -136,26 +128,21 @@ var Chains = map[ChainID]Chain{ // InfuraURLs contains the URLs for supported chains for Infura. var InfuraURLs = map[ChainID]string{ - ChainIDs.EthereumGoerli: "https://goerli.infura.io/v3/%s", - ChainIDs.Ethereum: "https://mainnet.infura.io/v3/%s", - ChainIDs.OptimismGoerli: "https://optimism-goerli.infura.io/v3/%s", - ChainIDs.Optimism: "https://optimism-mainnet.infura.io/v3/%s", - ChainIDs.ArbitrumGoerli: "https://arbitrum-goerli.infura.io/v3/%s", - ChainIDs.Arbitrum: "https://arbitrum-mainnet.infura.io/v3/%s", - ChainIDs.PolygonMumbai: "https://polygon-mumbai.infura.io/v3/%s", - ChainIDs.Polygon: "https://polygon-mainnet.infura.io/v3/%s", + ChainIDs.Ethereum: "https://mainnet.infura.io/v3/%s", + ChainIDs.Optimism: "https://optimism-mainnet.infura.io/v3/%s", + ChainIDs.Arbitrum: "https://arbitrum-mainnet.infura.io/v3/%s", + ChainIDs.Polygon: "https://polygon-mainnet.infura.io/v3/%s", } // AlchemyURLs contains the URLs for supported chains for Alchemy. var AlchemyURLs = map[ChainID]string{ - ChainIDs.EthereumGoerli: "https://eth-goerli.g.alchemy.com/v2/%s", ChainIDs.EthereumSepolia: "https://eth-sepolia.g.alchemy.com/v2/%s", ChainIDs.Ethereum: "https://eth-mainnet.g.alchemy.com/v2/%s", - ChainIDs.OptimismGoerli: "https://opt-goerli.g.alchemy.com/v2/%s", + ChainIDs.OptimismSepolia: "https://opt-sepolia.g.alchemy.com/v2/%s", ChainIDs.Optimism: "https://opt-mainnet.g.alchemy.com/v2/%s", - ChainIDs.ArbitrumGoerli: "https://arb-goerli.g.alchemy.com/v2/%s", + ChainIDs.ArbitrumSepolia: "https://arb-sepolia.g.alchemy.com/v2/%s", ChainIDs.Arbitrum: "https://arb-mainnet.g.alchemy.com/v2/%s", - ChainIDs.PolygonMumbai: "https://polygon-mumbai.g.alchemy.com/v2/%s", + ChainIDs.PolygonAmoy: "https://polygon-amoy.g.alchemy.com/v2/%s", ChainIDs.Polygon: "https://polygon-mainnet.g.alchemy.com/v2/%s", } diff --git a/pkg/client/v1/client.go b/pkg/client/v1/client.go index 72be9293..a63db319 100644 --- a/pkg/client/v1/client.go +++ b/pkg/client/v1/client.go @@ -20,7 +20,7 @@ import ( "github.com/textileio/go-tableland/pkg/wallet" ) -var defaultChain = client.Chains[client.ChainIDs.PolygonMumbai] +var defaultChain = client.Chains[client.ChainIDs.PolygonAmoy] // Client is the Tableland client. type Client struct { diff --git a/pkg/eventprocessor/eventfeed/impl/eventfeed.go b/pkg/eventprocessor/eventfeed/impl/eventfeed.go index bf47d0c1..bd2694a1 100644 --- a/pkg/eventprocessor/eventfeed/impl/eventfeed.go +++ b/pkg/eventprocessor/eventfeed/impl/eventfeed.go @@ -177,7 +177,11 @@ func (ef *EventFeed) Start( strings.Contains(err.Error(), "Log response size exceeded") || strings.Contains(err.Error(), "is greater than the limit") || strings.Contains(err.Error(), "eth_getLogs and eth_newFilter are limited to a 10,000 blocks range") || + strings.Contains(err.Error(), "eth_getLogs and eth_newFilter are limited to a 10000 blocks range") || strings.Contains(err.Error(), "range between to and from blocks is too large") || + strings.Contains(err.Error(), "getMultipleAccounts, eth_getLogs, and eth_newFilter are limited to a 5 range") || + strings.Contains(err.Error(), "eth_getLogs is limited to a 5 range") || + strings.Contains(err.Error(), "eth_getLogs is limited to a 10,000 range") || strings.Contains(err.Error(), "block range is too wide") { ef.maxBlocksFetchSize = ef.maxBlocksFetchSize * 80 / 100 } else {