From b6ad98ce13cb7f02535cc9e73f00047ca86f5430 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 9 Nov 2022 16:55:49 -0300 Subject: [PATCH 001/101] docker/mainnet: boostrap folder and add api assets Signed-off-by: Ignacio Hagopian --- .../mainnet/api/.env_validator.example | 9 + docker/deployed/mainnet/api/config.json | 166 ++++++++++++++++++ docker/deployed/testnet/api/config.json | 114 +----------- 3 files changed, 176 insertions(+), 113 deletions(-) create mode 100644 docker/deployed/mainnet/api/.env_validator.example create mode 100644 docker/deployed/mainnet/api/config.json diff --git a/docker/deployed/mainnet/api/.env_validator.example b/docker/deployed/mainnet/api/.env_validator.example new file mode 100644 index 00000000..ce107540 --- /dev/null +++ b/docker/deployed/mainnet/api/.env_validator.example @@ -0,0 +1,9 @@ +VALIDATOR_ALCHEMY_ARBITRUM_MAINNET_API_KEY= +VALIDATOR_ARBITRUM_MAINNET_SIGNER_PRIVATE_KEY= +VALIDATOR_ALCHEMY_ETHEREUM_MAINNET_API_KEY= +VALIDATOR_ETHEREUM_MAINNET_SIGNER_PRIVATE_KEY= +VALIDATOR_ALCHEMY_POLYGON_MAINNET_API_KEY= +VALIDATOR_POLYGON_MAINNET_SIGNER_PRIVATE_KEY= +VALIDATOR_ALCHEMY_OPTIMISM_MAINNET_API_KEY= +VALIDATOR_OPTIMISM_MAINNET_SIGNER_PRIVATE_KEY= +METRICS_HUB_API_KEY= diff --git a/docker/deployed/mainnet/api/config.json b/docker/deployed/mainnet/api/config.json new file mode 100644 index 00000000..a0bda6de --- /dev/null +++ b/docker/deployed/mainnet/api/config.json @@ -0,0 +1,166 @@ +{ + "Impl": "mesa", + "HTTP": { + "Port": "8080", + "RateLimInterval": "1s", + "MaxRequestPerInterval": 10, + "TLSCert": "${VALIDATOR_TLS_CERT}", + "TLSKey": "${VALIDATOR_TLS_KEY}" + }, + "Gateway": { + "ExternalURIPrefix": "https://tableland.network", + "MetadataRendererURI": "https://.tableland.xyz" + }, + "DB": { + "Port": "5432" + }, + "TableConstraints": { + "MaxRowCount": 500000 + }, + "QueryConstraints": { + "MaxWriteQuerySize": 35000, + "MaxReadQuerySize": 35000 + }, + "Metrics": { + "Port": "9090" + }, + "Log": { + "Human": false, + "Debug": true + }, + "Analytics": { + "FetchExtraBlockInfo": true + }, + "Backup": { + "Enabled": true, + "Dir": "backups", + "Frequency": 240, + "EnableVacuum": true, + "EnableCompression": true, + "Pruning": { + "Enabled": true, + "KeepFiles": 5 + } + }, + "TelemetryPublisher": { + "Enabled": true, + "MetricsHubURL": "https://metricshub--mrgr43cf5q-uw.a.run.app", + "MetricsHubApiKey": "${METRICS_HUB_API_KEY}", + "PublishingInterval": "10s", + "ChainStackCollectFrequency": "15m" + }, + "Chains": [ + { + "Name": "Ethereum Mainnet", + "ChainID": 1, + "AllowTransactionRelay": false, + "Registry": { + "EthEndpoint": "wss://eth-mainnet.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_ETHEREUM_MAINNET_API_KEY}", + "ContractAddress": "0x012969f7e3439a9B04025b5a049EB9BAD82A8C12" + }, + "Signer": { + "PrivateKey": "${VALIDATOR_ETHEREUM_MAINNET_SIGNER_PRIVATE_KEY}" + }, + "EventFeed": { + "ChainAPIBackoff": "15s", + "NewBlockPollFreq": "10s", + "MinBlockDepth": 1, + "PersistEvents": true + }, + "EventProcessor": { + "BlockFailedExecutionBackoff": "10s", + "DedupExecutedTxns": true + }, + "NonceTracker": { + "CheckInterval": "20s", + "StuckInterval": "10m", + "MinBlockDepth": 4 + }, + "HashCalculationStep": 150 + }, + { + "Name": "Arbitrum Mainnet", + "ChainID": 42161, + "AllowTransactionRelay": false, + "Registry": { + "EthEndpoint": "https://arb-mainnet.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_ARBITRUM_MAINNET_API_KEY}", + "ContractAddress": "0x9aBd75E8640871A5a20d3B4eE6330a04c962aFfd" + }, + "Signer": { + "PrivateKey": "${VALIDATOR_ARBITRUM_MAINNET_SIGNER_PRIVATE_KEY}" + }, + "EventFeed": { + "ChainAPIBackoff": "15s", + "NewBlockPollFreq": "5s", + "MinBlockDepth": 0, + "PersistEvents": true + }, + "EventProcessor": { + "BlockFailedExecutionBackoff": "10s", + "DedupExecutedTxns": true + }, + "NonceTracker": { + "CheckInterval": "20s", + "StuckInterval": "10m", + "MinBlockDepth": 0 + }, + "HashCalculationStep": 450 + }, + { + "Name": "Polygon Mainnet", + "ChainID": 137, + "AllowTransactionRelay": false, + "Registry": { + "EthEndpoint": "wss://polygon-mainnet.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_POLYGON_MAINNET_API_KEY}", + "ContractAddress": "0x5c4e6A9e5C1e1BF445A062006faF19EA6c49aFeA" + }, + "Signer": { + "PrivateKey": "${VALIDATOR_POLYGON_MAINNET_SIGNER_PRIVATE_KEY}" + }, + "EventFeed": { + "ChainAPIBackoff": "15s", + "NewBlockPollFreq": "5s", + "MinBlockDepth": 1, + "PersistEvents": true + }, + "EventProcessor": { + "BlockFailedExecutionBackoff": "10s", + "DedupExecutedTxns": true + }, + "NonceTracker": { + "CheckInterval": "15s", + "StuckInterval": "10m", + "MinBlockDepth": 1 + }, + "HashCalculationStep": 360 + }, + { + "Name": "Optimism Mainnet", + "ChainID": 10, + "AllowTransactionRelay": false, + "Registry": { + "EthEndpoint": "wss://opt-mainnet.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_OPTIMISM_MAINNET_API_KEY}", + "ContractAddress": "0xfad44BF5B843dE943a09D4f3E84949A11d3aa3e6" + }, + "Signer": { + "PrivateKey": "${VALIDATOR_OPTIMISM_MAINNET_SIGNER_PRIVATE_KEY}" + }, + "EventFeed": { + "ChainAPIBackoff": "15s", + "NewBlockPollFreq": "5s", + "MinBlockDepth": 0, + "PersistEvents": true + }, + "EventProcessor": { + "BlockFailedExecutionBackoff": "10s", + "DedupExecutedTxns": true + }, + "NonceTracker": { + "CheckInterval": "15s", + "StuckInterval": "10m", + "MinBlockDepth": 0 + }, + "HashCalculationStep": 1800 + } + ] +} \ No newline at end of file diff --git a/docker/deployed/testnet/api/config.json b/docker/deployed/testnet/api/config.json index 5b99ef2d..0b539f34 100644 --- a/docker/deployed/testnet/api/config.json +++ b/docker/deployed/testnet/api/config.json @@ -8,7 +8,7 @@ "TLSKey": "${VALIDATOR_TLS_KEY}" }, "Gateway": { - "ExternalURIPrefix": "https://testnet.tableland.network", + "ExternalURIPrefix": "https://testnets.tableland.network", "MetadataRendererURI": "https://render.tableland.xyz", "AnimationRendererURI": "https://render.tableland.xyz/anim" }, @@ -107,118 +107,6 @@ }, "HashCalculationStep": 360 }, - { - "Name": "Ethereum Mainnet", - "ChainID": 1, - "AllowTransactionRelay": false, - "Registry": { - "EthEndpoint": "wss://eth-mainnet.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_ETHEREUM_MAINNET_API_KEY}", - "ContractAddress": "0x012969f7e3439a9B04025b5a049EB9BAD82A8C12" - }, - "Signer": { - "PrivateKey": "${VALIDATOR_ETHEREUM_MAINNET_SIGNER_PRIVATE_KEY}" - }, - "EventFeed": { - "ChainAPIBackoff": "15s", - "NewBlockPollFreq": "10s", - "MinBlockDepth": 1, - "PersistEvents": true - }, - "EventProcessor": { - "BlockFailedExecutionBackoff": "10s", - "DedupExecutedTxns": true - }, - "NonceTracker": { - "CheckInterval": "20s", - "StuckInterval": "10m", - "MinBlockDepth": 1 - }, - "HashCalculationStep": 150 - }, - { - "Name": "Arbitrum Mainnet", - "ChainID": 42161, - "AllowTransactionRelay": false, - "Registry": { - "EthEndpoint": "https://arb-mainnet.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_ARBITRUM_MAINNET_API_KEY}", - "ContractAddress": "0x9aBd75E8640871A5a20d3B4eE6330a04c962aFfd" - }, - "Signer": { - "PrivateKey": "${VALIDATOR_ARBITRUM_MAINNET_SIGNER_PRIVATE_KEY}" - }, - "EventFeed": { - "ChainAPIBackoff": "15s", - "NewBlockPollFreq": "5s", - "MinBlockDepth": 0, - "PersistEvents": true - }, - "EventProcessor": { - "BlockFailedExecutionBackoff": "10s", - "DedupExecutedTxns": true - }, - "NonceTracker": { - "CheckInterval": "20s", - "StuckInterval": "10m", - "MinBlockDepth": 0 - }, - "HashCalculationStep": 450 - }, - { - "Name": "Polygon Mainnet", - "ChainID": 137, - "AllowTransactionRelay": false, - "Registry": { - "EthEndpoint": "wss://polygon-mainnet.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_POLYGON_MAINNET_API_KEY}", - "ContractAddress": "0x5c4e6A9e5C1e1BF445A062006faF19EA6c49aFeA" - }, - "Signer": { - "PrivateKey": "${VALIDATOR_POLYGON_MAINNET_SIGNER_PRIVATE_KEY}" - }, - "EventFeed": { - "ChainAPIBackoff": "15s", - "NewBlockPollFreq": "5s", - "MinBlockDepth": 1, - "PersistEvents": true - }, - "EventProcessor": { - "BlockFailedExecutionBackoff": "10s", - "DedupExecutedTxns": true - }, - "NonceTracker": { - "CheckInterval": "15s", - "StuckInterval": "10m", - "MinBlockDepth": 1 - }, - "HashCalculationStep": 360 - }, - { - "Name": "Optimism Mainnet", - "ChainID": 10, - "AllowTransactionRelay": false, - "Registry": { - "EthEndpoint": "wss://opt-mainnet.g.alchemy.com/v2/${VALIDATOR_ALCHEMY_OPTIMISM_MAINNET_API_KEY}", - "ContractAddress": "0xfad44BF5B843dE943a09D4f3E84949A11d3aa3e6" - }, - "Signer": { - "PrivateKey": "${VALIDATOR_OPTIMISM_MAINNET_SIGNER_PRIVATE_KEY}" - }, - "EventFeed": { - "ChainAPIBackoff": "15s", - "NewBlockPollFreq": "5s", - "MinBlockDepth": 0, - "PersistEvents": true - }, - "EventProcessor": { - "BlockFailedExecutionBackoff": "10s", - "DedupExecutedTxns": true - }, - "NonceTracker": { - "CheckInterval": "15s", - "StuckInterval": "10m", - "MinBlockDepth": 0 - }, - "HashCalculationStep": 1800 - }, { "Name": "Arbitrum Goerli", "ChainID": 421613, From e66182057c7dcf75c667386f5abb1cad2ca694ef Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 9 Nov 2022 17:03:43 -0300 Subject: [PATCH 002/101] docker: add mainnet to Makefile Signed-off-by: Ignacio Hagopian --- docker/Makefile | 18 +++++++++++++++++- docker/deployed/mainnet/healthbot/config.json | 11 +++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 docker/deployed/mainnet/healthbot/config.json diff --git a/docker/Makefile b/docker/Makefile index 8ea088c4..71a8b0b2 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -46,4 +46,20 @@ testnet-down: USER=$(shell id -u) \ ENVIRONMENT=deployed/testnet \ docker compose -f docker-compose.yml -f deployed/docker-compose.observability.yml $(HEALTHBOT_OVERRIDE) down -.PHONY: testnet-down \ No newline at end of file +.PHONY: testnet-down + +mainnet-up: + PLATFORM=$(shell uname -m) \ + USER=$(shell id -u) \ + ENVIRONMENT=deployed/mainnet \ + COMPOSE_DOCKER_CLI_BUILD=1 \ + BOOTSTRAP_BACKUP_URL=${BOOTSTRAP_BACKUP_URL} \ + docker compose -f docker-compose.yml -f deployed/docker-compose.observability.yml $(HEALTHBOT_OVERRIDE) up --build --remove-orphans --detach +.PHONY: mainnet-up + +mainnet-down: + PLATFORM=$(shell uname -m) \ + USER=$(shell id -u) \ + ENVIRONMENT=deployed/mainnet \ + docker compose -f docker-compose.yml -f deployed/docker-compose.observability.yml $(HEALTHBOT_OVERRIDE) down +.PHONY: mainnet-down \ No newline at end of file diff --git a/docker/deployed/mainnet/healthbot/config.json b/docker/deployed/mainnet/healthbot/config.json new file mode 100644 index 00000000..42c30fc2 --- /dev/null +++ b/docker/deployed/mainnet/healthbot/config.json @@ -0,0 +1,11 @@ +{ + "Metrics": { + "Port": "9090" + }, + "Log": { + "Human": false, + "Debug": true + }, + "Target": "https://tableland.network/rpc", + "Chains": [] +} \ No newline at end of file From ae4fd9fec8cb15493ff98534edc7392992fbbe66 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 10 Nov 2022 09:44:17 -0300 Subject: [PATCH 003/101] cd: include logic for mainnet deployment Signed-off-by: Ignacio Hagopian --- .github/workflows/deploy.yml | 62 +++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 27194652..d647d431 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,7 +14,7 @@ on: jobs: deploy: - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[stagingdeploy]') || contains(github.event.head_commit.message, '[testnetdeploy]') + if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[stagingdeploy]') || contains(github.event.head_commit.message, '[testnetdeploy]') || contains(github.event.head_commit.message, '[mainnetdeploy]') name: Deploy runs-on: ubuntu-latest steps: @@ -25,14 +25,6 @@ jobs: shell: bash id: prep run: | - if [[ ${{ github.ref }} == refs/heads/main ]] || [[ "${{github.event.head_commit.message}}" == *"[testnetdeploy]"* ]]; then - echo "::set-output name=deployment::testnet" - echo "::set-output name=vm_host::${{ secrets.TESTNET_VM_HOST }}" - else - echo "::set-output name=deployment::staging" - echo "::set-output name=vm_host::${{ secrets.STAGING_VM_HOST }}" - fi - # This is the official way to setup secret values that are multi-line, such as an SSH private key. echo 'vm_ssh_key<> $GITHUB_ENV echo "${{ secrets.VM_SSH_KEY }}" >> $GITHUB_ENV @@ -40,10 +32,34 @@ jobs: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" - - name: Connect via SSH, update the repo and run + - if: contains(github.event.head_commit.message, '[stagingdeploy]') + name: Deploy staging + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.STAGING_VM_HOST }} + username: validator + key: ${{ env.vm_ssh_key }} + port: 22 + script_stop: true + command_timeout: 30m + script: | + cd go-tableland + git fetch && git checkout -f ${{ github.sha }} + cd docker + + HEALTHBOT_ENABLED=true make staging-up + + # Wait to start and double-check we're running the expected version. + # This helps having a green check in the GH Action be high-signal that everything is fine. + sleep 5; + for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done + echo "All healthy!" + + - if: github.ref == 'refs/heads/main'|| contains(github.event.head_commit.message, '[testnetdeploy]' + name: Deploy testnet uses: appleboy/ssh-action@master with: - host: ${{ steps.prep.outputs.vm_host }} + host: ${{ secrets.TESTNET_VM_HOST }} username: validator key: ${{ env.vm_ssh_key }} port: 22 @@ -54,7 +70,7 @@ jobs: git fetch && git checkout -f ${{ github.sha }} cd docker - HEALTHBOT_ENABLED=true make ${{ steps.prep.outputs.deployment }}-up + HEALTHBOT_ENABLED=true make testnet-up # Wait to start and double-check we're running the expected version. # This helps having a green check in the GH Action be high-signal that everything is fine. @@ -62,3 +78,25 @@ jobs: for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" + - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[mainnetdeploy]') + name: Deploy testnet + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.MAINNET_VM_HOST }} + username: validator + key: ${{ env.vm_ssh_key }} + port: 22 + script_stop: true + command_timeout: 30m + script: | + cd go-tableland + git fetch && git checkout -f ${{ github.sha }} + cd docker + + make mainnet-up + + # Wait to start and double-check we're running the expected version. + # This helps having a green check in the GH Action be high-signal that everything is fine. + sleep 5; + for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done + echo "All healthy!" From 0bcdba8b5a22119f07b1b5446350fd88904ca46a Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 11 Nov 2022 14:57:57 -0300 Subject: [PATCH 004/101] docker/mainnet: extra files Signed-off-by: Ignacio Hagopian --- docker/deployed/mainnet/grafana/.env_grafana.example | 2 ++ docker/deployed/mainnet/grafana/data/.gitkeep | 0 2 files changed, 2 insertions(+) create mode 100644 docker/deployed/mainnet/grafana/.env_grafana.example create mode 100644 docker/deployed/mainnet/grafana/data/.gitkeep diff --git a/docker/deployed/mainnet/grafana/.env_grafana.example b/docker/deployed/mainnet/grafana/.env_grafana.example new file mode 100644 index 00000000..206c792a --- /dev/null +++ b/docker/deployed/mainnet/grafana/.env_grafana.example @@ -0,0 +1,2 @@ +GF_SECURITY_ADMIN_USER= +GF_SECURITY_ADMIN_PASSWORD= \ No newline at end of file diff --git a/docker/deployed/mainnet/grafana/data/.gitkeep b/docker/deployed/mainnet/grafana/data/.gitkeep new file mode 100644 index 00000000..e69de29b From 13b4d31273ea4066ca29af623bbed433ffb9c8b3 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 11 Nov 2022 17:40:47 -0300 Subject: [PATCH 005/101] ghactions: fix Signed-off-by: Ignacio Hagopian --- .github/workflows/deploy.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d647d431..42a73889 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -32,7 +32,7 @@ jobs: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" - - if: contains(github.event.head_commit.message, '[stagingdeploy]') + - if: contains(github.event.head_commit.message, '[stagingdeploy]') name: Deploy staging uses: appleboy/ssh-action@master with: @@ -46,7 +46,7 @@ jobs: cd go-tableland git fetch && git checkout -f ${{ github.sha }} cd docker - + HEALTHBOT_ENABLED=true make staging-up # Wait to start and double-check we're running the expected version. @@ -55,7 +55,7 @@ jobs: for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" - - if: github.ref == 'refs/heads/main'|| contains(github.event.head_commit.message, '[testnetdeploy]' + - if: github.ref == 'refs/heads/main'|| contains(github.event.head_commit.message, '[testnetdeploy]') name: Deploy testnet uses: appleboy/ssh-action@master with: @@ -69,7 +69,7 @@ jobs: cd go-tableland git fetch && git checkout -f ${{ github.sha }} cd docker - + HEALTHBOT_ENABLED=true make testnet-up # Wait to start and double-check we're running the expected version. @@ -78,7 +78,7 @@ jobs: for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" - - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[mainnetdeploy]') + - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[mainnetdeploy]') name: Deploy testnet uses: appleboy/ssh-action@master with: @@ -92,7 +92,7 @@ jobs: cd go-tableland git fetch && git checkout -f ${{ github.sha }} cd docker - + make mainnet-up # Wait to start and double-check we're running the expected version. From e63b0f771c32d55505bd98980394913c5a13e2a6 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 14 Nov 2022 17:05:24 -0300 Subject: [PATCH 006/101] docker/mainnet: update metrics hub URL Signed-off-by: Ignacio Hagopian --- docker/deployed/mainnet/api/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/deployed/mainnet/api/config.json b/docker/deployed/mainnet/api/config.json index a0bda6de..b84595fe 100644 --- a/docker/deployed/mainnet/api/config.json +++ b/docker/deployed/mainnet/api/config.json @@ -44,7 +44,7 @@ }, "TelemetryPublisher": { "Enabled": true, - "MetricsHubURL": "https://metricshub--mrgr43cf5q-uw.a.run.app", + "MetricsHubURL": "https://metricshub-mainnet-mrgr43cf5q-uw.a.run.app", "MetricsHubApiKey": "${METRICS_HUB_API_KEY}", "PublishingInterval": "10s", "ChainStackCollectFrequency": "15m" From 962d957bdc5796623c5e3a41e9f1d6ebe18f3cb9 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 15 Nov 2022 09:56:35 -0300 Subject: [PATCH 007/101] gh/deploy: use safer secret for testnet [mainnetdeploy] Signed-off-by: Ignacio Hagopian --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 42a73889..593fb700 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -59,7 +59,7 @@ jobs: name: Deploy testnet uses: appleboy/ssh-action@master with: - host: ${{ secrets.TESTNET_VM_HOST }} + host: ${{ secrets.TESTNET_V2_VM_HOST }} username: validator key: ${{ env.vm_ssh_key }} port: 22 From bc8b0150b710c96f9f1311ef11351b741d4620e6 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 15 Nov 2022 11:29:21 -0300 Subject: [PATCH 008/101] gh/deploy: temp disable healthbot in new testnet Signed-off-by: Ignacio Hagopian --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 593fb700..7c90f631 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -70,7 +70,7 @@ jobs: git fetch && git checkout -f ${{ github.sha }} cd docker - HEALTHBOT_ENABLED=true make testnet-up + make testnet-up # Wait to start and double-check we're running the expected version. # This helps having a green check in the GH Action be high-signal that everything is fine. From d02d63fbe49edc3e42cfbfb5e125f3db01120612 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 16 Nov 2022 12:11:08 -0300 Subject: [PATCH 009/101] docker/testnet: update metrics hub url [testnetdeploy] Signed-off-by: Ignacio Hagopian --- docker/deployed/testnet/api/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/deployed/testnet/api/config.json b/docker/deployed/testnet/api/config.json index 0b539f34..18c59693 100644 --- a/docker/deployed/testnet/api/config.json +++ b/docker/deployed/testnet/api/config.json @@ -45,7 +45,7 @@ }, "TelemetryPublisher": { "Enabled": true, - "MetricsHubURL": "https://metricshub-testnet-mrgr43cf5q-uw.a.run.app", + "MetricsHubURL": "https://metricshub-testnet-v2-mrgr43cf5q-uw.a.run.app", "MetricsHubApiKey": "${METRICS_HUB_API_KEY}", "PublishingInterval": "10s", "ChainStackCollectFrequency": "15m" From dab9a28fc9133dbed8247afd912c66cb4e6fa4f2 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 17 Nov 2022 09:30:10 -0300 Subject: [PATCH 010/101] infra: add GF_SERVER_ROOT_URL env Signed-off-by: Ignacio Hagopian --- docker/deployed/mainnet/grafana/.env_grafana.example | 3 ++- docker/deployed/staging/grafana/.env_grafana.example | 3 ++- docker/deployed/testnet/grafana/.env_grafana.example | 3 +++ infra/.env_grafana.example | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 docker/deployed/testnet/grafana/.env_grafana.example diff --git a/docker/deployed/mainnet/grafana/.env_grafana.example b/docker/deployed/mainnet/grafana/.env_grafana.example index 206c792a..0b6e7eb0 100644 --- a/docker/deployed/mainnet/grafana/.env_grafana.example +++ b/docker/deployed/mainnet/grafana/.env_grafana.example @@ -1,2 +1,3 @@ GF_SECURITY_ADMIN_USER= -GF_SECURITY_ADMIN_PASSWORD= \ No newline at end of file +GF_SECURITY_ADMIN_PASSWORD= +GF_SERVER_ROOT_URL= \ No newline at end of file diff --git a/docker/deployed/staging/grafana/.env_grafana.example b/docker/deployed/staging/grafana/.env_grafana.example index 206c792a..e1ff2119 100644 --- a/docker/deployed/staging/grafana/.env_grafana.example +++ b/docker/deployed/staging/grafana/.env_grafana.example @@ -1,2 +1,3 @@ GF_SECURITY_ADMIN_USER= -GF_SECURITY_ADMIN_PASSWORD= \ No newline at end of file +GF_SECURITY_ADMIN_PASSWORD= +GF_SERVER_ROOT_URL= diff --git a/docker/deployed/testnet/grafana/.env_grafana.example b/docker/deployed/testnet/grafana/.env_grafana.example new file mode 100644 index 00000000..0b6e7eb0 --- /dev/null +++ b/docker/deployed/testnet/grafana/.env_grafana.example @@ -0,0 +1,3 @@ +GF_SECURITY_ADMIN_USER= +GF_SECURITY_ADMIN_PASSWORD= +GF_SERVER_ROOT_URL= \ No newline at end of file diff --git a/infra/.env_grafana.example b/infra/.env_grafana.example index 206c792a..0b6e7eb0 100644 --- a/infra/.env_grafana.example +++ b/infra/.env_grafana.example @@ -1,2 +1,3 @@ GF_SECURITY_ADMIN_USER= -GF_SECURITY_ADMIN_PASSWORD= \ No newline at end of file +GF_SECURITY_ADMIN_PASSWORD= +GF_SERVER_ROOT_URL= \ No newline at end of file From 127c9e7f94357ada6952b05a54ea278a652cd735 Mon Sep 17 00:00:00 2001 From: Aaron Sutula Date: Fri, 18 Nov 2022 12:02:21 -0600 Subject: [PATCH 011/101] use mainnet url Signed-off-by: Aaron Sutula --- pkg/client/chains.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pkg/client/chains.go b/pkg/client/chains.go index e21dc13d..feaf3428 100644 --- a/pkg/client/chains.go +++ b/pkg/client/chains.go @@ -5,6 +5,7 @@ import ( ) const ( + mainnetURL = "https://tableland.network" testnetURL = "https://testnet.tableland.network" localURL = "http://localhost:8080" ) @@ -17,20 +18,20 @@ var ChainIDs = struct { Ethereum ChainID Optimism ChainID Polygon ChainID + Arbitrum ChainID EthereumGoerli ChainID OptimismGoerli ChainID ArbitrumGoerli ChainID - Arbitrum ChainID PolygonMumbai ChainID Local ChainID }{ Ethereum: 1, Optimism: 10, Polygon: 137, + Arbitrum: 42161, EthereumGoerli: 5, OptimismGoerli: 420, ArbitrumGoerli: 421613, - Arbitrum: 42161, PolygonMumbai: 80001, Local: 31337, } @@ -55,20 +56,25 @@ var Chains = struct { Local Chain }{ Ethereum: Chain{ - Endpoint: testnetURL, + Endpoint: mainnetURL, ID: ChainIDs.Ethereum, ContractAddr: common.HexToAddress("0x012969f7e3439a9B04025b5a049EB9BAD82A8C12"), }, Optimism: Chain{ - Endpoint: testnetURL, + Endpoint: mainnetURL, ID: ChainIDs.Optimism, ContractAddr: common.HexToAddress("0xfad44BF5B843dE943a09D4f3E84949A11d3aa3e6"), }, Polygon: Chain{ - Endpoint: testnetURL, + Endpoint: mainnetURL, ID: ChainIDs.Polygon, ContractAddr: common.HexToAddress("0x5c4e6A9e5C1e1BF445A062006faF19EA6c49aFeA"), }, + Arbitrum: Chain{ + Endpoint: mainnetURL, + ID: ChainIDs.Arbitrum, + ContractAddr: common.HexToAddress("0x9aBd75E8640871A5a20d3B4eE6330a04c962aFfd"), + }, EthereumGoerli: Chain{ Endpoint: testnetURL, ID: ChainIDs.EthereumGoerli, @@ -84,11 +90,6 @@ var Chains = struct { ID: ChainIDs.ArbitrumGoerli, ContractAddr: common.HexToAddress("0x033f69e8d119205089Ab15D340F5b797732f646b"), }, - Arbitrum: Chain{ - Endpoint: testnetURL, - ID: ChainIDs.Arbitrum, - ContractAddr: common.HexToAddress("0x9aBd75E8640871A5a20d3B4eE6330a04c962aFfd"), - }, PolygonMumbai: Chain{ Endpoint: testnetURL, ID: ChainIDs.PolygonMumbai, From 5efd1bde401f9494cd9cca414b6bde90b06e0eab Mon Sep 17 00:00:00 2001 From: Aaron Sutula Date: Mon, 21 Nov 2022 11:45:29 -0600 Subject: [PATCH 012/101] testnets.tableland.network update Signed-off-by: Aaron Sutula --- pkg/client/chains.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/client/chains.go b/pkg/client/chains.go index feaf3428..e991fa6e 100644 --- a/pkg/client/chains.go +++ b/pkg/client/chains.go @@ -6,7 +6,7 @@ import ( const ( mainnetURL = "https://tableland.network" - testnetURL = "https://testnet.tableland.network" + testnetURL = "https://testnets.tableland.network" localURL = "http://localhost:8080" ) From bb00806ba7b4f50050d299cc9868407a4945d51f Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 28 Nov 2022 11:45:27 -0300 Subject: [PATCH 013/101] docker/deployed: update URIs configs [mainnetdeploy] Signed-off-by: Ignacio Hagopian --- docker/deployed/mainnet/api/config.json | 3 ++- docker/deployed/testnet/api/config.json | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docker/deployed/mainnet/api/config.json b/docker/deployed/mainnet/api/config.json index b84595fe..11b73390 100644 --- a/docker/deployed/mainnet/api/config.json +++ b/docker/deployed/mainnet/api/config.json @@ -9,7 +9,8 @@ }, "Gateway": { "ExternalURIPrefix": "https://tableland.network", - "MetadataRendererURI": "https://.tableland.xyz" + "MetadataRendererURI": "https://render.tableland.xyz", + "AnimationRendererURI": "https://render.tableland.xyz/anim" }, "DB": { "Port": "5432" diff --git a/docker/deployed/testnet/api/config.json b/docker/deployed/testnet/api/config.json index 18c59693..b668e8e2 100644 --- a/docker/deployed/testnet/api/config.json +++ b/docker/deployed/testnet/api/config.json @@ -9,8 +9,8 @@ }, "Gateway": { "ExternalURIPrefix": "https://testnets.tableland.network", - "MetadataRendererURI": "https://render.tableland.xyz", - "AnimationRendererURI": "https://render.tableland.xyz/anim" + "MetadataRendererURI": "https://testnets.render.tableland.xyz", + "AnimationRendererURI": "https://testnets.render.tableland.xyz/anim" }, "DB": { "Port": "5432" From fe6d196a087ad9f0220f2a5936f5f161f5a2494a Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 28 Nov 2022 11:47:10 -0300 Subject: [PATCH 014/101] ci: fix deploy job name Signed-off-by: Ignacio Hagopian --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7c90f631..f8ba6fde 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -79,7 +79,7 @@ jobs: echo "All healthy!" - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[mainnetdeploy]') - name: Deploy testnet + name: Deploy mainnet uses: appleboy/ssh-action@master with: host: ${{ secrets.MAINNET_VM_HOST }} From cd13f3d115ad354c9e3b054483b428d12f0bbc35 Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Fri, 18 Nov 2022 11:13:57 -0300 Subject: [PATCH 015/101] Updates parser [stagingdeploy] - Implement spec changes that resolve rowid non-determinism - We need to reconsider supporting FLOAT types in our SQL spec - Upserts are powerful, but our parser doesn't support UPSERT semantics - COUNT only works when it is in lowercase Signed-off-by: Bruno Calza --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- internal/system/impl/sqlstore_test.go | 10 +++++----- internal/tableland/impl/testdata/any_queries.csv | 3 +-- pkg/backup/backuper_test.go | 2 +- pkg/backup/testdata/control.sql | 4 ++-- pkg/parsing/impl/validator_test.go | 16 ++++++++-------- pkg/sqlstore/impl/system/store.go | 8 ++++---- 8 files changed, 33 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 9b3b5f46..ac4492a5 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/hetiansu5/urlquery v1.2.7 github.com/json-iterator/go v1.1.12 github.com/klauspost/compress v1.15.11 - github.com/mattn/go-sqlite3 v1.14.15 + github.com/mattn/go-sqlite3 v1.14.16 github.com/omeid/uconfig v1.2.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.13.0 @@ -21,8 +21,8 @@ require ( github.com/sethvargo/go-limiter v0.7.2 github.com/spf13/cobra v1.6.0 github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff - github.com/stretchr/testify v1.8.0 - github.com/tablelandnetwork/sqlparser v0.0.0-20220923130758-1b39431a2fea + github.com/stretchr/testify v1.8.1 + github.com/tablelandnetwork/sqlparser v0.0.0-20221117210313-20a7e349a521 github.com/textileio/cli v1.0.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 go.opentelemetry.io/otel v1.11.0 @@ -90,7 +90,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.8.1 // indirect - github.com/stretchr/objx v0.4.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/textileio/go-log/v2 v2.1.3-gke-2 // indirect diff --git a/go.sum b/go.sum index 44854ec0..fe73d79d 100644 --- a/go.sum +++ b/go.sum @@ -994,8 +994,8 @@ github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOq github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= @@ -1279,8 +1279,6 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/spruceid/siwe-go v0.2.1-0.20220711143404-817846826282 h1:NyHE3/rvWbSxO5UsaAcPP22vhY8XTJAzKVa6wqa1Eis= -github.com/spruceid/siwe-go v0.2.1-0.20220711143404-817846826282/go.mod h1:X+Fj7GsCyLAjfrjkGzgoiRsoAh8+bz4fSz2N3jwN9bc= github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff h1:jBz/gRYeRf2MjtxtdTHUX3PbIYFJD2S7TViBrhGWbPA= github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff/go.mod h1:X+Fj7GsCyLAjfrjkGzgoiRsoAh8+bz4fSz2N3jwN9bc= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= @@ -1291,8 +1289,9 @@ github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -1303,8 +1302,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= @@ -1314,8 +1314,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tablelandnetwork/sqlparser v0.0.0-20220923130758-1b39431a2fea h1:tKGomA8Eu3t1v9SDPz2Zu3Fq2ESPQKoGzVS39PzGxmU= -github.com/tablelandnetwork/sqlparser v0.0.0-20220923130758-1b39431a2fea/go.mod h1:hEWKQ1CaX9T+3GgbIkgkcLk4x2V4wuWWC1fB6Kzfthg= +github.com/tablelandnetwork/sqlparser v0.0.0-20221117210313-20a7e349a521 h1:GeZKbhJKnHhCHamDhCEflGX9nO7lh7vHgeNsavMUIXg= +github.com/tablelandnetwork/sqlparser v0.0.0-20221117210313-20a7e349a521/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/textileio/cli v1.0.2 h1:qSp/x4d/9SZ93TxhgZnE5okRKqzqHqrzAwKAPjuPw50= github.com/textileio/cli v1.0.2/go.mod h1:vTlCvvVyOmXXLwddCcBg3PDavfUsCkRBZoyr6Nu1lkc= diff --git a/internal/system/impl/sqlstore_test.go b/internal/system/impl/sqlstore_test.go index 37e3b244..0987b471 100644 --- a/internal/system/impl/sqlstore_test.go +++ b/internal/system/impl/sqlstore_test.go @@ -149,16 +149,16 @@ func TestGetSchemaByTableName(t *testing.T) { require.Equal(t, "a", schema.Columns[0].Name) require.Equal(t, "int", schema.Columns[0].Type) require.Len(t, schema.Columns[0].Constraints, 1) - require.Equal(t, "PRIMARY KEY", schema.Columns[0].Constraints[0]) + require.Equal(t, "primary key", schema.Columns[0].Constraints[0]) require.Equal(t, "b", schema.Columns[1].Name) require.Equal(t, "text", schema.Columns[1].Type) require.Len(t, schema.Columns[1].Constraints, 3) - require.Equal(t, "NOT NULL", schema.Columns[1].Constraints[0]) - require.Equal(t, "DEFAULT 'foo'", schema.Columns[1].Constraints[1]) - require.Equal(t, "UNIQUE", schema.Columns[1].Constraints[2]) + require.Equal(t, "not null", schema.Columns[1].Constraints[0]) + require.Equal(t, "default 'foo'", schema.Columns[1].Constraints[1]) + require.Equal(t, "unique", schema.Columns[1].Constraints[2]) - require.Equal(t, "CHECK(a > 0)", schema.TableConstraints[0]) + require.Equal(t, "check(a > 0)", schema.TableConstraints[0]) } func TestGetMetadata(t *testing.T) { diff --git a/internal/tableland/impl/testdata/any_queries.csv b/internal/tableland/impl/testdata/any_queries.csv index e803f7fe..ce8f32b1 100644 --- a/internal/tableland/impl/testdata/any_queries.csv +++ b/internal/tableland/impl/testdata/any_queries.csv @@ -1,4 +1,3 @@ w,"INSERT INTO any_1337_1 VALUES ('hello')","" w,"INSERT INTO any_1337_1 VALUES (3)","" -w,"INSERT INTO any_1337_1 VALUES (3.1416)","" -r,"SELECT * FROM any_1337_1","{""columns"":[{""name"":""wild""}],""rows"":[[""hello""],[3],[3.1416]]}" +r,"SELECT * FROM any_1337_1","{""columns"":[{""name"":""wild""}],""rows"":[[""hello""],[3]]}" diff --git a/pkg/backup/backuper_test.go b/pkg/backup/backuper_test.go index 8aca5645..63cd1c72 100644 --- a/pkg/backup/backuper_test.go +++ b/pkg/backup/backuper_test.go @@ -96,7 +96,7 @@ func TestBackuperWithCompression(t *testing.T) { require.NoFileExists(t, fmt.Sprintf("%s/tbl_backup_2009-11-17T20:34:58Z.db", dir)) require.Greater(t, result.ElapsedTime, time.Duration(0)) require.Greater(t, result.CompressionElapsedTime, time.Duration(0)) - require.Equal(t, int64(39935), result.SizeAfterCompression) + require.Equal(t, int64(39934), result.SizeAfterCompression) require.NoError(t, backuper.Close()) } diff --git a/pkg/backup/testdata/control.sql b/pkg/backup/testdata/control.sql index 802d71b7..2503901c 100644 --- a/pkg/backup/testdata/control.sql +++ b/pkg/backup/testdata/control.sql @@ -1,12 +1,12 @@ -- Statements that helps to build a control table used to test the backuper -- --- SQLite version 3.39.2 +-- SQLite version 3.39.4 -- -- Stats to be checked in the test: -- -- Size: 311296 -- Size (vacuum): 159744 --- Size (vacuum/compression): 39999 +-- Size (vacuum/compression): 39934 create table mock ( id INT, diff --git a/pkg/parsing/impl/validator_test.go b/pkg/parsing/impl/validator_test.go index 6d6d83bd..8ccf74d9 100644 --- a/pkg/parsing/impl/validator_test.go +++ b/pkg/parsing/impl/validator_test.go @@ -588,9 +588,9 @@ func TestCreateTableResult(t *testing.T) { // echo -n bar:INT | shasum -a 256 expStructureHash: "5d70b398f938650871dd0d6d421e8d1d0c89fe9ed6c8a817c97e951186da7172", expRawQueries: []rawQueryTableID{ - {id: 1, rawQuery: "CREATE TABLE my_10_nth_table_1337_1 (bar INT) STRICT"}, - {id: 42, rawQuery: "CREATE TABLE my_10_nth_table_1337_42 (bar INT) STRICT"}, - {id: 2929392, rawQuery: "CREATE TABLE my_10_nth_table_1337_2929392 (bar INT) STRICT"}, + {id: 1, rawQuery: "create table my_10_nth_table_1337_1 (bar int) strict"}, + {id: 42, rawQuery: "create table my_10_nth_table_1337_42 (bar int) strict"}, + {id: 2929392, rawQuery: "create table my_10_nth_table_1337_2929392 (bar int) strict"}, }, }, { @@ -602,8 +602,8 @@ func TestCreateTableResult(t *testing.T) { // echo -n bar:INT | shasum -a 256 expStructureHash: "5d70b398f938650871dd0d6d421e8d1d0c89fe9ed6c8a817c97e951186da7172", expRawQueries: []rawQueryTableID{ - {id: 1, rawQuery: "CREATE TABLE _1337_1 (bar INT) STRICT"}, - {id: 42, rawQuery: "CREATE TABLE _1337_42 (bar INT) STRICT"}, + {id: 1, rawQuery: "create table _1337_1 (bar int) strict"}, + {id: 42, rawQuery: "create table _1337_42 (bar int) strict"}, }, }, { @@ -617,9 +617,9 @@ func TestCreateTableResult(t *testing.T) { // echo -n name:TEXT,age:INT,fav_color:TEXT | shasum -a 256 expStructureHash: "f45023b189891ad781070ac05374d4e7d7ec7ae007cfd836791c36d609ba7ddd", expRawQueries: []rawQueryTableID{ - {id: 1, rawQuery: "CREATE TABLE person_1337_1 (name TEXT, age INT, fav_color TEXT) STRICT"}, - {id: 42, rawQuery: "CREATE TABLE person_1337_42 (name TEXT, age INT, fav_color TEXT) STRICT"}, - {id: 2929392, rawQuery: "CREATE TABLE person_1337_2929392 (name TEXT, age INT, fav_color TEXT) STRICT"}, + {id: 1, rawQuery: "create table person_1337_1 (name text, age int, fav_color text) strict"}, + {id: 42, rawQuery: "create table person_1337_42 (name text, age int, fav_color text) strict"}, + {id: 2929392, rawQuery: "create table person_1337_2929392 (name text, age int, fav_color text) strict"}, }, }, } diff --git a/pkg/sqlstore/impl/system/store.go b/pkg/sqlstore/impl/system/store.go index b7f3b2f0..244b881f 100644 --- a/pkg/sqlstore/impl/system/store.go +++ b/pkg/sqlstore/impl/system/store.go @@ -246,7 +246,7 @@ func (s *SystemStore) GetSchemaByTableName(ctx context.Context, name string) (sq return sqlstore.TableSchema{}, fmt.Errorf("failed to get the table: %s", err) } - index := strings.LastIndex(createStmt, "STRICT") + index := strings.LastIndex(createStmt, "strict") ast, err := sqlparser.Parse(createStmt[:index]) if err != nil { return sqlstore.TableSchema{}, fmt.Errorf("failed to parse create stmt: %s", err) @@ -257,15 +257,15 @@ func (s *SystemStore) GetSchemaByTableName(ctx context.Context, name string) (sq } createTableNode := ast.Statements[0].(*sqlparser.CreateTable) - columns := make([]sqlstore.ColumnSchema, len(createTableNode.Columns)) - for i, col := range createTableNode.Columns { + columns := make([]sqlstore.ColumnSchema, len(createTableNode.ColumnsDef)) + for i, col := range createTableNode.ColumnsDef { colConstraints := []string{} for _, colConstraint := range col.Constraints { colConstraints = append(colConstraints, colConstraint.String()) } columns[i] = sqlstore.ColumnSchema{ - Name: col.Name.String(), + Name: col.Column.String(), Type: strings.ToLower(col.Type), Constraints: colConstraints, } From 1ece0f80ebac17b8def5cf5832fd381a75b4ff3a Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Fri, 18 Nov 2022 11:56:07 -0300 Subject: [PATCH 016/101] Modify test replay hashes because parser changes break state Signed-off-by: Bruno Calza --- .../impl/eventprocessor_replayhistory_test.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go index df2332cb..00d9da56 100644 --- a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go +++ b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go @@ -1,5 +1,3 @@ -//go:build !arm64 - package impl import ( @@ -37,14 +35,14 @@ func TestReplayProductionHistory(t *testing.T) { } expectedStateHashes := map[tableland.ChainID]string{ - 1: "87b02f2755e043a7d7f544bb9bf79765115f9b58", - 5: "b6f5f703af0e92d8f28773a024ed45119cef8c61", - 10: "57555e08de5b37270ddad6c2cad2c1ae7ca6901e", - 69: "f17f7c999790277cc91351a798eea2d08abe4285", - 137: "241425c72e622bb8574f7fe15ccf251ddc5c6367", - 420: "923d03c96ca0c3fa848b651697cf925bcdee5eff", - 80001: "7b15ca5f14bc4e7475d48fface3ac1a7022e3a27", - 421613: "df1fe80afc8d9fc0ae31057b82766dd82d81ad63", + 1: "ce4f083e256d3458a329b6cd1ba7d8e93d9703b3", + 5: "9ab5a92ac961d39ee07dd1e59518c527b39719c1", + 10: "3d907df6936eea9ab046d89c80b995d5db26e6ac", + 69: "643af9ad784444242c6ef415727203941a720197", + 137: "b5fb42f3538738ab5856abf9e3b2e38d82378ca4", + 420: "8673f7095da19c1fc51f1f84b4c4ffc115a176e0", + 80001: "e85654e780c5e98cef2a25cd8e3764f125b2e1d1", + 421613: "073727932afcee9a5dba19f43c023689ca855dc2", } historyDBURI := getHistoryDBURI(t) From c3a57b6d21e268ab1444f0905fc077eb74cafecc Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Wed, 7 Dec 2022 10:02:46 -0300 Subject: [PATCH 017/101] bumps parser version support for all JOIN operators, compound selects and INSERT with SELECT Signed-off-by: Bruno Calza --- go.mod | 2 +- go.sum | 8 +- pkg/parsing/impl/validator.go | 119 +++++++++++++---------------- pkg/parsing/impl/validator_test.go | 28 +++++-- pkg/parsing/query_validator.go | 11 +++ 5 files changed, 89 insertions(+), 79 deletions(-) diff --git a/go.mod b/go.mod index ac4492a5..8b15d72b 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/cobra v1.6.0 github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff github.com/stretchr/testify v1.8.1 - github.com/tablelandnetwork/sqlparser v0.0.0-20221117210313-20a7e349a521 + github.com/tablelandnetwork/sqlparser v0.0.0-20221206205623-de3c827d6e39 github.com/textileio/cli v1.0.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 go.opentelemetry.io/otel v1.11.0 diff --git a/go.sum b/go.sum index fe73d79d..cdc82bd7 100644 --- a/go.sum +++ b/go.sum @@ -1314,8 +1314,12 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tablelandnetwork/sqlparser v0.0.0-20221117210313-20a7e349a521 h1:GeZKbhJKnHhCHamDhCEflGX9nO7lh7vHgeNsavMUIXg= -github.com/tablelandnetwork/sqlparser v0.0.0-20221117210313-20a7e349a521/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20221202173423-7243894ff651 h1:iBE88lfYPJfbanmuQehy5t8V7m7Yv6Ge1OEKJWuCBTc= +github.com/tablelandnetwork/sqlparser v0.0.0-20221202173423-7243894ff651/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20221206182935-9aa9abb23647 h1:pAC4kr5yvv7wbQzx4wdTypNShaUnU/ECIVQRmc7Yg+M= +github.com/tablelandnetwork/sqlparser v0.0.0-20221206182935-9aa9abb23647/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20221206205623-de3c827d6e39 h1:Xi7Bt60Na70O/k4uyy1ws5FnoxFS6xZuGPdCYQ/UCPQ= +github.com/tablelandnetwork/sqlparser v0.0.0-20221206205623-de3c827d6e39/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/textileio/cli v1.0.2 h1:qSp/x4d/9SZ93TxhgZnE5okRKqzqHqrzAwKAPjuPw50= github.com/textileio/cli v1.0.2/go.mod h1:vTlCvvVyOmXXLwddCcBg3PDavfUsCkRBZoyr6Nu1lkc= diff --git a/pkg/parsing/impl/validator.go b/pkg/parsing/impl/validator.go index 97677566..36792fd5 100644 --- a/pkg/parsing/impl/validator.go +++ b/pkg/parsing/impl/validator.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "regexp" - "strconv" "strings" "github.com/ethereum/go-ethereum/common" @@ -62,25 +61,16 @@ func (pp *QueryValidator) ValidateCreateTable(query string, chainID tableland.Ch } node := stmt.(*sqlparser.CreateTable) - if !pp.createTableNameRegEx.MatchString(node.Table.String()) { - return nil, &parsing.ErrInvalidTableName{} - } - parts := strings.Split(node.Table.String(), "_") - if len(parts) < 2 { - return nil, fmt.Errorf("table name isn't referencing the chain id") + validTable, err := sqlparser.ValidateCreateTargetTable(node.Table) + if err != nil { + return nil, fmt.Errorf("create table name is not valid: %w", err) } - prefix := strings.Join(parts[:len(parts)-1], "_") - if hasPrefix(prefix, pp.systemTablePrefixes) { - return nil, &parsing.ErrPrefixTableName{Prefix: prefix} + if hasPrefix(validTable.Prefix(), pp.systemTablePrefixes) { + return nil, &parsing.ErrPrefixTableName{Prefix: validTable.Prefix()} } - strChainID := parts[len(parts)-1] - tableChainID, err := strconv.ParseInt(strChainID, 10, 64) - if err != nil { - return nil, fmt.Errorf("parsing chain id in table name: %s", err) - } - if tableChainID != int64(chainID) { + if validTable.ChainID() != int64(chainID) { return nil, &parsing.ErrInvalidTableName{} } @@ -88,7 +78,7 @@ func (pp *QueryValidator) ValidateCreateTable(query string, chainID tableland.Ch chainID: chainID, cNode: node, structureHash: node.StructureHash(), - prefix: prefix, + prefix: validTable.Prefix(), }, nil } @@ -117,7 +107,7 @@ func (pp *QueryValidator) ValidateMutatingQuery( // Since we support write queries with more than one statement, // do the write/grant-query validation in each of them. Also, check // that each statement reference always the same table. - var targetTable, refTable string + var targetTable, refTable *sqlparser.ValidatedTable for i := range ast.Statements { if ast.Errors[i] != nil { return nil, fmt.Errorf("non sysntax error in %d-th statement: %w", i, ast.Errors[i]) @@ -130,6 +120,7 @@ func (pp *QueryValidator) ValidateMutatingQuery( if err != nil { return nil, fmt.Errorf("validating write-query: %w", err) } + case sqlparser.GrantOrRevokeStatement: refTable, err = pp.validateGrantQuery(s) if err != nil { @@ -139,32 +130,28 @@ func (pp *QueryValidator) ValidateMutatingQuery( return nil, &parsing.ErrStatementIsNotSupported{} } - if targetTable == "" { + if targetTable == nil { targetTable = refTable - } else if targetTable != refTable { - return nil, &parsing.ErrMultiTableReference{Ref1: targetTable, Ref2: refTable} + } else if targetTable.Name() != refTable.Name() { + return nil, &parsing.ErrMultiTableReference{Ref1: targetTable.Name(), Ref2: refTable.Name()} } } - prefix, queryChainID, tableID, err := pp.deconstructRefTable(targetTable) - if err != nil { - return nil, fmt.Errorf("deconstructing referenced table name: %w", err) - } - if queryChainID != chainID { - return nil, fmt.Errorf("the query references chain-id %d but expected %d", queryChainID, chainID) + if targetTable.ChainID() != int64(chainID) { + return nil, fmt.Errorf("the query references chain-id %d but expected %d", targetTable.ChainID(), chainID) } ret := make([]parsing.MutatingStmt, len(ast.Statements)) for i := range ast.Statements { stmt := ast.Statements[i] - tblID, err := tables.NewTableID(tableID) + tblID, err := tables.NewTableID(fmt.Sprintf("%d", targetTable.TokenID())) if err != nil { return nil, &parsing.ErrInvalidTableName{} } mutatingStmt := &mutatingStmt{ node: stmt, - dbTableName: targetTable, - prefix: prefix, + dbTableName: targetTable.Name(), + prefix: targetTable.Prefix(), tableID: tblID, } @@ -223,38 +210,6 @@ func (pp *QueryValidator) ValidateReadQuery(query string) (parsing.ReadStmt, err }, nil } -// deconstructRefTable returns three main deconstructions of the reference table name in the query: -// 1) The {prefix} of {prefix}_{chainID}_{ID}, if any. -// 2) The {chainID} of {prefix}_{chainID}_{ID}. -// 3) The {tableID} of {prefix}_{chainID}_{ID}. -// If the referenced table is a system table, it will only return. -func (pp *QueryValidator) deconstructRefTable(refTable string) (string, tableland.ChainID, string, error) { - if hasPrefix(refTable, pp.systemTablePrefixes) { - return "", 0, refTable, nil - } - if !pp.queryTableNameRegEx.MatchString(refTable) { - return "", 0, "", &parsing.ErrInvalidTableName{} - } - - parts := strings.Split(refTable, "_") - // This validation is redundant considering that refTable matches the expected regex, - // so we're being a bit paranoid here since it's an easy check. - if len(parts) < 2 { - return "", 0, "", &parsing.ErrInvalidTableName{} - } - - tableID := parts[len(parts)-1] - partChainID := parts[len(parts)-2] - prefix := strings.Join(parts[:len(parts)-2], "_") - - chainID, err := strconv.ParseInt(partChainID, 10, 64) - if err != nil { - return "", 0, "", &parsing.ErrInvalidTableName{} - } - - return prefix, tableland.ChainID(chainID), tableID, nil -} - type mutatingStmt struct { node sqlparser.Statement prefix string // From {prefix}_{chainID}_{tableID} -> {prefix} @@ -398,24 +353,52 @@ func (s *readStmt) GetQuery() (string, error) { return s.query, nil } -func (pp *QueryValidator) validateWriteQuery(stmt sqlparser.WriteStatement) (string, error) { +func (pp *QueryValidator) validateWriteQuery(stmt sqlparser.WriteStatement) (*sqlparser.ValidatedTable, error) { if err := checkNoSystemTablesReferencing(stmt, pp.systemTablePrefixes); err != nil { - return "", fmt.Errorf("no system-table reference: %w", err) + return nil, fmt.Errorf("no system-table reference: %w", err) + } + + insertTable, err := sqlparser.ValidateTargetTable(stmt.GetTable()) + if err != nil { + return nil, fmt.Errorf("table name is not valid: %w", err) } - return stmt.GetTable().String(), nil + if insert, ok := stmt.(*sqlparser.Insert); ok && insert.Select != nil { + tables, err := sqlparser.ValidateTargetTables(insert.Select) + if err != nil { + return nil, fmt.Errorf("validating select table names: %w", err) + } + + if len(tables) > 1 { + return nil, fmt.Errorf("select should have only one table") + } + + if tables[0].ChainID() != insertTable.ChainID() { + return nil, &parsing.ErrInsertWithSelectChainMistmatch{ + InsertChainID: insertTable.ChainID(), + SelectChainID: tables[0].ChainID(), + } + } + } + + return insertTable, nil } -func (pp *QueryValidator) validateGrantQuery(stmt sqlparser.GrantOrRevokeStatement) (string, error) { +func (pp *QueryValidator) validateGrantQuery(stmt sqlparser.GrantOrRevokeStatement) (*sqlparser.ValidatedTable, error) { // check if roles are ETH addresses for _, role := range stmt.GetRoles() { addr := common.Address{} if err := addr.UnmarshalText([]byte(role)); err != nil { - return "", &parsing.ErrRoleIsNotAnEthAddress{} + return nil, &parsing.ErrRoleIsNotAnEthAddress{} } } - return stmt.GetTable().String(), nil + table, err := sqlparser.ValidateTargetTable(stmt.GetTable()) + if err != nil { + return nil, fmt.Errorf("table name is not valid: %w", err) + } + + return table, nil } func checkNonEmptyStatement(parsed *sqlparser.AST) error { diff --git a/pkg/parsing/impl/validator_test.go b/pkg/parsing/impl/validator_test.go index 8ccf74d9..b70ef327 100644 --- a/pkg/parsing/impl/validator_test.go +++ b/pkg/parsing/impl/validator_test.go @@ -166,7 +166,7 @@ func TestWriteQuery(t *testing.T) { { name: "table id or chain id is missing", query: "delete from Hello_4 where a=2", - expErrType: ptr2ErrInvalidTableName(), + expErrType: ptr2ErrWrongFormatTableName(), }, { name: "unprefixed table is missing underscore", @@ -176,12 +176,12 @@ func TestWriteQuery(t *testing.T) { { name: "non-numeric table id", query: "delete from person_4_wrong where a=2", - expErrType: ptr2ErrInvalidTableName(), + expErrType: ptr2ErrWrongFormatTableName(), }, { name: "non-numeric chain id", query: "delete from _wrong_4 where a=2", - expErrType: ptr2ErrInvalidTableName(), + expErrType: ptr2ErrWrongFormatTableName(), }, // Valid insert and updates. @@ -265,12 +265,14 @@ func TestWriteQuery(t *testing.T) { expErrType: ptr2ErrInvalidSyntax(), }, - // Disallow JOINs and sub-queries + // insert with select chain mismatch { - name: "insert subquery", - query: "insert into foo select * from bar", - expErrType: ptr2ErrInvalidSyntax(), + name: "insert subquery chain mismatch", + query: "insert into foo_1_1 select * from bar_2_1", + expErrType: ptr2ErrInsertWithSelectChainMistmatch(), }, + + // Disallow JOINs and sub-queries { name: "update join", query: "update foo set a=1 from bar", @@ -455,7 +457,7 @@ func TestCreateTableChecks(t *testing.T) { name: "missing chain id", query: "create table Hello (foo int)", chainID: 68, - expErrType: ptr2ErrInvalidTableName(), + expErrType: ptr2ErrWrongFormatTableName(), }, { name: "missing underscore", @@ -942,6 +944,11 @@ func ptr2ErrInvalidTableName() **parsing.ErrInvalidTableName { return &e } +func ptr2ErrWrongFormatTableName() **sqlparser.ErrTableNameWrongFormat { + var e *sqlparser.ErrTableNameWrongFormat + return &e +} + func ptr2ErrPrefixTableName() **parsing.ErrPrefixTableName { var e *parsing.ErrPrefixTableName return &e @@ -956,3 +963,8 @@ func ptr2ErrRoleIsNotAnEthAddress() **parsing.ErrRoleIsNotAnEthAddress { var e *parsing.ErrRoleIsNotAnEthAddress return &e } + +func ptr2ErrInsertWithSelectChainMistmatch() **parsing.ErrInsertWithSelectChainMistmatch { + var e *parsing.ErrInsertWithSelectChainMistmatch + return &e +} diff --git a/pkg/parsing/query_validator.go b/pkg/parsing/query_validator.go index 78c9b17c..21c4e68c 100644 --- a/pkg/parsing/query_validator.go +++ b/pkg/parsing/query_validator.go @@ -204,6 +204,17 @@ func (e *ErrWriteQueryTooLong) Error() string { e.Length, e.MaxAllowed) } +// ErrInsertWithSelectChainMistmatch is an error returned there is a mismatch of chains in a insert with select. +type ErrInsertWithSelectChainMistmatch struct { + InsertChainID int64 + SelectChainID int64 +} + +func (e *ErrInsertWithSelectChainMistmatch) Error() string { + return fmt.Sprintf( + "insert with select chain mismatch (insert chain %d, select chain %d)", e.InsertChainID, e.SelectChainID) +} + // Config contains configuration parameters for tableland. type Config struct { MaxReadQuerySize int From 69ed48840f0d6c4c9ce5c9b95905dd7fd5fafdef Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Wed, 7 Dec 2022 10:46:59 -0300 Subject: [PATCH 018/101] update state hashes Signed-off-by: Bruno Calza --- .../impl/eventprocessor_replayhistory_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go index 00d9da56..ad9faba9 100644 --- a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go +++ b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go @@ -36,12 +36,12 @@ func TestReplayProductionHistory(t *testing.T) { expectedStateHashes := map[tableland.ChainID]string{ 1: "ce4f083e256d3458a329b6cd1ba7d8e93d9703b3", - 5: "9ab5a92ac961d39ee07dd1e59518c527b39719c1", - 10: "3d907df6936eea9ab046d89c80b995d5db26e6ac", + 5: "b42740b92e40d616061a88872e19616c05469750", + 10: "c9afca82a8c30fc683da366b5f4920e7c131ec5d", 69: "643af9ad784444242c6ef415727203941a720197", 137: "b5fb42f3538738ab5856abf9e3b2e38d82378ca4", - 420: "8673f7095da19c1fc51f1f84b4c4ffc115a176e0", - 80001: "e85654e780c5e98cef2a25cd8e3764f125b2e1d1", + 420: "184800f533f4edd186853a85829fad8bc7802c4e", + 80001: "df269d9451e0bf1b77c7616aff4148a3f1a4559a", 421613: "073727932afcee9a5dba19f43c023689ca855dc2", } From fa0a96cb3367c41b2b060e6650e854a275cb1b31 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 28 Nov 2022 18:46:15 -0300 Subject: [PATCH 019/101] Makefile: add spec code generation rule Signed-off-by: Ignacio Hagopian --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 74b304be..eb44a930 100644 --- a/Makefile +++ b/Makefile @@ -83,3 +83,7 @@ test-replayhistory: lint: go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.49.0 run .PHONYY: lint + +# OpenAPI +openapi: + docker run -w /gen -e GEN_DIR=/gen -v ${PWD}:/gen swaggerapi/swagger-codegen-cli-v3 generate --lang go-server -o /gen/tablelandapi -i tableland-openapi-spec.yaml --additional-properties=packageName=tablelandapi \ No newline at end of file From 42bf3b345f60ad4afbc45a678020098725cff661 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 28 Nov 2022 18:49:28 -0300 Subject: [PATCH 020/101] spec: update to latest one Signed-off-by: Ignacio Hagopian --- tableland-openapi-spec.yaml | 764 ++++++++++-------------------------- 1 file changed, 214 insertions(+), 550 deletions(-) diff --git a/tableland-openapi-spec.yaml b/tableland-openapi-spec.yaml index a9675b42..29ec3db8 100644 --- a/tableland-openapi-spec.yaml +++ b/tableland-openapi-spec.yaml @@ -1,609 +1,273 @@ -openapi: 3.0.0 +openapi: 3.0.3 info: - title: Tableland Remote API - version: 0.0.1 -servers: - - url: https://testnet.tableland.network -paths: - /rpc: - post: - security: - - bearerAuth: [] - summary: Lets you interact with Tableland's JSON-RPC calls - description: > - The following JSON-RPC methods are available: - - * The `validateCreateTable` method allows you validate a CREATE TABLE query as a pre-mint check, and also calculate its corresponding structure hash. - - * The `runReadQuery` method allows you execute a read-query in the validator and get the result. - - * The `validateWriteQuery` method allows you validate a mutating query as a pre contract call check. - - * The `relayWriteQuery` method allows you to rely on the validator to send a runSQL SC call on your behalf for write-queries. + title: Tableland Validator - OpenAPI 3.0 + description: |- + 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. - * The `getReceipt` method allows you to get the receipt of a chain transaction to know if it was executed, and the execution details. + 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 `setController` method allows you to rely on the validator to send a setController SC call on your behalf for a table. - - All the above RPC calls expect an Authorization header with a signed SIWE except: - - runReadQuery - - requestBody: - required: true - content: - application/json: - schema: - oneOf: - - $ref: "#/components/schemas/runReadQuery" - - $ref: "#/components/schemas/relayWriteQuery" - - $ref: "#/components/schemas/validateCreateTable" - - $ref: "#/components/schemas/getReceipt" - - $ref: "#/components/schemas/setController" - examples: - validateCreateTable: - value: - jsonrpc: "2.0" - method: tableland_validateCreateTable - id: 1 - params: - - id: "0" - create_statement: "CREATE TABLE myname_31337 (column_a int, column_b text);" - validateWriteQuery: - value: - jsonrpc: "2.0" - method: tableland_validateWriteQuery - id: 1 - params: - - id: "0" - statement: "INSERT INTO healthbot_31337_1 VALUES (1);" - runReadQuery: - value: - jsonrpc: "2.0" - method: tableland_runReadQuery - id: 1 - params: - - statement: SELECT * FROM healthbot_31337_1; - relayWriteQuery: - value: - jsonrpc: "2.0" - method: tableland_relayWriteQuery - id: 1 - params: - - statement: INSERT INTO healthbot_31337_1 values (2); - getReceipt: - value: - jsonrpc: "2.0" - method: tableland_getReceipt - id: 1 - params: - - txn_hash: "0x400508d7cc035b14cc53f64393a8dafcc55f66ad8f9b44d626744157337e2098" - setController: - value: - jsonrpc: "2.0" - method: tableland_setController - id: 1 - params: - - controller: "0x0" - token_id: "1" - responses: - "200": - description: OK - headers: - Access-Control-Allow-Headers: - schema: - type: string - example: "Accept, Accept-Language, Content-Type, Authorization" - Access-Control-Allow-Origin: - schema: - type: string - example: "*" - Access-Control-Allow-Methods: - schema: - type: string - example: "GET, POST, OPTIONS" - Trace-Id: - schema: - type: string - example: "579bf7aa-9bcf-4405-9d9e-7fd6c1672d1b" - Content-Type: - schema: - type: string - example: application/json - content: - application/json: - schema: - type: object - examples: - validateCreateTable: - value: - jsonrpc: "2.0" - id: 1 - result: - structure_hash: "ef7be01282ea97380e4d3bbcba6774cbc7242c46ee51b7e611f1efdfa3623e53" - validateWriteQuery: - value: - jsonrpc: "2.0" - id: 1 - result: - table_id: "1" - relayWriteQuery: - value: - jsonrpc: "2.0" - id: 1 - result: - tx: - hash: "0xc3e7d1e81b59556f414a5f5c23760eb61b4bfaa18150d924d7d3b334941dbecd" - runReadQuery: - value: - jsonrpc: "2.0" - id: 1 - result: - data: - columns: - - name: column_a - rows: - - [1] - getReceipt: - value: - jsonrpc: "2.0" - id: 1 - result: - ok: true - receipt: - chain_id: 5 - txn_hash: "0xc3e7d1e81b59556f414a5f5c23760eb61b4bfaa18150d924d7d3b334941dbecd" - block_number: 1000 - table_id: "2" - setController: - value: - jsonrpc: "2.0" - id: 1 - result: - tx: - hash: "0xa69590589a9ae04bfde4ca07351c611f9ddb2ddc3bab6cd0165684dc959be5c7" - /chain/{chainID}/tables/controller/{address}: + termsOfService: http://docs.tableland.xyz + contact: + name: core devs + email: carson@textile.io + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 +externalDocs: + description: Tableland docs + url: http://docs.tableland.xyz +servers: + - url: https://testnet.tableland.xyz/api/v1 +tags: + - name: query + description: Query the Tableland network + externalDocs: + description: Find out more about queries + url: http://docs.tableland.xyz + - name: receipt + description: Get information about transaction progress + externalDocs: + description: Find out more about receipts + url: http://docs.tableland.xyz + - name: tables + description: Access to table information + externalDocs: + description: Find out more about tables + url: http://docs.tableland.xyz +paths: + /query: get: - summary: Get all tables controlled by an ETH address + tags: + - query + summary: Query the Tableland network + description: Returns the results of a SQL query against the Tabeland network + operationId: queryFromQuery parameters: - - in: path - name: chainID - schema: - type: integer + - name: statement + in: query + description: The SQL query statement required: true - description: The ChainID of the targeted chain. - - in: path - name: address schema: type: string - required: true - description: An ETH address - responses: - "200": - description: Successful response - content: - application/json: - schema: - type: array - items: - type: "object" - required: - - "name" - - "controller" - - "structure" - properties: - name: - type: "string" - controller: - type: "string" - structure: - type: "string" - example: - - controller: "0xbAb12215Ed94713A290e0c618fa8177fAb5eFd2D" - name: "healthbot_31337_1" - structure: "be1eb905f03347a439ecf9b612632fd53839b7f082dc2f9be6ef7da5dfddd660" - /chain/{chainID}/tables/structure/{hash}: - get: - summary: Get all tables that has the structure defined by the given hash - parameters: - - in: path - name: chainID - schema: - type: integer - required: true - description: The ChainID of the targeted chain. - - in: path - name: hash + - name: format + in: query + description: > + 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. + required: false schema: type: string - required: true - description: hash of the schema of the table + enum: + - objects + - table + default: "objects" + - name: extract + in: query + description: Whether or not to extract the JSON object from the single property of the surrounding JSON object. + required: false + schema: + type: boolean + default: false + - name: unwrap + in: query + description: Whether or not to unwrap the returned JSON objects from their surrounding array. + required: false + schema: + type: boolean + default: false responses: "200": - description: Successful response + description: successful operation content: application/json: schema: - type: array - items: - type: "object" - required: - - "name" - - "controller" - - "structure" - properties: - name: - type: "string" - controller: - type: "string" - structure: - type: "string" - example: - - controller: "0xbAb12215Ed94713A290e0c618fa8177fAb5eFd2D" - name: "healthbot_31337_1" - structure: "be1eb905f03347a439ecf9b612632fd53839b7f082dc2f9be6ef7da5dfddd660" - /chain/{chainID}/tables/{id}: + type: object + "400": + description: Invalid query/statement value + /receipt/{chainId}/{txnHash}: get: - summary: Get the metadata associated with a table + tags: + - receipt + summary: Query the Tableland network for transaction status + description: Returns the status of a given transaction receipt by hash + operationId: receiptByTxnHash parameters: - - in: path - name: chainID + - name: chainId + in: path + description: The parent chain to target + required: true schema: - type: integer + type: number + - name: txnHash + in: path + description: The transaction hash to request required: true - description: The ChainID of the targeted chain. - - in: path - name: id schema: type: string - required: true - description: The id of the table responses: "200": - description: Successful response - content: - application/json: - schema: - type: "object" - required: - - name - - description - - external_url - - image - - attributes - properties: - name: - type: "string" - description: - type: "string" - external_url: - type: "string" - image: - type: "string" - attributes: - type: array - items: - type: object - required: - - display_type - - trait_type - - value - properties: - display_type: - type: "string" - trait_type: - type: "string" - value: - type: "integer" - example: - name: "myname" - external_url: "https://testnet.tableland.network/tables/0" - image: "https://bafkreifhuhrjhzbj4onqgbrmhpysk2mop2jimvdvfut6taiyzt2yqzt43a.ipfs.dweb.link" - attributes: - - display_type: "date" - trait_type: "created" - value: 1644274661 - "500": - description: Internal Server Error + description: successful operation content: application/json: schema: - type: "object" - required: - - message - example: - message: "Failed to fetch metadata" + $ref: "#/components/schemas/TxnReceipt" "400": - description: Bad Request - content: - application/json: - schema: - type: "object" - required: - - message - example: - message: "Invalid id format" - /schema/{tableName}: + description: Invalid query/statement value + /tables/structure/{hash}: get: - summary: Get the schema of a table by its full name + tags: + - tables + summary: Finds tables by structure + description: Returns all tables that match a given structure + operationId: findTablesByStructure parameters: - - in: path - name: tableName + - name: hash + in: path + description: Structure hash to filter on + required: true schema: type: string - required: true - description: The full name of the table + - name: chainId + in: query + description: The parent chain to filter on + required: false + schema: + type: number responses: "200": - description: Successful response + description: successful operation content: application/json: schema: - type: object + type: array items: - type: "object" - required: - - "columns" - - "table_constraints" - properties: - columns: - type: "array" - items: - type: "object" - required: - - "name" - - "type" - - "constraints" - properties: - name: - type: "string" - type: - type: "string" - constraints: - type: "array" - items: - type: "string" - table_constraints: - type: "array" - items: - type: "string" - example: - columns: - - name: "a" - type: "int" - constraints: - - "PRIMARY KEY" - table_constraints: - - "CHECK (a > 0)" - /query?s={readStatement}: + $ref: "#/components/schemas/Info" + "400": + description: Invalid structure value + /tables/{tableName}: get: - summary: Get a read query with the statement in the `s` querystring parameter + tags: + - tables + summary: Get information about a table + description: Returns information about a single table, including schema information + operationId: getTableByName parameters: - - in: query - name: readStatement - description: The SQL statement describing the read query + - name: tableName + in: path + description: Full name of table to return required: true + schema: + type: string responses: "200": - description: Successful response + description: successful operation content: application/json: schema: - type: array - items: - type: "object" - required: - - "data" - properties: - data: - type: "object" - example: - columns: - - name: column_a - rows: - - [1] - headers: - Access-Control-Allow-Headers: - schema: - type: string - example: "Accept, Accept-Language, Content-Type, Authorization" - Access-Control-Allow-Origin: - schema: - type: string - example: "*" - Access-Control-Allow-Methods: - schema: - type: string - example: "GET, POST, OPTIONS" - Trace-Id: - schema: - type: string - example: "579bf7aa-9bcf-4405-9d9e-7fd6c1672d1b" - Content-Type: - schema: - type: string - example: application/json - + $ref: "#/components/schemas/Table" + "400": + description: Invalid name supplied + "404": + description: Table not found components: - securitySchemes: - bearerAuth: # arbitrary name for the security scheme - type: http - scheme: bearer - bearerFormat: SIWE schemas: - runReadQuery: - type: "object" - required: - - "method" - - "id" - - "jsonrpc" - - "params" + Table: + type: object properties: - method: - type: "string" - description: "Method name" - id: - type: "integer" - default: 1 - format: int32 - description: "Request ID" - jsonrpc: - type: "string" - default: "2.0" - description: "JSON-RPC Version (2.0)" - params: - type: "array" + name: + type: string + example: healthbot_5_1 + external_url: + type: string + example: https://testnet.tableland.network/tables/healthbot_5_1 + image: + type: string + example: https://render.tableland.xyz/healthbot_5_1 + attributes: + type: array items: type: "object" - required: - - "statement" properties: - statement: + display_type: type: "string" - relayWriteQuery: - type: "object" - required: - - "method" - - "id" - - "jsonrpc" - - "params" - properties: - method: - type: "string" - description: "Method name" - id: - type: "integer" - default: 1 - format: int32 - description: "Request ID" - jsonrpc: - type: "string" - default: "2.0" - description: "JSON-RPC Version (2.0)" - params: - type: "array" - items: - type: "object" - required: - - "statement" - properties: - statement: + description: "The display type for marketplaces" + trait_type: type: "string" - validateCreateTable: - type: "object" - required: - - "method" - - "id" - - "jsonrpc" - - "params" + description: "The trait type for marketplaces" + value: + description: "The value of the property" + oneOf: + - type: string + - type: number + - type: integer + - type: boolean + - type: object + example: + { + "display_type": "date", + "trait_type": "created", + "value": 1657113720, + } + schema: + $ref: "#/components/schemas/Schema" + TxnReceipt: + type: object properties: - method: - type: "string" - description: "Method name" - id: - type: "integer" - default: 1 - format: int32 - description: "Request ID" - jsonrpc: - type: "string" - default: "2.0" - description: "JSON-RPC Version (2.0)" - params: - type: "array" - items: - type: "object" - required: - - "create_statement" - properties: - create_statement: - type: "string" - validateWriteQuery: - type: "object" - required: - - "method" - - "id" - - "jsonrpc" - - "params" + tableId: + type: string + example: healthbot_5_1 + txnHash: + type: string + example: "0x400508d7cc035b14cc53f64393a8dafcc55f66ad8f9b44d626744157337e2098" + blockNumber: + type: number + example: 1 + chainId: + type: number + example: 80001 + Info: + type: object properties: - method: - type: "string" - description: "Method name" - id: - type: "integer" - default: 1 - format: int32 - description: "Request ID" - jsonrpc: - type: "string" - default: "2.0" - description: "JSON-RPC Version (2.0)" - params: - type: "array" - items: - type: "object" - required: - - "statement" - properties: - statement: - type: "string" - getReceipt: - type: "object" - required: - - "method" - - "id" - - "jsonrpc" - - "params" + owner: + type: string + example: "0xbAb12215Ed94713A290e0c618fa8177fAb5eFd2D" + name: + type: string + example: "healthbot_5_1" + structure: + type: string + example: "799dcf5ed5cfeb9e221500db95531ab9197224f8fc9cb9452ce30e4b5cea80d1" + Schema: + type: object properties: - method: - type: "string" - description: "Method name" - id: - type: "integer" - default: 1 - format: int32 - description: "Request ID" - jsonrpc: - type: "string" - default: "2.0" - description: "JSON-RPC Version (2.0)" - params: - type: "array" + columns: + type: array items: - type: "object" - required: - - "txn_hash" - properties: - txn_hash: - type: "string" - setController: - type: "object" - required: - - "method" - - "id" - - "jsonrpc" - - "params" + $ref: "#/components/schemas/Column" + tableConstraints: + type: array + items: + type: string + example: ["PRIMARY KEY (id)"] + Column: + type: object properties: - method: - type: "string" - description: "Method name" - id: - type: "integer" - default: 1 - format: int32 - description: "Request ID" - jsonrpc: - type: "string" - default: "2.0" - description: "JSON-RPC Version (2.0)" - params: - type: "array" + name: + type: string + example: "id" + type: + type: string + example: "integer" + constraints: + type: array items: - type: "object" - required: - - "controller" - - "token_id" - properties: - controller: - type: "string" - token_id: - type: "string" + type: string + example: ["NOT NULL", "PRIMARY KEY", "UNIQUE"] From 389b1a90d02d33c436627de1e09ae7e10e84e490 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 08:46:37 -0300 Subject: [PATCH 021/101] spec: remove yaml Signed-off-by: Ignacio Hagopian --- tableland-openapi-spec.yaml | 273 ------------------------------------ 1 file changed, 273 deletions(-) delete mode 100644 tableland-openapi-spec.yaml diff --git a/tableland-openapi-spec.yaml b/tableland-openapi-spec.yaml deleted file mode 100644 index 29ec3db8..00000000 --- a/tableland-openapi-spec.yaml +++ /dev/null @@ -1,273 +0,0 @@ -openapi: 3.0.3 -info: - title: Tableland Validator - OpenAPI 3.0 - description: |- - 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. - - termsOfService: http://docs.tableland.xyz - contact: - name: core devs - email: carson@textile.io - license: - name: Apache 2.0 - url: http://www.apache.org/licenses/LICENSE-2.0.html - version: 1.0.0 -externalDocs: - description: Tableland docs - url: http://docs.tableland.xyz -servers: - - url: https://testnet.tableland.xyz/api/v1 -tags: - - name: query - description: Query the Tableland network - externalDocs: - description: Find out more about queries - url: http://docs.tableland.xyz - - name: receipt - description: Get information about transaction progress - externalDocs: - description: Find out more about receipts - url: http://docs.tableland.xyz - - name: tables - description: Access to table information - externalDocs: - description: Find out more about tables - url: http://docs.tableland.xyz -paths: - /query: - get: - tags: - - query - summary: Query the Tableland network - description: Returns the results of a SQL query against the Tabeland network - operationId: queryFromQuery - parameters: - - name: statement - in: query - description: The SQL query statement - required: true - schema: - type: string - - name: format - in: query - description: > - 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. - required: false - schema: - type: string - enum: - - objects - - table - default: "objects" - - name: extract - in: query - description: Whether or not to extract the JSON object from the single property of the surrounding JSON object. - required: false - schema: - type: boolean - default: false - - name: unwrap - in: query - description: Whether or not to unwrap the returned JSON objects from their surrounding array. - required: false - schema: - type: boolean - default: false - responses: - "200": - description: successful operation - content: - application/json: - schema: - type: object - "400": - description: Invalid query/statement value - /receipt/{chainId}/{txnHash}: - get: - tags: - - receipt - summary: Query the Tableland network for transaction status - description: Returns the status of a given transaction receipt by hash - operationId: receiptByTxnHash - parameters: - - name: chainId - in: path - description: The parent chain to target - required: true - schema: - type: number - - name: txnHash - in: path - description: The transaction hash to request - required: true - schema: - type: string - responses: - "200": - description: successful operation - content: - application/json: - schema: - $ref: "#/components/schemas/TxnReceipt" - "400": - description: Invalid query/statement value - /tables/structure/{hash}: - get: - tags: - - tables - summary: Finds tables by structure - description: Returns all tables that match a given structure - operationId: findTablesByStructure - parameters: - - name: hash - in: path - description: Structure hash to filter on - required: true - schema: - type: string - - name: chainId - in: query - description: The parent chain to filter on - required: false - schema: - type: number - responses: - "200": - description: successful operation - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/Info" - "400": - description: Invalid structure value - /tables/{tableName}: - get: - tags: - - tables - summary: Get information about a table - description: Returns information about a single table, including schema information - operationId: getTableByName - parameters: - - name: tableName - in: path - description: Full name of table to return - required: true - schema: - type: string - responses: - "200": - description: successful operation - content: - application/json: - schema: - $ref: "#/components/schemas/Table" - "400": - description: Invalid name supplied - "404": - description: Table not found -components: - schemas: - Table: - type: object - properties: - name: - type: string - example: healthbot_5_1 - external_url: - type: string - example: https://testnet.tableland.network/tables/healthbot_5_1 - image: - type: string - example: https://render.tableland.xyz/healthbot_5_1 - attributes: - type: array - items: - type: "object" - properties: - display_type: - type: "string" - description: "The display type for marketplaces" - trait_type: - type: "string" - description: "The trait type for marketplaces" - value: - description: "The value of the property" - oneOf: - - type: string - - type: number - - type: integer - - type: boolean - - type: object - example: - { - "display_type": "date", - "trait_type": "created", - "value": 1657113720, - } - schema: - $ref: "#/components/schemas/Schema" - TxnReceipt: - type: object - properties: - tableId: - type: string - example: healthbot_5_1 - txnHash: - type: string - example: "0x400508d7cc035b14cc53f64393a8dafcc55f66ad8f9b44d626744157337e2098" - blockNumber: - type: number - example: 1 - chainId: - type: number - example: 80001 - Info: - type: object - properties: - owner: - type: string - example: "0xbAb12215Ed94713A290e0c618fa8177fAb5eFd2D" - name: - type: string - example: "healthbot_5_1" - structure: - type: string - example: "799dcf5ed5cfeb9e221500db95531ab9197224f8fc9cb9452ce30e4b5cea80d1" - Schema: - type: object - properties: - columns: - type: array - items: - $ref: "#/components/schemas/Column" - tableConstraints: - type: array - items: - type: string - example: ["PRIMARY KEY (id)"] - Column: - type: object - properties: - name: - type: string - example: "id" - type: - type: string - example: "integer" - constraints: - type: array - items: - type: string - example: ["NOT NULL", "PRIMARY KEY", "UNIQUE"] From d15dc716413c98d84804b779312dc618dd183978 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 08:48:23 -0300 Subject: [PATCH 022/101] .gitignore: add api spec file It should always be pulled from a tagged branch in the spec repo. Signed-off-by: Ignacio Hagopian --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 876ea11f..02d00de9 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ evm_history.db # Project .env* *.ignore +tableland-openapi-spec.yaml \ No newline at end of file From e0d236572e69012cdf26d3087df3886661554dc6 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 08:48:59 -0300 Subject: [PATCH 023/101] Makefile: pull api spec from docs repo Signed-off-by: Ignacio Hagopian --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eb44a930..95848a53 100644 --- a/Makefile +++ b/Makefile @@ -85,5 +85,9 @@ lint: .PHONYY: lint # OpenAPI +SPEC_URL=https://raw.githubusercontent.com/tablelandnetwork/docs/spec/validatorapi/specs/validator/tableland-openapi-spec.yaml openapi: - docker run -w /gen -e GEN_DIR=/gen -v ${PWD}:/gen swaggerapi/swagger-codegen-cli-v3 generate --lang go-server -o /gen/tablelandapi -i tableland-openapi-spec.yaml --additional-properties=packageName=tablelandapi \ No newline at end of file + curl -s ${SPEC_URL} > tableland-openapi-spec.yaml + docker run -w /gen -e GEN_DIR=/gen -v ${PWD}:/gen swaggerapi/swagger-codegen-cli-v3 \ + generate --lang go-server -o /gen/tablelandapi -i tableland-openapi-spec.yaml --additional-properties=packageName=tablelandapi + rm tableland-openapi-spec.yaml \ No newline at end of file From e9a873a3efde98fa5074928a3a9ab05e7f3e1f8c Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 10:09:00 -0300 Subject: [PATCH 024/101] Makefile: cleanup openapi generated files Signed-off-by: Ignacio Hagopian --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 95848a53..8ca0b181 100644 --- a/Makefile +++ b/Makefile @@ -90,4 +90,5 @@ openapi: curl -s ${SPEC_URL} > tableland-openapi-spec.yaml docker run -w /gen -e GEN_DIR=/gen -v ${PWD}:/gen swaggerapi/swagger-codegen-cli-v3 \ generate --lang go-server -o /gen/tablelandapi -i tableland-openapi-spec.yaml --additional-properties=packageName=tablelandapi + cd tablelandapi && sudo rm -rf Dockerfile go/README.md api .swagger-codegen .swagger-codegen-ignore rm tableland-openapi-spec.yaml \ No newline at end of file From 953bc5154704e65a4022fe96304496421ce2c18a Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 10:09:28 -0300 Subject: [PATCH 025/101] Makefile: formatting Signed-off-by: Ignacio Hagopian --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index 8ca0b181..b8ec22d1 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,6 @@ GOVVV=go run github.com/ahmetb/govvv@v0.3.0 GOVVV_FLAGS=$(shell $(GOVVV) -flags -version $(BIN_VERSION) -pkg $(shell go list ./buildinfo)) # Code generation - ethereum: ethereum-testcontroller ethereum-testerc721 ethereum-testerc721a go run github.com/ethereum/go-ethereum/cmd/abigen@v1.10.20 --abi ./pkg/tables/impl/ethereum/abi.json --pkg ethereum --type Contract --out pkg/tables/impl/ethereum/contract.go --bin pkg/tables/impl/ethereum/bytecode.bin .PHONY: ethereum @@ -52,7 +51,6 @@ generate-history-db: rm ${EVM_EVENTS_TARGET} # Build - build-api: go build -ldflags="${GOVVV_FLAGS}" ./cmd/api .PHONY: build-api @@ -70,7 +68,6 @@ image: .PHONY: image # Test - test: go test ./... -short -race .PHONY: test @@ -79,7 +76,6 @@ test-replayhistory: go test ./pkg/eventprocessor/impl -run=TestReplayProductionHistory -race # Lint - lint: go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.49.0 run .PHONYY: lint From 13f4e42174c291a0290f1e230b96fe7350de68a9 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 10:50:43 -0300 Subject: [PATCH 026/101] Makefile: remove extra unnecessary file in openapi generated files Signed-off-by: Ignacio Hagopian --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b8ec22d1..58ce4e40 100644 --- a/Makefile +++ b/Makefile @@ -86,5 +86,5 @@ openapi: curl -s ${SPEC_URL} > tableland-openapi-spec.yaml docker run -w /gen -e GEN_DIR=/gen -v ${PWD}:/gen swaggerapi/swagger-codegen-cli-v3 \ generate --lang go-server -o /gen/tablelandapi -i tableland-openapi-spec.yaml --additional-properties=packageName=tablelandapi - cd tablelandapi && sudo rm -rf Dockerfile go/README.md api .swagger-codegen .swagger-codegen-ignore + cd tablelandapi && sudo rm -rf main.go Dockerfile go/README.md api .swagger-codegen .swagger-codegen-ignore rm tableland-openapi-spec.yaml \ No newline at end of file From 79786a11ca1002fcf9872129a1eaac697279f3d1 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 10:51:28 -0300 Subject: [PATCH 027/101] router: avoid log.fatal in internal packages Signed-off-by: Ignacio Hagopian --- cmd/api/main.go | 5 ++++- internal/router/router.go | 18 +++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index aac6c739..5e10b639 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -480,7 +480,7 @@ func createHTTPServer( return nil, fmt.Errorf("parsing http ratelimiter interval: %s", err) } - router := router.ConfiguredRouter( + router, err := router.ConfiguredRouter( gatewayConfig.ExternalURIPrefix, gatewayConfig.MetadataRendererURI, gatewayConfig.AnimationRendererURI, @@ -490,6 +490,9 @@ func createHTTPServer( userStore, chainStacks, ) + if err != nil { + return nil, fmt.Errorf("configuring router: %s", err) + } server := &http.Server{ Addr: ":" + httpConfig.Port, diff --git a/internal/router/router.go b/internal/router/router.go index 26a12c82..a7e1a212 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -1,12 +1,12 @@ package router import ( + "fmt" "net/http" "time" "github.com/ethereum/go-ethereum/rpc" "github.com/gorilla/mux" - "github.com/rs/zerolog/log" "github.com/textileio/go-tableland/internal/chains" "github.com/textileio/go-tableland/internal/router/controllers" "github.com/textileio/go-tableland/internal/router/middlewares" @@ -30,23 +30,23 @@ func ConfiguredRouter( parser parsing.SQLValidator, userStore *user.UserStore, chainStacks map[tableland.ChainID]chains.ChainStack, -) *Router { +) (*Router, error) { instrUserStore, err := sqlstoreimpl.NewInstrumentedUserStore(userStore) if err != nil { - log.Fatal().Err(err).Msg("creating instrumented user store") + return nil, fmt.Errorf("creating instrumented user store: %s", err) } mesaService := impl.NewTablelandMesa(parser, instrUserStore, chainStacks) mesaService, err = impl.NewInstrumentedTablelandMesa(mesaService) if err != nil { - log.Fatal().Err(err).Msg("instrumenting mesa") + return nil, fmt.Errorf("instrumenting mesa: %s", err) } rpcService := rpcservice.NewRPCService(mesaService) userController := controllers.NewUserController(mesaService) server := rpc.NewServer() if err := server.RegisterName("tableland", rpcService); err != nil { - log.Fatal().Err(err).Msg("failed to register a json-rpc service") + return nil, fmt.Errorf("failed to register a json-rpc service: %s", err) } infraController := controllers.NewInfraController() @@ -56,11 +56,11 @@ func ConfiguredRouter( } sysStore, err := systemimpl.NewSystemSQLStoreService(stores, extURLPrefix, metadataRendererURI, animationRendererURI) if err != nil { - log.Fatal().Err(err).Msg("creating system store") + return nil, fmt.Errorf("creating system store: %s", err) } systemService, err := systemimpl.NewInstrumentedSystemSQLStoreService(sysStore) if err != nil { - log.Fatal().Err(err).Msg("instrumenting system sql store") + return nil, fmt.Errorf("instrumenting system sql store: %s", err) } systemController := controllers.NewSystemController(systemService) @@ -78,7 +78,7 @@ func ConfiguredRouter( } rateLim, err := middlewares.RateLimitController(cfg) if err != nil { - log.Fatal().Err(err).Msg("creating rate limit controller middleware") + return nil, fmt.Errorf("creating rate limit controller middleware: %s", err) } router.Post("/rpc", func(rw http.ResponseWriter, r *http.Request) { @@ -99,7 +99,7 @@ func ConfiguredRouter( router.Get("/healthz", healthHandler) router.Get("/health", healthHandler) - return router + return router, nil } func healthHandler(w http.ResponseWriter, _ *http.Request) { From 395e28a1cb67dc4766b4c1ea1d145d5058cb094e Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 15:12:37 -0300 Subject: [PATCH 028/101] Makefile: improve api spec autogeneration Signed-off-by: Ignacio Hagopian --- Makefile | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 58ce4e40..101b9e4e 100644 --- a/Makefile +++ b/Makefile @@ -78,13 +78,19 @@ test-replayhistory: # Lint lint: go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.49.0 run -.PHONYY: lint +.PHONY: lint # OpenAPI SPEC_URL=https://raw.githubusercontent.com/tablelandnetwork/docs/spec/validatorapi/specs/validator/tableland-openapi-spec.yaml -openapi: - curl -s ${SPEC_URL} > tableland-openapi-spec.yaml - docker run -w /gen -e GEN_DIR=/gen -v ${PWD}:/gen swaggerapi/swagger-codegen-cli-v3 \ - generate --lang go-server -o /gen/tablelandapi -i tableland-openapi-spec.yaml --additional-properties=packageName=tablelandapi - cd tablelandapi && sudo rm -rf main.go Dockerfile go/README.md api .swagger-codegen .swagger-codegen-ignore - rm tableland-openapi-spec.yaml \ No newline at end of file +APIV1=${PWD}/internal/router/controllers/apiv1 +gen-api-v1: + mkdir -p ${APIV1} + curl -s ${SPEC_URL} > ${APIV1}/tableland-openapi-spec.yaml + docker run -w /gen -e GEN_DIR=/gen -v ${APIV1}:/gen swaggerapi/swagger-codegen-cli-v3 \ + generate --lang go-server -o /gen -i tableland-openapi-spec.yaml --additional-properties=packageName=apiv1 + sudo chown -R ${USER} ${APIV1} + cd ${APIV1} && \ + mv go/* . && \ + rm -rf go main.go Dockerfile README.md api .swagger-codegen .swagger-codegen-ignore + rm ${APIV1}/tableland-openapi-spec.yaml +.PHONY: gen-api-v1 \ No newline at end of file From 12bd2fb7388ac59ab5e910eb7e9e9286dfbbd28e Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 29 Nov 2022 15:34:21 -0300 Subject: [PATCH 029/101] router/controllers: refactoring and code generation Signed-off-by: Ignacio Hagopian --- cmd/healthbot/counterprobe/counterprobe.go | 12 +-- .../router/controllers/apiv1/api_query.go | 19 +++++ .../router/controllers/apiv1/api_receipt.go | 19 +++++ .../router/controllers/apiv1/api_tables.go | 24 ++++++ internal/router/controllers/apiv1/logger.go | 32 +++++++ .../router/controllers/apiv1/model_column.go | 19 +++++ .../router/controllers/apiv1/model_info.go | 19 +++++ .../model_one_of_table_attributes_value.go | 13 +++ .../router/controllers/apiv1/model_schema.go | 17 ++++ .../router/controllers/apiv1/model_table.go | 23 +++++ .../apiv1/model_table_attributes.go | 19 +++++ .../controllers/apiv1/model_txn_receipt.go | 21 +++++ internal/router/controllers/apiv1/routers.go | 85 +++++++++++++++++++ .../router/controllers/{ => legacy}/infra.go | 2 +- .../legacy}/rpcservice.go | 5 +- .../legacy}/rpcservice_test.go | 2 +- .../router/controllers/{ => legacy}/system.go | 2 +- .../controllers/{ => legacy}/system_test.go | 2 +- .../router/controllers/{ => legacy}/user.go | 2 +- .../controllers/{ => legacy}/user_test.go | 2 +- internal/router/router.go | 11 ++- pkg/client/client.go | 38 ++++----- pkg/client/client_test.go | 3 +- 23 files changed, 350 insertions(+), 41 deletions(-) create mode 100644 internal/router/controllers/apiv1/api_query.go create mode 100644 internal/router/controllers/apiv1/api_receipt.go create mode 100644 internal/router/controllers/apiv1/api_tables.go create mode 100644 internal/router/controllers/apiv1/logger.go create mode 100644 internal/router/controllers/apiv1/model_column.go create mode 100644 internal/router/controllers/apiv1/model_info.go create mode 100644 internal/router/controllers/apiv1/model_one_of_table_attributes_value.go create mode 100644 internal/router/controllers/apiv1/model_schema.go create mode 100644 internal/router/controllers/apiv1/model_table.go create mode 100644 internal/router/controllers/apiv1/model_table_attributes.go create mode 100644 internal/router/controllers/apiv1/model_txn_receipt.go create mode 100644 internal/router/controllers/apiv1/routers.go rename internal/router/controllers/{ => legacy}/infra.go (96%) rename internal/router/{rpcservice => controllers/legacy}/rpcservice.go (98%) rename internal/router/{rpcservice => controllers/legacy}/rpcservice_test.go (99%) rename internal/router/controllers/{ => legacy}/system.go (99%) rename internal/router/controllers/{ => legacy}/system_test.go (99%) rename internal/router/controllers/{ => legacy}/user.go (99%) rename internal/router/controllers/{ => legacy}/user_test.go (99%) diff --git a/cmd/healthbot/counterprobe/counterprobe.go b/cmd/healthbot/counterprobe/counterprobe.go index 7d7d7473..037d4759 100644 --- a/cmd/healthbot/counterprobe/counterprobe.go +++ b/cmd/healthbot/counterprobe/counterprobe.go @@ -10,7 +10,7 @@ import ( "github.com/rs/zerolog" logger "github.com/rs/zerolog/log" - "github.com/textileio/go-tableland/internal/router/rpcservice" + "github.com/textileio/go-tableland/internal/router/controllers/legacy" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric/instrument/syncint64" @@ -149,22 +149,22 @@ func (cp *CounterProbe) healthCheck(ctx context.Context) (int64, error) { } func (cp *CounterProbe) increaseCounterValue(ctx context.Context) error { - updateCounterReq := rpcservice.RelayWriteQueryRequest{ + updateCounterReq := legacy.RelayWriteQueryRequest{ Statement: fmt.Sprintf("update %s set counter=counter+1", cp.tableName), } - var updateCounterRes rpcservice.RelayWriteQueryResponse + var updateCounterRes legacy.RelayWriteQueryResponse if err := cp.rpcClient.CallContext(ctx, &updateCounterRes, "tableland_relayWriteQuery", updateCounterReq); err != nil { return fmt.Errorf("calling tableland_runReadQuery: %s", err) } - getReceiptRequest := rpcservice.GetReceiptRequest{ + getReceiptRequest := legacy.GetReceiptRequest{ TxnHash: updateCounterRes.Transaction.Hash, } start := time.Now() deadline := time.Now().Add(cp.receiptTimeout) for time.Now().Before(deadline) { - var getReceiptResponse rpcservice.GetReceiptResponse + var getReceiptResponse legacy.GetReceiptResponse if err := cp.rpcClient.CallContext(ctx, &getReceiptResponse, "tableland_getReceipt", getReceiptRequest); err != nil { return fmt.Errorf("calling tableland_getReceipt: %s", err) } @@ -183,7 +183,7 @@ func (cp *CounterProbe) increaseCounterValue(ctx context.Context) error { func (cp *CounterProbe) getCurrentCounterValue(ctx context.Context) (int64, error) { output := "table" - getCounterReq := rpcservice.RunReadQueryRequest{ + getCounterReq := legacy.RunReadQueryRequest{ Statement: fmt.Sprintf("select * from %s", cp.tableName), Output: &output, } diff --git a/internal/router/controllers/apiv1/api_query.go b/internal/router/controllers/apiv1/api_query.go new file mode 100644 index 00000000..692b8502 --- /dev/null +++ b/internal/router/controllers/apiv1/api_query.go @@ -0,0 +1,19 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +import ( + "net/http" +) + +func QueryFromQuery(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 new file mode 100644 index 00000000..daa0d64a --- /dev/null +++ b/internal/router/controllers/apiv1/api_receipt.go @@ -0,0 +1,19 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +import ( + "net/http" +) + +func ReceiptByTxnHash(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_tables.go b/internal/router/controllers/apiv1/api_tables.go new file mode 100644 index 00000000..4c0e6028 --- /dev/null +++ b/internal/router/controllers/apiv1/api_tables.go @@ -0,0 +1,24 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +import ( + "net/http" +) + +func FindTablesByStructure(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func GetTableByName(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/logger.go b/internal/router/controllers/apiv1/logger.go new file mode 100644 index 00000000..ed473ba0 --- /dev/null +++ b/internal/router/controllers/apiv1/logger.go @@ -0,0 +1,32 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/internal/router/controllers/apiv1/model_column.go b/internal/router/controllers/apiv1/model_column.go new file mode 100644 index 00000000..56b9e071 --- /dev/null +++ b/internal/router/controllers/apiv1/model_column.go @@ -0,0 +1,19 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type Column struct { + + Name string `json:"name,omitempty"` + + Type_ string `json:"type,omitempty"` + + Constraints []string `json:"constraints,omitempty"` +} diff --git a/internal/router/controllers/apiv1/model_info.go b/internal/router/controllers/apiv1/model_info.go new file mode 100644 index 00000000..150be2a3 --- /dev/null +++ b/internal/router/controllers/apiv1/model_info.go @@ -0,0 +1,19 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type Info struct { + + Owner string `json:"owner,omitempty"` + + Name string `json:"name,omitempty"` + + Structure string `json:"structure,omitempty"` +} 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 new file mode 100644 index 00000000..b0bf2f62 --- /dev/null +++ b/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go @@ -0,0 +1,13 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type OneOfTableAttributesValue struct { +} diff --git a/internal/router/controllers/apiv1/model_schema.go b/internal/router/controllers/apiv1/model_schema.go new file mode 100644 index 00000000..8535b5a4 --- /dev/null +++ b/internal/router/controllers/apiv1/model_schema.go @@ -0,0 +1,17 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type Schema struct { + + Columns []Column `json:"columns,omitempty"` + + TableConstraints []string `json:"tableConstraints,omitempty"` +} diff --git a/internal/router/controllers/apiv1/model_table.go b/internal/router/controllers/apiv1/model_table.go new file mode 100644 index 00000000..3aa3dfce --- /dev/null +++ b/internal/router/controllers/apiv1/model_table.go @@ -0,0 +1,23 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type Table struct { + + Name string `json:"name,omitempty"` + + ExternalUrl string `json:"external_url,omitempty"` + + Image string `json:"image,omitempty"` + + Attributes []TableAttributes `json:"attributes,omitempty"` + + Schema *Schema `json:"schema,omitempty"` +} diff --git a/internal/router/controllers/apiv1/model_table_attributes.go b/internal/router/controllers/apiv1/model_table_attributes.go new file mode 100644 index 00000000..1b51c0b8 --- /dev/null +++ b/internal/router/controllers/apiv1/model_table_attributes.go @@ -0,0 +1,19 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type TableAttributes struct { + // The display type for marketplaces + DisplayType string `json:"display_type,omitempty"` + // The trait type for marketplaces + TraitType string `json:"trait_type,omitempty"` + // The value of the property + Value *OneOfTableAttributesValue `json:"value,omitempty"` +} diff --git a/internal/router/controllers/apiv1/model_txn_receipt.go b/internal/router/controllers/apiv1/model_txn_receipt.go new file mode 100644 index 00000000..245cfa05 --- /dev/null +++ b/internal/router/controllers/apiv1/model_txn_receipt.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 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type TxnReceipt struct { + + TableId string `json:"tableId,omitempty"` + + TxnHash string `json:"txnHash,omitempty"` + + BlockNumber int64 `json:"blockNumber,omitempty"` + + ChainId int32 `json:"chainId,omitempty"` +} diff --git a/internal/router/controllers/apiv1/routers.go b/internal/router/controllers/apiv1/routers.go new file mode 100644 index 00000000..b3fca249 --- /dev/null +++ b/internal/router/controllers/apiv1/routers.go @@ -0,0 +1,85 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "/api/v1/", + Index, + }, + + Route{ + "QueryFromQuery", + strings.ToUpper("Get"), + "/api/v1/query", + QueryFromQuery, + }, + + Route{ + "ReceiptByTxnHash", + strings.ToUpper("Get"), + "/api/v1/receipt/{chainId}/{txnHash}", + ReceiptByTxnHash, + }, + + Route{ + "FindTablesByStructure", + strings.ToUpper("Get"), + "/api/v1/tables/structure/{hash}", + FindTablesByStructure, + }, + + Route{ + "GetTableByName", + strings.ToUpper("Get"), + "/api/v1/tables/{tableName}", + GetTableByName, + }, +} diff --git a/internal/router/controllers/infra.go b/internal/router/controllers/legacy/infra.go similarity index 96% rename from internal/router/controllers/infra.go rename to internal/router/controllers/legacy/infra.go index 3ae77b1b..fbcdd8dc 100644 --- a/internal/router/controllers/infra.go +++ b/internal/router/controllers/legacy/infra.go @@ -1,4 +1,4 @@ -package controllers +package legacy import ( "encoding/json" diff --git a/internal/router/rpcservice/rpcservice.go b/internal/router/controllers/legacy/rpcservice.go similarity index 98% rename from internal/router/rpcservice/rpcservice.go rename to internal/router/controllers/legacy/rpcservice.go index c1d939a4..0c0d2950 100644 --- a/internal/router/rpcservice/rpcservice.go +++ b/internal/router/controllers/legacy/rpcservice.go @@ -1,4 +1,4 @@ -package rpcservice +package legacy import ( "context" @@ -9,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/textileio/go-tableland/internal/formatter" - "github.com/textileio/go-tableland/internal/router/controllers" "github.com/textileio/go-tableland/internal/router/middlewares" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/tables" @@ -211,7 +210,7 @@ func (rs *RPCService) RunReadQuery( return RunReadQueryResponse{}, errors.New("unwrapped results with more than one row aren't supported in JSON RPC API") } - controllers.CollectReadQueryMetric(ctx, req.Statement, config, took) + CollectReadQueryMetric(ctx, req.Statement, config, took) return RunReadQueryResponse{Result: json.RawMessage(formatted)}, nil } diff --git a/internal/router/rpcservice/rpcservice_test.go b/internal/router/controllers/legacy/rpcservice_test.go similarity index 99% rename from internal/router/rpcservice/rpcservice_test.go rename to internal/router/controllers/legacy/rpcservice_test.go index 3f50ccef..0981ec28 100644 --- a/internal/router/rpcservice/rpcservice_test.go +++ b/internal/router/controllers/legacy/rpcservice_test.go @@ -1,4 +1,4 @@ -package rpcservice +package legacy import ( "net/http" diff --git a/internal/router/controllers/system.go b/internal/router/controllers/legacy/system.go similarity index 99% rename from internal/router/controllers/system.go rename to internal/router/controllers/legacy/system.go index 3bec5313..18a1caaa 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/legacy/system.go @@ -1,4 +1,4 @@ -package controllers +package legacy import ( "encoding/json" diff --git a/internal/router/controllers/system_test.go b/internal/router/controllers/legacy/system_test.go similarity index 99% rename from internal/router/controllers/system_test.go rename to internal/router/controllers/legacy/system_test.go index 2b7c7db6..9997b441 100644 --- a/internal/router/controllers/system_test.go +++ b/internal/router/controllers/legacy/system_test.go @@ -1,4 +1,4 @@ -package controllers +package legacy import ( "fmt" diff --git a/internal/router/controllers/user.go b/internal/router/controllers/legacy/user.go similarity index 99% rename from internal/router/controllers/user.go rename to internal/router/controllers/legacy/user.go index ba5e87a1..cb3d0494 100644 --- a/internal/router/controllers/user.go +++ b/internal/router/controllers/legacy/user.go @@ -1,4 +1,4 @@ -package controllers +package legacy import ( "context" diff --git a/internal/router/controllers/user_test.go b/internal/router/controllers/legacy/user_test.go similarity index 99% rename from internal/router/controllers/user_test.go rename to internal/router/controllers/legacy/user_test.go index 41cb9acf..e1ba7448 100644 --- a/internal/router/controllers/user_test.go +++ b/internal/router/controllers/legacy/user_test.go @@ -1,4 +1,4 @@ -package controllers +package legacy import ( "errors" diff --git a/internal/router/router.go b/internal/router/router.go index a7e1a212..ba24a20a 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -8,9 +8,8 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/gorilla/mux" "github.com/textileio/go-tableland/internal/chains" - "github.com/textileio/go-tableland/internal/router/controllers" + "github.com/textileio/go-tableland/internal/router/controllers/legacy" "github.com/textileio/go-tableland/internal/router/middlewares" - "github.com/textileio/go-tableland/internal/router/rpcservice" systemimpl "github.com/textileio/go-tableland/internal/system/impl" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/internal/tableland/impl" @@ -41,14 +40,14 @@ func ConfiguredRouter( if err != nil { return nil, fmt.Errorf("instrumenting mesa: %s", err) } - rpcService := rpcservice.NewRPCService(mesaService) - userController := controllers.NewUserController(mesaService) + rpcService := legacy.NewRPCService(mesaService) + userController := legacy.NewUserController(mesaService) server := rpc.NewServer() if err := server.RegisterName("tableland", rpcService); err != nil { return nil, fmt.Errorf("failed to register a json-rpc service: %s", err) } - infraController := controllers.NewInfraController() + infraController := legacy.NewInfraController() stores := make(map[tableland.ChainID]sqlstore.SystemStore, len(chainStacks)) for chainID, stack := range chainStacks { @@ -62,7 +61,7 @@ func ConfiguredRouter( if err != nil { return nil, fmt.Errorf("instrumenting system sql store: %s", err) } - systemController := controllers.NewSystemController(systemService) + systemController := legacy.NewSystemController(systemService) // General router configuration. router := NewRouter() diff --git a/pkg/client/client.go b/pkg/client/client.go index 4bf0314d..47010620 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" - "github.com/textileio/go-tableland/internal/router/rpcservice" + "github.com/textileio/go-tableland/internal/router/controllers/legacy" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/siwe" @@ -251,8 +251,8 @@ func (c *Client) Create(ctx context.Context, schema string, opts ...CreateOption } createStatement := fmt.Sprintf("CREATE TABLE %s_%d %s", conf.prefix, c.chain.ID, schema) - req := &rpcservice.ValidateCreateTableRequest{CreateStatement: createStatement} - var res rpcservice.ValidateCreateTableResponse + req := &legacy.ValidateCreateTableRequest{CreateStatement: createStatement} + var res legacy.ValidateCreateTableResponse if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateCreateTable", req); err != nil { return TableID{}, "", fmt.Errorf("calling rpc validateCreateTable: %v", err) @@ -290,11 +290,11 @@ const ( ) // ReadOption controls the behavior of Read. -type ReadOption func(*rpcservice.RunReadQueryRequest) +type ReadOption func(*legacy.RunReadQueryRequest) // ReadOutput sets the output format. Default is Objects. func ReadOutput(output Output) ReadOption { - return func(rrqr *rpcservice.RunReadQueryRequest) { + return func(rrqr *legacy.RunReadQueryRequest) { rrqr.Output = (*string)(&output) } } @@ -303,7 +303,7 @@ func ReadOutput(output Output) ReadOption { // from the single property of the surrounding JSON object. // Default is false. func ReadExtract() ReadOption { - return func(rrqr *rpcservice.RunReadQueryRequest) { + return func(rrqr *legacy.RunReadQueryRequest) { v := true rrqr.Extract = &v } @@ -312,7 +312,7 @@ func ReadExtract() ReadOption { // ReadUnwrap specifies whether or not to unwrap the returned JSON objects from their surrounding array. // Default is false. func ReadUnwrap() ReadOption { - return func(rrqr *rpcservice.RunReadQueryRequest) { + return func(rrqr *legacy.RunReadQueryRequest) { v := true rrqr.Unwrap = &v } @@ -320,11 +320,11 @@ func ReadUnwrap() ReadOption { // Read runs a read query with the provided opts and unmarshals the results into target. func (c *Client) Read(ctx context.Context, query string, target interface{}, opts ...ReadOption) error { - req := &rpcservice.RunReadQueryRequest{Statement: query} + req := &legacy.RunReadQueryRequest{Statement: query} for _, opt := range opts { opt(req) } - res := &rpcservice.RunReadQueryResponse{ + res := &legacy.RunReadQueryResponse{ Result: target, } if err := c.tblRPC.CallContext(ctx, &res, "tableland_runReadQuery", req); err != nil { @@ -355,8 +355,8 @@ func (c *Client) Write(ctx context.Context, query string, opts ...WriteOption) ( opt(&conf) } if conf.relay { - req := &rpcservice.RelayWriteQueryRequest{Statement: query} - var res rpcservice.RelayWriteQueryResponse + req := &legacy.RelayWriteQueryRequest{Statement: query} + var res legacy.RelayWriteQueryResponse if err := c.tblRPC.CallContext(ctx, &res, "tableland_relayWriteQuery", req); err != nil { return "", fmt.Errorf("calling rpc relayWriteQuery: %v", err) } @@ -375,8 +375,8 @@ func (c *Client) Write(ctx context.Context, query string, opts ...WriteOption) ( // Hash validates the provided create table statement and returns its hash. func (c *Client) Hash(ctx context.Context, statement string) (string, error) { - req := &rpcservice.ValidateCreateTableRequest{CreateStatement: statement} - var res rpcservice.ValidateCreateTableResponse + req := &legacy.ValidateCreateTableRequest{CreateStatement: statement} + var res legacy.ValidateCreateTableResponse if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateCreateTable", req); err != nil { return "", fmt.Errorf("calling rpc validateCreateTable: %v", err) } @@ -385,8 +385,8 @@ func (c *Client) Hash(ctx context.Context, statement string) (string, error) { // Validate validates a write query, returning the table id. func (c *Client) Validate(ctx context.Context, statement string) (TableID, error) { - req := &rpcservice.ValidateWriteQueryRequest{Statement: statement} - var res rpcservice.ValidateWriteQueryResponse + req := &legacy.ValidateWriteQueryRequest{Statement: statement} + var res legacy.ValidateWriteQueryResponse if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateWriteQuery", req); err != nil { return TableID{}, fmt.Errorf("calling rpc validateWriteQuery: %v", err) } @@ -434,8 +434,8 @@ func (c *Client) SetController( controller common.Address, tableID TableID, ) (string, error) { - req := rpcservice.SetControllerRequest{Controller: controller.Hex(), TokenID: tableID.String()} - var res rpcservice.SetControllerResponse + req := legacy.SetControllerRequest{Controller: controller.Hex(), TokenID: tableID.String()} + var res legacy.SetControllerResponse if err := c.tblRPC.CallContext(ctx, &res, "tableland_setController", req); err != nil { return "", fmt.Errorf("calling rpc setController: %v", err) @@ -445,8 +445,8 @@ func (c *Client) SetController( } func (c *Client) getReceipt(ctx context.Context, txnHash string) (*TxnReceipt, bool, error) { - req := rpcservice.GetReceiptRequest{TxnHash: txnHash} - var res rpcservice.GetReceiptResponse + req := legacy.GetReceiptRequest{TxnHash: txnHash} + var res legacy.GetReceiptResponse if err := c.tblRPC.CallContext(ctx, &res, "tableland_getReceipt", req); err != nil { return nil, false, fmt.Errorf("calling rpc getReceipt: %v", err) } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 2b195dce..68e01adf 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -223,7 +223,7 @@ func setup(t *testing.T) clientCalls { }, } - router := router.ConfiguredRouter( + router, err := router.ConfiguredRouter( "https://testnet.tableland.network", "https://render.tableland.xyz", "", @@ -233,6 +233,7 @@ func setup(t *testing.T) clientCalls { userStore, chainStack, ) + require.NoError(t, err) server := httptest.NewServer(router.Handler()) From 2e728a8e34aec4a3bc0d7e2a745055e528426d35 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 1 Dec 2022 13:15:57 -0300 Subject: [PATCH 030/101] internal/router: refactoring && code gen Signed-off-by: Ignacio Hagopian --- Makefile | 2 +- .../router/controllers/apiv1/api_health.go | 19 +++ .../router/controllers/apiv1/api_tables.go | 7 +- .../router/controllers/apiv1/api_version.go | 19 +++ .../controllers/apiv1/model_txn_receipt.go | 2 +- .../controllers/apiv1/model_version_info.go | 27 ++++ internal/router/controllers/apiv1/routers.go | 19 ++- .../router/controllers/{legacy => }/infra.go | 2 +- .../router/controllers/{legacy => }/system.go | 8 +- .../controllers/{legacy => }/system_test.go | 2 +- .../router/controllers/{legacy => }/user.go | 2 +- .../controllers/{legacy => }/user_test.go | 2 +- internal/router/middlewares/rest.go | 2 +- internal/router/router.go | 118 +++++++++++++----- 14 files changed, 176 insertions(+), 55 deletions(-) create mode 100644 internal/router/controllers/apiv1/api_health.go create mode 100644 internal/router/controllers/apiv1/api_version.go create mode 100644 internal/router/controllers/apiv1/model_version_info.go rename internal/router/controllers/{legacy => }/infra.go (96%) rename internal/router/controllers/{legacy => }/system.go (97%) rename internal/router/controllers/{legacy => }/system_test.go (99%) rename internal/router/controllers/{legacy => }/user.go (99%) rename internal/router/controllers/{legacy => }/user_test.go (99%) diff --git a/Makefile b/Makefile index 101b9e4e..d33df963 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ lint: .PHONY: lint # OpenAPI -SPEC_URL=https://raw.githubusercontent.com/tablelandnetwork/docs/spec/validatorapi/specs/validator/tableland-openapi-spec.yaml +SPEC_URL=https://raw.githubusercontent.com/tablelandnetwork/docs/jsign/vh/specs/validator/tableland-openapi-spec.yaml APIV1=${PWD}/internal/router/controllers/apiv1 gen-api-v1: mkdir -p ${APIV1} diff --git a/internal/router/controllers/apiv1/api_health.go b/internal/router/controllers/apiv1/api_health.go new file mode 100644 index 00000000..c1a4e465 --- /dev/null +++ b/internal/router/controllers/apiv1/api_health.go @@ -0,0 +1,19 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +import ( + "net/http" +) + +func Health(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_tables.go b/internal/router/controllers/apiv1/api_tables.go index 4c0e6028..fced67cc 100644 --- a/internal/router/controllers/apiv1/api_tables.go +++ b/internal/router/controllers/apiv1/api_tables.go @@ -13,12 +13,7 @@ import ( "net/http" ) -func FindTablesByStructure(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - w.WriteHeader(http.StatusOK) -} - -func GetTableByName(w http.ResponseWriter, r *http.Request) { +func GetTableById(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_version.go b/internal/router/controllers/apiv1/api_version.go new file mode 100644 index 00000000..3f4aa476 --- /dev/null +++ b/internal/router/controllers/apiv1/api_version.go @@ -0,0 +1,19 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +import ( + "net/http" +) + +func Version(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/model_txn_receipt.go b/internal/router/controllers/apiv1/model_txn_receipt.go index 245cfa05..36a04898 100644 --- a/internal/router/controllers/apiv1/model_txn_receipt.go +++ b/internal/router/controllers/apiv1/model_txn_receipt.go @@ -11,7 +11,7 @@ package apiv1 type TxnReceipt struct { - TableId string `json:"tableId,omitempty"` + TableId string `json:"table_id,omitempty"` TxnHash string `json:"txnHash,omitempty"` diff --git a/internal/router/controllers/apiv1/model_version_info.go b/internal/router/controllers/apiv1/model_version_info.go new file mode 100644 index 00000000..ae404897 --- /dev/null +++ b/internal/router/controllers/apiv1/model_version_info.go @@ -0,0 +1,27 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type VersionInfo struct { + + Version string `json:"version,omitempty"` + + GitCommit string `json:"gitCommit,omitempty"` + + GitBranch string `json:"gitBranch,omitempty"` + + GitState string `json:"gitState,omitempty"` + + GitSummary string `json:"gitSummary,omitempty"` + + BuildDate string `json:"buildDate,omitempty"` + + BinaryVersion string `json:"binary_version,omitempty"` +} diff --git a/internal/router/controllers/apiv1/routers.go b/internal/router/controllers/apiv1/routers.go index b3fca249..3d5ad0ad 100644 --- a/internal/router/controllers/apiv1/routers.go +++ b/internal/router/controllers/apiv1/routers.go @@ -55,6 +55,13 @@ var routes = Routes{ Index, }, + Route{ + "Health", + strings.ToUpper("Get"), + "/api/v1/health", + Health, + }, + Route{ "QueryFromQuery", strings.ToUpper("Get"), @@ -70,16 +77,16 @@ var routes = Routes{ }, Route{ - "FindTablesByStructure", + "GetTableById", strings.ToUpper("Get"), - "/api/v1/tables/structure/{hash}", - FindTablesByStructure, + "/api/v1/tables/{chainId}/{tableId}", + GetTableById, }, Route{ - "GetTableByName", + "Version", strings.ToUpper("Get"), - "/api/v1/tables/{tableName}", - GetTableByName, + "/api/v1/version", + Version, }, } diff --git a/internal/router/controllers/legacy/infra.go b/internal/router/controllers/infra.go similarity index 96% rename from internal/router/controllers/legacy/infra.go rename to internal/router/controllers/infra.go index fbcdd8dc..3ae77b1b 100644 --- a/internal/router/controllers/legacy/infra.go +++ b/internal/router/controllers/infra.go @@ -1,4 +1,4 @@ -package legacy +package controllers import ( "encoding/json" diff --git a/internal/router/controllers/legacy/system.go b/internal/router/controllers/system.go similarity index 97% rename from internal/router/controllers/legacy/system.go rename to internal/router/controllers/system.go index 18a1caaa..85ab2012 100644 --- a/internal/router/controllers/legacy/system.go +++ b/internal/router/controllers/system.go @@ -1,4 +1,4 @@ -package legacy +package controllers import ( "encoding/json" @@ -27,7 +27,7 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-type", "application/json") vars := mux.Vars(r) - id, err := tables.NewTableID(vars["id"]) + id, err := tables.NewTableID(vars["tableId"]) if err != nil { rw.WriteHeader(http.StatusBadRequest) log.Ctx(ctx). @@ -197,3 +197,7 @@ func (c *SystemController) GetSchemaByTableName(rw http.ResponseWriter, r *http. TableConstraints: schema.TableConstraints, }) } + +func HealthHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} diff --git a/internal/router/controllers/legacy/system_test.go b/internal/router/controllers/system_test.go similarity index 99% rename from internal/router/controllers/legacy/system_test.go rename to internal/router/controllers/system_test.go index 9997b441..2b7c7db6 100644 --- a/internal/router/controllers/legacy/system_test.go +++ b/internal/router/controllers/system_test.go @@ -1,4 +1,4 @@ -package legacy +package controllers import ( "fmt" diff --git a/internal/router/controllers/legacy/user.go b/internal/router/controllers/user.go similarity index 99% rename from internal/router/controllers/legacy/user.go rename to internal/router/controllers/user.go index cb3d0494..ba5e87a1 100644 --- a/internal/router/controllers/legacy/user.go +++ b/internal/router/controllers/user.go @@ -1,4 +1,4 @@ -package legacy +package controllers import ( "context" diff --git a/internal/router/controllers/legacy/user_test.go b/internal/router/controllers/user_test.go similarity index 99% rename from internal/router/controllers/legacy/user_test.go rename to internal/router/controllers/user_test.go index e1ba7448..41cb9acf 100644 --- a/internal/router/controllers/legacy/user_test.go +++ b/internal/router/controllers/user_test.go @@ -1,4 +1,4 @@ -package legacy +package controllers import ( "errors" diff --git a/internal/router/middlewares/rest.go b/internal/router/middlewares/rest.go index 59bf10d8..a16752d7 100644 --- a/internal/router/middlewares/rest.go +++ b/internal/router/middlewares/rest.go @@ -16,7 +16,7 @@ func RESTChainID(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - chainID, err := strconv.ParseInt(vars["chainID"], 10, 64) + chainID, err := strconv.ParseInt(vars["chainId"], 10, 64) if err != nil { w.WriteHeader(http.StatusBadRequest) _ = json.NewEncoder(w).Encode(errors.ServiceError{Message: "no chain id in path"}) diff --git a/internal/router/router.go b/internal/router/router.go index ba24a20a..44b10844 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/gorilla/mux" "github.com/textileio/go-tableland/internal/chains" + "github.com/textileio/go-tableland/internal/router/controllers" + "github.com/textileio/go-tableland/internal/router/controllers/apiv1" "github.com/textileio/go-tableland/internal/router/controllers/legacy" "github.com/textileio/go-tableland/internal/router/middlewares" systemimpl "github.com/textileio/go-tableland/internal/system/impl" @@ -41,13 +43,13 @@ func ConfiguredRouter( return nil, fmt.Errorf("instrumenting mesa: %s", err) } rpcService := legacy.NewRPCService(mesaService) - userController := legacy.NewUserController(mesaService) - server := rpc.NewServer() if err := server.RegisterName("tableland", rpcService); err != nil { return nil, fmt.Errorf("failed to register a json-rpc service: %s", err) } - infraController := legacy.NewInfraController() + userController := controllers.NewUserController(mesaService) + + infraController := controllers.NewInfraController() stores := make(map[tableland.ChainID]sqlstore.SystemStore, len(chainStacks)) for chainID, stack := range chainStacks { @@ -61,11 +63,11 @@ func ConfiguredRouter( if err != nil { return nil, fmt.Errorf("instrumenting system sql store: %s", err) } - systemController := legacy.NewSystemController(systemService) + systemController := controllers.NewSystemController(systemService) // General router configuration. - router := NewRouter() - router.Use(middlewares.CORS, middlewares.TraceID) + router := newRouter() + router.use(middlewares.CORS, middlewares.TraceID) // RPC configuration. cfg := middlewares.RateLimiterConfig{ @@ -80,29 +82,84 @@ func ConfiguredRouter( return nil, fmt.Errorf("creating rate limit controller middleware: %s", err) } - router.Post("/rpc", func(rw http.ResponseWriter, r *http.Request) { + if err := configureLegacyAPI(router, server, rateLim, systemController, userController, infraController); err != nil { + return nil, fmt.Errorf("configuring legacy API: %s", err) + } + if err := configureAPIv1(router, rateLim, systemController, userController, infraController); err != nil { + return nil, fmt.Errorf("configuring API v1: %s", err) + } + + return router, nil +} + +func configureLegacyAPI( + router *Router, + server *rpc.Server, + rateLim mux.MiddlewareFunc, + systemController *controllers.SystemController, + userController *controllers.UserController, + infraController *controllers.InfraController, +) error { + router.post("/rpc", func(rw http.ResponseWriter, r *http.Request) { server.ServeHTTP(rw, r) }, middlewares.WithLogging, middlewares.OtelHTTP("rpc"), middlewares.Authentication, rateLim) // Gateway configuration. - router.Get("/chain/{chainID}/tables/{id}", systemController.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID, rateLim) // nolint - router.Get("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID, rateLim) // nolint - router.Get("/chain/{chainID}/tables/controller/{address}", systemController.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID, rateLim) // nolint - router.Get("/chain/{chainID}/tables/structure/{hash}", systemController.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID, rateLim) // nolint - router.Get("/schema/{table_name}", systemController.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint + router.get("/chain/{chainId}/tables/{tableId}", systemController.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID, rateLim) // nolint + router.get("/chain/{chainId}/tables/{id}/{key}/{value}", userController.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID, rateLim) // nolint + router.get("/chain/{chainId}/tables/controller/{address}", systemController.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID, rateLim) // nolint + router.get("/chain/{chainId}/tables/structure/{hash}", systemController.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID, rateLim) // nolint + router.get("/schema/{table_name}", systemController.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint - router.Get("/query", userController.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint - router.Get("/version", infraController.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint + router.get("/query", userController.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint + router.get("/version", infraController.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint // Health endpoint configuration. - router.Get("/healthz", healthHandler) - router.Get("/health", healthHandler) + router.get("/healthz", controllers.HealthHandler) + router.get("/health", controllers.HealthHandler) - return router, nil + return nil } -func healthHandler(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) +func configureAPIv1( + router *Router, + rateLim mux.MiddlewareFunc, + systemController *controllers.SystemController, + userController *controllers.UserController, + infraController *controllers.InfraController, +) error { + handlers := map[string]http.HandlerFunc{ + "QueryFromQuery": userController.GetTableQuery, + "ReceiptByTxnHash": systemController.GetTxnHash, // TODO(jsign): do it. + "GetTableById": systemController.GetTable, // TODO(jsign): verify output. + "Version": infraController.Version, + "Health": controllers.HealthHandler, + } + + var specRoutesCount int + if err := apiv1.NewRouter().Walk(func(route *mux.Route, _ *mux.Router, _ []*mux.Route) error { + handle, ok := handlers[route.GetName()] + if !ok { + return fmt.Errorf("route with name %s not found in handler", route.GetName()) + } + pathTemplate, err := route.GetPathTemplate() + if err != nil { + return fmt.Errorf("get path template: %s", err) + } + router.get( + pathTemplate, + handle, + middlewares.WithLogging, middlewares.OtelHTTP(route.GetName()), middlewares.RESTChainID, rateLim) + specRoutesCount++ + return nil + }); err != nil { + return fmt.Errorf("configuring api v1 router: %s", err) + } + if specRoutesCount != len(handlers) { + return fmt.Errorf("the spec has less defined routes than expected handlers to be used") + } + + return nil } // Router provides a nice api around mux.Router. @@ -110,36 +167,29 @@ type Router struct { r *mux.Router } -// NewRouter is a Mux HTTP router constructor. -func NewRouter() *Router { +// newRouter is a Mux HTTP router constructor. +func newRouter() *Router { r := mux.NewRouter() r.PathPrefix("/").Methods(http.MethodOptions) // accept OPTIONS on all routes and do nothing return &Router{r: r} } -// Get creates a subroute on the specified URI that only accepts GET. You can provide specific middlewares. -func (r *Router) Get(uri string, f func(http.ResponseWriter, *http.Request), mid ...mux.MiddlewareFunc) { +// get creates a subroute on the specified URI that only accepts GET. You can provide specific middlewares. +func (r *Router) get(uri string, f http.HandlerFunc, mid ...mux.MiddlewareFunc) { sub := r.r.Path(uri).Subrouter() sub.HandleFunc("", f).Methods(http.MethodGet) 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 func(http.ResponseWriter, *http.Request), mid ...mux.MiddlewareFunc) { +// post creates a subroute on the specified URI that only accepts POST. You can provide specific middlewares. +func (r *Router) post(uri string, f func(http.ResponseWriter, *http.Request), mid ...mux.MiddlewareFunc) { sub := r.r.Path(uri).Subrouter() sub.HandleFunc("", f).Methods(http.MethodPost) sub.Use(mid...) } -// Delete creates a subroute on the specified URI that only accepts DELETE. You can provide specific middlewares. -func (r *Router) Delete(uri string, f func(http.ResponseWriter, *http.Request), mid ...mux.MiddlewareFunc) { - sub := r.r.Path(uri).Subrouter() - sub.HandleFunc("", f).Methods(http.MethodDelete) - 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) { +// 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...) } From 53233cdfd6c630b7eba0ca36c2267f41042e9807 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 1 Dec 2022 14:31:59 -0300 Subject: [PATCH 031/101] refactor: replicate idea of full stack harness #279 Signed-off-by: Ignacio Hagopian --- cmd/api/main.go | 36 ++- .../router/controllers/legacy/rpcservice.go | 3 +- internal/router/router.go | 110 ++++------ pkg/client/client_test.go | 111 +--------- tests/fullstack/fullstack.go | 205 ++++++++++++++++++ 5 files changed, 288 insertions(+), 177 deletions(-) create mode 100644 tests/fullstack/fullstack.go diff --git a/cmd/api/main.go b/cmd/api/main.go index 5e10b639..dcbe7d30 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -35,6 +35,7 @@ import ( nonceimpl "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/parsing" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" + "github.com/textileio/go-tableland/pkg/sqlstore" sqlstoreimpl "github.com/textileio/go-tableland/pkg/sqlstore/impl" "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" @@ -99,7 +100,7 @@ func main() { } // HTTP API server. - closeHTTPServer, err := createHTTPServer(config.HTTP, config.Gateway, parser, userStore, chainStacks) + closeHTTPServer, err := createAPIServer(config.HTTP, config.Gateway, parser, userStore, chainStacks) if err != nil { log.Fatal().Err(err).Msg("creating HTTP server") } @@ -468,27 +469,46 @@ func createChainStacks( return chainStacks, closeModule, nil } -func createHTTPServer( +func createAPIServer( httpConfig HTTPConfig, gatewayConfig GatewayConfig, parser parsing.SQLValidator, userStore *user.UserStore, chainStacks map[tableland.ChainID]chains.ChainStack, ) (moduleCloser, error) { + instrUserStore, err := sqlstoreimpl.NewInstrumentedUserStore(userStore) + if err != nil { + return nil, fmt.Errorf("creating instrumented user store: %s", err) + } + + mesaService := impl.NewTablelandMesa(parser, instrUserStore, chainStacks) + mesaService, err = impl.NewInstrumentedTablelandMesa(mesaService) + if err != nil { + return nil, fmt.Errorf("instrumenting mesa: %s", err) + } + + stores := make(map[tableland.ChainID]sqlstore.SystemStore, len(chainStacks)) + for chainID, stack := range chainStacks { + stores[chainID] = stack.Store + } + sysStore, err := systemimpl.NewSystemSQLStoreService(stores, gatewayConfig.ExternalURIPrefix, gatewayConfig.MetadataRendererURI, gatewayConfig.AnimationRendererURI) + if err != nil { + return nil, fmt.Errorf("creating system store: %s", err) + } + systemService, err := systemimpl.NewInstrumentedSystemSQLStoreService(sysStore) + if err != nil { + return nil, fmt.Errorf("instrumenting system sql store: %s", err) + } rateLimInterval, err := time.ParseDuration(httpConfig.RateLimInterval) if err != nil { return nil, fmt.Errorf("parsing http ratelimiter interval: %s", err) } router, err := router.ConfiguredRouter( - gatewayConfig.ExternalURIPrefix, - gatewayConfig.MetadataRendererURI, - gatewayConfig.AnimationRendererURI, + mesaService, + systemService, httpConfig.MaxRequestPerInterval, rateLimInterval, - parser, - userStore, - chainStacks, ) if err != nil { return nil, fmt.Errorf("configuring router: %s", err) diff --git a/internal/router/controllers/legacy/rpcservice.go b/internal/router/controllers/legacy/rpcservice.go index 0c0d2950..f3a44e8d 100644 --- a/internal/router/controllers/legacy/rpcservice.go +++ b/internal/router/controllers/legacy/rpcservice.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/textileio/go-tableland/internal/formatter" + "github.com/textileio/go-tableland/internal/router/controllers" "github.com/textileio/go-tableland/internal/router/middlewares" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/tables" @@ -210,7 +211,7 @@ func (rs *RPCService) RunReadQuery( return RunReadQueryResponse{}, errors.New("unwrapped results with more than one row aren't supported in JSON RPC API") } - CollectReadQueryMetric(ctx, req.Statement, config, took) + controllers.CollectReadQueryMetric(ctx, req.Statement, config, took) return RunReadQueryResponse{Result: json.RawMessage(formatted)}, nil } diff --git a/internal/router/router.go b/internal/router/router.go index 44b10844..601181c1 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -7,112 +7,82 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/gorilla/mux" - "github.com/textileio/go-tableland/internal/chains" "github.com/textileio/go-tableland/internal/router/controllers" "github.com/textileio/go-tableland/internal/router/controllers/apiv1" "github.com/textileio/go-tableland/internal/router/controllers/legacy" "github.com/textileio/go-tableland/internal/router/middlewares" - systemimpl "github.com/textileio/go-tableland/internal/system/impl" + "github.com/textileio/go-tableland/internal/system" "github.com/textileio/go-tableland/internal/tableland" - "github.com/textileio/go-tableland/internal/tableland/impl" - "github.com/textileio/go-tableland/pkg/parsing" - "github.com/textileio/go-tableland/pkg/sqlstore" - sqlstoreimpl "github.com/textileio/go-tableland/pkg/sqlstore/impl" - "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" ) // ConfiguredRouter returns a fully configured Router that can be used as an http handler. func ConfiguredRouter( - extURLPrefix string, - metadataRendererURI string, - animationRendererURI string, + tableland tableland.Tableland, + systemService system.SystemService, maxRPI uint64, rateLimInterval time.Duration, - parser parsing.SQLValidator, - userStore *user.UserStore, - chainStacks map[tableland.ChainID]chains.ChainStack, ) (*Router, error) { - instrUserStore, err := sqlstoreimpl.NewInstrumentedUserStore(userStore) - if err != nil { - return nil, fmt.Errorf("creating instrumented user store: %s", err) - } - - mesaService := impl.NewTablelandMesa(parser, instrUserStore, chainStacks) - mesaService, err = impl.NewInstrumentedTablelandMesa(mesaService) - if err != nil { - return nil, fmt.Errorf("instrumenting mesa: %s", err) - } - rpcService := legacy.NewRPCService(mesaService) + rpcService := legacy.NewRPCService(tableland) server := rpc.NewServer() if err := server.RegisterName("tableland", rpcService); err != nil { return nil, fmt.Errorf("failed to register a json-rpc service: %s", err) } - userController := controllers.NewUserController(mesaService) - - infraController := controllers.NewInfraController() + userCtrl := controllers.NewUserController(tableland) - stores := make(map[tableland.ChainID]sqlstore.SystemStore, len(chainStacks)) - for chainID, stack := range chainStacks { - stores[chainID] = stack.Store - } - sysStore, err := systemimpl.NewSystemSQLStoreService(stores, extURLPrefix, metadataRendererURI, animationRendererURI) - if err != nil { - return nil, fmt.Errorf("creating system store: %s", err) - } - systemService, err := systemimpl.NewInstrumentedSystemSQLStoreService(sysStore) - if err != nil { - return nil, fmt.Errorf("instrumenting system sql store: %s", err) - } - systemController := controllers.NewSystemController(systemService) + systemCtrl := controllers.NewSystemController(systemService) + infraCtrl := controllers.NewInfraController() // General router configuration. router := newRouter() router.use(middlewares.CORS, middlewares.TraceID) - // RPC configuration. cfg := middlewares.RateLimiterConfig{ Default: middlewares.RateLimiterRouteConfig{ MaxRPI: maxRPI, Interval: rateLimInterval, }, - JSONRPCRoute: "/rpc", + JSONRPCRoute: "/rpc", // TODO(json-rpc): remove this feature in the rate-limiter when we drop support. } rateLim, err := middlewares.RateLimitController(cfg) if err != nil { return nil, fmt.Errorf("creating rate limit controller middleware: %s", err) } - if err := configureLegacyAPI(router, server, rateLim, systemController, userController, infraController); err != nil { + // TODO(json-rpc): remove this when dropping support. + // APIs Legacy (REST + JSON-RPC) + if err := configureLegacyRoutes(router, server, rateLim, systemCtrl, userCtrl, infraCtrl); err != nil { return nil, fmt.Errorf("configuring legacy API: %s", err) } - if err := configureAPIv1(router, rateLim, systemController, userController, infraController); err != nil { + + // APIs V1 + if err := configureAPIV1Routes(router, rateLim, systemCtrl, userCtrl, infraCtrl); err != nil { return nil, fmt.Errorf("configuring API v1: %s", err) } return router, nil } -func configureLegacyAPI( +func configureLegacyRoutes( router *Router, server *rpc.Server, rateLim mux.MiddlewareFunc, - systemController *controllers.SystemController, - userController *controllers.UserController, - infraController *controllers.InfraController, + systemCtrl *controllers.SystemController, + userCtrl *controllers.UserController, + infraCtrl *controllers.InfraController, ) error { router.post("/rpc", func(rw http.ResponseWriter, r *http.Request) { server.ServeHTTP(rw, r) }, middlewares.WithLogging, middlewares.OtelHTTP("rpc"), middlewares.Authentication, rateLim) // Gateway configuration. - router.get("/chain/{chainId}/tables/{tableId}", systemController.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID, rateLim) // nolint - router.get("/chain/{chainId}/tables/{id}/{key}/{value}", userController.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID, rateLim) // nolint - router.get("/chain/{chainId}/tables/controller/{address}", systemController.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID, rateLim) // nolint - router.get("/chain/{chainId}/tables/structure/{hash}", systemController.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID, rateLim) // nolint - router.get("/schema/{table_name}", systemController.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint + router.get("/chain/{chainId}/tables/{tableId}", systemCtrl.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID, rateLim) // nolint + router.get("/chain/{chainId}/tables/{id}/{key}/{value}", userCtrl.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID, rateLim) // nolint + router.get("/chain/{chainId}/tables/controller/{address}", systemCtrl.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID, rateLim) // nolint + router.get("/chain/{chainId}/tables/structure/{hash}", systemCtrl.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID, rateLim) // nolint + router.get("/schema/{table_name}", systemCtrl.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint - router.get("/query", userController.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint - router.get("/version", infraController.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint + router.get("/query", userCtrl.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint + router.get("/version", infraCtrl.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint // Health endpoint configuration. router.get("/healthz", controllers.HealthHandler) @@ -121,26 +91,33 @@ func configureLegacyAPI( return nil } -func configureAPIv1( +func configureAPIV1Routes( router *Router, rateLim mux.MiddlewareFunc, - systemController *controllers.SystemController, - userController *controllers.UserController, - infraController *controllers.InfraController, + systemCtrl *controllers.SystemController, + userCtrl *controllers.UserController, + infraCtrl *controllers.InfraController, ) error { handlers := map[string]http.HandlerFunc{ - "QueryFromQuery": userController.GetTableQuery, - "ReceiptByTxnHash": systemController.GetTxnHash, // TODO(jsign): do it. - "GetTableById": systemController.GetTable, // TODO(jsign): verify output. - "Version": infraController.Version, + "QueryFromQuery": userCtrl.GetTableQuery, + "ReceiptByTxnHash": nil, // systemCtrl.GetTxnHash, // TODO(jsign): do it. + "GetTableById": systemCtrl.GetTable, // TODO(jsign): verify output. + "Version": infraCtrl.Version, "Health": controllers.HealthHandler, } var specRoutesCount int if err := apiv1.NewRouter().Walk(func(route *mux.Route, _ *mux.Router, _ []*mux.Route) error { - handle, ok := handlers[route.GetName()] + routeName := route.GetName() + // Ignore the "Index" API that OpenAPI 3.0 code generator always create for the base `/` route. + if routeName == "Index" { + return nil + } + + specRoutesCount++ + handle, ok := handlers[routeName] if !ok { - return fmt.Errorf("route with name %s not found in handler", route.GetName()) + return fmt.Errorf("route with name %s not found in handler", routeName) } pathTemplate, err := route.GetPathTemplate() if err != nil { @@ -149,8 +126,7 @@ func configureAPIv1( router.get( pathTemplate, handle, - middlewares.WithLogging, middlewares.OtelHTTP(route.GetName()), middlewares.RESTChainID, rateLim) - specRoutesCount++ + middlewares.WithLogging, middlewares.OtelHTTP(routeName), middlewares.RESTChainID, rateLim) return nil }); err != nil { return fmt.Errorf("configuring api v1 router: %s", err) diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 68e01adf..19d6e76b 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -3,34 +3,18 @@ package client import ( "context" "database/sql" - "encoding/hex" "fmt" - "net/http/httptest" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" - "github.com/textileio/go-tableland/internal/chains" - "github.com/textileio/go-tableland/internal/router" "github.com/textileio/go-tableland/internal/tableland" tblimpl "github.com/textileio/go-tableland/internal/tableland/impl" - "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed" - efimpl "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed/impl" - epimpl "github.com/textileio/go-tableland/pkg/eventprocessor/impl" - "github.com/textileio/go-tableland/pkg/nonce/impl" - parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" "github.com/textileio/go-tableland/pkg/sqlstore" - "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" - "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" "github.com/textileio/go-tableland/pkg/tables" - "github.com/textileio/go-tableland/pkg/tables/impl/ethereum" - "github.com/textileio/go-tableland/pkg/tables/impl/testutil" - "github.com/textileio/go-tableland/pkg/wallet" - "github.com/textileio/go-tableland/tests" - - executor "github.com/textileio/go-tableland/pkg/eventprocessor/impl/executor/impl" + "github.com/textileio/go-tableland/tests/fullstack" ) func TestCreate(t *testing.T) { @@ -179,96 +163,21 @@ type clientCalls struct { } func setup(t *testing.T) clientCalls { - t.Helper() - - ctx := context.Background() - - dbURI := tests.Sqlite3URI(t) - - store, err := system.New(dbURI, tableland.ChainID(1337)) - require.NoError(t, err) - - parser, err := parserimpl.New([]string{"system_", "registry", "sqlite_"}) - require.NoError(t, err) - - db, err := sql.Open("sqlite3", dbURI) - require.NoError(t, err) - db.SetMaxOpenConns(1) - - ex, err := executor.NewExecutor(1337, db, parser, 0, &aclHalfMock{store}) - require.NoError(t, err) - - backend, addr, _, _, sk := testutil.Setup(t) - - wallet, err := wallet.NewWallet(hex.EncodeToString(crypto.FromECDSA(sk))) - require.NoError(t, err) - - registry, err := ethereum.NewClient( - backend, - 1337, - addr, - wallet, - impl.NewSimpleTracker(wallet, backend), - ) - require.NoError(t, err) - - userStore, err := user.New(dbURI) - require.NoError(t, err) - - chainStack := map[tableland.ChainID]chains.ChainStack{ - 1337: { - Store: store, - Registry: registry, - AllowTransactionRelay: true, - }, - } - - router, err := router.ConfiguredRouter( - "https://testnet.tableland.network", - "https://render.tableland.xyz", - "", - 10, - time.Second, - parser, - userStore, - chainStack, - ) - require.NoError(t, err) - - server := httptest.NewServer(router.Handler()) + stack := fullstack.CreateFullStack(t, fullstack.Deps{}) c := Chain{ - Endpoint: server.URL, - ID: ChainID(1337), - ContractAddr: addr, + Endpoint: stack.Server.URL, + ID: ChainID(fullstack.ChainID), + ContractAddr: stack.Address, } - client, err := NewClient(ctx, wallet, NewClientChain(c), NewClientContractBackend(backend)) - require.NoError(t, err) - - // Spin up dependencies needed for the EventProcessor. - // i.e: Executor, Parser, and EventFeed (connected to the EVM chain) - ef, err := efimpl.New( - store, - 1337, - backend, - addr, - eventfeed.WithNewHeadPollFreq(time.Millisecond), - eventfeed.WithMinBlockDepth(0)) - require.NoError(t, err) - - // Create EventProcessor for our test. - ep, err := epimpl.New(parser, ex, ef, 1337) - require.NoError(t, err) - - err = ep.Start() + client, err := NewClient(context.Background(), stack.Wallet, NewClientChain(c), NewClientContractBackend(stack.Backend)) require.NoError(t, err) t.Cleanup(func() { - ep.Stop() client.Close() - server.Close() }) + ctx := context.Background() return clientCalls{ list: func() []TableInfo { res, err := client.List(ctx) @@ -278,7 +187,7 @@ func setup(t *testing.T) clientCalls { create: func(schema string, opts ...CreateOption) (TableID, string) { go func() { time.Sleep(time.Second * 1) - backend.Commit() + stack.Backend.Commit() }() id, table, err := client.Create(ctx, schema, opts...) require.NoError(t, err) @@ -291,7 +200,7 @@ func setup(t *testing.T) clientCalls { write: func(query string, opts ...WriteOption) string { hash, err := client.Write(ctx, query, opts...) require.NoError(t, err) - backend.Commit() + stack.Backend.Commit() return hash }, hash: func(statement string) string { @@ -312,7 +221,7 @@ func setup(t *testing.T) clientCalls { setController: func(controller common.Address, tableID TableID) string { hash, err := client.SetController(ctx, controller, tableID) require.NoError(t, err) - backend.Commit() + stack.Backend.Commit() return hash }, } diff --git a/tests/fullstack/fullstack.go b/tests/fullstack/fullstack.go new file mode 100644 index 00000000..1ac91515 --- /dev/null +++ b/tests/fullstack/fullstack.go @@ -0,0 +1,205 @@ +package fullstack + +import ( + "context" + "database/sql" + "encoding/hex" + "net/http/httptest" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" + "github.com/textileio/go-tableland/internal/chains" + "github.com/textileio/go-tableland/internal/router" + "github.com/textileio/go-tableland/internal/system" + systemimpl "github.com/textileio/go-tableland/internal/system/impl" + "github.com/textileio/go-tableland/internal/tableland" + "github.com/textileio/go-tableland/internal/tableland/impl" + "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed" + efimpl "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed/impl" + epimpl "github.com/textileio/go-tableland/pkg/eventprocessor/impl" + executor "github.com/textileio/go-tableland/pkg/eventprocessor/impl/executor/impl" + nonceimpl "github.com/textileio/go-tableland/pkg/nonce/impl" + "github.com/textileio/go-tableland/pkg/parsing" + parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" + "github.com/textileio/go-tableland/pkg/sqlstore" + sqlstoreimplsystem "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" + "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" + "github.com/textileio/go-tableland/pkg/tables" + "github.com/textileio/go-tableland/pkg/tables/impl/ethereum" + "github.com/textileio/go-tableland/pkg/tables/impl/testutil" + "github.com/textileio/go-tableland/pkg/wallet" + "github.com/textileio/go-tableland/tests" +) + +// ChainID is the test chain id. +var ChainID = tableland.ChainID(1337) + +// FullStack holds all potentially useful components of the Tableland test stack. +type FullStack struct { + Backend *backends.SimulatedBackend + Address common.Address + Contract *ethereum.Contract + TransactOpts *bind.TransactOpts + Wallet *wallet.Wallet + TblContractClient *ethereum.Client + Server *httptest.Server +} + +// Deps holds possile dependencies that can optionally be provided to spin up the full stack. +type Deps struct { + DBURI string + Parser parsing.SQLValidator + SystemStore sqlstore.SystemStore + UserStore sqlstore.UserStore + ACL tableland.ACL + Tableland tableland.Tableland + SystemService system.SystemService +} + +func CreateFullStack(t *testing.T, deps Deps) FullStack { + t.Helper() + + var err error + + parser := deps.Parser + if parser == nil { + parser, err = parserimpl.New([]string{"system_", "registry", "sqlite_"}) + require.NoError(t, err) + } + + dbURI := deps.DBURI + if dbURI == "" { + dbURI = tests.Sqlite3URI(t) + } + + systemStore := deps.SystemStore + if systemStore == nil { + systemStore, err = sqlstoreimplsystem.New(dbURI, ChainID) + require.NoError(t, err) + } + + userStore := deps.UserStore + if userStore == nil { + userStore, err = user.New(dbURI) + require.NoError(t, err) + } + + backend, addr, contract, transactOpts, sk := testutil.Setup(t) + + wallet, err := wallet.NewWallet(hex.EncodeToString(crypto.FromECDSA(sk))) + require.NoError(t, err) + + registry, err := ethereum.NewClient( + backend, + ChainID, + addr, + wallet, + nonceimpl.NewSimpleTracker(wallet, backend), + ) + + chainStacks := map[tableland.ChainID]chains.ChainStack{ + 1337: { + Store: systemStore, + Registry: registry, + AllowTransactionRelay: true, + }, + } + + tbl := deps.Tableland + if tbl == nil { + tbl = impl.NewTablelandMesa(parser, userStore, chainStacks) + tbl, err = impl.NewInstrumentedTablelandMesa(tbl) + require.NoError(t, err) + } + + stores := make(map[tableland.ChainID]sqlstore.SystemStore, len(chainStacks)) + for chainID, stack := range chainStacks { + stores[chainID] = stack.Store + } + + systemService := deps.SystemService + if systemService == nil { + systemService, err = systemimpl.NewSystemSQLStoreService( + stores, + "https://testnet.tableland.network", + "https://render.tableland.xyz", + "https://render.tableland.xyz/anim", + ) + require.NoError(t, err) + systemService, err = systemimpl.NewInstrumentedSystemSQLStoreService(systemService) + require.NoError(t, err) + } + + acl := deps.ACL + if acl == nil { + acl = &aclHalfMock{systemStore} + } + + db, err := sql.Open("sqlite3", dbURI) + require.NoError(t, err) + db.SetMaxOpenConns(1) + + ex, err := executor.NewExecutor(1337, db, parser, 0, &aclHalfMock{systemStore}) + require.NoError(t, err) + + router, err := router.ConfiguredRouter(tbl, systemService, 10, time.Second) + require.NoError(t, err) + + server := httptest.NewServer(router.Handler()) + + // Spin up dependencies needed for the EventProcessor. + // i.e: Executor, Parser, and EventFeed (connected to the EVM chain) + ef, err := efimpl.New( + systemStore, + ChainID, + backend, + addr, + eventfeed.WithNewHeadPollFreq(time.Millisecond), + eventfeed.WithMinBlockDepth(0)) + require.NoError(t, err) + + // Create EventProcessor for our test. + ep, err := epimpl.New(parser, ex, ef, 1337) + require.NoError(t, err) + + err = ep.Start() + require.NoError(t, err) + t.Cleanup(func() { + ep.Stop() + server.Close() + }) + + return FullStack{ + Backend: backend, + Address: addr, + Contract: contract, + TransactOpts: transactOpts, + Wallet: wallet, + TblContractClient: registry, + Server: server, + } +} + +type aclHalfMock struct { + sqlStore sqlstore.SystemStore +} + +func (acl *aclHalfMock) CheckPrivileges( + ctx context.Context, + tx *sql.Tx, + controller common.Address, + id tables.TableID, + op tableland.Operation, +) (bool, error) { + aclImpl := impl.NewACL(acl.sqlStore, nil) + return aclImpl.CheckPrivileges(ctx, tx, controller, id, op) +} + +func (acl *aclHalfMock) IsOwner(_ context.Context, _ common.Address, _ tables.TableID) (bool, error) { + return true, nil +} From e0ad472db9233375b718686796ad95712c8b8691 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 1 Dec 2022 15:24:04 -0300 Subject: [PATCH 032/101] pkg/client: separate legacy and new client so we can keep testing legacy APIs and is easily droppable later Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system_test.go | 4 +- pkg/client/chains.go | 6 +- pkg/client/client.go | 6 +- pkg/client_legacy/client.go | 521 +++++++++++++++++++++ pkg/client_legacy/client_test.go | 229 +++++++++ 5 files changed, 758 insertions(+), 8 deletions(-) create mode 100644 pkg/client_legacy/client.go create mode 100644 pkg/client_legacy/client_test.go diff --git a/internal/router/controllers/system_test.go b/internal/router/controllers/system_test.go index 2b7c7db6..27ece54f 100644 --- a/internal/router/controllers/system_test.go +++ b/internal/router/controllers/system_test.go @@ -23,7 +23,7 @@ func TestSystemControllerMock(t *testing.T) { require.NoError(t, err) router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/{id}", systemController.GetTable) + router.HandleFunc("/chain/{chainID}/tables/{tableId}", systemController.GetTable) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -158,7 +158,7 @@ func TestTableNotFoundMock(t *testing.T) { systemController := NewSystemController(systemService) router := mux.NewRouter() - router.HandleFunc("/tables/{id}", systemController.GetTable) + router.HandleFunc("/tables/{tableId}", systemController.GetTable) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) diff --git a/pkg/client/chains.go b/pkg/client/chains.go index e991fa6e..34f0ba7b 100644 --- a/pkg/client/chains.go +++ b/pkg/client/chains.go @@ -107,7 +107,7 @@ func (c Chain) CanRelayWrites() bool { return c.ID != ChainIDs.Ethereum && c.ID != ChainIDs.Optimism && c.ID != ChainIDs.Polygon } -var infuraURLs = map[ChainID]string{ +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", @@ -118,7 +118,7 @@ var infuraURLs = map[ChainID]string{ ChainIDs.Polygon: "https://polygon-mainnet.infura.io/v3/%s", } -var alchemyURLs = map[ChainID]string{ +var AlchemyURLs = map[ChainID]string{ ChainIDs.EthereumGoerli: "https://eth-goerli.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", @@ -129,6 +129,6 @@ var alchemyURLs = map[ChainID]string{ ChainIDs.Polygon: "https://polygon-mainnet.g.alchemy.com/v2/%s", } -var localURLs = map[ChainID]string{ +var LocalURLs = map[ChainID]string{ ChainIDs.Local: "http://localhost:8545", } diff --git a/pkg/client/client.go b/pkg/client/client.go index 47010620..75c69cb0 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -497,19 +497,19 @@ func getContractBackend(ctx context.Context, config config) (bind.ContractBacken if config.contractBackend != nil && config.infuraAPIKey == "" && config.alchemyAPIKey == "" { return config.contractBackend, nil } else if config.infuraAPIKey != "" && config.contractBackend == nil && config.alchemyAPIKey == "" { - tmpl, found := infuraURLs[config.chain.ID] + tmpl, found := InfuraURLs[config.chain.ID] if !found { return nil, fmt.Errorf("chain id %v not supported for Infura", config.chain.ID) } return ethclient.DialContext(ctx, fmt.Sprintf(tmpl, config.infuraAPIKey)) } else if config.alchemyAPIKey != "" && config.contractBackend == nil && config.infuraAPIKey == "" { - tmpl, found := alchemyURLs[config.chain.ID] + tmpl, found := AlchemyURLs[config.chain.ID] if !found { return nil, fmt.Errorf("chain id %v not supported for Alchemy", config.chain.ID) } return ethclient.DialContext(ctx, fmt.Sprintf(tmpl, config.alchemyAPIKey)) } else if config.local { - url, found := localURLs[config.chain.ID] + url, found := LocalURLs[config.chain.ID] if !found { return nil, fmt.Errorf("chain id %v not supported for Local", config.chain.ID) } diff --git a/pkg/client_legacy/client.go b/pkg/client_legacy/client.go new file mode 100644 index 00000000..6d31d8b6 --- /dev/null +++ b/pkg/client_legacy/client.go @@ -0,0 +1,521 @@ +package client_legacy + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "math/big" + "net/http" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + "github.com/textileio/go-tableland/internal/router/controllers/legacy" + "github.com/textileio/go-tableland/internal/tableland" + "github.com/textileio/go-tableland/pkg/client" + "github.com/textileio/go-tableland/pkg/nonce/impl" + "github.com/textileio/go-tableland/pkg/siwe" + "github.com/textileio/go-tableland/pkg/tables" + "github.com/textileio/go-tableland/pkg/tables/impl/ethereum" + "github.com/textileio/go-tableland/pkg/wallet" +) + +var defaultChain = client.Chains.PolygonMumbai + +// TODO(json-rpc): remove client_legacy package when support is dropped. +// TxnReceipt is a Tableland event processing receipt. +type TxnReceipt struct { + ChainID client.ChainID `json:"chain_id"` + TxnHash string `json:"txn_hash"` + BlockNumber int64 `json:"block_number"` + Error string `json:"error"` + ErrorEventIdx int `json:"error_event_idx"` + TableID *string `json:"table_id,omitempty"` +} + +// TableID is the ID of a Table. +type TableID big.Int + +// String returns a string representation of the TableID. +func (tid TableID) String() string { + bi := (big.Int)(tid) + return bi.String() +} + +// ToBigInt returns a *big.Int representation of the TableID. +func (tid TableID) ToBigInt() *big.Int { + bi := (big.Int)(tid) + b := &big.Int{} + b.Set(&bi) + return b +} + +// TableInfo summarizes information about a table. +type TableInfo struct { + Controller string `json:"controller"` + Name string `json:"name"` + Structure string `json:"structure"` + CreatedAt time.Time `json:"created_at"` +} + +// NewTableID creates a TableID from a string representation of the uint256. +func NewTableID(strID string) (TableID, error) { + tableID := &big.Int{} + if _, ok := tableID.SetString(strID, 10); !ok { + return TableID{}, fmt.Errorf("parsing stringified id failed") + } + if tableID.Cmp(&big.Int{}) < 0 { + return TableID{}, fmt.Errorf("table id is negative") + } + return TableID(*tableID), nil +} + +// Client is the Tableland client. +type Client struct { + tblRPC *rpc.Client + tblHTTP *http.Client + tblContract *ethereum.Client + chain client.Chain + relayWrites bool + wallet *wallet.Wallet +} + +type config struct { + chain *client.Chain + relayWrites *bool + infuraAPIKey string + alchemyAPIKey string + local bool + contractBackend bind.ContractBackend +} + +// NewClientOption controls the behavior of NewClient. +type NewClientOption func(*config) + +// NewClientChain specifies chaininfo. +func NewClientChain(chain client.Chain) NewClientOption { + return func(ncc *config) { + ncc.chain = &chain + } +} + +// NewClientRelayWrites specifies whether or not to relay write queries through the Tableland validator. +func NewClientRelayWrites(relay bool) NewClientOption { + return func(ncc *config) { + ncc.relayWrites = &relay + } +} + +// NewClientInfuraAPIKey specifies an Infura API to use when creating an EVM backend. +func NewClientInfuraAPIKey(key string) NewClientOption { + return func(c *config) { + c.infuraAPIKey = key + } +} + +// NewClientAlchemyAPIKey specifies an Alchemy API to use when creating an EVM backend. +func NewClientAlchemyAPIKey(key string) NewClientOption { + return func(c *config) { + c.alchemyAPIKey = key + } +} + +// NewClientLocal specifies that a local EVM backend should be used. +func NewClientLocal() NewClientOption { + return func(c *config) { + c.local = true + } +} + +// NewClientContractBackend specifies a custom EVM backend to use. +func NewClientContractBackend(backend bind.ContractBackend) NewClientOption { + return func(c *config) { + c.contractBackend = backend + } +} + +// NewClient creates a new Client. +func NewClient(ctx context.Context, wallet *wallet.Wallet, opts ...NewClientOption) (*Client, error) { + config := config{chain: &defaultChain} + for _, opt := range opts { + opt(&config) + } + var relay bool + if config.relayWrites != nil { + relay = *config.relayWrites + } else { + relay = config.chain.CanRelayWrites() + } + if relay && !config.chain.CanRelayWrites() { + return nil, errors.New("options specified to relay writes for a chain that doesn't support it") + } + + contractBackend, err := getContractBackend(ctx, config) + if err != nil { + return nil, fmt.Errorf("getting contract backend: %v", err) + } + + tblContract, err := ethereum.NewClient( + contractBackend, + tableland.ChainID(config.chain.ID), + config.chain.ContractAddr, + wallet, + impl.NewSimpleTracker(wallet, contractBackend), + ) + if err != nil { + return nil, fmt.Errorf("creating contract client: %v", err) + } + + siwe, err := siwe.EncodedSIWEMsg(tableland.ChainID(config.chain.ID), wallet, time.Hour*24*365) + if err != nil { + return nil, fmt.Errorf("creating siwe value: %v", err) + } + + tblRPC, err := rpc.DialContext(ctx, config.chain.Endpoint+"/rpc") + if err != nil { + return nil, fmt.Errorf("creating rpc client: %v", err) + } + tblRPC.SetHeader("Authorization", "Bearer "+siwe) + + return &Client{ + tblRPC: tblRPC, + tblHTTP: &http.Client{}, + tblContract: tblContract, + chain: *config.chain, + relayWrites: relay, + wallet: wallet, + }, nil +} + +// List lists something. +func (c *Client) List(ctx context.Context) ([]TableInfo, error) { + url := fmt.Sprintf( + "%s/chain/%d/tables/controller/%s", + c.chain.Endpoint, + c.chain.ID, + c.wallet.Address().Hex(), + ) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, fmt.Errorf("creating request: %v", err) + } + req = req.WithContext(ctx) + res, err := c.tblHTTP.Do(req) + if err != nil { + return nil, fmt.Errorf("calling http endpoint: %v", err) + } + defer func() { + _ = res.Body.Close() + }() + + var ret []TableInfo + + if err := json.NewDecoder(res.Body).Decode(&ret); err != nil { + return nil, fmt.Errorf("decoding response body: %v", err) + } + + return ret, nil +} + +type createConfig struct { + prefix string + receiptTimeout *time.Duration +} + +// CreateOption controls the behavior of Create. +type CreateOption func(*createConfig) + +// WithPrefix allows you to specify an optional table name prefix where +// the final table name will be __. +func WithPrefix(prefix string) CreateOption { + return func(cc *createConfig) { + cc.prefix = prefix + } +} + +// WithReceiptTimeout specifies how long to wait for the Tableland +// receipt that contains the table id. +func WithReceiptTimeout(timeout time.Duration) CreateOption { + return func(cc *createConfig) { + cc.receiptTimeout = &timeout + } +} + +// Create creates a new table on the Tableland. +func (c *Client) Create(ctx context.Context, schema string, opts ...CreateOption) (TableID, string, error) { + defaultTimeout := time.Minute * 10 + conf := createConfig{receiptTimeout: &defaultTimeout} + for _, opt := range opts { + opt(&conf) + } + + createStatement := fmt.Sprintf("CREATE TABLE %s_%d %s", conf.prefix, c.chain.ID, schema) + req := &legacy.ValidateCreateTableRequest{CreateStatement: createStatement} + var res legacy.ValidateCreateTableResponse + + if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateCreateTable", req); err != nil { + return TableID{}, "", fmt.Errorf("calling rpc validateCreateTable: %v", err) + } + + t, err := c.tblContract.CreateTable(ctx, c.wallet.Address(), createStatement) + if err != nil { + return TableID{}, "", fmt.Errorf("calling contract create table: %v", err) + } + + r, found, err := c.waitForReceipt(ctx, t.Hash().Hex(), *conf.receiptTimeout) + if err != nil { + return TableID{}, "", fmt.Errorf("waiting for txn receipt: %v", err) + } + if !found { + return TableID{}, "", errors.New("no receipt found before timeout") + } + + tableID, ok := big.NewInt(0).SetString(*r.TableID, 10) + if !ok { + return TableID{}, "", errors.New("parsing table id from response") + } + + return TableID(*tableID), fmt.Sprintf("%s_%d_%s", conf.prefix, c.chain.ID, *r.TableID), nil +} + +// Output is used to control the output format of a Read using the ReadOutput option. +type Output string + +const ( + // Table returns the query results as a JSON object with columns and rows properties. + Table Output = "table" + // Objects returns the query results as a JSON array of JSON objects. This is the default. + Objects Output = "objects" +) + +// ReadOption controls the behavior of Read. +type ReadOption func(*legacy.RunReadQueryRequest) + +// ReadOutput sets the output format. Default is Objects. +func ReadOutput(output Output) ReadOption { + return func(rrqr *legacy.RunReadQueryRequest) { + rrqr.Output = (*string)(&output) + } +} + +// ReadExtract specifies whether or not to extract the JSON object +// from the single property of the surrounding JSON object. +// Default is false. +func ReadExtract() ReadOption { + return func(rrqr *legacy.RunReadQueryRequest) { + v := true + rrqr.Extract = &v + } +} + +// ReadUnwrap specifies whether or not to unwrap the returned JSON objects from their surrounding array. +// Default is false. +func ReadUnwrap() ReadOption { + return func(rrqr *legacy.RunReadQueryRequest) { + v := true + rrqr.Unwrap = &v + } +} + +// Read runs a read query with the provided opts and unmarshals the results into target. +func (c *Client) Read(ctx context.Context, query string, target interface{}, opts ...ReadOption) error { + req := &legacy.RunReadQueryRequest{Statement: query} + for _, opt := range opts { + opt(req) + } + res := &legacy.RunReadQueryResponse{ + Result: target, + } + if err := c.tblRPC.CallContext(ctx, &res, "tableland_runReadQuery", req); err != nil { + return fmt.Errorf("calling rpc runReadQuery: %v", err) + } + return nil +} + +type writeConfig struct { + relay bool +} + +// WriteOption controls the behavior of Write. +type WriteOption func(*writeConfig) + +// WriteRelay specifies whether or not to relay write queries through the Tableland validator. +// Default behavior is false for main net EVM chains, true for all others. +func WriteRelay(relay bool) WriteOption { + return func(wc *writeConfig) { + wc.relay = relay + } +} + +// Write initiates a write query, returning the txn hash. +func (c *Client) Write(ctx context.Context, query string, opts ...WriteOption) (string, error) { + conf := writeConfig{relay: c.relayWrites} + for _, opt := range opts { + opt(&conf) + } + if conf.relay { + req := &legacy.RelayWriteQueryRequest{Statement: query} + var res legacy.RelayWriteQueryResponse + if err := c.tblRPC.CallContext(ctx, &res, "tableland_relayWriteQuery", req); err != nil { + return "", fmt.Errorf("calling rpc relayWriteQuery: %v", err) + } + return res.Transaction.Hash, nil + } + tableID, err := c.Validate(ctx, query) + if err != nil { + return "", fmt.Errorf("calling Validate: %v", err) + } + res, err := c.tblContract.RunSQL(ctx, c.wallet.Address(), tables.TableID(tableID), query) + if err != nil { + return "", fmt.Errorf("calling RunSQL: %v", err) + } + return res.Hash().Hex(), nil +} + +// Hash validates the provided create table statement and returns its hash. +func (c *Client) Hash(ctx context.Context, statement string) (string, error) { + req := &legacy.ValidateCreateTableRequest{CreateStatement: statement} + var res legacy.ValidateCreateTableResponse + if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateCreateTable", req); err != nil { + return "", fmt.Errorf("calling rpc validateCreateTable: %v", err) + } + return res.StructureHash, nil +} + +// Validate validates a write query, returning the table id. +func (c *Client) Validate(ctx context.Context, statement string) (TableID, error) { + req := &legacy.ValidateWriteQueryRequest{Statement: statement} + var res legacy.ValidateWriteQueryResponse + if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateWriteQuery", req); err != nil { + return TableID{}, fmt.Errorf("calling rpc validateWriteQuery: %v", err) + } + tableID, ok := big.NewInt(0).SetString(res.TableID, 10) + if !ok { + return TableID{}, errors.New("parsing table id from response") + } + + return TableID(*tableID), nil +} + +type receiptConfig struct { + timeout *time.Duration +} + +// ReceiptOption controls the behavior of calls to Receipt. +type ReceiptOption func(*receiptConfig) + +// WaitFor causes calls to Receipt to wait for the specified duration. +func WaitFor(timeout time.Duration) ReceiptOption { + return func(rc *receiptConfig) { + rc.timeout = &timeout + } +} + +// Receipt gets a transaction receipt. +func (c *Client) Receipt( + ctx context.Context, + txnHash string, + options ...ReceiptOption, +) (*TxnReceipt, bool, error) { + config := receiptConfig{} + for _, option := range options { + option(&config) + } + if config.timeout != nil { + return c.waitForReceipt(ctx, txnHash, *config.timeout) + } + return c.getReceipt(ctx, txnHash) +} + +// SetController sets the controller address for the specified table. +func (c *Client) SetController( + ctx context.Context, + controller common.Address, + tableID TableID, +) (string, error) { + req := legacy.SetControllerRequest{Controller: controller.Hex(), TokenID: tableID.String()} + var res legacy.SetControllerResponse + + if err := c.tblRPC.CallContext(ctx, &res, "tableland_setController", req); err != nil { + return "", fmt.Errorf("calling rpc setController: %v", err) + } + + return res.Transaction.Hash, nil +} + +func (c *Client) getReceipt(ctx context.Context, txnHash string) (*TxnReceipt, bool, error) { + req := legacy.GetReceiptRequest{TxnHash: txnHash} + var res legacy.GetReceiptResponse + if err := c.tblRPC.CallContext(ctx, &res, "tableland_getReceipt", req); err != nil { + return nil, false, fmt.Errorf("calling rpc getReceipt: %v", err) + } + if !res.Ok { + return nil, res.Ok, nil + } + + receipt := TxnReceipt{ + ChainID: client.ChainID(res.Receipt.ChainID), + TxnHash: res.Receipt.TxnHash, + BlockNumber: res.Receipt.BlockNumber, + Error: res.Receipt.Error, + ErrorEventIdx: res.Receipt.ErrorEventIdx, + TableID: res.Receipt.TableID, + } + return &receipt, res.Ok, nil +} + +func (c *Client) waitForReceipt( + ctx context.Context, + txnHash string, + timeout time.Duration, +) (*TxnReceipt, bool, error) { + for stay, timeout := true, time.After(timeout); stay; { + select { + case <-timeout: + stay = false + default: + receipt, found, err := c.getReceipt(ctx, txnHash) + if err != nil { + return nil, false, err + } + if found { + return receipt, found, nil + } + time.Sleep(time.Second) + } + } + return nil, false, nil +} + +// Close implements Close. +func (c *Client) Close() { + c.tblRPC.Close() +} + +func getContractBackend(ctx context.Context, config config) (bind.ContractBackend, error) { + if config.contractBackend != nil && config.infuraAPIKey == "" && config.alchemyAPIKey == "" { + return config.contractBackend, nil + } else if config.infuraAPIKey != "" && config.contractBackend == nil && config.alchemyAPIKey == "" { + tmpl, found := client.InfuraURLs[config.chain.ID] + if !found { + return nil, fmt.Errorf("chain id %v not supported for Infura", config.chain.ID) + } + return ethclient.DialContext(ctx, fmt.Sprintf(tmpl, config.infuraAPIKey)) + } else if config.alchemyAPIKey != "" && config.contractBackend == nil && config.infuraAPIKey == "" { + tmpl, found := client.AlchemyURLs[config.chain.ID] + if !found { + return nil, fmt.Errorf("chain id %v not supported for Alchemy", config.chain.ID) + } + return ethclient.DialContext(ctx, fmt.Sprintf(tmpl, config.alchemyAPIKey)) + } else if config.local { + url, found := client.LocalURLs[config.chain.ID] + if !found { + return nil, fmt.Errorf("chain id %v not supported for Local", config.chain.ID) + } + return ethclient.DialContext(ctx, url) + } + return nil, errors.New("no provider specified, must provide an Infura API key, Alchemy API key, or an ETH backend") +} diff --git a/pkg/client_legacy/client_test.go b/pkg/client_legacy/client_test.go new file mode 100644 index 00000000..b82e7a8b --- /dev/null +++ b/pkg/client_legacy/client_test.go @@ -0,0 +1,229 @@ +package client_legacy + +import ( + "context" + "database/sql" + "fmt" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" + "github.com/textileio/go-tableland/internal/tableland" + tblimpl "github.com/textileio/go-tableland/internal/tableland/impl" + "github.com/textileio/go-tableland/pkg/client" + "github.com/textileio/go-tableland/pkg/sqlstore" + "github.com/textileio/go-tableland/pkg/tables" + "github.com/textileio/go-tableland/tests/fullstack" +) + +func TestCreate(t *testing.T) { + t.Parallel() + + calls := setup(t) + requireCreate(t, calls) +} + +func TestList(t *testing.T) { + t.Parallel() + + calls := setup(t) + requireCreate(t, calls) + res := calls.list() + require.Len(t, res, 1) +} + +func TestRelayWrite(t *testing.T) { + t.Parallel() + + calls := setup(t) + _, table := requireCreate(t, calls) + requireWrite(t, calls, table, WriteRelay(true)) +} + +func TestDirectWrite(t *testing.T) { + t.Parallel() + + calls := setup(t) + _, table := requireCreate(t, calls) + requireWrite(t, calls, table, WriteRelay(false)) +} + +func TestRead(t *testing.T) { + t.Parallel() + + calls := setup(t) + _, table := requireCreate(t, calls) + hash := requireWrite(t, calls, table) + requireReceipt(t, calls, hash, WaitFor(time.Second*10)) + + type result struct { + Bar string `json:"bar"` + } + + res0 := []result{} + calls.read(fmt.Sprintf("select * from %s", table), &res0) + require.Len(t, res0, 1) + require.Equal(t, "baz", res0[0].Bar) + + res1 := map[string]interface{}{} + calls.read(fmt.Sprintf("select * from %s", table), &res1, ReadOutput(Table)) + require.Len(t, res1, 2) + + res2 := result{} + calls.read(fmt.Sprintf("select * from %s", table), &res2, ReadUnwrap()) + require.Equal(t, "baz", res2.Bar) + + res3 := []string{} + calls.read(fmt.Sprintf("select * from %s", table), &res3, ReadExtract()) + require.Len(t, res3, 1) + require.Equal(t, "baz", res3[0]) + + res4 := "" + calls.read(fmt.Sprintf("select * from %s", table), &res4, ReadUnwrap(), ReadExtract()) + require.Equal(t, "baz", res4) +} + +func TestHash(t *testing.T) { + t.Parallel() + + calls := setup(t) + hash := calls.hash("create table foo_1337 (bar text)") + require.NotEmpty(t, hash) +} + +func TestValidate(t *testing.T) { + t.Parallel() + + calls := setup(t) + id, table := requireCreate(t, calls) + res := calls.validate(fmt.Sprintf("insert into %s (bar) values ('hi')", table)) + require.Equal(t, id, res) +} + +func TestSetController(t *testing.T) { + t.Parallel() + + calls := setup(t) + tableID, _ := requireCreate(t, calls) + key, err := crypto.GenerateKey() + require.NoError(t, err) + controller := common.HexToAddress(crypto.PubkeyToAddress(key.PublicKey).Hex()) + hash := calls.setController(controller, tableID) + require.NotEmpty(t, hash) +} + +func requireCreate(t *testing.T, calls clientCalls) (TableID, string) { + id, table := calls.create("(bar text)", WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) + require.Equal(t, "foo_1337_1", table) + return id, table +} + +func requireWrite(t *testing.T, calls clientCalls, table string, opts ...WriteOption) string { + hash := calls.write(fmt.Sprintf("insert into %s (bar) values('baz')", table), opts...) + require.NotEmpty(t, hash) + return hash +} + +func requireReceipt(t *testing.T, calls clientCalls, hash string, opts ...ReceiptOption) *TxnReceipt { + res, found := calls.receipt(hash, opts...) + require.True(t, found) + require.NotNil(t, res) + return res +} + +type aclHalfMock struct { + sqlStore sqlstore.SystemStore +} + +func (acl *aclHalfMock) CheckPrivileges( + ctx context.Context, + tx *sql.Tx, + controller common.Address, + id tables.TableID, + op tableland.Operation, +) (bool, error) { + aclImpl := tblimpl.NewACL(acl.sqlStore, nil) + return aclImpl.CheckPrivileges(ctx, tx, controller, id, op) +} + +func (acl *aclHalfMock) IsOwner(_ context.Context, _ common.Address, _ tables.TableID) (bool, error) { + return true, nil +} + +type clientCalls struct { + list func() []TableInfo + create func(schema string, opts ...CreateOption) (TableID, string) + read func(query string, target interface{}, opts ...ReadOption) + write func(query string, opts ...WriteOption) string + hash func(statement string) string + validate func(statement string) TableID + receipt func(txnHash string, options ...ReceiptOption) (*TxnReceipt, bool) + setController func(controller common.Address, tableID TableID) string +} + +func setup(t *testing.T) clientCalls { + stack := fullstack.CreateFullStack(t, fullstack.Deps{}) + + c := client.Chain{ + Endpoint: stack.Server.URL, + ID: client.ChainID(fullstack.ChainID), + ContractAddr: stack.Address, + } + + client, err := NewClient(context.Background(), stack.Wallet, NewClientChain(c), NewClientContractBackend(stack.Backend)) + require.NoError(t, err) + t.Cleanup(func() { + client.Close() + }) + + ctx := context.Background() + return clientCalls{ + list: func() []TableInfo { + res, err := client.List(ctx) + require.NoError(t, err) + return res + }, + create: func(schema string, opts ...CreateOption) (TableID, string) { + go func() { + time.Sleep(time.Second * 1) + stack.Backend.Commit() + }() + id, table, err := client.Create(ctx, schema, opts...) + require.NoError(t, err) + return id, table + }, + read: func(query string, target interface{}, opts ...ReadOption) { + err := client.Read(ctx, query, target, opts...) + require.NoError(t, err) + }, + write: func(query string, opts ...WriteOption) string { + hash, err := client.Write(ctx, query, opts...) + require.NoError(t, err) + stack.Backend.Commit() + return hash + }, + hash: func(statement string) string { + hash, err := client.Hash(ctx, statement) + require.NoError(t, err) + return hash + }, + validate: func(statement string) TableID { + tableID, err := client.Validate(ctx, statement) + require.NoError(t, err) + return tableID + }, + receipt: func(txnHash string, options ...ReceiptOption) (*TxnReceipt, bool) { + receipt, found, err := client.Receipt(ctx, txnHash, options...) + require.NoError(t, err) + return receipt, found + }, + setController: func(controller common.Address, tableID TableID) string { + hash, err := client.SetController(ctx, controller, tableID) + require.NoError(t, err) + stack.Backend.Commit() + return hash + }, + } +} From 51b8840bff63de35b8dc9396ef898c62fd53209c Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 2 Dec 2022 10:10:37 -0300 Subject: [PATCH 033/101] api/spec: update generated code from new spec version Signed-off-by: Ignacio Hagopian --- .../router/controllers/apiv1/api_receipt.go | 2 +- .../apiv1/model_transaction_receipt.go | 25 +++++++++++++++++++ .../controllers/apiv1/model_version_info.go | 2 +- internal/router/controllers/apiv1/routers.go | 6 ++--- 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 internal/router/controllers/apiv1/model_transaction_receipt.go diff --git a/internal/router/controllers/apiv1/api_receipt.go b/internal/router/controllers/apiv1/api_receipt.go index daa0d64a..4b4747f4 100644 --- a/internal/router/controllers/apiv1/api_receipt.go +++ b/internal/router/controllers/apiv1/api_receipt.go @@ -13,7 +13,7 @@ import ( "net/http" ) -func ReceiptByTxnHash(w http.ResponseWriter, r *http.Request) { +func ReceiptByTransactionnHash(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/model_transaction_receipt.go b/internal/router/controllers/apiv1/model_transaction_receipt.go new file mode 100644 index 00000000..ea1b8a2d --- /dev/null +++ b/internal/router/controllers/apiv1/model_transaction_receipt.go @@ -0,0 +1,25 @@ +/* + * 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. + * + * API version: 1.0.0 + * Contact: carson@textile.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package apiv1 + +type TransactionReceipt struct { + + TableId string `json:"tableId,omitempty"` + + TransactionHash string `json:"transactionHash,omitempty"` + + BlockNumber int64 `json:"blockNumber,omitempty"` + + ChainId int32 `json:"chainId,omitempty"` + + Error_ string `json:"error,omitempty"` + + ErrorEventIdx int32 `json:"errorEventIdx,omitempty"` +} diff --git a/internal/router/controllers/apiv1/model_version_info.go b/internal/router/controllers/apiv1/model_version_info.go index ae404897..3695bc02 100644 --- a/internal/router/controllers/apiv1/model_version_info.go +++ b/internal/router/controllers/apiv1/model_version_info.go @@ -23,5 +23,5 @@ type VersionInfo struct { BuildDate string `json:"buildDate,omitempty"` - BinaryVersion string `json:"binary_version,omitempty"` + BinaryVersion string `json:"binaryVersion,omitempty"` } diff --git a/internal/router/controllers/apiv1/routers.go b/internal/router/controllers/apiv1/routers.go index 3d5ad0ad..6139fa89 100644 --- a/internal/router/controllers/apiv1/routers.go +++ b/internal/router/controllers/apiv1/routers.go @@ -70,10 +70,10 @@ var routes = Routes{ }, Route{ - "ReceiptByTxnHash", + "ReceiptByTransactionnHash", strings.ToUpper("Get"), - "/api/v1/receipt/{chainId}/{txnHash}", - ReceiptByTxnHash, + "/api/v1/receipt/{chainId}/{transactionHash}", + ReceiptByTransactionnHash, }, Route{ From 20de7b17c6bfb87d6bf625772cc37c5d4ed21fa9 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 2 Dec 2022 15:16:51 -0300 Subject: [PATCH 034/101] api: update models to new spec Signed-off-by: Ignacio Hagopian --- .../router/controllers/apiv1/api_receipt.go | 2 +- .../controllers/apiv1/model_txn_receipt.go | 21 ----------- internal/router/controllers/apiv1/routers.go | 4 +- internal/router/controllers/system.go | 37 +++++++++++++++++++ internal/router/router.go | 10 ++--- 5 files changed, 45 insertions(+), 29 deletions(-) delete mode 100644 internal/router/controllers/apiv1/model_txn_receipt.go diff --git a/internal/router/controllers/apiv1/api_receipt.go b/internal/router/controllers/apiv1/api_receipt.go index 4b4747f4..81177b33 100644 --- a/internal/router/controllers/apiv1/api_receipt.go +++ b/internal/router/controllers/apiv1/api_receipt.go @@ -13,7 +13,7 @@ import ( "net/http" ) -func ReceiptByTransactionnHash(w http.ResponseWriter, r *http.Request) { +func ReceiptByTransactionHash(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/model_txn_receipt.go b/internal/router/controllers/apiv1/model_txn_receipt.go deleted file mode 100644 index 36a04898..00000000 --- a/internal/router/controllers/apiv1/model_txn_receipt.go +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - * - * API version: 1.0.0 - * Contact: carson@textile.io - * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) - */ -package apiv1 - -type TxnReceipt struct { - - TableId string `json:"table_id,omitempty"` - - TxnHash string `json:"txnHash,omitempty"` - - BlockNumber int64 `json:"blockNumber,omitempty"` - - ChainId int32 `json:"chainId,omitempty"` -} diff --git a/internal/router/controllers/apiv1/routers.go b/internal/router/controllers/apiv1/routers.go index 6139fa89..657c9b84 100644 --- a/internal/router/controllers/apiv1/routers.go +++ b/internal/router/controllers/apiv1/routers.go @@ -70,10 +70,10 @@ var routes = Routes{ }, Route{ - "ReceiptByTransactionnHash", + "ReceiptByTransactionHash", strings.ToUpper("Get"), "/api/v1/receipt/{chainId}/{transactionHash}", - ReceiptByTransactionnHash, + ReceiptByTransactionHash, }, Route{ diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 85ab2012..b6e4ccef 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -4,8 +4,10 @@ import ( "encoding/json" "net/http" + "github.com/ethereum/go-ethereum/common" "github.com/gorilla/mux" "github.com/rs/zerolog/log" + "github.com/textileio/go-tableland/internal/router/controllers/apiv1" "github.com/textileio/go-tableland/internal/system" "github.com/textileio/go-tableland/pkg/errors" "github.com/textileio/go-tableland/pkg/tables" @@ -21,6 +23,41 @@ func NewSystemController(svc system.SystemService) *SystemController { return &SystemController{svc} } +func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + ctx := r.Context() + + paramTxnHash := mux.Vars(r)["transactionhash"] + txnHash := common.HexToHash(paramTxnHash) + + receipt, exists, err := c.systemService.GetReceiptByTransactionHash(ctx, txnHash) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + log.Ctx(ctx).Error().Err(err).Msg("get receipt by transaction hash") + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Get receipt by transaction hash failed"}) + return + } + if !exists { + rw.WriteHeader(http.StatusNotFound) + return + } + + receiptResponse := apiv1.TransactionReceipt{ + TransactionHash: paramTxnHash, + BlockNumber: receipt.BlockNumber, + ChainId: int32(receipt.ChainID), + } + if receipt.TableID != nil { + receiptResponse.TableId = receipt.TableID.String() + } + if receipt.Error != nil { + receiptResponse.Error_ = *receipt.Error + receiptResponse.ErrorEventIdx = int32(*receipt.ErrorEventIdx) + } + rw.WriteHeader(http.StatusOK) + _ = json.NewEncoder(rw).Encode(receiptResponse) +} + // GetTable handles the GET /chain/{chainID}/tables/{id} call. func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/internal/router/router.go b/internal/router/router.go index 601181c1..6834e13c 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -99,11 +99,11 @@ func configureAPIV1Routes( infraCtrl *controllers.InfraController, ) error { handlers := map[string]http.HandlerFunc{ - "QueryFromQuery": userCtrl.GetTableQuery, - "ReceiptByTxnHash": nil, // systemCtrl.GetTxnHash, // TODO(jsign): do it. - "GetTableById": systemCtrl.GetTable, // TODO(jsign): verify output. - "Version": infraCtrl.Version, - "Health": controllers.HealthHandler, + "QueryFromQuery": userCtrl.GetTableQuery, + "ReceiptByTransactionHash": systemCtrl.GetReceiptByTransactionHash, + "GetTableById": systemCtrl.GetTable, // TODO(jsign): verify output. + "Version": infraCtrl.Version, + "Health": controllers.HealthHandler, } var specRoutesCount int From 73cbf5848284fa4aab8226facbf413d8d48076db Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 2 Dec 2022 15:17:18 -0300 Subject: [PATCH 035/101] api: implement REST GetReceiptByTransactionHash Signed-off-by: Ignacio Hagopian --- internal/system/impl/mock.go | 20 ++++++++++++ internal/system/impl/sqlstore.go | 32 +++++++++++++++++++ internal/system/impl/sqlstore_instrumented.go | 21 +++++++++++- internal/system/system.go | 3 ++ pkg/sqlstore/table.go | 11 +++++++ 5 files changed, 86 insertions(+), 1 deletion(-) diff --git a/internal/system/impl/mock.go b/internal/system/impl/mock.go index 99710fcc..9243f1da 100644 --- a/internal/system/impl/mock.go +++ b/internal/system/impl/mock.go @@ -6,6 +6,7 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/textileio/go-tableland/internal/system" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/sqlstore" @@ -20,6 +21,20 @@ func NewSystemMockService() system.SystemService { return &SystemMockService{} } +// GetReceiptByTransactionHash implements system.SystemService +func (*SystemMockService) GetReceiptByTransactionHash(context.Context, common.Hash) (sqlstore.Receipt, bool, error) { + tableID, _ := tables.NewTableID("10") + return sqlstore.Receipt{ + ChainID: 1337, + BlockNumber: 10, + IndexInBlock: 1, + TxnHash: "0xDEADBEEF", + TableID: &tableID, + Error: nil, + ErrorEventIdx: nil, + }, true, nil +} + // GetTableMetadata returns a fixed value for testing and demo purposes. func (*SystemMockService) GetTableMetadata(_ context.Context, id tables.TableID) (sqlstore.TableMetadata, error) { return sqlstore.TableMetadata{ @@ -109,6 +124,11 @@ func NewSystemMockErrService() system.SystemService { return &SystemMockErrService{} } +// GetReceiptByTransactionHash implements system.SystemService +func (*SystemMockErrService) GetReceiptByTransactionHash(context.Context, common.Hash) (sqlstore.Receipt, bool, error) { + return sqlstore.Receipt{}, false, nil +} + // GetTableMetadata returns a fixed value for testing and demo purposes. func (*SystemMockErrService) GetTableMetadata( _ context.Context, diff --git a/internal/system/impl/sqlstore.go b/internal/system/impl/sqlstore.go index 6948bc1f..78a661d5 100644 --- a/internal/system/impl/sqlstore.go +++ b/internal/system/impl/sqlstore.go @@ -9,6 +9,7 @@ import ( "net/url" "strings" + "github.com/ethereum/go-ethereum/common" logger "github.com/rs/zerolog/log" "github.com/textileio/go-tableland/internal/router/middlewares" "github.com/textileio/go-tableland/internal/system" @@ -127,6 +128,37 @@ func (s *SystemSQLStoreService) GetTableMetadata( }, nil } +func (s *SystemSQLStoreService) GetReceiptByTransactionHash( + ctx context.Context, + txnHash common.Hash, +) (sqlstore.Receipt, bool, error) { + ctxChainID := ctx.Value(middlewares.ContextKeyChainID) + chainID, ok := ctxChainID.(tableland.ChainID) + if !ok { + return sqlstore.Receipt{}, false, errors.New("no chain id found in context") + } + store, ok := s.stores[chainID] + if !ok { + return sqlstore.Receipt{}, false, fmt.Errorf("chain id %d isn't supported in the validator", chainID) + } + receipt, exists, err := store.GetReceipt(ctx, txnHash.Hex()) + if err != nil { + return sqlstore.Receipt{}, false, fmt.Errorf("transaction receipt lookup: %s", err) + } + if !exists { + return sqlstore.Receipt{}, false, nil + } + return sqlstore.Receipt{ + ChainID: chainID, + BlockNumber: receipt.BlockNumber, + IndexInBlock: receipt.IndexInBlock, + TxnHash: receipt.TxnHash, + TableID: receipt.TableID, + Error: receipt.Error, + ErrorEventIdx: receipt.ErrorEventIdx, + }, true, nil +} + // GetTablesByController returns table's fetched from SQLStore by controller address. func (s *SystemSQLStoreService) GetTablesByController( ctx context.Context, diff --git a/internal/system/impl/sqlstore_instrumented.go b/internal/system/impl/sqlstore_instrumented.go index a1549376..1541fdb0 100644 --- a/internal/system/impl/sqlstore_instrumented.go +++ b/internal/system/impl/sqlstore_instrumented.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/ethereum/go-ethereum/common" "github.com/textileio/go-tableland/internal/router/middlewares" "github.com/textileio/go-tableland/internal/system" "github.com/textileio/go-tableland/internal/tableland" @@ -38,6 +39,25 @@ func NewInstrumentedSystemSQLStoreService(system system.SystemService) (system.S return &InstrumentedSystemSQLStoreService{system, callCount, latencyHistogram}, nil } +// GetReceiptByTransactionHash implements system.SystemService +func (s *InstrumentedSystemSQLStoreService) GetReceiptByTransactionHash(ctx context.Context, hash common.Hash) (sqlstore.Receipt, bool, error) { + start := time.Now() + receipt, exists, err := s.system.GetReceiptByTransactionHash(ctx, hash) + latency := time.Since(start).Milliseconds() + chainID, _ := ctx.Value(middlewares.ContextKeyChainID).(tableland.ChainID) + + attributes := append([]attribute.KeyValue{ + {Key: "method", Value: attribute.StringValue("GetReceiptByTransactionHash")}, + {Key: "success", Value: attribute.BoolValue(err == nil)}, + {Key: "chainID", Value: attribute.Int64Value(int64(chainID))}, + }, metrics.BaseAttrs...) + + s.callCount.Add(ctx, 1, attributes...) + s.latencyHistogram.Record(ctx, latency, attributes...) + + return receipt, exists, err +} + // GetTableMetadata returns table's metadata fetched from SQLStore. func (s *InstrumentedSystemSQLStoreService) GetTableMetadata( ctx context.Context, @@ -51,7 +71,6 @@ func (s *InstrumentedSystemSQLStoreService) GetTableMetadata( // NOTE: we may face a risk of high-cardilatity in the future. This should be revised. attributes := append([]attribute.KeyValue{ {Key: "method", Value: attribute.StringValue("GetTableMetadata")}, - {Key: "id", Value: attribute.StringValue(id.String())}, {Key: "success", Value: attribute.BoolValue(err == nil)}, {Key: "chainID", Value: attribute.Int64Value(int64(chainID))}, }, metrics.BaseAttrs...) diff --git a/internal/system/system.go b/internal/system/system.go index 36d3a73d..606fa0e3 100644 --- a/internal/system/system.go +++ b/internal/system/system.go @@ -3,14 +3,17 @@ package system import ( "context" + "github.com/ethereum/go-ethereum/common" "github.com/textileio/go-tableland/pkg/sqlstore" "github.com/textileio/go-tableland/pkg/tables" ) +// TODO(json-rpc): this interface should be cleaned up after dropping support. // SystemService defines what system operations can be done. type SystemService interface { GetTableMetadata(context.Context, tables.TableID) (sqlstore.TableMetadata, error) GetTablesByController(context.Context, string) ([]sqlstore.Table, error) GetTablesByStructure(context.Context, string) ([]sqlstore.Table, error) GetSchemaByTableName(context.Context, string) (sqlstore.TableSchema, error) + GetReceiptByTransactionHash(context.Context, common.Hash) (sqlstore.Receipt, bool, error) } diff --git a/pkg/sqlstore/table.go b/pkg/sqlstore/table.go index 620faf63..c1e24b04 100644 --- a/pkg/sqlstore/table.go +++ b/pkg/sqlstore/table.go @@ -62,3 +62,14 @@ type SystemACL struct { CreatedAt time.Time UpdatedAt *time.Time } + +type Receipt struct { + ChainID tableland.ChainID + BlockNumber int64 + IndexInBlock int64 + TxnHash string + + TableID *tables.TableID + Error *string + ErrorEventIdx *int +} From b672a71865940df4e2061d3b4dd2f45b143d1d94 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 2 Dec 2022 15:17:40 -0300 Subject: [PATCH 036/101] client: add new REST client skeleton Signed-off-by: Ignacio Hagopian --- pkg/client/client.go | 29 +------ pkg/client/client_test.go | 135 +++++++------------------------ pkg/client_legacy/client_test.go | 24 ------ 3 files changed, 29 insertions(+), 159 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 75c69cb0..eced3070 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -333,35 +333,8 @@ func (c *Client) Read(ctx context.Context, query string, target interface{}, opt return nil } -type writeConfig struct { - relay bool -} - -// WriteOption controls the behavior of Write. -type WriteOption func(*writeConfig) - -// WriteRelay specifies whether or not to relay write queries through the Tableland validator. -// Default behavior is false for main net EVM chains, true for all others. -func WriteRelay(relay bool) WriteOption { - return func(wc *writeConfig) { - wc.relay = relay - } -} - // Write initiates a write query, returning the txn hash. -func (c *Client) Write(ctx context.Context, query string, opts ...WriteOption) (string, error) { - conf := writeConfig{relay: c.relayWrites} - for _, opt := range opts { - opt(&conf) - } - if conf.relay { - req := &legacy.RelayWriteQueryRequest{Statement: query} - var res legacy.RelayWriteQueryResponse - if err := c.tblRPC.CallContext(ctx, &res, "tableland_relayWriteQuery", req); err != nil { - return "", fmt.Errorf("calling rpc relayWriteQuery: %v", err) - } - return res.Transaction.Hash, nil - } +func (c *Client) Write(ctx context.Context, query string) (string, error) { tableID, err := c.Validate(ctx, query) if err != nil { return "", fmt.Errorf("calling Validate: %v", err) diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 19d6e76b..31b8e898 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -2,18 +2,11 @@ package client import ( "context" - "database/sql" "fmt" "testing" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" - "github.com/textileio/go-tableland/internal/tableland" - tblimpl "github.com/textileio/go-tableland/internal/tableland/impl" - "github.com/textileio/go-tableland/pkg/sqlstore" - "github.com/textileio/go-tableland/pkg/tables" "github.com/textileio/go-tableland/tests/fullstack" ) @@ -24,29 +17,12 @@ func TestCreate(t *testing.T) { requireCreate(t, calls) } -func TestList(t *testing.T) { - t.Parallel() - - calls := setup(t) - requireCreate(t, calls) - res := calls.list() - require.Len(t, res, 1) -} - -func TestRelayWrite(t *testing.T) { +func TestWrite(t *testing.T) { t.Parallel() calls := setup(t) _, table := requireCreate(t, calls) - requireWrite(t, calls, table, WriteRelay(true)) -} - -func TestDirectWrite(t *testing.T) { - t.Parallel() - - calls := setup(t) - _, table := requireCreate(t, calls) - requireWrite(t, calls, table, WriteRelay(false)) + requireWrite(t, calls, table) } func TestRead(t *testing.T) { @@ -62,55 +38,38 @@ func TestRead(t *testing.T) { } res0 := []result{} - calls.read(fmt.Sprintf("select * from %s", table), &res0) + calls.query(fmt.Sprintf("select * from %s", table), &res0) require.Len(t, res0, 1) require.Equal(t, "baz", res0[0].Bar) res1 := map[string]interface{}{} - calls.read(fmt.Sprintf("select * from %s", table), &res1, ReadOutput(Table)) + calls.query(fmt.Sprintf("select * from %s", table), &res1, ReadOutput(Table)) require.Len(t, res1, 2) res2 := result{} - calls.read(fmt.Sprintf("select * from %s", table), &res2, ReadUnwrap()) + calls.query(fmt.Sprintf("select * from %s", table), &res2, ReadUnwrap()) require.Equal(t, "baz", res2.Bar) res3 := []string{} - calls.read(fmt.Sprintf("select * from %s", table), &res3, ReadExtract()) + calls.query(fmt.Sprintf("select * from %s", table), &res3, ReadExtract()) require.Len(t, res3, 1) require.Equal(t, "baz", res3[0]) res4 := "" - calls.read(fmt.Sprintf("select * from %s", table), &res4, ReadUnwrap(), ReadExtract()) + calls.query(fmt.Sprintf("select * from %s", table), &res4, ReadUnwrap(), ReadExtract()) require.Equal(t, "baz", res4) } -func TestHash(t *testing.T) { - t.Parallel() - - calls := setup(t) - hash := calls.hash("create table foo_1337 (bar text)") - require.NotEmpty(t, hash) +func TestGetTableByID(t *testing.T) { + t.Fail() } -func TestValidate(t *testing.T) { - t.Parallel() - - calls := setup(t) - id, table := requireCreate(t, calls) - res := calls.validate(fmt.Sprintf("insert into %s (bar) values ('hi')", table)) - require.Equal(t, id, res) +func TestVersion(t *testing.T) { + t.Fail() } -func TestSetController(t *testing.T) { - t.Parallel() - - calls := setup(t) - tableID, _ := requireCreate(t, calls) - key, err := crypto.GenerateKey() - require.NoError(t, err) - controller := common.HexToAddress(crypto.PubkeyToAddress(key.PublicKey).Hex()) - hash := calls.setController(controller, tableID) - require.NotEmpty(t, hash) +func TestHealth(t *testing.T) { + t.Fail() } func requireCreate(t *testing.T, calls clientCalls) (TableID, string) { @@ -119,8 +78,8 @@ func requireCreate(t *testing.T, calls clientCalls) (TableID, string) { return id, table } -func requireWrite(t *testing.T, calls clientCalls, table string, opts ...WriteOption) string { - hash := calls.write(fmt.Sprintf("insert into %s (bar) values('baz')", table), opts...) +func requireWrite(t *testing.T, calls clientCalls, table string) string { + hash := calls.write(fmt.Sprintf("insert into %s (bar) values('baz')", table)) require.NotEmpty(t, hash) return hash } @@ -132,34 +91,14 @@ func requireReceipt(t *testing.T, calls clientCalls, hash string, opts ...Receip return res } -type aclHalfMock struct { - sqlStore sqlstore.SystemStore -} - -func (acl *aclHalfMock) CheckPrivileges( - ctx context.Context, - tx *sql.Tx, - controller common.Address, - id tables.TableID, - op tableland.Operation, -) (bool, error) { - aclImpl := tblimpl.NewACL(acl.sqlStore, nil) - return aclImpl.CheckPrivileges(ctx, tx, controller, id, op) -} - -func (acl *aclHalfMock) IsOwner(_ context.Context, _ common.Address, _ tables.TableID) (bool, error) { - return true, nil -} - type clientCalls struct { - list func() []TableInfo - create func(schema string, opts ...CreateOption) (TableID, string) - read func(query string, target interface{}, opts ...ReadOption) - write func(query string, opts ...WriteOption) string - hash func(statement string) string - validate func(statement string) TableID - receipt func(txnHash string, options ...ReceiptOption) (*TxnReceipt, bool) - setController func(controller common.Address, tableID TableID) string + create func(schema string, opts ...CreateOption) (TableID, string) + write func(query string) string + query func(query string, target interface{}, opts ...ReadOption) + receipt func(txnHash string, options ...ReceiptOption) (*TxnReceipt, bool) + getTableById func(tableID int64) (*TxnReceipt, bool) + version func() error + health func() (bool, error) } func setup(t *testing.T) clientCalls { @@ -179,11 +118,6 @@ func setup(t *testing.T) clientCalls { ctx := context.Background() return clientCalls{ - list: func() []TableInfo { - res, err := client.List(ctx) - require.NoError(t, err) - return res - }, create: func(schema string, opts ...CreateOption) (TableID, string) { go func() { time.Sleep(time.Second * 1) @@ -193,36 +127,23 @@ func setup(t *testing.T) clientCalls { require.NoError(t, err) return id, table }, - read: func(query string, target interface{}, opts ...ReadOption) { + query: func(query string, target interface{}, opts ...ReadOption) { err := client.Read(ctx, query, target, opts...) require.NoError(t, err) }, - write: func(query string, opts ...WriteOption) string { - hash, err := client.Write(ctx, query, opts...) + write: func(query string) string { + hash, err := client.Write(ctx, query) require.NoError(t, err) stack.Backend.Commit() return hash }, - hash: func(statement string) string { - hash, err := client.Hash(ctx, statement) - require.NoError(t, err) - return hash - }, - validate: func(statement string) TableID { - tableID, err := client.Validate(ctx, statement) - require.NoError(t, err) - return tableID - }, receipt: func(txnHash string, options ...ReceiptOption) (*TxnReceipt, bool) { receipt, found, err := client.Receipt(ctx, txnHash, options...) require.NoError(t, err) return receipt, found }, - setController: func(controller common.Address, tableID TableID) string { - hash, err := client.SetController(ctx, controller, tableID) - require.NoError(t, err) - stack.Backend.Commit() - return hash - }, + getTableById: func(tableID int64) (*TxnReceipt, bool) { panic("TODO") }, + version: func() error { panic("TODO") }, + health: func() (bool, error) { panic("TODO") }, } } diff --git a/pkg/client_legacy/client_test.go b/pkg/client_legacy/client_test.go index b82e7a8b..ff702e29 100644 --- a/pkg/client_legacy/client_test.go +++ b/pkg/client_legacy/client_test.go @@ -2,7 +2,6 @@ package client_legacy import ( "context" - "database/sql" "fmt" "testing" "time" @@ -10,11 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" - "github.com/textileio/go-tableland/internal/tableland" - tblimpl "github.com/textileio/go-tableland/internal/tableland/impl" "github.com/textileio/go-tableland/pkg/client" - "github.com/textileio/go-tableland/pkg/sqlstore" - "github.com/textileio/go-tableland/pkg/tables" "github.com/textileio/go-tableland/tests/fullstack" ) @@ -133,25 +128,6 @@ func requireReceipt(t *testing.T, calls clientCalls, hash string, opts ...Receip return res } -type aclHalfMock struct { - sqlStore sqlstore.SystemStore -} - -func (acl *aclHalfMock) CheckPrivileges( - ctx context.Context, - tx *sql.Tx, - controller common.Address, - id tables.TableID, - op tableland.Operation, -) (bool, error) { - aclImpl := tblimpl.NewACL(acl.sqlStore, nil) - return aclImpl.CheckPrivileges(ctx, tx, controller, id, op) -} - -func (acl *aclHalfMock) IsOwner(_ context.Context, _ common.Address, _ tables.TableID) (bool, error) { - return true, nil -} - type clientCalls struct { list func() []TableInfo create func(schema string, opts ...CreateOption) (TableID, string) From e093c1e040e3645e4aa81aae7f935e1669165327 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 2 Dec 2022 17:29:04 -0300 Subject: [PATCH 037/101] client: progress in new api support Signed-off-by: Ignacio Hagopian --- pkg/client/client.go | 319 +++++++------------------------------ pkg/client/health.go | 16 ++ pkg/client/queryhelpers.go | 26 +++ pkg/client/readquery.go | 93 +++++++++++ pkg/client/receipt.go | 89 +++++++++++ pkg/client/version.go | 23 +++ pkg/client/writequery.go | 83 ++++++++++ 7 files changed, 388 insertions(+), 261 deletions(-) create mode 100644 pkg/client/health.go create mode 100644 pkg/client/queryhelpers.go create mode 100644 pkg/client/readquery.go create mode 100644 pkg/client/receipt.go create mode 100644 pkg/client/version.go create mode 100644 pkg/client/writequery.go diff --git a/pkg/client/client.go b/pkg/client/client.go index eced3070..cbb90117 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -2,88 +2,40 @@ package client import ( "context" - "encoding/json" "errors" "fmt" "math/big" "net/http" + "net/url" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" "github.com/textileio/go-tableland/internal/router/controllers/legacy" + systemimpl "github.com/textileio/go-tableland/internal/system/impl" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/nonce/impl" - "github.com/textileio/go-tableland/pkg/siwe" - "github.com/textileio/go-tableland/pkg/tables" + "github.com/textileio/go-tableland/pkg/parsing" + parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" "github.com/textileio/go-tableland/pkg/tables/impl/ethereum" "github.com/textileio/go-tableland/pkg/wallet" ) var defaultChain = Chains.PolygonMumbai -// TxnReceipt is a Tableland event processing receipt. -type TxnReceipt struct { - ChainID ChainID `json:"chain_id"` - TxnHash string `json:"txn_hash"` - BlockNumber int64 `json:"block_number"` - Error string `json:"error"` - ErrorEventIdx int `json:"error_event_idx"` - TableID *string `json:"table_id,omitempty"` -} - -// TableID is the ID of a Table. -type TableID big.Int - -// String returns a string representation of the TableID. -func (tid TableID) String() string { - bi := (big.Int)(tid) - return bi.String() -} - -// ToBigInt returns a *big.Int representation of the TableID. -func (tid TableID) ToBigInt() *big.Int { - bi := (big.Int)(tid) - b := &big.Int{} - b.Set(&bi) - return b -} - -// TableInfo summarizes information about a table. -type TableInfo struct { - Controller string `json:"controller"` - Name string `json:"name"` - Structure string `json:"structure"` - CreatedAt time.Time `json:"created_at"` -} - -// NewTableID creates a TableID from a string representation of the uint256. -func NewTableID(strID string) (TableID, error) { - tableID := &big.Int{} - if _, ok := tableID.SetString(strID, 10); !ok { - return TableID{}, fmt.Errorf("parsing stringified id failed") - } - if tableID.Cmp(&big.Int{}) < 0 { - return TableID{}, fmt.Errorf("table id is negative") - } - return TableID(*tableID), nil -} - // Client is the Tableland client. type Client struct { - tblRPC *rpc.Client tblHTTP *http.Client tblContract *ethereum.Client chain Chain - relayWrites bool wallet *wallet.Wallet + parser parsing.SQLValidator + baseURL *url.URL } type config struct { chain *Chain - relayWrites *bool infuraAPIKey string alchemyAPIKey string local bool @@ -100,13 +52,6 @@ func NewClientChain(chain Chain) NewClientOption { } } -// NewClientRelayWrites specifies whether or not to relay write queries through the Tableland validator. -func NewClientRelayWrites(relay bool) NewClientOption { - return func(ncc *config) { - ncc.relayWrites = &relay - } -} - // NewClientInfuraAPIKey specifies an Infura API to use when creating an EVM backend. func NewClientInfuraAPIKey(key string) NewClientOption { return func(c *config) { @@ -141,15 +86,6 @@ func NewClient(ctx context.Context, wallet *wallet.Wallet, opts ...NewClientOpti for _, opt := range opts { opt(&config) } - var relay bool - if config.relayWrites != nil { - relay = *config.relayWrites - } else { - relay = config.chain.CanRelayWrites() - } - if relay && !config.chain.CanRelayWrites() { - return nil, errors.New("options specified to relay writes for a chain that doesn't support it") - } contractBackend, err := getContractBackend(ctx, config) if err != nil { @@ -167,208 +103,40 @@ func NewClient(ctx context.Context, wallet *wallet.Wallet, opts ...NewClientOpti return nil, fmt.Errorf("creating contract client: %v", err) } - siwe, err := siwe.EncodedSIWEMsg(tableland.ChainID(config.chain.ID), wallet, time.Hour*24*365) - if err != nil { - return nil, fmt.Errorf("creating siwe value: %v", err) - } - - tblRPC, err := rpc.DialContext(ctx, config.chain.Endpoint+"/rpc") - if err != nil { - return nil, fmt.Errorf("creating rpc client: %v", err) - } - tblRPC.SetHeader("Authorization", "Bearer "+siwe) - - return &Client{ - tblRPC: tblRPC, - tblHTTP: &http.Client{}, - tblContract: tblContract, - chain: *config.chain, - relayWrites: relay, - wallet: wallet, - }, nil -} - -// List lists something. -func (c *Client) List(ctx context.Context) ([]TableInfo, error) { - url := fmt.Sprintf( - "%s/chain/%d/tables/controller/%s", - c.chain.Endpoint, - c.chain.ID, - c.wallet.Address().Hex(), - ) - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, fmt.Errorf("creating request: %v", err) - } - req = req.WithContext(ctx) - res, err := c.tblHTTP.Do(req) - if err != nil { - return nil, fmt.Errorf("calling http endpoint: %v", err) - } - defer func() { - _ = res.Body.Close() - }() - - var ret []TableInfo - - if err := json.NewDecoder(res.Body).Decode(&ret); err != nil { - return nil, fmt.Errorf("decoding response body: %v", err) - } - - return ret, nil -} - -type createConfig struct { - prefix string - receiptTimeout *time.Duration -} - -// CreateOption controls the behavior of Create. -type CreateOption func(*createConfig) - -// WithPrefix allows you to specify an optional table name prefix where -// the final table name will be __. -func WithPrefix(prefix string) CreateOption { - return func(cc *createConfig) { - cc.prefix = prefix - } -} - -// WithReceiptTimeout specifies how long to wait for the Tableland -// receipt that contains the table id. -func WithReceiptTimeout(timeout time.Duration) CreateOption { - return func(cc *createConfig) { - cc.receiptTimeout = &timeout - } -} - -// Create creates a new table on the Tableland. -func (c *Client) Create(ctx context.Context, schema string, opts ...CreateOption) (TableID, string, error) { - defaultTimeout := time.Minute * 10 - conf := createConfig{receiptTimeout: &defaultTimeout} - for _, opt := range opts { - opt(&conf) - } - - createStatement := fmt.Sprintf("CREATE TABLE %s_%d %s", conf.prefix, c.chain.ID, schema) - req := &legacy.ValidateCreateTableRequest{CreateStatement: createStatement} - var res legacy.ValidateCreateTableResponse - - if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateCreateTable", req); err != nil { - return TableID{}, "", fmt.Errorf("calling rpc validateCreateTable: %v", err) + parserOpts := []parsing.Option{ + parsing.WithMaxReadQuerySize(35000), + parsing.WithMaxWriteQuerySize(35000), } - t, err := c.tblContract.CreateTable(ctx, c.wallet.Address(), createStatement) + parser, err := parserimpl.New([]string{ + "sqlite_", + systemimpl.SystemTablesPrefix, + systemimpl.RegistryTableName, + }, parserOpts...) if err != nil { - return TableID{}, "", fmt.Errorf("calling contract create table: %v", err) + return nil, fmt.Errorf("new parser: %s", err) } - r, found, err := c.waitForReceipt(ctx, t.Hash().Hex(), *conf.receiptTimeout) + parser, err = parserimpl.NewInstrumentedSQLValidator(parser) if err != nil { - return TableID{}, "", fmt.Errorf("waiting for txn receipt: %v", err) - } - if !found { - return TableID{}, "", errors.New("no receipt found before timeout") - } - - tableID, ok := big.NewInt(0).SetString(*r.TableID, 10) - if !ok { - return TableID{}, "", errors.New("parsing table id from response") - } - - return TableID(*tableID), fmt.Sprintf("%s_%d_%s", conf.prefix, c.chain.ID, *r.TableID), nil -} - -// Output is used to control the output format of a Read using the ReadOutput option. -type Output string - -const ( - // Table returns the query results as a JSON object with columns and rows properties. - Table Output = "table" - // Objects returns the query results as a JSON array of JSON objects. This is the default. - Objects Output = "objects" -) - -// ReadOption controls the behavior of Read. -type ReadOption func(*legacy.RunReadQueryRequest) - -// ReadOutput sets the output format. Default is Objects. -func ReadOutput(output Output) ReadOption { - return func(rrqr *legacy.RunReadQueryRequest) { - rrqr.Output = (*string)(&output) - } -} - -// ReadExtract specifies whether or not to extract the JSON object -// from the single property of the surrounding JSON object. -// Default is false. -func ReadExtract() ReadOption { - return func(rrqr *legacy.RunReadQueryRequest) { - v := true - rrqr.Extract = &v + return nil, fmt.Errorf("instrumenting parser: %s", err) } -} - -// ReadUnwrap specifies whether or not to unwrap the returned JSON objects from their surrounding array. -// Default is false. -func ReadUnwrap() ReadOption { - return func(rrqr *legacy.RunReadQueryRequest) { - v := true - rrqr.Unwrap = &v - } -} - -// Read runs a read query with the provided opts and unmarshals the results into target. -func (c *Client) Read(ctx context.Context, query string, target interface{}, opts ...ReadOption) error { - req := &legacy.RunReadQueryRequest{Statement: query} - for _, opt := range opts { - opt(req) - } - res := &legacy.RunReadQueryResponse{ - Result: target, - } - if err := c.tblRPC.CallContext(ctx, &res, "tableland_runReadQuery", req); err != nil { - return fmt.Errorf("calling rpc runReadQuery: %v", err) - } - return nil -} -// Write initiates a write query, returning the txn hash. -func (c *Client) Write(ctx context.Context, query string) (string, error) { - tableID, err := c.Validate(ctx, query) - if err != nil { - return "", fmt.Errorf("calling Validate: %v", err) - } - res, err := c.tblContract.RunSQL(ctx, c.wallet.Address(), tables.TableID(tableID), query) + baseURL, err := url.Parse(config.chain.Endpoint) if err != nil { - return "", fmt.Errorf("calling RunSQL: %v", err) - } - return res.Hash().Hex(), nil -} - -// Hash validates the provided create table statement and returns its hash. -func (c *Client) Hash(ctx context.Context, statement string) (string, error) { - req := &legacy.ValidateCreateTableRequest{CreateStatement: statement} - var res legacy.ValidateCreateTableResponse - if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateCreateTable", req); err != nil { - return "", fmt.Errorf("calling rpc validateCreateTable: %v", err) - } - return res.StructureHash, nil -} - -// Validate validates a write query, returning the table id. -func (c *Client) Validate(ctx context.Context, statement string) (TableID, error) { - req := &legacy.ValidateWriteQueryRequest{Statement: statement} - var res legacy.ValidateWriteQueryResponse - if err := c.tblRPC.CallContext(ctx, &res, "tableland_validateWriteQuery", req); err != nil { - return TableID{}, fmt.Errorf("calling rpc validateWriteQuery: %v", err) - } - tableID, ok := big.NewInt(0).SetString(res.TableID, 10) - if !ok { - return TableID{}, errors.New("parsing table id from response") + return nil, fmt.Errorf("invalid endpoint URL: %s", err) } - return TableID(*tableID), nil + return &Client{ + tblHTTP: &http.Client{ + Timeout: time.Second * 30, + }, + tblContract: tblContract, + chain: *config.chain, + wallet: wallet, + parser: parser, + baseURL: baseURL, + }, nil } type receiptConfig struct { @@ -490,3 +258,32 @@ func getContractBackend(ctx context.Context, config config) (bind.ContractBacken } return nil, errors.New("no provider specified, must provide an Infura API key, Alchemy API key, or an ETH backend") } + +// TableID is the ID of a Table. +type TableID big.Int + +// String returns a string representation of the TableID. +func (tid TableID) String() string { + bi := (big.Int)(tid) + return bi.String() +} + +// ToBigInt returns a *big.Int representation of the TableID. +func (tid TableID) ToBigInt() *big.Int { + bi := (big.Int)(tid) + b := &big.Int{} + b.Set(&bi) + return b +} + +// NewTableID creates a TableID from a string representation of the uint256. +func NewTableID(strID string) (TableID, error) { + tableID := &big.Int{} + if _, ok := tableID.SetString(strID, 10); !ok { + return TableID{}, fmt.Errorf("parsing stringified id failed") + } + if tableID.Cmp(&big.Int{}) < 0 { + return TableID{}, fmt.Errorf("table id is negative") + } + return TableID(*tableID), nil +} diff --git a/pkg/client/health.go b/pkg/client/health.go new file mode 100644 index 00000000..49c95e81 --- /dev/null +++ b/pkg/client/health.go @@ -0,0 +1,16 @@ +package client + +import ( + "context" + "fmt" + "net/http" +) + +func (c *Client) CheckHealth(ctx context.Context) (bool, error) { + res, err := c.tblHTTP.Get(c.chain.Endpoint + "/health") + if err != nil { + return false, fmt.Errorf("http get error: %s", err) + } + + return res.StatusCode == http.StatusOK, nil +} diff --git a/pkg/client/queryhelpers.go b/pkg/client/queryhelpers.go new file mode 100644 index 00000000..ef66300a --- /dev/null +++ b/pkg/client/queryhelpers.go @@ -0,0 +1,26 @@ +package client + +import ( + "context" + "fmt" + + "github.com/textileio/go-tableland/internal/tableland" +) + +// Hash validates the provided create table statement and returns its hash. +func (c *Client) Hash(ctx context.Context, statement string) (string, error) { + stmt, err := c.parser.ValidateCreateTable(statement, tableland.ChainID(c.chain.ID)) + if err != nil { + return "", fmt.Errorf("invalid create statement: %s", err) + } + return stmt.GetStructureHash(), nil +} + +// Validate validates a write query, returning the table id. +func (c *Client) Validate(ctx context.Context, statement string) (TableID, error) { + stmts, err := c.parser.ValidateMutatingQuery(statement, tableland.ChainID(c.chain.ID)) + if err != nil { + return TableID{}, fmt.Errorf("invalid create statement: %s", err) + } + return NewTableID(stmts[0].GetTableID().String()) +} diff --git a/pkg/client/readquery.go b/pkg/client/readquery.go new file mode 100644 index 00000000..54202efa --- /dev/null +++ b/pkg/client/readquery.go @@ -0,0 +1,93 @@ +package client + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" +) + +// Output is used to control the output format of a Read using the ReadOutput option. +type Output string + +const ( + // Table returns the query results as a JSON object with columns and rows properties. + Table Output = "table" + // Objects returns the query results as a JSON array of JSON objects. This is the default. + Objects Output = "objects" +) + +type readQueryParameters struct { + format Output + extract bool + unwrap bool +} + +var defaultReadQueryParameters = readQueryParameters{ + format: Objects, + extract: false, + unwrap: false, +} + +// ReadOption controls the behavior of Read. +type ReadOption func(*readQueryParameters) + +// ReadOutput sets the output format. Default is Objects. +func ReadOutput(output Output) ReadOption { + return func(params *readQueryParameters) { + params.format = output + } +} + +// ReadExtract specifies whether or not to extract the JSON object +// from the single property of the surrounding JSON object. +// Default is false. +func ReadExtract() ReadOption { + return func(params *readQueryParameters) { + params.extract = true + } +} + +// ReadUnwrap specifies whether or not to unwrap the returned JSON objects from their surrounding array. +// Default is false. +func ReadUnwrap() ReadOption { + return func(params *readQueryParameters) { + params.unwrap = true + } +} + +// Read runs a read query with the provided opts and unmarshals the results into target. +func (c *Client) Read(ctx context.Context, query string, target interface{}, opts ...ReadOption) error { + params := defaultReadQueryParameters + for _, opt := range opts { + opt(¶ms) + } + + url := *c.baseURL // This is a shallow-copy, but it's safe. + values := url.Query() + values.Set("statement", query) + values.Set("format", string(params.format)) + if params.extract { + values.Set("extract", "true") + } + if params.unwrap { + values.Set("unwrap", "true") + } + url.RawQuery = values.Encode() + + response, err := c.tblHTTP.Get(url.String()) + if err != nil { + return fmt.Errorf("calling query: %s", err) + } + if response.StatusCode != http.StatusOK { + msg, _ := io.ReadAll(response.Body) + return fmt.Errorf("the response wasn't successful: %s", msg) + } + + if err := json.NewDecoder(response.Body).Decode(&target); err != nil { + return fmt.Errorf("decoding result into struct: %s", err) + } + + return nil +} diff --git a/pkg/client/receipt.go b/pkg/client/receipt.go new file mode 100644 index 00000000..e583ad26 --- /dev/null +++ b/pkg/client/receipt.go @@ -0,0 +1,89 @@ +package client + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + "time" + + "github.com/textileio/go-tableland/internal/router/controllers/apiv1" +) + +type receiptConfig struct { + timeout *time.Duration +} + +// ReceiptOption controls the behavior of calls to Receipt. +type ReceiptOption func(*receiptConfig) + +// WaitFor causes calls to Receipt to wait for the specified duration. +func WaitFor(timeout time.Duration) ReceiptOption { + return func(rc *receiptConfig) { + rc.timeout = &timeout + } +} + +// Receipt gets a transaction receipt. +func (c *Client) Receipt( + ctx context.Context, + txnHash string, + options ...ReceiptOption, +) (*apiv1.TransactionReceipt, bool, error) { + config := receiptConfig{} + for _, option := range options { + option(&config) + } + if config.timeout != nil { + return c.waitForReceipt(ctx, txnHash, *config.timeout) + } + return c.getReceipt(ctx, txnHash) +} + +func (c *Client) getReceipt(ctx context.Context, txnHash string) (*apiv1.TransactionReceipt, bool, error) { + url := (*c.baseURL). + JoinPath(strconv.FormatInt(int64(c.chain.ID), 10)). + JoinPath(txnHash) + + response, err := c.tblHTTP.Get(url.String()) + if err != nil { + return nil, false, fmt.Errorf("calling get receipt by transaction hash: %s", err) + } + if response.StatusCode == http.StatusNotFound { + return nil, false, nil + } + if response.StatusCode != http.StatusOK { + msg, _ := io.ReadAll(response.Body) + return nil, false, fmt.Errorf("failed call: %s", msg) + } + var tr apiv1.TransactionReceipt + if err := json.NewDecoder(response.Body).Decode(&tr); err != nil { + return nil, false, fmt.Errorf("unmarshaling result: %s", err) + } + return &tr, true, nil +} + +func (c *Client) waitForReceipt( + ctx context.Context, + txnHash string, + timeout time.Duration, +) (*apiv1.TransactionReceipt, bool, error) { + for stay, timeout := true, time.After(timeout); stay; { + select { + case <-timeout: + stay = false + default: + receipt, found, err := c.getReceipt(ctx, txnHash) + if err != nil { + return nil, false, err + } + if found { + return receipt, found, nil + } + time.Sleep(time.Second) + } + } + return nil, false, nil +} diff --git a/pkg/client/version.go b/pkg/client/version.go new file mode 100644 index 00000000..654e108e --- /dev/null +++ b/pkg/client/version.go @@ -0,0 +1,23 @@ +package client + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/textileio/go-tableland/internal/router/controllers/apiv1" +) + +func (c *Client) Version(ctx context.Context) (apiv1.VersionInfo, error) { + res, err := c.tblHTTP.Get(c.chain.Endpoint + "/version") + if err != nil { + return apiv1.VersionInfo{}, fmt.Errorf("http get error: %s", err) + } + + var versionInfo apiv1.VersionInfo + if err := json.NewDecoder(res.Body).Decode(&versionInfo); err != nil { + return apiv1.VersionInfo{}, fmt.Errorf("decoding version info: %s", err) + } + + return versionInfo, nil +} diff --git a/pkg/client/writequery.go b/pkg/client/writequery.go new file mode 100644 index 00000000..36bd0fe7 --- /dev/null +++ b/pkg/client/writequery.go @@ -0,0 +1,83 @@ +package client + +import ( + "context" + "errors" + "fmt" + "math/big" + "time" + + "github.com/textileio/go-tableland/internal/tableland" + "github.com/textileio/go-tableland/pkg/tables" +) + +type createConfig struct { + prefix string + receiptTimeout *time.Duration +} + +// CreateOption controls the behavior of Create. +type CreateOption func(*createConfig) + +// WithPrefix allows you to specify an optional table name prefix where +// the final table name will be __. +func WithPrefix(prefix string) CreateOption { + return func(cc *createConfig) { + cc.prefix = prefix + } +} + +// WithReceiptTimeout specifies how long to wait for the Tableland +// receipt that contains the table id. +func WithReceiptTimeout(timeout time.Duration) CreateOption { + return func(cc *createConfig) { + cc.receiptTimeout = &timeout + } +} + +// Create creates a new table on the Tableland. +func (c *Client) Create(ctx context.Context, schema string, opts ...CreateOption) (TableID, string, error) { + defaultTimeout := time.Minute * 10 + conf := createConfig{receiptTimeout: &defaultTimeout} + for _, opt := range opts { + opt(&conf) + } + + createStatement := fmt.Sprintf("CREATE TABLE %s_%d %s", conf.prefix, c.chain.ID, schema) + if _, err := c.parser.ValidateCreateTable(createStatement, tableland.ChainID(c.chain.ID)); err != nil { + return TableID{}, "", fmt.Errorf("invalid create statement: %s", err) + } + + t, err := c.tblContract.CreateTable(ctx, c.wallet.Address(), createStatement) + if err != nil { + return TableID{}, "", fmt.Errorf("calling contract create table: %v", err) + } + + r, found, err := c.waitForReceipt(ctx, t.Hash().Hex(), *conf.receiptTimeout) + if err != nil { + return TableID{}, "", fmt.Errorf("waiting for txn receipt: %v", err) + } + if !found { + return TableID{}, "", errors.New("no receipt found before timeout") + } + + tableID, ok := big.NewInt(0).SetString(*r.TableID, 10) + if !ok { + return TableID{}, "", errors.New("parsing table id from response") + } + + return TableID(*tableID), fmt.Sprintf("%s_%d_%s", conf.prefix, c.chain.ID, *r.TableID), nil +} + +// Write initiates a write query, returning the txn hash. +func (c *Client) Write(ctx context.Context, query string) (string, error) { + tableID, err := c.Validate(ctx, query) + if err != nil { + return "", fmt.Errorf("calling Validate: %v", err) + } + res, err := c.tblContract.RunSQL(ctx, c.wallet.Address(), tables.TableID(tableID), query) + if err != nil { + return "", fmt.Errorf("calling RunSQL: %v", err) + } + return res.Hash().Hex(), nil +} From 1255aa71baef12b6a9cf04496a025fdf724e69ff Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 2 Dec 2022 18:17:29 -0300 Subject: [PATCH 038/101] client: more progress Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system.go | 2 +- pkg/client/client.go | 97 --------------------------- pkg/client/client_test.go | 47 +++++++++---- pkg/client/receipt.go | 1 + pkg/client/version.go | 8 +-- pkg/client/writequery.go | 4 +- 6 files changed, 41 insertions(+), 118 deletions(-) diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index b6e4ccef..62247b17 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -27,7 +27,7 @@ func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r rw.Header().Set("Content-Type", "application/json") ctx := r.Context() - paramTxnHash := mux.Vars(r)["transactionhash"] + paramTxnHash := mux.Vars(r)["transactionHash"] txnHash := common.HexToHash(paramTxnHash) receipt, exists, err := c.systemService.GetReceiptByTransactionHash(ctx, txnHash) diff --git a/pkg/client/client.go b/pkg/client/client.go index cbb90117..bdb2bc9f 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -10,9 +10,7 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" - "github.com/textileio/go-tableland/internal/router/controllers/legacy" systemimpl "github.com/textileio/go-tableland/internal/system/impl" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/nonce/impl" @@ -139,101 +137,6 @@ func NewClient(ctx context.Context, wallet *wallet.Wallet, opts ...NewClientOpti }, nil } -type receiptConfig struct { - timeout *time.Duration -} - -// ReceiptOption controls the behavior of calls to Receipt. -type ReceiptOption func(*receiptConfig) - -// WaitFor causes calls to Receipt to wait for the specified duration. -func WaitFor(timeout time.Duration) ReceiptOption { - return func(rc *receiptConfig) { - rc.timeout = &timeout - } -} - -// Receipt gets a transaction receipt. -func (c *Client) Receipt( - ctx context.Context, - txnHash string, - options ...ReceiptOption, -) (*TxnReceipt, bool, error) { - config := receiptConfig{} - for _, option := range options { - option(&config) - } - if config.timeout != nil { - return c.waitForReceipt(ctx, txnHash, *config.timeout) - } - return c.getReceipt(ctx, txnHash) -} - -// SetController sets the controller address for the specified table. -func (c *Client) SetController( - ctx context.Context, - controller common.Address, - tableID TableID, -) (string, error) { - req := legacy.SetControllerRequest{Controller: controller.Hex(), TokenID: tableID.String()} - var res legacy.SetControllerResponse - - if err := c.tblRPC.CallContext(ctx, &res, "tableland_setController", req); err != nil { - return "", fmt.Errorf("calling rpc setController: %v", err) - } - - return res.Transaction.Hash, nil -} - -func (c *Client) getReceipt(ctx context.Context, txnHash string) (*TxnReceipt, bool, error) { - req := legacy.GetReceiptRequest{TxnHash: txnHash} - var res legacy.GetReceiptResponse - if err := c.tblRPC.CallContext(ctx, &res, "tableland_getReceipt", req); err != nil { - return nil, false, fmt.Errorf("calling rpc getReceipt: %v", err) - } - if !res.Ok { - return nil, res.Ok, nil - } - - receipt := TxnReceipt{ - ChainID: ChainID(res.Receipt.ChainID), - TxnHash: res.Receipt.TxnHash, - BlockNumber: res.Receipt.BlockNumber, - Error: res.Receipt.Error, - ErrorEventIdx: res.Receipt.ErrorEventIdx, - TableID: res.Receipt.TableID, - } - return &receipt, res.Ok, nil -} - -func (c *Client) waitForReceipt( - ctx context.Context, - txnHash string, - timeout time.Duration, -) (*TxnReceipt, bool, error) { - for stay, timeout := true, time.After(timeout); stay; { - select { - case <-timeout: - stay = false - default: - receipt, found, err := c.getReceipt(ctx, txnHash) - if err != nil { - return nil, false, err - } - if found { - return receipt, found, nil - } - time.Sleep(time.Second) - } - } - return nil, false, nil -} - -// Close implements Close. -func (c *Client) Close() { - c.tblRPC.Close() -} - func getContractBackend(ctx context.Context, config config) (bind.ContractBackend, error) { if config.contractBackend != nil && config.infuraAPIKey == "" && config.alchemyAPIKey == "" { return config.contractBackend, nil diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 31b8e898..191f8e4b 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/stretchr/testify/require" + "github.com/textileio/go-tableland/internal/router/controllers/apiv1" "github.com/textileio/go-tableland/tests/fullstack" ) @@ -61,15 +62,32 @@ func TestRead(t *testing.T) { } func TestGetTableByID(t *testing.T) { - t.Fail() + t.SkipNow() } func TestVersion(t *testing.T) { - t.Fail() + t.Parallel() + + calls := setup(t) + info, err := calls.version() + require.NoError(t, err) + + require.NotEmpty(t, info.Version) + require.NotEmpty(t, info.GitCommit) + require.NotEmpty(t, info.GitBranch) + require.NotEmpty(t, info.GitState) + require.NotEmpty(t, info.GitSummary) + require.NotEmpty(t, info.BuildDate) + require.NotEmpty(t, info.BinaryVersion) } func TestHealth(t *testing.T) { - t.Fail() + t.Parallel() + + calls := setup(t) + healthy, err := calls.health() + require.NoError(t, err) + require.True(t, healthy) } func requireCreate(t *testing.T, calls clientCalls) (TableID, string) { @@ -84,7 +102,7 @@ func requireWrite(t *testing.T, calls clientCalls, table string) string { return hash } -func requireReceipt(t *testing.T, calls clientCalls, hash string, opts ...ReceiptOption) *TxnReceipt { +func requireReceipt(t *testing.T, calls clientCalls, hash string, opts ...ReceiptOption) *apiv1.TransactionReceipt { res, found := calls.receipt(hash, opts...) require.True(t, found) require.NotNil(t, res) @@ -95,9 +113,9 @@ type clientCalls struct { create func(schema string, opts ...CreateOption) (TableID, string) write func(query string) string query func(query string, target interface{}, opts ...ReadOption) - receipt func(txnHash string, options ...ReceiptOption) (*TxnReceipt, bool) - getTableById func(tableID int64) (*TxnReceipt, bool) - version func() error + receipt func(txnHash string, options ...ReceiptOption) (*apiv1.TransactionReceipt, bool) + getTableById func(tableID int64) bool + version func() (*apiv1.VersionInfo, error) health func() (bool, error) } @@ -112,9 +130,6 @@ func setup(t *testing.T) clientCalls { client, err := NewClient(context.Background(), stack.Wallet, NewClientChain(c), NewClientContractBackend(stack.Backend)) require.NoError(t, err) - t.Cleanup(func() { - client.Close() - }) ctx := context.Background() return clientCalls{ @@ -137,13 +152,17 @@ func setup(t *testing.T) clientCalls { stack.Backend.Commit() return hash }, - receipt: func(txnHash string, options ...ReceiptOption) (*TxnReceipt, bool) { + receipt: func(txnHash string, options ...ReceiptOption) (*apiv1.TransactionReceipt, bool) { receipt, found, err := client.Receipt(ctx, txnHash, options...) require.NoError(t, err) return receipt, found }, - getTableById: func(tableID int64) (*TxnReceipt, bool) { panic("TODO") }, - version: func() error { panic("TODO") }, - health: func() (bool, error) { panic("TODO") }, + getTableById: func(tableID int64) bool { panic("TODO") }, + version: func() (*apiv1.VersionInfo, error) { + return client.Version(ctx) + }, + health: func() (bool, error) { + return client.CheckHealth(ctx) + }, } } diff --git a/pkg/client/receipt.go b/pkg/client/receipt.go index e583ad26..b9ff60d3 100644 --- a/pkg/client/receipt.go +++ b/pkg/client/receipt.go @@ -44,6 +44,7 @@ func (c *Client) Receipt( func (c *Client) getReceipt(ctx context.Context, txnHash string) (*apiv1.TransactionReceipt, bool, error) { url := (*c.baseURL). + JoinPath("api/v1/receipt"). JoinPath(strconv.FormatInt(int64(c.chain.ID), 10)). JoinPath(txnHash) diff --git a/pkg/client/version.go b/pkg/client/version.go index 654e108e..b68f8530 100644 --- a/pkg/client/version.go +++ b/pkg/client/version.go @@ -8,16 +8,16 @@ import ( "github.com/textileio/go-tableland/internal/router/controllers/apiv1" ) -func (c *Client) Version(ctx context.Context) (apiv1.VersionInfo, error) { +func (c *Client) Version(ctx context.Context) (*apiv1.VersionInfo, error) { res, err := c.tblHTTP.Get(c.chain.Endpoint + "/version") if err != nil { - return apiv1.VersionInfo{}, fmt.Errorf("http get error: %s", err) + return nil, fmt.Errorf("http get error: %s", err) } var versionInfo apiv1.VersionInfo if err := json.NewDecoder(res.Body).Decode(&versionInfo); err != nil { - return apiv1.VersionInfo{}, fmt.Errorf("decoding version info: %s", err) + return nil, fmt.Errorf("decoding version info: %s", err) } - return versionInfo, nil + return &versionInfo, nil } diff --git a/pkg/client/writequery.go b/pkg/client/writequery.go index 36bd0fe7..f0963cba 100644 --- a/pkg/client/writequery.go +++ b/pkg/client/writequery.go @@ -61,12 +61,12 @@ func (c *Client) Create(ctx context.Context, schema string, opts ...CreateOption return TableID{}, "", errors.New("no receipt found before timeout") } - tableID, ok := big.NewInt(0).SetString(*r.TableID, 10) + tableID, ok := big.NewInt(0).SetString(r.TableId, 10) if !ok { return TableID{}, "", errors.New("parsing table id from response") } - return TableID(*tableID), fmt.Sprintf("%s_%d_%s", conf.prefix, c.chain.ID, *r.TableID), nil + return TableID(*tableID), fmt.Sprintf("%s_%d_%s", conf.prefix, c.chain.ID, r.TableId), nil } // Write initiates a write query, returning the txn hash. From b54c20d04b4b580eb30b079901502139e40bba7b Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 10:42:21 -0300 Subject: [PATCH 039/101] internal/router: allow parametrizing middlewares in routes Signed-off-by: Ignacio Hagopian --- internal/router/router.go | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/internal/router/router.go b/internal/router/router.go index 6834e13c..0ab7c614 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -98,12 +98,30 @@ func configureAPIV1Routes( userCtrl *controllers.UserController, infraCtrl *controllers.InfraController, ) error { - handlers := map[string]http.HandlerFunc{ - "QueryFromQuery": userCtrl.GetTableQuery, - "ReceiptByTransactionHash": systemCtrl.GetReceiptByTransactionHash, - "GetTableById": systemCtrl.GetTable, // TODO(jsign): verify output. - "Version": infraCtrl.Version, - "Health": controllers.HealthHandler, + handlers := map[string]struct { + handler http.HandlerFunc + middlewares []mux.MiddlewareFunc + }{ + "QueryFromQuery": { + userCtrl.GetTableQuery, + []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, + }, + "ReceiptByTransactionHash": { + systemCtrl.GetReceiptByTransactionHash, + []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID, rateLim}, + }, + "GetTableById": { // TODO(jsign): verify output. + systemCtrl.GetTable, + []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID, rateLim}, + }, + "Version": { + infraCtrl.Version, + []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, + }, + "Health": { + controllers.HealthHandler, + []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, + }, } var specRoutesCount int @@ -115,7 +133,7 @@ func configureAPIV1Routes( } specRoutesCount++ - handle, ok := handlers[routeName] + endpoint, ok := handlers[routeName] if !ok { return fmt.Errorf("route with name %s not found in handler", routeName) } @@ -123,10 +141,12 @@ func configureAPIV1Routes( if err != nil { return fmt.Errorf("get path template: %s", err) } + router.get( pathTemplate, - handle, - middlewares.WithLogging, middlewares.OtelHTTP(routeName), middlewares.RESTChainID, rateLim) + endpoint.handler, + append(endpoint.middlewares, middlewares.OtelHTTP(routeName))..., + ) return nil }); err != nil { return fmt.Errorf("configuring api v1 router: %s", err) From cbc05429cf8b2978e115cf6620101c6ee24c766d Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 10:42:33 -0300 Subject: [PATCH 040/101] api: fix read query endpoint Signed-off-by: Ignacio Hagopian --- internal/router/controllers/user.go | 12 ++++++++++-- pkg/client/readquery.go | 9 ++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/internal/router/controllers/user.go b/internal/router/controllers/user.go index ba5e87a1..d7f2776f 100644 --- a/internal/router/controllers/user.go +++ b/internal/router/controllers/user.go @@ -214,7 +214,11 @@ func (c *UserController) GetTableRow(rw http.ResponseWriter, r *http.Request) { func (c *UserController) GetTableQuery(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-Type", "application/json") - stm := r.URL.Query().Get("s") + stm := r.URL.Query().Get("s") // TODO(json-rpc): remove query parameter "s" when dropping support. + if stm == "" { + stm = r.URL.Query().Get("statement") + } + start := time.Now() res, ok := c.runReadRequest(r.Context(), stm, rw) if !ok { @@ -299,7 +303,11 @@ type formatterParams struct { func getFormatterParams(r *http.Request) (formatterParams, error) { c := formatterParams{} - output := r.URL.Query().Get("output") + output := r.URL.Query().Get("output") // TODO(json-rpc): drop "output" when dropping support. + if output == "" { + output = r.URL.Query().Get("format") + } + extract := r.URL.Query().Get("extract") unwrap := r.URL.Query().Get("unwrap") if output != "" { diff --git a/pkg/client/readquery.go b/pkg/client/readquery.go index 54202efa..a08d6f78 100644 --- a/pkg/client/readquery.go +++ b/pkg/client/readquery.go @@ -1,6 +1,7 @@ package client import ( + "bytes" "context" "encoding/json" "fmt" @@ -64,7 +65,8 @@ func (c *Client) Read(ctx context.Context, query string, target interface{}, opt opt(¶ms) } - url := *c.baseURL // This is a shallow-copy, but it's safe. + url := *c.baseURL.JoinPath("api/v1/query") + values := url.Query() values.Set("statement", query) values.Set("format", string(params.format)) @@ -82,10 +84,11 @@ func (c *Client) Read(ctx context.Context, query string, target interface{}, opt } if response.StatusCode != http.StatusOK { msg, _ := io.ReadAll(response.Body) - return fmt.Errorf("the response wasn't successful: %s", msg) + return fmt.Errorf("the response wasn't successful (status: %d, body: %s)", response.StatusCode, msg) } - if err := json.NewDecoder(response.Body).Decode(&target); err != nil { + debug, _ := io.ReadAll(response.Body) + if err := json.NewDecoder(bytes.NewReader(debug)).Decode(&target); err != nil { return fmt.Errorf("decoding result into struct: %s", err) } From 0c7d1822197685f380ae487a5a313dc9c09107f5 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 14:02:43 -0300 Subject: [PATCH 041/101] client: add support for GetTableByID Signed-off-by: Ignacio Hagopian --- Makefile | 4 +- .../router/controllers/apiv1/model_info.go | 19 --------- .../router/controllers/apiv1/model_schema.go | 2 +- .../router/controllers/apiv1/model_table.go | 2 + .../apiv1/model_table_attributes.go | 2 +- internal/router/controllers/system.go | 41 ++++++++++++++++++- internal/router/controllers/user.go | 1 + internal/system/impl/sqlstore.go | 8 +++- pkg/client/client_test.go | 32 ++++++++++++--- pkg/client/table.go | 40 ++++++++++++++++++ pkg/sqlstore/table.go | 1 + 11 files changed, 121 insertions(+), 31 deletions(-) delete mode 100644 internal/router/controllers/apiv1/model_info.go create mode 100644 pkg/client/table.go diff --git a/Makefile b/Makefile index d33df963..29466cee 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,6 @@ gen-api-v1: sudo chown -R ${USER} ${APIV1} cd ${APIV1} && \ mv go/* . && \ - rm -rf go main.go Dockerfile README.md api .swagger-codegen .swagger-codegen-ignore - rm ${APIV1}/tableland-openapi-spec.yaml + rm -rf go main.go Dockerfile README.md api .swagger-codegen .swagger-codegen-ignore *.yaml + sed -i 's/\*OneOfTableAttributesValue/interface{}/' internal/router/controllers/apiv1/model_table_attributes.go .PHONY: gen-api-v1 \ No newline at end of file diff --git a/internal/router/controllers/apiv1/model_info.go b/internal/router/controllers/apiv1/model_info.go deleted file mode 100644 index 150be2a3..00000000 --- a/internal/router/controllers/apiv1/model_info.go +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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. - * - * API version: 1.0.0 - * Contact: carson@textile.io - * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) - */ -package apiv1 - -type Info struct { - - Owner string `json:"owner,omitempty"` - - Name string `json:"name,omitempty"` - - Structure string `json:"structure,omitempty"` -} diff --git a/internal/router/controllers/apiv1/model_schema.go b/internal/router/controllers/apiv1/model_schema.go index 8535b5a4..83060b06 100644 --- a/internal/router/controllers/apiv1/model_schema.go +++ b/internal/router/controllers/apiv1/model_schema.go @@ -13,5 +13,5 @@ type Schema struct { Columns []Column `json:"columns,omitempty"` - TableConstraints []string `json:"tableConstraints,omitempty"` + TableConstraints []string `json:"table_constraints,omitempty"` } diff --git a/internal/router/controllers/apiv1/model_table.go b/internal/router/controllers/apiv1/model_table.go index 3aa3dfce..08a21d59 100644 --- a/internal/router/controllers/apiv1/model_table.go +++ b/internal/router/controllers/apiv1/model_table.go @@ -15,6 +15,8 @@ type Table struct { ExternalUrl string `json:"external_url,omitempty"` + AnimationUrl string `json:"animation_url,omitempty"` + Image string `json:"image,omitempty"` Attributes []TableAttributes `json:"attributes,omitempty"` diff --git a/internal/router/controllers/apiv1/model_table_attributes.go b/internal/router/controllers/apiv1/model_table_attributes.go index 1b51c0b8..e519d6b6 100644 --- a/internal/router/controllers/apiv1/model_table_attributes.go +++ b/internal/router/controllers/apiv1/model_table_attributes.go @@ -15,5 +15,5 @@ type TableAttributes struct { // The trait type for marketplaces TraitType string `json:"trait_type,omitempty"` // The value of the property - Value *OneOfTableAttributesValue `json:"value,omitempty"` + Value interface{} `json:"value,omitempty"` } diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 62247b17..fa2366d5 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -3,6 +3,7 @@ package controllers import ( "encoding/json" "net/http" + "strings" "github.com/ethereum/go-ethereum/common" "github.com/gorilla/mux" @@ -89,12 +90,48 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { return } + var metadataRes interface{} + metadataRes = metadata + // TODO(json-rpc): remove this if when dropping support. It won't be needed anymore for compatibility reasons. + if strings.HasPrefix(r.RequestURI, "/api/v1/tables") { + metadataV1 := apiv1.Table{ + Name: metadata.Name, + ExternalUrl: metadata.ExternalURL, + AnimationUrl: metadata.AnimationURL, + Image: metadata.Image, + Attributes: make([]apiv1.TableAttributes, len(metadata.Attributes)), + Schema: &apiv1.Schema{ + Columns: make([]apiv1.Column, len(metadata.Schema.Columns)), + TableConstraints: make([]string, len(metadata.Schema.TableConstraints)), + }, + } + for i, attr := range metadata.Attributes { + metadataV1.Attributes[i] = apiv1.TableAttributes{ + DisplayType: attr.DisplayType, + TraitType: attr.TraitType, + Value: attr.Value, + } + } + for i, schemaColumn := range metadata.Schema.Columns { + metadataV1.Schema.Columns[i] = apiv1.Column{ + Name: schemaColumn.Name, + Type_: schemaColumn.Type, + Constraints: make([]string, len(schemaColumn.Constraints)), + } + copy(metadataV1.Schema.Columns[i].Constraints, schemaColumn.Constraints) + } + copy(metadataV1.Schema.TableConstraints, metadata.Schema.TableConstraints) + + metadataRes = metadataV1 + } + rw.WriteHeader(http.StatusOK) enc := json.NewEncoder(rw) enc.SetEscapeHTML(false) - _ = enc.Encode(metadata) + _ = enc.Encode(metadataRes) } +// TODO(json-rpc): delete when dropping support. // GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. func (c *SystemController) GetTablesByController(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -137,6 +174,7 @@ func (c *SystemController) GetTablesByController(rw http.ResponseWriter, r *http _ = json.NewEncoder(rw).Encode(retTables) } +// TODO(json-rpc): delete when dropping support. // GetTablesByStructureHash handles the GET /chain/{id}/tables/structure/{hash} call. func (c *SystemController) GetTablesByStructureHash(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -176,6 +214,7 @@ func (c *SystemController) GetTablesByStructureHash(rw http.ResponseWriter, r *h _ = json.NewEncoder(rw).Encode(retTables) } +// TODO(json-rpc): delete when droppping support. // GetSchemaByTableName handles the GET /schema/{table_name} call. func (c *SystemController) GetSchemaByTableName(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/internal/router/controllers/user.go b/internal/router/controllers/user.go index d7f2776f..83a4bd90 100644 --- a/internal/router/controllers/user.go +++ b/internal/router/controllers/user.go @@ -126,6 +126,7 @@ func userRowToMap(cols []tableland.Column, row []*tableland.ColumnValue) map[str return m } +// TODO(json-rpc): delete method when dropping support. // GetTableRow handles the GET /chain/{chainID}/tables/{id}/{key}/{value} call. // Use format=erc721 query param to generate JSON for ERC721 metadata. func (c *UserController) GetTableRow(rw http.ResponseWriter, r *http.Request) { diff --git a/internal/system/impl/sqlstore.go b/internal/system/impl/sqlstore.go index 78a661d5..428bf8a5 100644 --- a/internal/system/impl/sqlstore.go +++ b/internal/system/impl/sqlstore.go @@ -112,9 +112,14 @@ func (s *SystemSQLStoreService) GetTableMetadata( Message: "Table not found", }, nil } + tableName := fmt.Sprintf("%s_%d_%s", table.Prefix, table.ChainID, table.ID) + schema, err := store.GetSchemaByTableName(ctx, tableName) + if err != nil { + return sqlstore.TableMetadata{}, fmt.Errorf("get table schema information: %s", err) + } return sqlstore.TableMetadata{ - Name: fmt.Sprintf("%s_%d_%s", table.Prefix, table.ChainID, table.ID), + Name: tableName, ExternalURL: fmt.Sprintf("%s/chain/%d/tables/%s", s.extURLPrefix, table.ChainID, table.ID), Image: s.getMetadataImage(table.ChainID, table.ID), AnimationURL: s.getAnimationURL(table.ChainID, table.ID), @@ -125,6 +130,7 @@ func (s *SystemSQLStoreService) GetTableMetadata( Value: table.CreatedAt.Unix(), }, }, + Schema: schema, }, nil } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 191f8e4b..f2724548 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -62,7 +62,21 @@ func TestRead(t *testing.T) { } func TestGetTableByID(t *testing.T) { - t.SkipNow() + t.Parallel() + + calls := setup(t) + id, fullName := requireCreate(t, calls) + + table := calls.getTableById(id) + require.NotEmpty(t, fullName, table.Name) + require.NotEmpty(t, table.ExternalUrl) + require.NotEmpty(t, table.AnimationUrl) + require.NotEmpty(t, table.Image) + require.Greater(t, len(table.Attributes), 0) + + require.NotNil(t, table.Schema) + require.NotEmpty(t, table.Schema.Columns) + require.NotEmpty(t, table.Schema.TableConstraints) } func TestVersion(t *testing.T) { @@ -91,9 +105,11 @@ func TestHealth(t *testing.T) { } func requireCreate(t *testing.T, calls clientCalls) (TableID, string) { - id, table := calls.create("(bar text)", WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) - require.Equal(t, "foo_1337_1", table) - return id, table + id, tableName := calls.create( + "(bar text DEFAULT 'foo',zar int, CHECK (zar>0))", + WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) + require.Equal(t, "foo_1337_1", tableName) + return id, tableName } func requireWrite(t *testing.T, calls clientCalls, table string) string { @@ -114,7 +130,7 @@ type clientCalls struct { write func(query string) string query func(query string, target interface{}, opts ...ReadOption) receipt func(txnHash string, options ...ReceiptOption) (*apiv1.TransactionReceipt, bool) - getTableById func(tableID int64) bool + getTableById func(tableID TableID) *apiv1.Table version func() (*apiv1.VersionInfo, error) health func() (bool, error) } @@ -157,7 +173,11 @@ func setup(t *testing.T) clientCalls { require.NoError(t, err) return receipt, found }, - getTableById: func(tableID int64) bool { panic("TODO") }, + getTableById: func(tableID TableID) *apiv1.Table { + table, err := client.GetTable(ctx, tableID) + require.NoError(t, err) + return table + }, version: func() (*apiv1.VersionInfo, error) { return client.Version(ctx) }, diff --git a/pkg/client/table.go b/pkg/client/table.go new file mode 100644 index 00000000..2ea68909 --- /dev/null +++ b/pkg/client/table.go @@ -0,0 +1,40 @@ +package client + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/textileio/go-tableland/internal/router/controllers/apiv1" +) + +var ErrTableNotFound = errors.New("table not found") + +func (c *Client) GetTable(ctx context.Context, tableID TableID) (*apiv1.Table, error) { + url := *c.baseURL. + JoinPath("api/v1/tables/"). + JoinPath(strconv.FormatInt(int64(c.chain.ID), 10)). + JoinPath(strconv.FormatInt(tableID.ToBigInt().Int64(), 10)) + + response, err := c.tblHTTP.Get(url.String()) + if err != nil { + return nil, fmt.Errorf("calling get tables by id: %s", err) + } + if response.StatusCode == http.StatusNotFound { + return nil, ErrTableNotFound + } + if response.StatusCode != http.StatusOK { + msg, _ := io.ReadAll(response.Body) + return nil, fmt.Errorf("failed call (status: %d, body: %s)", response.StatusCode, msg) + } + var table apiv1.Table + if err := json.NewDecoder(response.Body).Decode(&table); err != nil { + return nil, fmt.Errorf("unmarshaling result: %s", err) + } + + return &table, nil +} diff --git a/pkg/sqlstore/table.go b/pkg/sqlstore/table.go index c1e24b04..e1aab548 100644 --- a/pkg/sqlstore/table.go +++ b/pkg/sqlstore/table.go @@ -44,6 +44,7 @@ type TableMetadata struct { Message string `json:"message,omitempty"` AnimationURL string `json:"animation_url,omitempty"` Attributes []TableMetadataAttribute `json:"attributes,omitempty"` + Schema TableSchema } // TableMetadataAttribute represents the table metadata attribute. From 4ccbc90c47d330dbfb9fcfdcdb32a21943e9d9d1 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 14:08:59 -0300 Subject: [PATCH 042/101] client: make get table by id have stricter checks Signed-off-by: Ignacio Hagopian --- pkg/client/client_test.go | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index f2724548..f45e02d9 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -69,14 +69,24 @@ func TestGetTableByID(t *testing.T) { table := calls.getTableById(id) require.NotEmpty(t, fullName, table.Name) - require.NotEmpty(t, table.ExternalUrl) - require.NotEmpty(t, table.AnimationUrl) - require.NotEmpty(t, table.Image) - require.Greater(t, len(table.Attributes), 0) + require.Equal(t, "https://testnet.tableland.network/chain/1337/tables/1", table.ExternalUrl) + require.Equal(t, "https://render.tableland.xyz/anim/?chain=1337&id=1", table.AnimationUrl) + require.Equal(t, "https://render.tableland.xyz/1337/1", table.Image) + + require.Len(t, table.Attributes, 1) + require.Equal(t, "date", table.Attributes[0].DisplayType) + require.Equal(t, "created", table.Attributes[0].TraitType) + require.NotEmpty(t, table.Attributes[0].Value) require.NotNil(t, table.Schema) - require.NotEmpty(t, table.Schema.Columns) - require.NotEmpty(t, table.Schema.TableConstraints) + require.Len(t, table.Schema.Columns, 2) + require.Equal(t, "bar", table.Schema.Columns[0].Name) + require.Equal(t, "text", table.Schema.Columns[0].Type_) + require.Len(t, table.Schema.Columns[0].Constraints, 1) + require.Equal(t, "DEFAULT 'foo'", table.Schema.Columns[0].Constraints[0]) + + require.Len(t, table.Schema.TableConstraints, 1) + require.Equal(t, "CHECK(zar > 0)", table.Schema.TableConstraints[0]) } func TestVersion(t *testing.T) { From 690f59c3cc4ccdb5e4304b323641877906af12ed Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 14:27:40 -0300 Subject: [PATCH 043/101] client: fix version endpoint Signed-off-by: Ignacio Hagopian --- .github/workflows/deploy.yml | 6 +++--- .../router/controllers/apiv1/model_version_info.go | 2 +- internal/router/controllers/infra.go | 12 +++++++++++- pkg/client/client_test.go | 11 ++++++----- pkg/client/version.go | 9 +++++++-- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f8ba6fde..962fdd3f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -52,7 +52,7 @@ jobs: # Wait to start and double-check we're running the expected version. # This helps having a green check in the GH Action be high-signal that everything is fine. sleep 5; - for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done + for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .gitCommit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" - if: github.ref == 'refs/heads/main'|| contains(github.event.head_commit.message, '[testnetdeploy]') @@ -75,7 +75,7 @@ jobs: # Wait to start and double-check we're running the expected version. # This helps having a green check in the GH Action be high-signal that everything is fine. sleep 5; - for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done + for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .gitCommit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[mainnetdeploy]') @@ -98,5 +98,5 @@ jobs: # Wait to start and double-check we're running the expected version. # This helps having a green check in the GH Action be high-signal that everything is fine. sleep 5; - for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done + for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .gitCommit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" diff --git a/internal/router/controllers/apiv1/model_version_info.go b/internal/router/controllers/apiv1/model_version_info.go index 3695bc02..4e523fa6 100644 --- a/internal/router/controllers/apiv1/model_version_info.go +++ b/internal/router/controllers/apiv1/model_version_info.go @@ -11,7 +11,7 @@ package apiv1 type VersionInfo struct { - Version string `json:"version,omitempty"` + Version int32 `json:"version,omitempty"` GitCommit string `json:"gitCommit,omitempty"` diff --git a/internal/router/controllers/infra.go b/internal/router/controllers/infra.go index 3ae77b1b..b670ea3b 100644 --- a/internal/router/controllers/infra.go +++ b/internal/router/controllers/infra.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/textileio/go-tableland/buildinfo" + "github.com/textileio/go-tableland/internal/router/controllers/apiv1" ) // InfraController defines the HTTP handlers for infrastructure APIs. @@ -20,5 +21,14 @@ func (c *InfraController) Version(rw http.ResponseWriter, _ *http.Request) { rw.Header().Set("Content-type", "application/json") summary := buildinfo.GetSummary() rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(summary) + + _ = json.NewEncoder(rw).Encode(apiv1.VersionInfo{ + Version: int32(summary.Version), + GitCommit: summary.GitCommit, + GitBranch: summary.GitBranch, + GitState: summary.GitState, + GitSummary: summary.GitSummary, + BuildDate: summary.BuildDate, + BinaryVersion: summary.BinaryVersion, + }) } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index f45e02d9..a4c68087 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -65,7 +65,9 @@ func TestGetTableByID(t *testing.T) { t.Parallel() calls := setup(t) - id, fullName := requireCreate(t, calls) + id, fullName := calls.create( + "(bar text DEFAULT 'foo',zar int, CHECK (zar>0))", + WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) table := calls.getTableById(id) require.NotEmpty(t, fullName, table.Name) @@ -96,7 +98,7 @@ func TestVersion(t *testing.T) { info, err := calls.version() require.NoError(t, err) - require.NotEmpty(t, info.Version) + require.Equal(t, int32(0), info.Version) require.NotEmpty(t, info.GitCommit) require.NotEmpty(t, info.GitBranch) require.NotEmpty(t, info.GitState) @@ -115,9 +117,7 @@ func TestHealth(t *testing.T) { } func requireCreate(t *testing.T, calls clientCalls) (TableID, string) { - id, tableName := calls.create( - "(bar text DEFAULT 'foo',zar int, CHECK (zar>0))", - WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) + id, tableName := calls.create("(bar text)", WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) require.Equal(t, "foo_1337_1", tableName) return id, tableName } @@ -166,6 +166,7 @@ func setup(t *testing.T) clientCalls { }() id, table, err := client.Create(ctx, schema, opts...) require.NoError(t, err) + stack.Backend.Commit() return id, table }, query: func(query string, target interface{}, opts ...ReadOption) { diff --git a/pkg/client/version.go b/pkg/client/version.go index b68f8530..dadbfaea 100644 --- a/pkg/client/version.go +++ b/pkg/client/version.go @@ -1,21 +1,26 @@ package client import ( + "bytes" "context" "encoding/json" "fmt" + "io" "github.com/textileio/go-tableland/internal/router/controllers/apiv1" ) func (c *Client) Version(ctx context.Context) (*apiv1.VersionInfo, error) { - res, err := c.tblHTTP.Get(c.chain.Endpoint + "/version") + url := *c.baseURL.JoinPath("api/v1/version") + res, err := c.tblHTTP.Get(url.String()) if err != nil { return nil, fmt.Errorf("http get error: %s", err) } + bb, _ := io.ReadAll(res.Body) + var versionInfo apiv1.VersionInfo - if err := json.NewDecoder(res.Body).Decode(&versionInfo); err != nil { + if err := json.NewDecoder(bytes.NewReader(bb)).Decode(&versionInfo); err != nil { return nil, fmt.Errorf("decoding version info: %s", err) } From d10340340d119e4828065d5ad0b9b13269390162 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 14:28:58 -0300 Subject: [PATCH 044/101] client: fix endpoints Signed-off-by: Ignacio Hagopian --- pkg/client/health.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/client/health.go b/pkg/client/health.go index 49c95e81..53a64587 100644 --- a/pkg/client/health.go +++ b/pkg/client/health.go @@ -7,7 +7,8 @@ import ( ) func (c *Client) CheckHealth(ctx context.Context) (bool, error) { - res, err := c.tblHTTP.Get(c.chain.Endpoint + "/health") + url := *c.baseURL.JoinPath("api/v1/health") + res, err := c.tblHTTP.Get(url.String()) if err != nil { return false, fmt.Errorf("http get error: %s", err) } From bc3641180b4846744db0a44fffc87ea6a3d199c0 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 16:32:28 -0300 Subject: [PATCH 045/101] internal/router: regen apis for snake case Signed-off-by: Ignacio Hagopian --- .github/workflows/deploy.yml | 6 +++--- .../controllers/apiv1/model_transaction_receipt.go | 10 +++++----- .../router/controllers/apiv1/model_version_info.go | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 962fdd3f..7df6c4bd 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -52,7 +52,7 @@ jobs: # Wait to start and double-check we're running the expected version. # This helps having a green check in the GH Action be high-signal that everything is fine. sleep 5; - for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .gitCommit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done + for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" - if: github.ref == 'refs/heads/main'|| contains(github.event.head_commit.message, '[testnetdeploy]') @@ -75,7 +75,7 @@ jobs: # Wait to start and double-check we're running the expected version. # This helps having a green check in the GH Action be high-signal that everything is fine. sleep 5; - for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .gitCommit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done + for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[mainnetdeploy]') @@ -98,5 +98,5 @@ jobs: # Wait to start and double-check we're running the expected version. # This helps having a green check in the GH Action be high-signal that everything is fine. sleep 5; - for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .gitCommit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done + for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" diff --git a/internal/router/controllers/apiv1/model_transaction_receipt.go b/internal/router/controllers/apiv1/model_transaction_receipt.go index ea1b8a2d..bf8d16e1 100644 --- a/internal/router/controllers/apiv1/model_transaction_receipt.go +++ b/internal/router/controllers/apiv1/model_transaction_receipt.go @@ -11,15 +11,15 @@ package apiv1 type TransactionReceipt struct { - TableId string `json:"tableId,omitempty"` + TableId string `json:"table_id,omitempty"` - TransactionHash string `json:"transactionHash,omitempty"` + TransactionHash string `json:"transaction_hash,omitempty"` - BlockNumber int64 `json:"blockNumber,omitempty"` + BlockNumber int64 `json:"block_number,omitempty"` - ChainId int32 `json:"chainId,omitempty"` + ChainId int32 `json:"chain_id,omitempty"` Error_ string `json:"error,omitempty"` - ErrorEventIdx int32 `json:"errorEventIdx,omitempty"` + ErrorEventIdx int32 `json:"error_event_idx,omitempty"` } diff --git a/internal/router/controllers/apiv1/model_version_info.go b/internal/router/controllers/apiv1/model_version_info.go index 4e523fa6..d460bc98 100644 --- a/internal/router/controllers/apiv1/model_version_info.go +++ b/internal/router/controllers/apiv1/model_version_info.go @@ -13,15 +13,15 @@ type VersionInfo struct { Version int32 `json:"version,omitempty"` - GitCommit string `json:"gitCommit,omitempty"` + GitCommit string `json:"git_commit,omitempty"` - GitBranch string `json:"gitBranch,omitempty"` + GitBranch string `json:"git_branch,omitempty"` - GitState string `json:"gitState,omitempty"` + GitState string `json:"git_state,omitempty"` - GitSummary string `json:"gitSummary,omitempty"` + GitSummary string `json:"git_summary,omitempty"` - BuildDate string `json:"buildDate,omitempty"` + BuildDate string `json:"build_date,omitempty"` - BinaryVersion string `json:"binaryVersion,omitempty"` + BinaryVersion string `json:"binary_version,omitempty"` } From ddd97a2c08f4608f10f85862ef4b243d64f602c6 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 17:37:26 -0300 Subject: [PATCH 046/101] fixes Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system_test.go | 3 ++- internal/system/impl/mock.go | 3 +++ pkg/client/client_test.go | 1 - pkg/client/receipt.go | 2 +- pkg/client/writequery.go | 2 +- pkg/sqlstore/table.go | 12 ++++++------ 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/internal/router/controllers/system_test.go b/internal/router/controllers/system_test.go index 27ece54f..44e5c2dc 100644 --- a/internal/router/controllers/system_test.go +++ b/internal/router/controllers/system_test.go @@ -34,7 +34,8 @@ func TestSystemControllerMock(t *testing.T) { "name":"name-1", "external_url":"https://tableland.network/tables/100", "image":"https://bafkreifhuhrjhzbj4onqgbrmhpysk2mop2jimvdvfut6taiyzt2yqzt43a.ipfs.dweb.link", - "attributes":[{"display_type":"date","trait_type":"created","value":1546360800}] + "attributes":[{"display_type":"date","trait_type":"created","value":1546360800}], + "schema":{"columns":[{"name":"foo","type":"text","constraints":null}],"table_constraints":null}} }` require.JSONEq(t, expJSON, rr.Body.String()) }) diff --git a/internal/system/impl/mock.go b/internal/system/impl/mock.go index 9243f1da..0471d687 100644 --- a/internal/system/impl/mock.go +++ b/internal/system/impl/mock.go @@ -48,6 +48,9 @@ func (*SystemMockService) GetTableMetadata(_ context.Context, id tables.TableID) Value: 1546360800, }, }, + Schema: sqlstore.TableSchema{ + Columns: []sqlstore.ColumnSchema{{Name: "foo", Type: "text"}}, + }, }, nil } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index a4c68087..f2b05a50 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -166,7 +166,6 @@ func setup(t *testing.T) clientCalls { }() id, table, err := client.Create(ctx, schema, opts...) require.NoError(t, err) - stack.Backend.Commit() return id, table }, query: func(query string, target interface{}, opts ...ReadOption) { diff --git a/pkg/client/receipt.go b/pkg/client/receipt.go index b9ff60d3..47c183ca 100644 --- a/pkg/client/receipt.go +++ b/pkg/client/receipt.go @@ -57,7 +57,7 @@ func (c *Client) getReceipt(ctx context.Context, txnHash string) (*apiv1.Transac } if response.StatusCode != http.StatusOK { msg, _ := io.ReadAll(response.Body) - return nil, false, fmt.Errorf("failed call: %s", msg) + return nil, false, fmt.Errorf("failed call (status: %d, body: %s)", response.StatusCode, msg) } var tr apiv1.TransactionReceipt if err := json.NewDecoder(response.Body).Decode(&tr); err != nil { diff --git a/pkg/client/writequery.go b/pkg/client/writequery.go index f0963cba..9a6d1eae 100644 --- a/pkg/client/writequery.go +++ b/pkg/client/writequery.go @@ -37,7 +37,7 @@ func WithReceiptTimeout(timeout time.Duration) CreateOption { // Create creates a new table on the Tableland. func (c *Client) Create(ctx context.Context, schema string, opts ...CreateOption) (TableID, string, error) { - defaultTimeout := time.Minute * 10 + defaultTimeout := time.Minute conf := createConfig{receiptTimeout: &defaultTimeout} for _, opt := range opts { opt(&conf) diff --git a/pkg/sqlstore/table.go b/pkg/sqlstore/table.go index e1aab548..77228a4d 100644 --- a/pkg/sqlstore/table.go +++ b/pkg/sqlstore/table.go @@ -25,15 +25,15 @@ func (t Table) Name() string { // TableSchema represents the schema of a table. type TableSchema struct { - Columns []ColumnSchema - TableConstraints []string + Columns []ColumnSchema `json:"columns"` + TableConstraints []string `json:"table_constraints"` } // ColumnSchema represents the schema of a column. type ColumnSchema struct { - Name string - Type string - Constraints []string + Name string `json:"name"` + Type string `json:"type"` + Constraints []string `json:"constraints"` } // TableMetadata represents table metadata (OpenSea standard). @@ -44,7 +44,7 @@ type TableMetadata struct { Message string `json:"message,omitempty"` AnimationURL string `json:"animation_url,omitempty"` Attributes []TableMetadataAttribute `json:"attributes,omitempty"` - Schema TableSchema + Schema TableSchema `json:"schema"` } // TableMetadataAttribute represents the table metadata attribute. From afdac3676c37c323ce552af48a6a8e71fd98f8a3 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 5 Dec 2022 17:40:04 -0300 Subject: [PATCH 047/101] rebase & fix nits Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/router/controllers/system_test.go b/internal/router/controllers/system_test.go index 44e5c2dc..b2a67a0d 100644 --- a/internal/router/controllers/system_test.go +++ b/internal/router/controllers/system_test.go @@ -35,7 +35,7 @@ func TestSystemControllerMock(t *testing.T) { "external_url":"https://tableland.network/tables/100", "image":"https://bafkreifhuhrjhzbj4onqgbrmhpysk2mop2jimvdvfut6taiyzt2yqzt43a.ipfs.dweb.link", "attributes":[{"display_type":"date","trait_type":"created","value":1546360800}], - "schema":{"columns":[{"name":"foo","type":"text","constraints":null}],"table_constraints":null}} + "schema":{"columns":[{"name":"foo","type":"text","constraints":null}],"table_constraints":null} }` require.JSONEq(t, expJSON, rr.Body.String()) }) From ed7772b113880c85fe2eb3506008bd2507f32ea7 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 6 Dec 2022 16:33:35 -0300 Subject: [PATCH 048/101] pkg/client: more test coverage Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system.go | 11 ++ internal/system/impl/sqlstore.go | 6 +- internal/system/system.go | 3 + pkg/client/client_test.go | 151 +++++++++++++++++--------- pkg/client/readquery.go | 4 +- 5 files changed, 114 insertions(+), 61 deletions(-) diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index fa2366d5..8c7b6d54 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -29,6 +29,13 @@ func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r ctx := r.Context() paramTxnHash := mux.Vars(r)["transactionHash"] + if _, err := common.ParseHexOrString(paramTxnHash); err != nil { + rw.WriteHeader(http.StatusBadRequest) + log.Ctx(ctx).Error().Err(err).Msg("invalid transaction hash") + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Invalid transaction hash"}) + return + + } txnHash := common.HexToHash(paramTxnHash) receipt, exists, err := c.systemService.GetReceiptByTransactionHash(ctx, txnHash) @@ -78,6 +85,10 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { } metadata, err := c.systemService.GetTableMetadata(ctx, id) + if err == system.ErrTableNotFound { + rw.WriteHeader(http.StatusNotFound) + return + } if err != nil { rw.WriteHeader(http.StatusInternalServerError) log.Ctx(ctx). diff --git a/internal/system/impl/sqlstore.go b/internal/system/impl/sqlstore.go index 428bf8a5..f0bc9f13 100644 --- a/internal/system/impl/sqlstore.go +++ b/internal/system/impl/sqlstore.go @@ -106,11 +106,7 @@ func (s *SystemSQLStoreService) GetTableMetadata( }, nil } - return sqlstore.TableMetadata{ - ExternalURL: fmt.Sprintf("%s/chain/%d/tables/%s", s.extURLPrefix, chainID, id), - Image: s.emptyMetadataImage(), - Message: "Table not found", - }, nil + return sqlstore.TableMetadata{}, system.ErrTableNotFound } tableName := fmt.Sprintf("%s_%d_%s", table.Prefix, table.ChainID, table.ID) schema, err := store.GetSchemaByTableName(ctx, tableName) diff --git a/internal/system/system.go b/internal/system/system.go index 606fa0e3..7bcf34cd 100644 --- a/internal/system/system.go +++ b/internal/system/system.go @@ -2,12 +2,15 @@ package system import ( "context" + "errors" "github.com/ethereum/go-ethereum/common" "github.com/textileio/go-tableland/pkg/sqlstore" "github.com/textileio/go-tableland/pkg/tables" ) +var ErrTableNotFound = errors.New("table not found") + // TODO(json-rpc): this interface should be cleaned up after dropping support. // SystemService defines what system operations can be done. type SystemService interface { diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index f2b05a50..3eec6aa6 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -29,66 +29,109 @@ func TestWrite(t *testing.T) { func TestRead(t *testing.T) { t.Parallel() - calls := setup(t) - _, table := requireCreate(t, calls) - hash := requireWrite(t, calls, table) - requireReceipt(t, calls, hash, WaitFor(time.Second*10)) - - type result struct { - Bar string `json:"bar"` - } - - res0 := []result{} - calls.query(fmt.Sprintf("select * from %s", table), &res0) - require.Len(t, res0, 1) - require.Equal(t, "baz", res0[0].Bar) - - res1 := map[string]interface{}{} - calls.query(fmt.Sprintf("select * from %s", table), &res1, ReadOutput(Table)) - require.Len(t, res1, 2) - - res2 := result{} - calls.query(fmt.Sprintf("select * from %s", table), &res2, ReadUnwrap()) - require.Equal(t, "baz", res2.Bar) + t.Run("status 200", func(t *testing.T) { + calls := setup(t) + _, table := requireCreate(t, calls) + hash := requireWrite(t, calls, table) + requireReceipt(t, calls, hash, WaitFor(time.Second*10)) + + type result struct { + Bar string `json:"bar"` + } + + res0 := []result{} + calls.query(fmt.Sprintf("select * from %s", table), &res0) + require.Len(t, res0, 1) + require.Equal(t, "baz", res0[0].Bar) + + res1 := map[string]interface{}{} + calls.query(fmt.Sprintf("select * from %s", table), &res1, ReadOutput(Table)) + require.Len(t, res1, 2) + + res2 := result{} + calls.query(fmt.Sprintf("select * from %s", table), &res2, ReadUnwrap()) + require.Equal(t, "baz", res2.Bar) + + res3 := []string{} + calls.query(fmt.Sprintf("select * from %s", table), &res3, ReadExtract()) + require.Len(t, res3, 1) + require.Equal(t, "baz", res3[0]) + + res4 := "" + calls.query(fmt.Sprintf("select * from %s", table), &res4, ReadUnwrap(), ReadExtract()) + require.Equal(t, "baz", res4) + }) + + t.Run("status 400", func(t *testing.T) { + calls := setup(t) + err := calls.client.Read(context.Background(), "SELECTZ * FROM foo_1", struct{}{}) + require.Error(t, err) + }) +} - res3 := []string{} - calls.query(fmt.Sprintf("select * from %s", table), &res3, ReadExtract()) - require.Len(t, res3, 1) - require.Equal(t, "baz", res3[0]) +func TestGetReceipt(t *testing.T) { + t.Parallel() - res4 := "" - calls.query(fmt.Sprintf("select * from %s", table), &res4, ReadUnwrap(), ReadExtract()) - require.Equal(t, "baz", res4) + t.Run("status 200", func(t *testing.T) { + calls := setup(t) + _, table := requireCreate(t, calls) + hash := requireWrite(t, calls, table) + requireReceipt(t, calls, hash, WaitFor(time.Second*10)) + }) + + t.Run("status 400", func(t *testing.T) { + calls := setup(t) + _, _ = requireCreate(t, calls) + _, _, err := calls.client.Receipt(context.Background(), "0xINVALIDHASH") + require.Error(t, err) + }) + + t.Run("status 404", func(t *testing.T) { + calls := setup(t) + _, _ = requireCreate(t, calls) + _, exists, err := calls.client.Receipt(context.Background(), "0x5c6f90e52284726a7276d6a20a3df94a4532a8fa4c921233a301e95673ad0255") //nolint + require.NoError(t, err) + require.False(t, exists) + }) } func TestGetTableByID(t *testing.T) { t.Parallel() - calls := setup(t) - id, fullName := calls.create( - "(bar text DEFAULT 'foo',zar int, CHECK (zar>0))", - WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) - - table := calls.getTableById(id) - require.NotEmpty(t, fullName, table.Name) - require.Equal(t, "https://testnet.tableland.network/chain/1337/tables/1", table.ExternalUrl) - require.Equal(t, "https://render.tableland.xyz/anim/?chain=1337&id=1", table.AnimationUrl) - require.Equal(t, "https://render.tableland.xyz/1337/1", table.Image) - - require.Len(t, table.Attributes, 1) - require.Equal(t, "date", table.Attributes[0].DisplayType) - require.Equal(t, "created", table.Attributes[0].TraitType) - require.NotEmpty(t, table.Attributes[0].Value) - - require.NotNil(t, table.Schema) - require.Len(t, table.Schema.Columns, 2) - require.Equal(t, "bar", table.Schema.Columns[0].Name) - require.Equal(t, "text", table.Schema.Columns[0].Type_) - require.Len(t, table.Schema.Columns[0].Constraints, 1) - require.Equal(t, "DEFAULT 'foo'", table.Schema.Columns[0].Constraints[0]) - - require.Len(t, table.Schema.TableConstraints, 1) - require.Equal(t, "CHECK(zar > 0)", table.Schema.TableConstraints[0]) + t.Run("status 200", func(t *testing.T) { + calls := setup(t) + id, fullName := calls.create( + "(bar text DEFAULT 'foo',zar int, CHECK (zar>0))", + WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) + + table := calls.getTableById(id) + require.NotEmpty(t, fullName, table.Name) + require.Equal(t, "https://testnet.tableland.network/chain/1337/tables/1", table.ExternalUrl) + require.Equal(t, "https://render.tableland.xyz/anim/?chain=1337&id=1", table.AnimationUrl) + require.Equal(t, "https://render.tableland.xyz/1337/1", table.Image) + + require.Len(t, table.Attributes, 1) + require.Equal(t, "date", table.Attributes[0].DisplayType) + require.Equal(t, "created", table.Attributes[0].TraitType) + require.NotEmpty(t, table.Attributes[0].Value) + + require.NotNil(t, table.Schema) + require.Len(t, table.Schema.Columns, 2) + require.Equal(t, "bar", table.Schema.Columns[0].Name) + require.Equal(t, "text", table.Schema.Columns[0].Type_) + require.Len(t, table.Schema.Columns[0].Constraints, 1) + require.Equal(t, "DEFAULT 'foo'", table.Schema.Columns[0].Constraints[0]) + + require.Len(t, table.Schema.TableConstraints, 1) + require.Equal(t, "CHECK(zar > 0)", table.Schema.TableConstraints[0]) + }) + t.Run("status 404", func(t *testing.T) { + calls := setup(t) + id, err := NewTableID("1337") + require.NoError(t, err) + _, err = calls.client.GetTable(context.Background(), id) + require.ErrorIs(t, err, ErrTableNotFound) + }) } func TestVersion(t *testing.T) { @@ -136,6 +179,7 @@ func requireReceipt(t *testing.T, calls clientCalls, hash string, opts ...Receip } type clientCalls struct { + client *Client create func(schema string, opts ...CreateOption) (TableID, string) write func(query string) string query func(query string, target interface{}, opts ...ReadOption) @@ -159,6 +203,7 @@ func setup(t *testing.T) clientCalls { ctx := context.Background() return clientCalls{ + client: client, create: func(schema string, opts ...CreateOption) (TableID, string) { go func() { time.Sleep(time.Second * 1) diff --git a/pkg/client/readquery.go b/pkg/client/readquery.go index a08d6f78..ced4ede7 100644 --- a/pkg/client/readquery.go +++ b/pkg/client/readquery.go @@ -1,7 +1,6 @@ package client import ( - "bytes" "context" "encoding/json" "fmt" @@ -87,8 +86,7 @@ func (c *Client) Read(ctx context.Context, query string, target interface{}, opt return fmt.Errorf("the response wasn't successful (status: %d, body: %s)", response.StatusCode, msg) } - debug, _ := io.ReadAll(response.Body) - if err := json.NewDecoder(bytes.NewReader(debug)).Decode(&target); err != nil { + if err := json.NewDecoder(response.Body).Decode(&target); err != nil { return fmt.Errorf("decoding result into struct: %s", err) } From df71ed8a7d386c9b201af73982df1679e94ae772 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 6 Dec 2022 16:46:02 -0300 Subject: [PATCH 049/101] fix some lints Signed-off-by: Ignacio Hagopian --- cmd/api/main.go | 6 ++++- internal/router/controllers/system.go | 3 +-- internal/router/router.go | 8 ++----- internal/system/impl/mock.go | 2 +- pkg/client/client_test.go | 32 +++++++++++++-------------- pkg/client/health.go | 7 +++++- pkg/client/queryhelpers.go | 5 ++--- pkg/client/readquery.go | 7 +++++- pkg/client/receipt.go | 7 +++++- pkg/client/table.go | 7 +++++- pkg/client/version.go | 9 +++++++- pkg/client/writequery.go | 2 +- tests/fullstack/fullstack.go | 3 ++- 13 files changed, 62 insertions(+), 36 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index dcbe7d30..9814e360 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -491,7 +491,11 @@ func createAPIServer( for chainID, stack := range chainStacks { stores[chainID] = stack.Store } - sysStore, err := systemimpl.NewSystemSQLStoreService(stores, gatewayConfig.ExternalURIPrefix, gatewayConfig.MetadataRendererURI, gatewayConfig.AnimationRendererURI) + sysStore, err := systemimpl.NewSystemSQLStoreService( + stores, + gatewayConfig.ExternalURIPrefix, + gatewayConfig.MetadataRendererURI, + gatewayConfig.AnimationRendererURI) if err != nil { return nil, fmt.Errorf("creating system store: %s", err) } diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 8c7b6d54..5fcfa312 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -34,7 +34,6 @@ func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r log.Ctx(ctx).Error().Err(err).Msg("invalid transaction hash") _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Invalid transaction hash"}) return - } txnHash := common.HexToHash(paramTxnHash) @@ -142,8 +141,8 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { _ = enc.Encode(metadataRes) } -// TODO(json-rpc): delete when dropping support. // GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. +// TODO(json-rpc): delete when dropping support. func (c *SystemController) GetTablesByController(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() rw.Header().Set("Content-type", "application/json") diff --git a/internal/router/router.go b/internal/router/router.go index 0ab7c614..4e7948e9 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -50,9 +50,7 @@ func ConfiguredRouter( // TODO(json-rpc): remove this when dropping support. // APIs Legacy (REST + JSON-RPC) - if err := configureLegacyRoutes(router, server, rateLim, systemCtrl, userCtrl, infraCtrl); err != nil { - return nil, fmt.Errorf("configuring legacy API: %s", err) - } + configureLegacyRoutes(router, server, rateLim, systemCtrl, userCtrl, infraCtrl) // APIs V1 if err := configureAPIV1Routes(router, rateLim, systemCtrl, userCtrl, infraCtrl); err != nil { @@ -69,7 +67,7 @@ func configureLegacyRoutes( systemCtrl *controllers.SystemController, userCtrl *controllers.UserController, infraCtrl *controllers.InfraController, -) error { +) { router.post("/rpc", func(rw http.ResponseWriter, r *http.Request) { server.ServeHTTP(rw, r) }, middlewares.WithLogging, middlewares.OtelHTTP("rpc"), middlewares.Authentication, rateLim) @@ -87,8 +85,6 @@ func configureLegacyRoutes( // Health endpoint configuration. router.get("/healthz", controllers.HealthHandler) router.get("/health", controllers.HealthHandler) - - return nil } func configureAPIV1Routes( diff --git a/internal/system/impl/mock.go b/internal/system/impl/mock.go index 0471d687..825888c2 100644 --- a/internal/system/impl/mock.go +++ b/internal/system/impl/mock.go @@ -127,7 +127,7 @@ func NewSystemMockErrService() system.SystemService { return &SystemMockErrService{} } -// GetReceiptByTransactionHash implements system.SystemService +// GetReceiptByTransactionHash implements system.SystemService. func (*SystemMockErrService) GetReceiptByTransactionHash(context.Context, common.Hash) (sqlstore.Receipt, bool, error) { return sqlstore.Receipt{}, false, nil } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 3eec6aa6..45f71722 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -22,8 +22,8 @@ func TestWrite(t *testing.T) { t.Parallel() calls := setup(t) - _, table := requireCreate(t, calls) - requireWrite(t, calls, table) + tableName := requireCreate(t, calls) + requireWrite(t, calls, tableName) } func TestRead(t *testing.T) { @@ -31,8 +31,8 @@ func TestRead(t *testing.T) { t.Run("status 200", func(t *testing.T) { calls := setup(t) - _, table := requireCreate(t, calls) - hash := requireWrite(t, calls, table) + tableName := requireCreate(t, calls) + hash := requireWrite(t, calls, tableName) requireReceipt(t, calls, hash, WaitFor(time.Second*10)) type result struct { @@ -40,25 +40,25 @@ func TestRead(t *testing.T) { } res0 := []result{} - calls.query(fmt.Sprintf("select * from %s", table), &res0) + calls.query(fmt.Sprintf("select * from %s", tableName), &res0) require.Len(t, res0, 1) require.Equal(t, "baz", res0[0].Bar) res1 := map[string]interface{}{} - calls.query(fmt.Sprintf("select * from %s", table), &res1, ReadOutput(Table)) + calls.query(fmt.Sprintf("select * from %s", tableName), &res1, ReadOutput(Table)) require.Len(t, res1, 2) res2 := result{} - calls.query(fmt.Sprintf("select * from %s", table), &res2, ReadUnwrap()) + calls.query(fmt.Sprintf("select * from %s", tableName), &res2, ReadUnwrap()) require.Equal(t, "baz", res2.Bar) res3 := []string{} - calls.query(fmt.Sprintf("select * from %s", table), &res3, ReadExtract()) + calls.query(fmt.Sprintf("select * from %s", tableName), &res3, ReadExtract()) require.Len(t, res3, 1) require.Equal(t, "baz", res3[0]) res4 := "" - calls.query(fmt.Sprintf("select * from %s", table), &res4, ReadUnwrap(), ReadExtract()) + calls.query(fmt.Sprintf("select * from %s", tableName), &res4, ReadUnwrap(), ReadExtract()) require.Equal(t, "baz", res4) }) @@ -74,21 +74,21 @@ func TestGetReceipt(t *testing.T) { t.Run("status 200", func(t *testing.T) { calls := setup(t) - _, table := requireCreate(t, calls) - hash := requireWrite(t, calls, table) + tableName := requireCreate(t, calls) + hash := requireWrite(t, calls, tableName) requireReceipt(t, calls, hash, WaitFor(time.Second*10)) }) t.Run("status 400", func(t *testing.T) { calls := setup(t) - _, _ = requireCreate(t, calls) + _ = requireCreate(t, calls) _, _, err := calls.client.Receipt(context.Background(), "0xINVALIDHASH") require.Error(t, err) }) t.Run("status 404", func(t *testing.T) { calls := setup(t) - _, _ = requireCreate(t, calls) + _ = requireCreate(t, calls) _, exists, err := calls.client.Receipt(context.Background(), "0x5c6f90e52284726a7276d6a20a3df94a4532a8fa4c921233a301e95673ad0255") //nolint require.NoError(t, err) require.False(t, exists) @@ -159,10 +159,10 @@ func TestHealth(t *testing.T) { require.True(t, healthy) } -func requireCreate(t *testing.T, calls clientCalls) (TableID, string) { - id, tableName := calls.create("(bar text)", WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) +func requireCreate(t *testing.T, calls clientCalls) string { + _, tableName := calls.create("(bar text)", WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) require.Equal(t, "foo_1337_1", tableName) - return id, tableName + return tableName } func requireWrite(t *testing.T, calls clientCalls, table string) string { diff --git a/pkg/client/health.go b/pkg/client/health.go index 53a64587..4c3edf93 100644 --- a/pkg/client/health.go +++ b/pkg/client/health.go @@ -8,10 +8,15 @@ import ( func (c *Client) CheckHealth(ctx context.Context) (bool, error) { url := *c.baseURL.JoinPath("api/v1/health") - res, err := c.tblHTTP.Get(url.String()) + req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + if err != nil { + return false, fmt.Errorf("creating request: %s", err) + } + res, err := c.tblHTTP.Do(req) if err != nil { return false, fmt.Errorf("http get error: %s", err) } + defer res.Body.Close() return res.StatusCode == http.StatusOK, nil } diff --git a/pkg/client/queryhelpers.go b/pkg/client/queryhelpers.go index ef66300a..5678fa75 100644 --- a/pkg/client/queryhelpers.go +++ b/pkg/client/queryhelpers.go @@ -1,14 +1,13 @@ package client import ( - "context" "fmt" "github.com/textileio/go-tableland/internal/tableland" ) // Hash validates the provided create table statement and returns its hash. -func (c *Client) Hash(ctx context.Context, statement string) (string, error) { +func (c *Client) Hash(statement string) (string, error) { stmt, err := c.parser.ValidateCreateTable(statement, tableland.ChainID(c.chain.ID)) if err != nil { return "", fmt.Errorf("invalid create statement: %s", err) @@ -17,7 +16,7 @@ func (c *Client) Hash(ctx context.Context, statement string) (string, error) { } // Validate validates a write query, returning the table id. -func (c *Client) Validate(ctx context.Context, statement string) (TableID, error) { +func (c *Client) Validate(statement string) (TableID, error) { stmts, err := c.parser.ValidateMutatingQuery(statement, tableland.ChainID(c.chain.ID)) if err != nil { return TableID{}, fmt.Errorf("invalid create statement: %s", err) diff --git a/pkg/client/readquery.go b/pkg/client/readquery.go index ced4ede7..8c263d17 100644 --- a/pkg/client/readquery.go +++ b/pkg/client/readquery.go @@ -77,10 +77,15 @@ func (c *Client) Read(ctx context.Context, query string, target interface{}, opt } url.RawQuery = values.Encode() - response, err := c.tblHTTP.Get(url.String()) + req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + if err != nil { + return fmt.Errorf("creating request: %s", err) + } + response, err := c.tblHTTP.Do(req) if err != nil { return fmt.Errorf("calling query: %s", err) } + defer response.Body.Close() if response.StatusCode != http.StatusOK { msg, _ := io.ReadAll(response.Body) return fmt.Errorf("the response wasn't successful (status: %d, body: %s)", response.StatusCode, msg) diff --git a/pkg/client/receipt.go b/pkg/client/receipt.go index 47c183ca..244ca666 100644 --- a/pkg/client/receipt.go +++ b/pkg/client/receipt.go @@ -48,10 +48,15 @@ func (c *Client) getReceipt(ctx context.Context, txnHash string) (*apiv1.Transac JoinPath(strconv.FormatInt(int64(c.chain.ID), 10)). JoinPath(txnHash) - response, err := c.tblHTTP.Get(url.String()) + req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + if err != nil { + return nil, false, fmt.Errorf("creating request: %s", err) + } + response, err := c.tblHTTP.Do(req) if err != nil { return nil, false, fmt.Errorf("calling get receipt by transaction hash: %s", err) } + defer response.Body.Close() if response.StatusCode == http.StatusNotFound { return nil, false, nil } diff --git a/pkg/client/table.go b/pkg/client/table.go index 2ea68909..bd7f0e6a 100644 --- a/pkg/client/table.go +++ b/pkg/client/table.go @@ -20,10 +20,15 @@ func (c *Client) GetTable(ctx context.Context, tableID TableID) (*apiv1.Table, e JoinPath(strconv.FormatInt(int64(c.chain.ID), 10)). JoinPath(strconv.FormatInt(tableID.ToBigInt().Int64(), 10)) - response, err := c.tblHTTP.Get(url.String()) + req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + if err != nil { + return nil, fmt.Errorf("creating request: %s", err) + } + response, err := c.tblHTTP.Do(req) if err != nil { return nil, fmt.Errorf("calling get tables by id: %s", err) } + defer response.Body.Close() if response.StatusCode == http.StatusNotFound { return nil, ErrTableNotFound } diff --git a/pkg/client/version.go b/pkg/client/version.go index dadbfaea..f180c86a 100644 --- a/pkg/client/version.go +++ b/pkg/client/version.go @@ -6,16 +6,23 @@ import ( "encoding/json" "fmt" "io" + "net/http" "github.com/textileio/go-tableland/internal/router/controllers/apiv1" ) func (c *Client) Version(ctx context.Context) (*apiv1.VersionInfo, error) { url := *c.baseURL.JoinPath("api/v1/version") - res, err := c.tblHTTP.Get(url.String()) + + req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + if err != nil { + return nil, fmt.Errorf("creating request: %s", err) + } + res, err := c.tblHTTP.Do(req) if err != nil { return nil, fmt.Errorf("http get error: %s", err) } + defer res.Body.Close() bb, _ := io.ReadAll(res.Body) diff --git a/pkg/client/writequery.go b/pkg/client/writequery.go index 9a6d1eae..82322f1e 100644 --- a/pkg/client/writequery.go +++ b/pkg/client/writequery.go @@ -71,7 +71,7 @@ func (c *Client) Create(ctx context.Context, schema string, opts ...CreateOption // Write initiates a write query, returning the txn hash. func (c *Client) Write(ctx context.Context, query string) (string, error) { - tableID, err := c.Validate(ctx, query) + tableID, err := c.Validate(query) if err != nil { return "", fmt.Errorf("calling Validate: %v", err) } diff --git a/tests/fullstack/fullstack.go b/tests/fullstack/fullstack.go index 1ac91515..7b62a022 100644 --- a/tests/fullstack/fullstack.go +++ b/tests/fullstack/fullstack.go @@ -101,6 +101,7 @@ func CreateFullStack(t *testing.T, deps Deps) FullStack { wallet, nonceimpl.NewSimpleTracker(wallet, backend), ) + require.NoError(t, err) chainStacks := map[tableland.ChainID]chains.ChainStack{ 1337: { @@ -144,7 +145,7 @@ func CreateFullStack(t *testing.T, deps Deps) FullStack { require.NoError(t, err) db.SetMaxOpenConns(1) - ex, err := executor.NewExecutor(1337, db, parser, 0, &aclHalfMock{systemStore}) + ex, err := executor.NewExecutor(1337, db, parser, 0, acl) require.NoError(t, err) router, err := router.ConfiguredRouter(tbl, systemService, 10, time.Second) From 594bf8a2602ad5d6e5ce5c8511a328d195d7aa08 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 6 Dec 2022 16:56:07 -0300 Subject: [PATCH 050/101] fix lints Signed-off-by: Ignacio Hagopian --- .golangci.yml | 53 ++++++++++--------- internal/router/controllers/system.go | 6 ++- internal/router/controllers/user.go | 2 +- internal/system/impl/mock.go | 2 +- internal/system/impl/sqlstore.go | 1 + internal/system/impl/sqlstore_instrumented.go | 7 ++- internal/system/system.go | 3 +- pkg/client/chains.go | 3 ++ pkg/client/client_test.go | 12 +++-- pkg/client/health.go | 3 +- pkg/client/readquery.go | 2 +- pkg/client/receipt.go | 2 +- pkg/client/table.go | 5 +- pkg/client/version.go | 3 +- pkg/{client_legacy => clientlegacy}/client.go | 4 +- .../client_test.go | 8 ++- pkg/sqlstore/table.go | 1 + tests/fullstack/fullstack.go | 1 + 18 files changed, 72 insertions(+), 46 deletions(-) rename pkg/{client_legacy => clientlegacy}/client.go (99%) rename pkg/{client_legacy => clientlegacy}/client_test.go (97%) diff --git a/.golangci.yml b/.golangci.yml index daff7905..d7331330 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,31 +6,31 @@ linters-settings: errorCode: 0 warningCode: 0 rules: - - name: blank-imports - - name: context-as-argument - - name: context-keys-type - - name: dot-imports - - name: error-return - - name: error-strings - - name: error-naming - - name: exported - - name: if-return - - name: increment-decrement - - name: var-naming - - name: var-declaration - - name: package-comments + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: exported + - name: if-return + - name: increment-decrement + - name: var-naming + - name: var-declaration + - name: package-comments disabled: true - - name: range - - name: receiver-naming - - name: time-naming - - name: unexported-return - - name: indent-error-flow - - name: errorf - - name: empty-block - - name: superfluous-else - - name: unused-parameter - - name: unreachable-code - - name: redefines-builtin-id + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unused-parameter + - name: unreachable-code + - name: redefines-builtin-id misspell: locale: US @@ -54,9 +54,10 @@ issues: exclude: - stutters - + run: timeout: 30m skip-dirs: - - "pkg/sqlstore/impl/system/internal/db" \ No newline at end of file + - "pkg/sqlstore/impl/system/internal/db" + - "internal/router/controllers/apiv1" diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 5fcfa312..3df72d09 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -24,6 +24,7 @@ func NewSystemController(svc system.SystemService) *SystemController { return &SystemController{svc} } +// GetReceiptByTransactionHash handles request asking for a transaction receipt. func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-Type", "application/json") ctx := r.Context() @@ -184,8 +185,8 @@ func (c *SystemController) GetTablesByController(rw http.ResponseWriter, r *http _ = json.NewEncoder(rw).Encode(retTables) } -// TODO(json-rpc): delete when dropping support. // GetTablesByStructureHash handles the GET /chain/{id}/tables/structure/{hash} call. +// TODO(json-rpc): delete when dropping support. func (c *SystemController) GetTablesByStructureHash(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -224,8 +225,8 @@ func (c *SystemController) GetTablesByStructureHash(rw http.ResponseWriter, r *h _ = json.NewEncoder(rw).Encode(retTables) } -// TODO(json-rpc): delete when droppping support. // GetSchemaByTableName handles the GET /schema/{table_name} call. +// TODO(json-rpc): delete when droppping support. func (c *SystemController) GetSchemaByTableName(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -284,6 +285,7 @@ func (c *SystemController) GetSchemaByTableName(rw http.ResponseWriter, r *http. }) } +// HealthHandler serves health check requests. func HealthHandler(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) } diff --git a/internal/router/controllers/user.go b/internal/router/controllers/user.go index 83a4bd90..c456d1f7 100644 --- a/internal/router/controllers/user.go +++ b/internal/router/controllers/user.go @@ -126,9 +126,9 @@ func userRowToMap(cols []tableland.Column, row []*tableland.ColumnValue) map[str return m } -// TODO(json-rpc): delete method when dropping support. // GetTableRow handles the GET /chain/{chainID}/tables/{id}/{key}/{value} call. // Use format=erc721 query param to generate JSON for ERC721 metadata. +// TODO(json-rpc): delete method when dropping support. func (c *UserController) GetTableRow(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) diff --git a/internal/system/impl/mock.go b/internal/system/impl/mock.go index 825888c2..17edb5c6 100644 --- a/internal/system/impl/mock.go +++ b/internal/system/impl/mock.go @@ -21,7 +21,7 @@ func NewSystemMockService() system.SystemService { return &SystemMockService{} } -// GetReceiptByTransactionHash implements system.SystemService +// GetReceiptByTransactionHash implements system.SystemService. func (*SystemMockService) GetReceiptByTransactionHash(context.Context, common.Hash) (sqlstore.Receipt, bool, error) { tableID, _ := tables.NewTableID("10") return sqlstore.Receipt{ diff --git a/internal/system/impl/sqlstore.go b/internal/system/impl/sqlstore.go index f0bc9f13..4c9ebdd1 100644 --- a/internal/system/impl/sqlstore.go +++ b/internal/system/impl/sqlstore.go @@ -130,6 +130,7 @@ func (s *SystemSQLStoreService) GetTableMetadata( }, nil } +// GetReceiptByTransactionHash returns a receipt by transaction hash. func (s *SystemSQLStoreService) GetReceiptByTransactionHash( ctx context.Context, txnHash common.Hash, diff --git a/internal/system/impl/sqlstore_instrumented.go b/internal/system/impl/sqlstore_instrumented.go index 1541fdb0..86ecbdc6 100644 --- a/internal/system/impl/sqlstore_instrumented.go +++ b/internal/system/impl/sqlstore_instrumented.go @@ -39,8 +39,11 @@ func NewInstrumentedSystemSQLStoreService(system system.SystemService) (system.S return &InstrumentedSystemSQLStoreService{system, callCount, latencyHistogram}, nil } -// GetReceiptByTransactionHash implements system.SystemService -func (s *InstrumentedSystemSQLStoreService) GetReceiptByTransactionHash(ctx context.Context, hash common.Hash) (sqlstore.Receipt, bool, error) { +// GetReceiptByTransactionHash implements system.SystemService. +func (s *InstrumentedSystemSQLStoreService) GetReceiptByTransactionHash( + ctx context.Context, + hash common.Hash, +) (sqlstore.Receipt, bool, error) { start := time.Now() receipt, exists, err := s.system.GetReceiptByTransactionHash(ctx, hash) latency := time.Since(start).Milliseconds() diff --git a/internal/system/system.go b/internal/system/system.go index 7bcf34cd..a3ee19aa 100644 --- a/internal/system/system.go +++ b/internal/system/system.go @@ -9,10 +9,11 @@ import ( "github.com/textileio/go-tableland/pkg/tables" ) +// ErrTableNotFound indicates that the table doesn't exist. var ErrTableNotFound = errors.New("table not found") -// TODO(json-rpc): this interface should be cleaned up after dropping support. // SystemService defines what system operations can be done. +// TODO(json-rpc): this interface should be cleaned up after dropping support. type SystemService interface { GetTableMetadata(context.Context, tables.TableID) (sqlstore.TableMetadata, error) GetTablesByController(context.Context, string) ([]sqlstore.Table, error) diff --git a/pkg/client/chains.go b/pkg/client/chains.go index 34f0ba7b..224b99d6 100644 --- a/pkg/client/chains.go +++ b/pkg/client/chains.go @@ -107,6 +107,7 @@ func (c Chain) CanRelayWrites() bool { return c.ID != ChainIDs.Ethereum && c.ID != ChainIDs.Optimism && c.ID != ChainIDs.Polygon } +// 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", @@ -118,6 +119,7 @@ var InfuraURLs = map[ChainID]string{ 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.Ethereum: "https://eth-mainnet.g.alchemy.com/v2/%s", @@ -129,6 +131,7 @@ var AlchemyURLs = map[ChainID]string{ ChainIDs.Polygon: "https://polygon-mainnet.g.alchemy.com/v2/%s", } +// LocalURLs contains the URLs for a local network. var LocalURLs = map[ChainID]string{ ChainIDs.Local: "http://localhost:8545", } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 45f71722..d8be9651 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -104,7 +104,7 @@ func TestGetTableByID(t *testing.T) { "(bar text DEFAULT 'foo',zar int, CHECK (zar>0))", WithPrefix("foo"), WithReceiptTimeout(time.Second*10)) - table := calls.getTableById(id) + table := calls.getTableByID(id) require.NotEmpty(t, fullName, table.Name) require.Equal(t, "https://testnet.tableland.network/chain/1337/tables/1", table.ExternalUrl) require.Equal(t, "https://render.tableland.xyz/anim/?chain=1337&id=1", table.AnimationUrl) @@ -184,7 +184,7 @@ type clientCalls struct { write func(query string) string query func(query string, target interface{}, opts ...ReadOption) receipt func(txnHash string, options ...ReceiptOption) (*apiv1.TransactionReceipt, bool) - getTableById func(tableID TableID) *apiv1.Table + getTableByID func(tableID TableID) *apiv1.Table version func() (*apiv1.VersionInfo, error) health func() (bool, error) } @@ -198,7 +198,11 @@ func setup(t *testing.T) clientCalls { ContractAddr: stack.Address, } - client, err := NewClient(context.Background(), stack.Wallet, NewClientChain(c), NewClientContractBackend(stack.Backend)) + client, err := NewClient( + context.Background(), + stack.Wallet, + NewClientChain(c), + NewClientContractBackend(stack.Backend)) require.NoError(t, err) ctx := context.Background() @@ -228,7 +232,7 @@ func setup(t *testing.T) clientCalls { require.NoError(t, err) return receipt, found }, - getTableById: func(tableID TableID) *apiv1.Table { + getTableByID: func(tableID TableID) *apiv1.Table { table, err := client.GetTable(ctx, tableID) require.NoError(t, err) return table diff --git a/pkg/client/health.go b/pkg/client/health.go index 4c3edf93..2330ae7c 100644 --- a/pkg/client/health.go +++ b/pkg/client/health.go @@ -6,6 +6,7 @@ import ( "net/http" ) +// CheckHealth returns true if the targeted validator endpoint is considered healthy, and false otherwise. func (c *Client) CheckHealth(ctx context.Context) (bool, error) { url := *c.baseURL.JoinPath("api/v1/health") req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) @@ -16,7 +17,7 @@ func (c *Client) CheckHealth(ctx context.Context) (bool, error) { if err != nil { return false, fmt.Errorf("http get error: %s", err) } - defer res.Body.Close() + defer func() { _ = res.Body.Close() }() return res.StatusCode == http.StatusOK, nil } diff --git a/pkg/client/readquery.go b/pkg/client/readquery.go index 8c263d17..1c933cca 100644 --- a/pkg/client/readquery.go +++ b/pkg/client/readquery.go @@ -85,7 +85,7 @@ func (c *Client) Read(ctx context.Context, query string, target interface{}, opt if err != nil { return fmt.Errorf("calling query: %s", err) } - defer response.Body.Close() + defer func() { _ = response.Body.Close() }() if response.StatusCode != http.StatusOK { msg, _ := io.ReadAll(response.Body) return fmt.Errorf("the response wasn't successful (status: %d, body: %s)", response.StatusCode, msg) diff --git a/pkg/client/receipt.go b/pkg/client/receipt.go index 244ca666..c5c5f25a 100644 --- a/pkg/client/receipt.go +++ b/pkg/client/receipt.go @@ -56,7 +56,7 @@ func (c *Client) getReceipt(ctx context.Context, txnHash string) (*apiv1.Transac if err != nil { return nil, false, fmt.Errorf("calling get receipt by transaction hash: %s", err) } - defer response.Body.Close() + defer func() { _ = response.Body.Close() }() if response.StatusCode == http.StatusNotFound { return nil, false, nil } diff --git a/pkg/client/table.go b/pkg/client/table.go index bd7f0e6a..cd0fb222 100644 --- a/pkg/client/table.go +++ b/pkg/client/table.go @@ -12,8 +12,11 @@ import ( "github.com/textileio/go-tableland/internal/router/controllers/apiv1" ) +// ErrTableNotFound is returned if the provided table ID isn't found in the network. var ErrTableNotFound = errors.New("table not found") +// GetTable returns the table information given its ID. If the table ID doesn't exist, +// it returns ErrTableNotFound. func (c *Client) GetTable(ctx context.Context, tableID TableID) (*apiv1.Table, error) { url := *c.baseURL. JoinPath("api/v1/tables/"). @@ -28,7 +31,7 @@ func (c *Client) GetTable(ctx context.Context, tableID TableID) (*apiv1.Table, e if err != nil { return nil, fmt.Errorf("calling get tables by id: %s", err) } - defer response.Body.Close() + defer func() { _ = response.Body.Close() }() if response.StatusCode == http.StatusNotFound { return nil, ErrTableNotFound } diff --git a/pkg/client/version.go b/pkg/client/version.go index f180c86a..c856f8a0 100644 --- a/pkg/client/version.go +++ b/pkg/client/version.go @@ -11,6 +11,7 @@ import ( "github.com/textileio/go-tableland/internal/router/controllers/apiv1" ) +// Version returns the validator version information. func (c *Client) Version(ctx context.Context) (*apiv1.VersionInfo, error) { url := *c.baseURL.JoinPath("api/v1/version") @@ -22,7 +23,7 @@ func (c *Client) Version(ctx context.Context) (*apiv1.VersionInfo, error) { if err != nil { return nil, fmt.Errorf("http get error: %s", err) } - defer res.Body.Close() + defer func() { _ = res.Body.Close() }() bb, _ := io.ReadAll(res.Body) diff --git a/pkg/client_legacy/client.go b/pkg/clientlegacy/client.go similarity index 99% rename from pkg/client_legacy/client.go rename to pkg/clientlegacy/client.go index 6d31d8b6..dbfc5927 100644 --- a/pkg/client_legacy/client.go +++ b/pkg/clientlegacy/client.go @@ -1,4 +1,4 @@ -package client_legacy +package clientlegacy import ( "context" @@ -25,8 +25,8 @@ import ( var defaultChain = client.Chains.PolygonMumbai -// TODO(json-rpc): remove client_legacy package when support is dropped. // TxnReceipt is a Tableland event processing receipt. +// TODO(json-rpc): remove client_legacy package when support is dropped. type TxnReceipt struct { ChainID client.ChainID `json:"chain_id"` TxnHash string `json:"txn_hash"` diff --git a/pkg/client_legacy/client_test.go b/pkg/clientlegacy/client_test.go similarity index 97% rename from pkg/client_legacy/client_test.go rename to pkg/clientlegacy/client_test.go index ff702e29..d2ca915a 100644 --- a/pkg/client_legacy/client_test.go +++ b/pkg/clientlegacy/client_test.go @@ -1,4 +1,4 @@ -package client_legacy +package clientlegacy import ( "context" @@ -148,7 +148,11 @@ func setup(t *testing.T) clientCalls { ContractAddr: stack.Address, } - client, err := NewClient(context.Background(), stack.Wallet, NewClientChain(c), NewClientContractBackend(stack.Backend)) + client, err := NewClient( + context.Background(), + stack.Wallet, + NewClientChain(c), + NewClientContractBackend(stack.Backend)) require.NoError(t, err) t.Cleanup(func() { client.Close() diff --git a/pkg/sqlstore/table.go b/pkg/sqlstore/table.go index 77228a4d..d7369737 100644 --- a/pkg/sqlstore/table.go +++ b/pkg/sqlstore/table.go @@ -64,6 +64,7 @@ type SystemACL struct { UpdatedAt *time.Time } +// Receipt represents a Tableland receipt. type Receipt struct { ChainID tableland.ChainID BlockNumber int64 diff --git a/tests/fullstack/fullstack.go b/tests/fullstack/fullstack.go index 7b62a022..e6be6505 100644 --- a/tests/fullstack/fullstack.go +++ b/tests/fullstack/fullstack.go @@ -61,6 +61,7 @@ type Deps struct { SystemService system.SystemService } +// CreateFullStack creates a running validator with the provided dependencies, or defaults otherwise. func CreateFullStack(t *testing.T, deps Deps) FullStack { t.Helper() From 4e5be2fe0a48dd6229741186ed497ff6242c4e39 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 10:20:20 -0300 Subject: [PATCH 051/101] api: avoid 404 in legacy api for GetTable Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system.go | 7 +++++++ internal/system/impl/sqlstore.go | 6 +++++- internal/system/impl/sqlstore_test.go | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 3df72d09..a437730a 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -84,8 +84,15 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { return } + isAPIV1 := strings.HasPrefix(r.RequestURI, "/api/v1/tables") + metadata, err := c.systemService.GetTableMetadata(ctx, id) if err == system.ErrTableNotFound { + if !isAPIV1 { + rw.WriteHeader(http.StatusOK) + _ = json.NewEncoder(rw).Encode(metadata) + return + } rw.WriteHeader(http.StatusNotFound) return } diff --git a/internal/system/impl/sqlstore.go b/internal/system/impl/sqlstore.go index 4c9ebdd1..723ccf46 100644 --- a/internal/system/impl/sqlstore.go +++ b/internal/system/impl/sqlstore.go @@ -106,7 +106,11 @@ func (s *SystemSQLStoreService) GetTableMetadata( }, nil } - return sqlstore.TableMetadata{}, system.ErrTableNotFound + return sqlstore.TableMetadata{ + ExternalURL: fmt.Sprintf("%s/chain/%d/tables/%s", s.extURLPrefix, chainID, id), + Image: s.emptyMetadataImage(), + Message: "Table not found", + }, system.ErrTableNotFound } tableName := fmt.Sprintf("%s_%d_%s", table.Prefix, table.ChainID, table.ID) schema, err := store.GetSchemaByTableName(ctx, tableName) diff --git a/internal/system/impl/sqlstore_test.go b/internal/system/impl/sqlstore_test.go index 0987b471..786df02a 100644 --- a/internal/system/impl/sqlstore_test.go +++ b/internal/system/impl/sqlstore_test.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "github.com/textileio/go-tableland/internal/router/middlewares" + sys "github.com/textileio/go-tableland/internal/system" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed" executor "github.com/textileio/go-tableland/pkg/eventprocessor/impl/executor/impl" @@ -270,8 +271,7 @@ func TestGetMetadata(t *testing.T) { require.NoError(t, err) metadata, err := svc.GetTableMetadata(ctx, id) - require.NoError(t, err) - + require.ErrorIs(t, err, sys.ErrTableNotFound) require.Equal(t, fmt.Sprintf("https://tableland.network/tables/chain/%d/tables/%s", 1337, id), metadata.ExternalURL) require.Equal(t, "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0nNTEyJyBoZWlnaHQ9JzUxMicgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJz48cmVjdCB3aWR0aD0nNTEyJyBoZWlnaHQ9JzUxMicgZmlsbD0nIzAwMCcvPjwvc3ZnPg==", metadata.Image) // nolint require.Equal(t, "Table not found", metadata.Message) From 2d4d96f75a93f650a606cbd1ac542a52b6f83eb0 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 10:53:09 -0300 Subject: [PATCH 052/101] pkg/client: restructure folders Signed-off-by: Ignacio Hagopian --- pkg/{clientlegacy => client/legacy}/client.go | 0 .../legacy}/client_test.go | 0 pkg/client/{ => v1}/client.go | 17 +++++++------ pkg/client/{ => v1}/client_test.go | 25 +++++-------------- pkg/client/{ => v1}/health.go | 2 +- pkg/client/{ => v1}/queryhelpers.go | 2 +- pkg/client/{ => v1}/readquery.go | 2 +- pkg/client/{ => v1}/receipt.go | 2 +- pkg/client/{ => v1}/table.go | 2 +- pkg/client/{ => v1}/version.go | 2 +- pkg/client/{ => v1}/writequery.go | 2 +- 11 files changed, 22 insertions(+), 34 deletions(-) rename pkg/{clientlegacy => client/legacy}/client.go (100%) rename pkg/{clientlegacy => client/legacy}/client_test.go (100%) rename pkg/client/{ => v1}/client.go (93%) rename pkg/client/{ => v1}/client_test.go (95%) rename pkg/client/{ => v1}/health.go (97%) rename pkg/client/{ => v1}/queryhelpers.go (98%) rename pkg/client/{ => v1}/readquery.go (99%) rename pkg/client/{ => v1}/receipt.go (99%) rename pkg/client/{ => v1}/table.go (98%) rename pkg/client/{ => v1}/version.go (98%) rename pkg/client/{ => v1}/writequery.go (99%) diff --git a/pkg/clientlegacy/client.go b/pkg/client/legacy/client.go similarity index 100% rename from pkg/clientlegacy/client.go rename to pkg/client/legacy/client.go diff --git a/pkg/clientlegacy/client_test.go b/pkg/client/legacy/client_test.go similarity index 100% rename from pkg/clientlegacy/client_test.go rename to pkg/client/legacy/client_test.go diff --git a/pkg/client/client.go b/pkg/client/v1/client.go similarity index 93% rename from pkg/client/client.go rename to pkg/client/v1/client.go index bdb2bc9f..e1cecc9b 100644 --- a/pkg/client/client.go +++ b/pkg/client/v1/client.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "context" @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" systemimpl "github.com/textileio/go-tableland/internal/system/impl" "github.com/textileio/go-tableland/internal/tableland" + "github.com/textileio/go-tableland/pkg/client" "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/parsing" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" @@ -20,20 +21,20 @@ import ( "github.com/textileio/go-tableland/pkg/wallet" ) -var defaultChain = Chains.PolygonMumbai +var defaultChain = client.Chains.PolygonMumbai // Client is the Tableland client. type Client struct { tblHTTP *http.Client tblContract *ethereum.Client - chain Chain + chain client.Chain wallet *wallet.Wallet parser parsing.SQLValidator baseURL *url.URL } type config struct { - chain *Chain + chain *client.Chain infuraAPIKey string alchemyAPIKey string local bool @@ -44,7 +45,7 @@ type config struct { type NewClientOption func(*config) // NewClientChain specifies chaininfo. -func NewClientChain(chain Chain) NewClientOption { +func NewClientChain(chain client.Chain) NewClientOption { return func(ncc *config) { ncc.chain = &chain } @@ -141,19 +142,19 @@ func getContractBackend(ctx context.Context, config config) (bind.ContractBacken if config.contractBackend != nil && config.infuraAPIKey == "" && config.alchemyAPIKey == "" { return config.contractBackend, nil } else if config.infuraAPIKey != "" && config.contractBackend == nil && config.alchemyAPIKey == "" { - tmpl, found := InfuraURLs[config.chain.ID] + tmpl, found := client.InfuraURLs[config.chain.ID] if !found { return nil, fmt.Errorf("chain id %v not supported for Infura", config.chain.ID) } return ethclient.DialContext(ctx, fmt.Sprintf(tmpl, config.infuraAPIKey)) } else if config.alchemyAPIKey != "" && config.contractBackend == nil && config.infuraAPIKey == "" { - tmpl, found := AlchemyURLs[config.chain.ID] + tmpl, found := client.AlchemyURLs[config.chain.ID] if !found { return nil, fmt.Errorf("chain id %v not supported for Alchemy", config.chain.ID) } return ethclient.DialContext(ctx, fmt.Sprintf(tmpl, config.alchemyAPIKey)) } else if config.local { - url, found := LocalURLs[config.chain.ID] + url, found := client.LocalURLs[config.chain.ID] if !found { return nil, fmt.Errorf("chain id %v not supported for Local", config.chain.ID) } diff --git a/pkg/client/client_test.go b/pkg/client/v1/client_test.go similarity index 95% rename from pkg/client/client_test.go rename to pkg/client/v1/client_test.go index d8be9651..4ea6e65f 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/v1/client_test.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "context" @@ -8,27 +8,22 @@ import ( "github.com/stretchr/testify/require" "github.com/textileio/go-tableland/internal/router/controllers/apiv1" + "github.com/textileio/go-tableland/pkg/client" "github.com/textileio/go-tableland/tests/fullstack" ) func TestCreate(t *testing.T) { - t.Parallel() - calls := setup(t) requireCreate(t, calls) } func TestWrite(t *testing.T) { - t.Parallel() - calls := setup(t) tableName := requireCreate(t, calls) requireWrite(t, calls, tableName) } func TestRead(t *testing.T) { - t.Parallel() - t.Run("status 200", func(t *testing.T) { calls := setup(t) tableName := requireCreate(t, calls) @@ -70,8 +65,6 @@ func TestRead(t *testing.T) { } func TestGetReceipt(t *testing.T) { - t.Parallel() - t.Run("status 200", func(t *testing.T) { calls := setup(t) tableName := requireCreate(t, calls) @@ -96,8 +89,6 @@ func TestGetReceipt(t *testing.T) { } func TestGetTableByID(t *testing.T) { - t.Parallel() - t.Run("status 200", func(t *testing.T) { calls := setup(t) id, fullName := calls.create( @@ -120,10 +111,10 @@ func TestGetTableByID(t *testing.T) { require.Equal(t, "bar", table.Schema.Columns[0].Name) require.Equal(t, "text", table.Schema.Columns[0].Type_) require.Len(t, table.Schema.Columns[0].Constraints, 1) - require.Equal(t, "DEFAULT 'foo'", table.Schema.Columns[0].Constraints[0]) + require.Equal(t, "default 'foo'", table.Schema.Columns[0].Constraints[0]) require.Len(t, table.Schema.TableConstraints, 1) - require.Equal(t, "CHECK(zar > 0)", table.Schema.TableConstraints[0]) + require.Equal(t, "check(zar > 0)", table.Schema.TableConstraints[0]) }) t.Run("status 404", func(t *testing.T) { calls := setup(t) @@ -135,8 +126,6 @@ func TestGetTableByID(t *testing.T) { } func TestVersion(t *testing.T) { - t.Parallel() - calls := setup(t) info, err := calls.version() require.NoError(t, err) @@ -151,8 +140,6 @@ func TestVersion(t *testing.T) { } func TestHealth(t *testing.T) { - t.Parallel() - calls := setup(t) healthy, err := calls.health() require.NoError(t, err) @@ -192,9 +179,9 @@ type clientCalls struct { func setup(t *testing.T) clientCalls { stack := fullstack.CreateFullStack(t, fullstack.Deps{}) - c := Chain{ + c := client.Chain{ Endpoint: stack.Server.URL, - ID: ChainID(fullstack.ChainID), + ID: client.ChainID(fullstack.ChainID), ContractAddr: stack.Address, } diff --git a/pkg/client/health.go b/pkg/client/v1/health.go similarity index 97% rename from pkg/client/health.go rename to pkg/client/v1/health.go index 2330ae7c..31d83b09 100644 --- a/pkg/client/health.go +++ b/pkg/client/v1/health.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "context" diff --git a/pkg/client/queryhelpers.go b/pkg/client/v1/queryhelpers.go similarity index 98% rename from pkg/client/queryhelpers.go rename to pkg/client/v1/queryhelpers.go index 5678fa75..1dd32000 100644 --- a/pkg/client/queryhelpers.go +++ b/pkg/client/v1/queryhelpers.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "fmt" diff --git a/pkg/client/readquery.go b/pkg/client/v1/readquery.go similarity index 99% rename from pkg/client/readquery.go rename to pkg/client/v1/readquery.go index 1c933cca..ee0f3d9d 100644 --- a/pkg/client/readquery.go +++ b/pkg/client/v1/readquery.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "context" diff --git a/pkg/client/receipt.go b/pkg/client/v1/receipt.go similarity index 99% rename from pkg/client/receipt.go rename to pkg/client/v1/receipt.go index c5c5f25a..dc162048 100644 --- a/pkg/client/receipt.go +++ b/pkg/client/v1/receipt.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "context" diff --git a/pkg/client/table.go b/pkg/client/v1/table.go similarity index 98% rename from pkg/client/table.go rename to pkg/client/v1/table.go index cd0fb222..874d0f75 100644 --- a/pkg/client/table.go +++ b/pkg/client/v1/table.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "context" diff --git a/pkg/client/version.go b/pkg/client/v1/version.go similarity index 98% rename from pkg/client/version.go rename to pkg/client/v1/version.go index c856f8a0..4b504a8d 100644 --- a/pkg/client/version.go +++ b/pkg/client/v1/version.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "bytes" diff --git a/pkg/client/writequery.go b/pkg/client/v1/writequery.go similarity index 99% rename from pkg/client/writequery.go rename to pkg/client/v1/writequery.go index 82322f1e..17ed2d34 100644 --- a/pkg/client/writequery.go +++ b/pkg/client/v1/writequery.go @@ -1,4 +1,4 @@ -package client +package v1 import ( "context" From 7ebc115842d6ebbd6be602977ed36402deb9396f Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 11:02:16 -0300 Subject: [PATCH 053/101] remove toolkit main change Signed-off-by: Ignacio Hagopian --- cmd/toolkit/gaspricebumper.go | 83 ----------------------------------- cmd/toolkit/main.go | 4 -- 2 files changed, 87 deletions(-) diff --git a/cmd/toolkit/gaspricebumper.go b/cmd/toolkit/gaspricebumper.go index f3c7e2a1..9d349c75 100644 --- a/cmd/toolkit/gaspricebumper.go +++ b/cmd/toolkit/gaspricebumper.go @@ -7,7 +7,6 @@ import ( "fmt" "log" "math/big" - "strconv" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -52,46 +51,6 @@ var gasPriceBumperCmd = &cobra.Command{ }, } -var replaceNonceRangeCmd = &cobra.Command{ - Use: "replacenoncerange", - Short: "Sends transactions to replace a nonce range", - Long: "Sends transactions to replace a nonce range", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - privateKey, err := cmd.Flags().GetString("privatekey") - if err != nil { - return errors.New("failed to parse privatekey") - } - gatewayEndpoint, err := cmd.Flags().GetString("gateway") - if err != nil { - return errors.New("failed to parse gateway") - } - - start, err := strconv.ParseUint(args[0], 10, 64) - if err != nil { - return fmt.Errorf("invalid nonce start: %s", err) - } - end, err := strconv.ParseUint(args[1], 10, 64) - if err != nil { - return fmt.Errorf("invalid nonce end: %s", err) - } - - conn, err := ethclient.Dial(gatewayEndpoint) - if err != nil { - log.Fatalf("failed to connect to ethereum endpoint: %s", err) - } - pk, err := crypto.HexToECDSA(privateKey) - if err != nil { - log.Fatalf("decoding private key: %s", err) - } - if err := replaceNonceRange(conn, pk, start, end); err != nil { - log.Fatalf("bumpint txn fee: %s", err) - } - - return nil - }, -} - func bumpTxnFee( conn *ethclient.Client, pk *ecdsa.PrivateKey, @@ -147,45 +106,3 @@ func bumpTxnFee( return txn.Hash(), nil } - -func replaceNonceRange( - conn *ethclient.Client, - pk *ecdsa.PrivateKey, - start, end uint64, -) error { - for nonce := start; nonce <= end; nonce++ { - ctx := context.Background() - - candidateGasPriceSuggested, err := conn.SuggestGasPrice(ctx) - if err != nil { - return fmt.Errorf("get suggested gas price: %s", err) - } - newGasPrice := candidateGasPriceSuggested.Mul(candidateGasPriceSuggested, big.NewInt(125)) - newGasPrice = newGasPrice.Div(newGasPrice, big.NewInt(100)) - fmt.Printf("**New gas price: %s**\n", newGasPrice) - - targetAddress := common.HexToAddress("0xb468b686d190937905b0138c9f5746e9325be121") - ltxn := &types.LegacyTx{ - Nonce: nonce, - GasPrice: newGasPrice, - Gas: 21000, - To: &targetAddress, - Value: big.NewInt(0), - } - - chainID, err := conn.ChainID(ctx) - if err != nil { - return fmt.Errorf("get chain id: %s", err) - } - signer := types.NewLondonSigner(chainID) - txn, err := types.SignTx(types.NewTx(ltxn), signer, pk) - if err != nil { - return fmt.Errorf("signing txn: %s", err) - } - if err := conn.SendTransaction(ctx, txn); err != nil { - return fmt.Errorf("sending txn: %s", err) - } - } - - return nil -} diff --git a/cmd/toolkit/main.go b/cmd/toolkit/main.go index 4ee3be58..da7700a6 100644 --- a/cmd/toolkit/main.go +++ b/cmd/toolkit/main.go @@ -24,7 +24,6 @@ func init() { rootCmd.AddCommand(scCmd) rootCmd.AddCommand(walletCmd) rootCmd.AddCommand(gasPriceBumperCmd) - rootCmd.AddCommand(replaceNonceRangeCmd) siweCreateCmd.Flags().Duration("duration", time.Hour*24*365*100, "validity duration") siweCreateCmd.Flags().Int("chain-id", 69, "chain id") @@ -43,7 +42,4 @@ func init() { gasPriceBumperCmd.PersistentFlags().String("privatekey", "", "the private key used to make the contract calls") gasPriceBumperCmd.PersistentFlags().String("gateway", "", "URL of an Ethereum node API (i.e: Alchemy/Infura)") - - replaceNonceRangeCmd.PersistentFlags().String("privatekey", "", "the private key used to make the contract calls") - replaceNonceRangeCmd.PersistentFlags().String("gateway", "", "URL of an Ethereum node API (i.e: Alchemy/Infura)") } From 84a661114085105cf89fa22f33c12e7abd2729de Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 11:40:32 -0300 Subject: [PATCH 054/101] avoid go 1.19 specific functions for a while Signed-off-by: Ignacio Hagopian --- pkg/client/v1/health.go | 4 ++-- pkg/client/v1/readquery.go | 6 ++++-- pkg/client/v1/receipt.go | 9 ++------- pkg/client/v1/table.go | 9 ++------- pkg/client/v1/version.go | 4 ++-- 5 files changed, 12 insertions(+), 20 deletions(-) diff --git a/pkg/client/v1/health.go b/pkg/client/v1/health.go index 31d83b09..ebe79e54 100644 --- a/pkg/client/v1/health.go +++ b/pkg/client/v1/health.go @@ -8,8 +8,8 @@ import ( // CheckHealth returns true if the targeted validator endpoint is considered healthy, and false otherwise. func (c *Client) CheckHealth(ctx context.Context) (bool, error) { - url := *c.baseURL.JoinPath("api/v1/health") - req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + url := fmt.Sprintf("%s/api/v1/health", c.baseURL) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return false, fmt.Errorf("creating request: %s", err) } diff --git a/pkg/client/v1/readquery.go b/pkg/client/v1/readquery.go index ee0f3d9d..5d332eab 100644 --- a/pkg/client/v1/readquery.go +++ b/pkg/client/v1/readquery.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "net/url" ) // Output is used to control the output format of a Read using the ReadOutput option. @@ -57,6 +58,8 @@ func ReadUnwrap() ReadOption { } } +var queryURL, _ = url.Parse("/api/v1/query") + // Read runs a read query with the provided opts and unmarshals the results into target. func (c *Client) Read(ctx context.Context, query string, target interface{}, opts ...ReadOption) error { params := defaultReadQueryParameters @@ -64,8 +67,7 @@ func (c *Client) Read(ctx context.Context, query string, target interface{}, opt opt(¶ms) } - url := *c.baseURL.JoinPath("api/v1/query") - + url := c.baseURL.ResolveReference(queryURL) values := url.Query() values.Set("statement", query) values.Set("format", string(params.format)) diff --git a/pkg/client/v1/receipt.go b/pkg/client/v1/receipt.go index dc162048..541d2ce8 100644 --- a/pkg/client/v1/receipt.go +++ b/pkg/client/v1/receipt.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "net/http" - "strconv" "time" "github.com/textileio/go-tableland/internal/router/controllers/apiv1" @@ -43,12 +42,8 @@ func (c *Client) Receipt( } func (c *Client) getReceipt(ctx context.Context, txnHash string) (*apiv1.TransactionReceipt, bool, error) { - url := (*c.baseURL). - JoinPath("api/v1/receipt"). - JoinPath(strconv.FormatInt(int64(c.chain.ID), 10)). - JoinPath(txnHash) - - req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + url := fmt.Sprintf("%s/api/v1/receipt/%d/%s", c.baseURL, c.chain.ID, txnHash) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return nil, false, fmt.Errorf("creating request: %s", err) } diff --git a/pkg/client/v1/table.go b/pkg/client/v1/table.go index 874d0f75..8d71f238 100644 --- a/pkg/client/v1/table.go +++ b/pkg/client/v1/table.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "net/http" - "strconv" "github.com/textileio/go-tableland/internal/router/controllers/apiv1" ) @@ -18,12 +17,8 @@ var ErrTableNotFound = errors.New("table not found") // GetTable returns the table information given its ID. If the table ID doesn't exist, // it returns ErrTableNotFound. func (c *Client) GetTable(ctx context.Context, tableID TableID) (*apiv1.Table, error) { - url := *c.baseURL. - JoinPath("api/v1/tables/"). - JoinPath(strconv.FormatInt(int64(c.chain.ID), 10)). - JoinPath(strconv.FormatInt(tableID.ToBigInt().Int64(), 10)) - - req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + url := fmt.Sprintf("%s/api/v1/tables/%d/%d", c.baseURL, c.chain.ID, tableID.ToBigInt().Uint64()) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return nil, fmt.Errorf("creating request: %s", err) } diff --git a/pkg/client/v1/version.go b/pkg/client/v1/version.go index 4b504a8d..6bf319bd 100644 --- a/pkg/client/v1/version.go +++ b/pkg/client/v1/version.go @@ -13,9 +13,9 @@ import ( // Version returns the validator version information. func (c *Client) Version(ctx context.Context) (*apiv1.VersionInfo, error) { - url := *c.baseURL.JoinPath("api/v1/version") + url := fmt.Sprintf("%s/api/v1/version", c.baseURL) - req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return nil, fmt.Errorf("creating request: %s", err) } From 3011cb71aa434cb24eed02ffbb1e934fe5869641 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 11:48:39 -0300 Subject: [PATCH 055/101] docker: Makefile revert main chainges Signed-off-by: Ignacio Hagopian --- docker/Makefile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index 71a8b0b2..01ddf5fb 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -1,16 +1,11 @@ local-up: - touch local/api/.env_validator PLATFORM=$(shell uname -m) \ ENVIRONMENT=local \ COMPOSE_DOCKER_CLI_BUILD=1 \ - BOOTSTRAP_BACKUP_URL= \ docker compose -f docker-compose.yml -f local/docker-compose.override.yml up --build .PHONY: local-up local-down: - PLATFORM=$(shell uname -m) \ - ENVIRONMENT=local \ - BOOTSTRAP_BACKUP_URL= \ docker compose -f docker-compose.yml -f local/docker-compose.override.yml down .PHONY: local-down @@ -62,4 +57,4 @@ mainnet-down: USER=$(shell id -u) \ ENVIRONMENT=deployed/mainnet \ docker compose -f docker-compose.yml -f deployed/docker-compose.observability.yml $(HEALTHBOT_OVERRIDE) down -.PHONY: mainnet-down \ No newline at end of file +.PHONY: mainnet-down From 8d3918392e777c5fc07713e0581b58591d0710ac Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 13:51:35 -0300 Subject: [PATCH 056/101] fix nit Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index a437730a..03dbc586 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -111,7 +111,7 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { var metadataRes interface{} metadataRes = metadata // TODO(json-rpc): remove this if when dropping support. It won't be needed anymore for compatibility reasons. - if strings.HasPrefix(r.RequestURI, "/api/v1/tables") { + if isAPIV1 { metadataV1 := apiv1.Table{ Name: metadata.Name, ExternalUrl: metadata.ExternalURL, From 3eb504066275f1955f9398d0790b80728da0c6df Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 14:13:21 -0300 Subject: [PATCH 057/101] unify behavior for API GetTable Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system.go | 57 ++++++++++------------ internal/router/controllers/system_test.go | 2 +- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 03dbc586..0f747229 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -108,45 +108,38 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { return } - var metadataRes interface{} - metadataRes = metadata - // TODO(json-rpc): remove this if when dropping support. It won't be needed anymore for compatibility reasons. - if isAPIV1 { - metadataV1 := apiv1.Table{ - Name: metadata.Name, - ExternalUrl: metadata.ExternalURL, - AnimationUrl: metadata.AnimationURL, - Image: metadata.Image, - Attributes: make([]apiv1.TableAttributes, len(metadata.Attributes)), - Schema: &apiv1.Schema{ - Columns: make([]apiv1.Column, len(metadata.Schema.Columns)), - TableConstraints: make([]string, len(metadata.Schema.TableConstraints)), - }, - } - for i, attr := range metadata.Attributes { - metadataV1.Attributes[i] = apiv1.TableAttributes{ - DisplayType: attr.DisplayType, - TraitType: attr.TraitType, - Value: attr.Value, - } + metadataV1 := apiv1.Table{ + Name: metadata.Name, + ExternalUrl: metadata.ExternalURL, + AnimationUrl: metadata.AnimationURL, + Image: metadata.Image, + Attributes: make([]apiv1.TableAttributes, len(metadata.Attributes)), + Schema: &apiv1.Schema{ + Columns: make([]apiv1.Column, len(metadata.Schema.Columns)), + TableConstraints: make([]string, len(metadata.Schema.TableConstraints)), + }, + } + for i, attr := range metadata.Attributes { + metadataV1.Attributes[i] = apiv1.TableAttributes{ + DisplayType: attr.DisplayType, + TraitType: attr.TraitType, + Value: attr.Value, } - for i, schemaColumn := range metadata.Schema.Columns { - metadataV1.Schema.Columns[i] = apiv1.Column{ - Name: schemaColumn.Name, - Type_: schemaColumn.Type, - Constraints: make([]string, len(schemaColumn.Constraints)), - } - copy(metadataV1.Schema.Columns[i].Constraints, schemaColumn.Constraints) + } + for i, schemaColumn := range metadata.Schema.Columns { + metadataV1.Schema.Columns[i] = apiv1.Column{ + Name: schemaColumn.Name, + Type_: schemaColumn.Type, + Constraints: make([]string, len(schemaColumn.Constraints)), } - copy(metadataV1.Schema.TableConstraints, metadata.Schema.TableConstraints) - - metadataRes = metadataV1 + copy(metadataV1.Schema.Columns[i].Constraints, schemaColumn.Constraints) } + copy(metadataV1.Schema.TableConstraints, metadata.Schema.TableConstraints) rw.WriteHeader(http.StatusOK) enc := json.NewEncoder(rw) enc.SetEscapeHTML(false) - _ = enc.Encode(metadataRes) + _ = enc.Encode(metadataV1) } // GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. diff --git a/internal/router/controllers/system_test.go b/internal/router/controllers/system_test.go index b2a67a0d..d48b3adb 100644 --- a/internal/router/controllers/system_test.go +++ b/internal/router/controllers/system_test.go @@ -35,7 +35,7 @@ func TestSystemControllerMock(t *testing.T) { "external_url":"https://tableland.network/tables/100", "image":"https://bafkreifhuhrjhzbj4onqgbrmhpysk2mop2jimvdvfut6taiyzt2yqzt43a.ipfs.dweb.link", "attributes":[{"display_type":"date","trait_type":"created","value":1546360800}], - "schema":{"columns":[{"name":"foo","type":"text","constraints":null}],"table_constraints":null} + "schema":{"columns":[{"name":"foo","type":"text"}]} }` require.JSONEq(t, expJSON, rr.Body.String()) }) From 504b78f68f9fbcbf23c3fdc9f58e09ef24652a7e Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 14:25:05 -0300 Subject: [PATCH 058/101] remove todo comment Signed-off-by: Ignacio Hagopian --- internal/router/router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/router/router.go b/internal/router/router.go index 4e7948e9..f7ddb168 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -106,7 +106,7 @@ func configureAPIV1Routes( systemCtrl.GetReceiptByTransactionHash, []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID, rateLim}, }, - "GetTableById": { // TODO(jsign): verify output. + "GetTableById": { systemCtrl.GetTable, []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID, rateLim}, }, From 26832798edaa686c6ec3aa02638d80699a35567c Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Wed, 7 Dec 2022 14:59:06 -0300 Subject: [PATCH 059/101] remove unecessary json tags Signed-off-by: Ignacio Hagopian --- pkg/sqlstore/table.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/sqlstore/table.go b/pkg/sqlstore/table.go index d7369737..45e32486 100644 --- a/pkg/sqlstore/table.go +++ b/pkg/sqlstore/table.go @@ -25,15 +25,15 @@ func (t Table) Name() string { // TableSchema represents the schema of a table. type TableSchema struct { - Columns []ColumnSchema `json:"columns"` - TableConstraints []string `json:"table_constraints"` + Columns []ColumnSchema + TableConstraints []string } // ColumnSchema represents the schema of a column. type ColumnSchema struct { - Name string `json:"name"` - Type string `json:"type"` - Constraints []string `json:"constraints"` + Name string + Type string + Constraints []string } // TableMetadata represents table metadata (OpenSea standard). From e10ef39f882805a8c639646ccf3c1b66b63095ca Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 8 Dec 2022 09:55:41 -0300 Subject: [PATCH 060/101] Makefile: update api spec url [testnetdeploy] Signed-off-by: Ignacio Hagopian --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 29466cee..dcb31990 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ lint: .PHONY: lint # OpenAPI -SPEC_URL=https://raw.githubusercontent.com/tablelandnetwork/docs/jsign/vh/specs/validator/tableland-openapi-spec.yaml +SPEC_URL=https://raw.githubusercontent.com/tablelandnetwork/docs/main/specs/validator/tableland-openapi-spec.yaml APIV1=${PWD}/internal/router/controllers/apiv1 gen-api-v1: mkdir -p ${APIV1} From 91507499eb3ede403a6b1ff63568716819cdd477 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 8 Dec 2022 10:10:35 -0300 Subject: [PATCH 061/101] sqlstore: fix strict keyword lookup in a backwards compatible way [testnetdeploy] Signed-off-by: Ignacio Hagopian --- pkg/sqlstore/impl/system/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sqlstore/impl/system/store.go b/pkg/sqlstore/impl/system/store.go index 244b881f..a0aef69f 100644 --- a/pkg/sqlstore/impl/system/store.go +++ b/pkg/sqlstore/impl/system/store.go @@ -246,7 +246,7 @@ func (s *SystemStore) GetSchemaByTableName(ctx context.Context, name string) (sq return sqlstore.TableSchema{}, fmt.Errorf("failed to get the table: %s", err) } - index := strings.LastIndex(createStmt, "strict") + index := strings.LastIndex(strings.ToLower(createStmt), "strict") ast, err := sqlparser.Parse(createStmt[:index]) if err != nil { return sqlstore.TableSchema{}, fmt.Errorf("failed to parse create stmt: %s", err) From 331ee2a4074fe3d91485e45bf398d2e774112c98 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 8 Dec 2022 10:13:50 -0300 Subject: [PATCH 062/101] pkg/client/v1: nit renaming Signed-off-by: Ignacio Hagopian --- pkg/client/v1/client_test.go | 2 +- pkg/client/v1/readquery.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/client/v1/client_test.go b/pkg/client/v1/client_test.go index 4ea6e65f..d0c7737d 100644 --- a/pkg/client/v1/client_test.go +++ b/pkg/client/v1/client_test.go @@ -40,7 +40,7 @@ func TestRead(t *testing.T) { require.Equal(t, "baz", res0[0].Bar) res1 := map[string]interface{}{} - calls.query(fmt.Sprintf("select * from %s", tableName), &res1, ReadOutput(Table)) + calls.query(fmt.Sprintf("select * from %s", tableName), &res1, ReadFormat(Table)) require.Len(t, res1, 2) res2 := result{} diff --git a/pkg/client/v1/readquery.go b/pkg/client/v1/readquery.go index 5d332eab..de226f59 100644 --- a/pkg/client/v1/readquery.go +++ b/pkg/client/v1/readquery.go @@ -34,8 +34,8 @@ var defaultReadQueryParameters = readQueryParameters{ // ReadOption controls the behavior of Read. type ReadOption func(*readQueryParameters) -// ReadOutput sets the output format. Default is Objects. -func ReadOutput(output Output) ReadOption { +// ReadFormat sets the output format. Default is Objects. +func ReadFormat(output Output) ReadOption { return func(params *readQueryParameters) { params.format = output } From 52befc3d7d09c12b4987db34189ceb785a7c75f2 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 8 Dec 2022 13:43:46 -0300 Subject: [PATCH 063/101] pkg/client/v1: remove instrumentation from parser Signed-off-by: Ignacio Hagopian --- pkg/client/v1/client.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkg/client/v1/client.go b/pkg/client/v1/client.go index e1cecc9b..a5c5ce9b 100644 --- a/pkg/client/v1/client.go +++ b/pkg/client/v1/client.go @@ -116,11 +116,6 @@ func NewClient(ctx context.Context, wallet *wallet.Wallet, opts ...NewClientOpti return nil, fmt.Errorf("new parser: %s", err) } - parser, err = parserimpl.NewInstrumentedSQLValidator(parser) - if err != nil { - return nil, fmt.Errorf("instrumenting parser: %s", err) - } - baseURL, err := url.Parse(config.chain.Endpoint) if err != nil { return nil, fmt.Errorf("invalid endpoint URL: %s", err) From d41be067e8dda1d9d553721fa2da52f5944bc63f Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 8 Dec 2022 15:42:10 -0300 Subject: [PATCH 064/101] review feedback Signed-off-by: Ignacio Hagopian --- Makefile | 2 +- internal/router/controllers/system.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index dcb31990..4e919e4c 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ APIV1=${PWD}/internal/router/controllers/apiv1 gen-api-v1: mkdir -p ${APIV1} curl -s ${SPEC_URL} > ${APIV1}/tableland-openapi-spec.yaml - docker run -w /gen -e GEN_DIR=/gen -v ${APIV1}:/gen swaggerapi/swagger-codegen-cli-v3 \ + docker run -w /gen -e GEN_DIR=/gen -v ${APIV1}:/gen swaggerapi/swagger-codegen-cli-v3:3.0.36 \ generate --lang go-server -o /gen -i tableland-openapi-spec.yaml --additional-properties=packageName=apiv1 sudo chown -R ${USER} ${APIV1} cd ${APIV1} && \ diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 0f747229..5993dd53 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -66,7 +66,7 @@ func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r _ = json.NewEncoder(rw).Encode(receiptResponse) } -// GetTable handles the GET /chain/{chainID}/tables/{id} call. +// GetTable handles the GET /chain/{chainID}/tables/{tableId} call. func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() rw.Header().Set("Content-type", "application/json") From 8e995d82b80c527055681ac2e34b0ac7356a601c Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 8 Dec 2022 16:25:39 -0300 Subject: [PATCH 065/101] middleware: validate chain id values [testnetdeploy] Signed-off-by: Ignacio Hagopian --- cmd/api/main.go | 3 +++ internal/router/middlewares/rest.go | 39 +++++++++++++++++++---------- internal/router/router.go | 21 +++++++++------- tests/fullstack/fullstack.go | 2 +- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 9814e360..db2bb093 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -487,9 +487,11 @@ func createAPIServer( return nil, fmt.Errorf("instrumenting mesa: %s", err) } + supportedChainIDs := make([]tableland.ChainID, 0, len(chainStacks)) stores := make(map[tableland.ChainID]sqlstore.SystemStore, len(chainStacks)) for chainID, stack := range chainStacks { stores[chainID] = stack.Store + supportedChainIDs = append(supportedChainIDs, chainID) } sysStore, err := systemimpl.NewSystemSQLStoreService( stores, @@ -513,6 +515,7 @@ func createAPIServer( systemService, httpConfig.MaxRequestPerInterval, rateLimInterval, + supportedChainIDs, ) if err != nil { return nil, fmt.Errorf("configuring router: %s", err) diff --git a/internal/router/middlewares/rest.go b/internal/router/middlewares/rest.go index a16752d7..346bd57e 100644 --- a/internal/router/middlewares/rest.go +++ b/internal/router/middlewares/rest.go @@ -12,18 +12,31 @@ import ( ) // RESTChainID adds to the request context the {chainID} that must be present in the REST path. -func RESTChainID(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) +func RESTChainID(acceptedChainIDs []tableland.ChainID) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) - chainID, err := strconv.ParseInt(vars["chainId"], 10, 64) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - _ = json.NewEncoder(w).Encode(errors.ServiceError{Message: "no chain id in path"}) - return - } - r = r.WithContext(context.WithValue(r.Context(), ContextKeyChainID, tableland.ChainID(chainID))) - - next.ServeHTTP(w, r) - }) + chainID, err := strconv.ParseInt(vars["chainId"], 10, 64) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + _ = json.NewEncoder(w).Encode(errors.ServiceError{Message: "no chain id in path"}) + return + } + var found bool + for _, acceptedChainID := range acceptedChainIDs { + if chainID == int64(acceptedChainID) { + found = true + break + } + } + if !found { + w.WriteHeader(http.StatusBadRequest) + _ = json.NewEncoder(w).Encode(errors.ServiceError{Message: "unsupported chain id"}) + return + } + r = r.WithContext(context.WithValue(r.Context(), ContextKeyChainID, tableland.ChainID(chainID))) + next.ServeHTTP(w, r) + }) + } } diff --git a/internal/router/router.go b/internal/router/router.go index f7ddb168..b23d1ce3 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -21,6 +21,7 @@ func ConfiguredRouter( systemService system.SystemService, maxRPI uint64, rateLimInterval time.Duration, + supportedChainIDs []tableland.ChainID, ) (*Router, error) { rpcService := legacy.NewRPCService(tableland) server := rpc.NewServer() @@ -50,10 +51,10 @@ func ConfiguredRouter( // TODO(json-rpc): remove this when dropping support. // APIs Legacy (REST + JSON-RPC) - configureLegacyRoutes(router, server, rateLim, systemCtrl, userCtrl, infraCtrl) + configureLegacyRoutes(router, server, supportedChainIDs, rateLim, systemCtrl, userCtrl, infraCtrl) // APIs V1 - if err := configureAPIV1Routes(router, rateLim, systemCtrl, userCtrl, infraCtrl); err != nil { + if err := configureAPIV1Routes(router, supportedChainIDs, rateLim, systemCtrl, userCtrl, infraCtrl); err != nil { return nil, fmt.Errorf("configuring API v1: %s", err) } @@ -63,6 +64,7 @@ func ConfiguredRouter( func configureLegacyRoutes( router *Router, server *rpc.Server, + supportedChainIDs []tableland.ChainID, rateLim mux.MiddlewareFunc, systemCtrl *controllers.SystemController, userCtrl *controllers.UserController, @@ -73,11 +75,11 @@ func configureLegacyRoutes( }, middlewares.WithLogging, middlewares.OtelHTTP("rpc"), middlewares.Authentication, rateLim) // Gateway configuration. - router.get("/chain/{chainId}/tables/{tableId}", systemCtrl.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID, rateLim) // nolint - router.get("/chain/{chainId}/tables/{id}/{key}/{value}", userCtrl.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID, rateLim) // nolint - router.get("/chain/{chainId}/tables/controller/{address}", systemCtrl.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID, rateLim) // nolint - router.get("/chain/{chainId}/tables/structure/{hash}", systemCtrl.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID, rateLim) // nolint - router.get("/schema/{table_name}", systemCtrl.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint + router.get("/chain/{chainId}/tables/{tableId}", systemCtrl.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/{id}/{key}/{value}", userCtrl.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/controller/{address}", systemCtrl.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/structure/{hash}", systemCtrl.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/schema/{table_name}", systemCtrl.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint router.get("/query", userCtrl.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint router.get("/version", infraCtrl.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint @@ -89,6 +91,7 @@ func configureLegacyRoutes( func configureAPIV1Routes( router *Router, + supportedChainIDs []tableland.ChainID, rateLim mux.MiddlewareFunc, systemCtrl *controllers.SystemController, userCtrl *controllers.UserController, @@ -104,11 +107,11 @@ func configureAPIV1Routes( }, "ReceiptByTransactionHash": { systemCtrl.GetReceiptByTransactionHash, - []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID, rateLim}, + []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim}, }, "GetTableById": { systemCtrl.GetTable, - []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID, rateLim}, + []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim}, }, "Version": { infraCtrl.Version, diff --git a/tests/fullstack/fullstack.go b/tests/fullstack/fullstack.go index e6be6505..e3fa9a46 100644 --- a/tests/fullstack/fullstack.go +++ b/tests/fullstack/fullstack.go @@ -149,7 +149,7 @@ func CreateFullStack(t *testing.T, deps Deps) FullStack { ex, err := executor.NewExecutor(1337, db, parser, 0, acl) require.NoError(t, err) - router, err := router.ConfiguredRouter(tbl, systemService, 10, time.Second) + router, err := router.ConfiguredRouter(tbl, systemService, 10, time.Second, []tableland.ChainID{ChainID}) require.NoError(t, err) server := httptest.NewServer(router.Handler()) From 2dd3553371a1cf0928c278f5a257326ce5b9bb65 Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Fri, 9 Dec 2022 11:19:47 -0300 Subject: [PATCH 066/101] parser: drop support for ANY, and allows dot inside enclosed identifiers Signed-off-by: Bruno Calza --- go.mod | 2 +- go.sum | 2 ++ internal/tableland/impl/mesa_test.go | 21 ------------------- .../tableland/impl/testdata/any_queries.csv | 3 --- 4 files changed, 3 insertions(+), 25 deletions(-) delete mode 100644 internal/tableland/impl/testdata/any_queries.csv diff --git a/go.mod b/go.mod index 8b15d72b..9c9af8e5 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/cobra v1.6.0 github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff github.com/stretchr/testify v1.8.1 - github.com/tablelandnetwork/sqlparser v0.0.0-20221206205623-de3c827d6e39 + github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527 github.com/textileio/cli v1.0.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 go.opentelemetry.io/otel v1.11.0 diff --git a/go.sum b/go.sum index cdc82bd7..bf8e553c 100644 --- a/go.sum +++ b/go.sum @@ -1320,6 +1320,8 @@ github.com/tablelandnetwork/sqlparser v0.0.0-20221206182935-9aa9abb23647 h1:pAC4 github.com/tablelandnetwork/sqlparser v0.0.0-20221206182935-9aa9abb23647/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tablelandnetwork/sqlparser v0.0.0-20221206205623-de3c827d6e39 h1:Xi7Bt60Na70O/k4uyy1ws5FnoxFS6xZuGPdCYQ/UCPQ= github.com/tablelandnetwork/sqlparser v0.0.0-20221206205623-de3c827d6e39/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527 h1:cwTLUHmgeUSoV+cgvKfxG8zSjmCLTwrzBALjxVrPz/g= +github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/textileio/cli v1.0.2 h1:qSp/x4d/9SZ93TxhgZnE5okRKqzqHqrzAwKAPjuPw50= github.com/textileio/cli v1.0.2/go.mod h1:vTlCvvVyOmXXLwddCcBg3PDavfUsCkRBZoyr6Nu1lkc= diff --git a/internal/tableland/impl/mesa_test.go b/internal/tableland/impl/mesa_test.go index 6e7ff2b9..3f8d045a 100644 --- a/internal/tableland/impl/mesa_test.go +++ b/internal/tableland/impl/mesa_test.go @@ -64,27 +64,6 @@ func TestTodoAppWorkflow(t *testing.T) { processCSV(ctx, t, chainID, caller, tbld, "testdata/todoapp_queries.csv", backend) } -func TestAny(t *testing.T) { - t.Parallel() - - setup := newTablelandSetupBuilder(). - withAllowTransactionRelay(true). - build(t) - tablelandClient := setup.newTablelandClient(t) - - ctx, chainID, backend, sc := setup.ctx, setup.chainID, setup.ethClient, setup.contract - tbld, txOpts := tablelandClient.tableland, tablelandClient.txOpts - - caller := txOpts.From - _, err := sc.CreateTable(txOpts, caller, - `CREATE TABLE any_1337 ( - wild ANY - );`) - require.NoError(t, err) - - processCSV(ctx, t, chainID, caller, tbld, "testdata/any_queries.csv", backend) -} - func TestInsertOnConflict(t *testing.T) { t.Parallel() // TODO: This test was passing because the "DO UPDATE SET" clause didn't have a table name. diff --git a/internal/tableland/impl/testdata/any_queries.csv b/internal/tableland/impl/testdata/any_queries.csv deleted file mode 100644 index ce8f32b1..00000000 --- a/internal/tableland/impl/testdata/any_queries.csv +++ /dev/null @@ -1,3 +0,0 @@ -w,"INSERT INTO any_1337_1 VALUES ('hello')","" -w,"INSERT INTO any_1337_1 VALUES (3)","" -r,"SELECT * FROM any_1337_1","{""columns"":[{""name"":""wild""}],""rows"":[[""hello""],[3]]}" From dd54aaa36dd591392d31e8cf928bfe158b31dba4 Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Fri, 9 Dec 2022 11:36:48 -0300 Subject: [PATCH 067/101] updates state hashes dropping support for ANY changes the state of the database Signed-off-by: Bruno Calza --- .../impl/eventprocessor_replayhistory_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go index ad9faba9..ef15ffe7 100644 --- a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go +++ b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go @@ -36,12 +36,12 @@ func TestReplayProductionHistory(t *testing.T) { expectedStateHashes := map[tableland.ChainID]string{ 1: "ce4f083e256d3458a329b6cd1ba7d8e93d9703b3", - 5: "b42740b92e40d616061a88872e19616c05469750", - 10: "c9afca82a8c30fc683da366b5f4920e7c131ec5d", + 5: "08af7e7055f266ea75d3b06350c47a52cfa59843", + 10: "2bce2d62e7f5eeadc4736f470ca2959b871e5d91", 69: "643af9ad784444242c6ef415727203941a720197", 137: "b5fb42f3538738ab5856abf9e3b2e38d82378ca4", 420: "184800f533f4edd186853a85829fad8bc7802c4e", - 80001: "df269d9451e0bf1b77c7616aff4148a3f1a4559a", + 80001: "9336d3a3a36e57a86e4f95d3464048c954e46bc6", 421613: "073727932afcee9a5dba19f43c023689ca855dc2", } From fadd9716b281fc3eb4f653cc0a780c7dd0d7ca12 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 9 Dec 2022 15:46:15 -0300 Subject: [PATCH 068/101] internal/router: update spec Signed-off-by: Ignacio Hagopian --- internal/router/controllers/apiv1/api_query.go | 2 +- internal/router/controllers/apiv1/routers.go | 4 ++-- internal/router/router.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/router/controllers/apiv1/api_query.go b/internal/router/controllers/apiv1/api_query.go index 692b8502..0d2ccd80 100644 --- a/internal/router/controllers/apiv1/api_query.go +++ b/internal/router/controllers/apiv1/api_query.go @@ -13,7 +13,7 @@ import ( "net/http" ) -func QueryFromQuery(w http.ResponseWriter, r *http.Request) { +func QueryByStatement(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/routers.go b/internal/router/controllers/apiv1/routers.go index 657c9b84..f61e6894 100644 --- a/internal/router/controllers/apiv1/routers.go +++ b/internal/router/controllers/apiv1/routers.go @@ -63,10 +63,10 @@ var routes = Routes{ }, Route{ - "QueryFromQuery", + "QueryByStatement", strings.ToUpper("Get"), "/api/v1/query", - QueryFromQuery, + QueryByStatement, }, Route{ diff --git a/internal/router/router.go b/internal/router/router.go index b23d1ce3..9791d66f 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -101,7 +101,7 @@ func configureAPIV1Routes( handler http.HandlerFunc middlewares []mux.MiddlewareFunc }{ - "QueryFromQuery": { + "QueryByStatement": { userCtrl.GetTableQuery, []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, }, From b50d3998a6ced468e6025a54a63f50d7115dff03 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 9 Dec 2022 16:25:54 -0300 Subject: [PATCH 069/101] mod: update otel deps [testnetdeploy] Signed-off-by: Ignacio Hagopian --- .../deployed/docker-compose.observability.yml | 2 +- go.mod | 20 +++---- go.sum | 54 +++++++++---------- pkg/metrics/instrumenting.go | 38 ++++++------- 4 files changed, 55 insertions(+), 59 deletions(-) diff --git a/docker/deployed/docker-compose.observability.yml b/docker/deployed/docker-compose.observability.yml index bff8fcbc..31e52cde 100644 --- a/docker/deployed/docker-compose.observability.yml +++ b/docker/deployed/docker-compose.observability.yml @@ -1,6 +1,6 @@ services: prometheus: - image: prom/prometheus:v2.36.2 + image: prom/prometheus:v2.39.1 container_name: prometheus volumes: - ${PWD}/observability/prometheus:/etc/prometheus diff --git a/go.mod b/go.mod index 9c9af8e5..4a6354a2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( cloud.google.com/go/bigquery v1.42.0 cloud.google.com/go/logging v1.5.0 - github.com/XSAM/otelsql v0.16.0 + github.com/XSAM/otelsql v0.17.0 github.com/ethereum/go-ethereum v1.10.25 github.com/golang-migrate/migrate/v4 v4.15.2 github.com/google/uuid v1.3.0 @@ -16,7 +16,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.16 github.com/omeid/uconfig v1.2.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.13.0 + github.com/prometheus/client_golang v1.14.0 github.com/rs/zerolog v1.28.0 github.com/sethvargo/go-limiter v0.7.2 github.com/spf13/cobra v1.6.0 @@ -25,10 +25,10 @@ require ( github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527 github.com/textileio/cli v1.0.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 - go.opentelemetry.io/otel v1.11.0 - go.opentelemetry.io/otel/exporters/prometheus v0.32.3 - go.opentelemetry.io/otel/metric v0.32.3 - go.opentelemetry.io/otel/sdk/metric v0.32.3 + go.opentelemetry.io/otel v1.11.2 + go.opentelemetry.io/otel/exporters/prometheus v0.34.0 + go.opentelemetry.io/otel/metric v0.34.0 + go.opentelemetry.io/otel/sdk/metric v0.34.0 go.uber.org/atomic v1.10.0 golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f ) @@ -56,7 +56,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect github.com/googleapis/gax-go/v2 v2.5.1 // indirect github.com/gorilla/websocket v1.4.2 // indirect @@ -78,7 +78,7 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml v1.9.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/tsdb v0.7.1 // indirect @@ -97,8 +97,8 @@ require ( github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect go.opencensus.io v0.23.0 // indirect - go.opentelemetry.io/otel/sdk v1.11.0 // indirect - go.opentelemetry.io/otel/trace v1.11.0 // indirect + go.opentelemetry.io/otel/sdk v1.11.2 // indirect + go.opentelemetry.io/otel/trace v1.11.2 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.0 // indirect golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e // indirect diff --git a/go.sum b/go.sum index bf8e553c..23431d98 100644 --- a/go.sum +++ b/go.sum @@ -142,8 +142,8 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIO github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= -github.com/XSAM/otelsql v0.16.0 h1:pOqeHGYCJmP5ezW0OvAGA+zzdgW/sV8nLHTxVnPgiXU= -github.com/XSAM/otelsql v0.16.0/go.mod h1:DpO7NCSeqQdr23nU0yapjR3jGx2OdO/PihPRG+/PV0Y= +github.com/XSAM/otelsql v0.17.0 h1:eq9yWwFY6t+nruMmjzhbdbkIo+HnUTziimkBbIqNKwM= +github.com/XSAM/otelsql v0.17.0/go.mod h1:zGN8fF5r7Xclr92eMl8JM8pYquSWV8Kjf2fUeWvpd3Y= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -678,8 +678,9 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -1155,14 +1156,15 @@ github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1314,12 +1316,6 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tablelandnetwork/sqlparser v0.0.0-20221202173423-7243894ff651 h1:iBE88lfYPJfbanmuQehy5t8V7m7Yv6Ge1OEKJWuCBTc= -github.com/tablelandnetwork/sqlparser v0.0.0-20221202173423-7243894ff651/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20221206182935-9aa9abb23647 h1:pAC4kr5yvv7wbQzx4wdTypNShaUnU/ECIVQRmc7Yg+M= -github.com/tablelandnetwork/sqlparser v0.0.0-20221206182935-9aa9abb23647/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20221206205623-de3c827d6e39 h1:Xi7Bt60Na70O/k4uyy1ws5FnoxFS6xZuGPdCYQ/UCPQ= -github.com/tablelandnetwork/sqlparser v0.0.0-20221206205623-de3c827d6e39/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527 h1:cwTLUHmgeUSoV+cgvKfxG8zSjmCLTwrzBALjxVrPz/g= github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= @@ -1418,40 +1414,38 @@ go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzox go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ= go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= -go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= -go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo= -go.opentelemetry.io/otel v1.11.0 h1:kfToEGMDq6TrVrJ9Vht84Y8y9enykSZzDDZglV0kIEk= -go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0= +go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= -go.opentelemetry.io/otel/exporters/prometheus v0.32.3 h1:17C3zlnAFjmoyWueoQrESV/FvogMq2EmtJWpk7acX4Y= -go.opentelemetry.io/otel/exporters/prometheus v0.32.3/go.mod h1:7T6oLYJY+ydl+dEteIw+xCDJ7vaTRVWZ4CxEhpCUHFA= +go.opentelemetry.io/otel/exporters/prometheus v0.34.0 h1:L5D+HxdaC/ORB47ribbTBbkXRZs9JzPjq0EoIOMWncM= +go.opentelemetry.io/otel/exporters/prometheus v0.34.0/go.mod h1:6gUoJyfhoWqF0tOLaY0ZmKgkQRcvEQx6p5rVlKHp3s4= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw= -go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A= -go.opentelemetry.io/otel/metric v0.32.3 h1:dMpnJYk2KULXr0j8ph6N7+IcuiIQXlPXD4kix9t7L9c= -go.opentelemetry.io/otel/metric v0.32.3/go.mod h1:pgiGmKohxHyTPHGOff+vrtIH39/R9fiO/WoenUQ3kcc= +go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= +go.opentelemetry.io/otel/metric v0.34.0 h1:MCPoQxcg/26EuuJwpYN1mZTeCYAUGx8ABxfW07YkjP8= +go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= -go.opentelemetry.io/otel/sdk v1.9.0/go.mod h1:AEZc8nt5bd2F7BC24J5R0mrjYnpEgYHyTcM/vrSple4= -go.opentelemetry.io/otel/sdk v1.11.0 h1:ZnKIL9V9Ztaq+ME43IUi/eo22mNsb6a7tGfzaOWB5fo= -go.opentelemetry.io/otel/sdk v1.11.0/go.mod h1:REusa8RsyKaq0OlyangWXaw97t2VogoO4SSEeKkSTAk= +go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= +go.opentelemetry.io/otel/sdk v1.11.2 h1:GF4JoaEx7iihdMFu30sOyRx52HDHOkl9xQ8SMqNXUiU= +go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU= go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= -go.opentelemetry.io/otel/sdk/metric v0.32.3 h1:lY46wXBbo8IuPDlh1fpVPVy/bCT4wwo3RBYve6UaHOA= -go.opentelemetry.io/otel/sdk/metric v0.32.3/go.mod h1:nqJPheSpNDSGXhg22BQRgTQedRalfei6tZkmqTavDSk= +go.opentelemetry.io/otel/sdk/metric v0.34.0 h1:7ElxfQpXCFZlRTvVRTkcUvK8Gt5DC8QzmzsLsO2gdzo= +go.opentelemetry.io/otel/sdk/metric v0.34.0/go.mod h1:l4r16BIqiqPy5rd14kkxllPy/fOI4tWo1jkpD9Z3ffQ= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE= go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= -go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= -go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo= -go.opentelemetry.io/otel/trace v1.11.0 h1:20U/Vj42SX+mASlXLmSGBg6jpI1jQtv682lZtTAOVFI= -go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= +go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= diff --git a/pkg/metrics/instrumenting.go b/pkg/metrics/instrumenting.go index 0d0909a8..2ae1263f 100644 --- a/pkg/metrics/instrumenting.go +++ b/pkg/metrics/instrumenting.go @@ -7,7 +7,6 @@ import ( "runtime" "time" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "go.opentelemetry.io/otel/attribute" otelprom "go.opentelemetry.io/otel/exporters/prometheus" @@ -18,7 +17,6 @@ import ( "go.opentelemetry.io/otel/metric/instrument/asyncint64" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/aggregation" - "go.opentelemetry.io/otel/sdk/metric/view" ) // BaseAttrs contains attributes that should be added in all exported metrics. @@ -28,26 +26,15 @@ var BaseAttrs []attribute.KeyValue func SetupInstrumentation(prometheusAddr string, serviceName string) error { BaseAttrs = []attribute.KeyValue{attribute.String("service_name", serviceName)} - exporter := otelprom.New() - - v, err := view.New( - view.MatchInstrumentKind(view.SyncHistogram), - view.WithSetAggregation(aggregation.ExplicitBucketHistogram{ - Boundaries: []float64{0.5, 1, 2, 4, 10, 50, 100, 500, 1000, 5000}, - }), - ) + exporter, err := otelprom.New(otelprom.WithAggregationSelector(aggregatorSelector)) if err != nil { - return fmt.Errorf("configuring histogram buckets: %s", err) + return fmt.Errorf("creating prometheus exporter: %s", err) } - provider := metric.NewMeterProvider(metric.WithReader(exporter, v)) - global.SetMeterProvider(provider) - registry := prometheus.NewRegistry() - if err := registry.Register(exporter.Collector); err != nil { - return fmt.Errorf("error registering collector: %v", err) - } + provider := metric.NewMeterProvider(metric.WithReader(exporter)) + global.SetMeterProvider(provider) - http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) + http.Handle("/metrics", promhttp.Handler()) go func() { _ = http.ListenAndServe(prometheusAddr, nil) }() @@ -166,3 +153,18 @@ func startCollectingMemoryMetrics() error { } return nil } + +func aggregatorSelector(ik metric.InstrumentKind) aggregation.Aggregation { + switch ik { + case metric.InstrumentKindSyncCounter, metric.InstrumentKindSyncUpDownCounter, metric.InstrumentKindAsyncCounter, metric.InstrumentKindAsyncUpDownCounter: + return aggregation.Sum{} + case metric.InstrumentKindAsyncGauge: + return aggregation.LastValue{} + case metric.InstrumentKindSyncHistogram: + return aggregation.ExplicitBucketHistogram{ + Boundaries: []float64{0.5, 1, 2, 4, 10, 50, 100, 500, 1000, 5000}, + NoMinMax: false, + } + } + panic("unknown instrument kind") +} From 465fbbb7e1a957be58c760ab59ecafda0215d75e Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 9 Dec 2022 16:46:56 -0300 Subject: [PATCH 070/101] fix dashboard [testnetdeploy] Signed-off-by: Ignacio Hagopian --- .../dashboards/validator-dashboard.json | 258 +++++++++++++++--- 1 file changed, 215 insertions(+), 43 deletions(-) diff --git a/docker/observability/grafana/provisioning/dashboards/validator-dashboard.json b/docker/observability/grafana/provisioning/dashboards/validator-dashboard.json index d2b30a76..eeccea3e 100644 --- a/docker/observability/grafana/provisioning/dashboards/validator-dashboard.json +++ b/docker/observability/grafana/provisioning/dashboards/validator-dashboard.json @@ -112,7 +112,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -186,7 +186,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -273,7 +273,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -348,7 +348,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -419,7 +419,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -448,6 +448,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -509,7 +511,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -583,7 +586,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -647,7 +650,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -709,7 +712,7 @@ }, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -717,7 +720,7 @@ "uid": "P1809F7CD0C75ACF3" }, "editorMode": "code", - "expr": "runtime_uptime", + "expr": "runtime_uptime_milliseconds", "legendFormat": "{{job}}", "range": true, "refId": "A" @@ -764,6 +767,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -815,7 +820,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -851,6 +857,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -903,7 +911,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -939,6 +948,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -996,7 +1007,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1009,10 +1021,12 @@ "type": "prometheus", "uid": "P1809F7CD0C75ACF3" }, + "editorMode": "code", "exemplar": true, - "expr": "sum by (chain_id, name) (rate(tableland_eventfeed_eventypes_count{service_name=\"tableland:api\"}[5m]))", + "expr": "sum by (chain_id, name) (rate(tableland_eventfeed_eventypes_count_total{service_name=\"tableland:api\"}[5m]))", "interval": "", "legendFormat": "ChainID: {{chain_id}} Event: {{name}}", + "range": true, "refId": "A" } ], @@ -1031,6 +1045,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1088,7 +1104,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1101,10 +1118,12 @@ "type": "prometheus", "uid": "P1809F7CD0C75ACF3" }, + "editorMode": "code", "exemplar": true, - "expr": "sum by (chaind_id, eventtype) (rate(tableland_eventprocessor_event_execution_count{service_name=\"tableland:api\"}[5m]))", + "expr": "sum by (chaind_id, eventtype) (rate(tableland_eventprocessor_event_execution_count_total{service_name=\"tableland:api\"}[5m]))", "interval": "", "legendFormat": "{{chain_id}} {{eventtype}}", + "range": true, "refId": "A" } ], @@ -1125,6 +1144,21 @@ "type": "prometheus", "uid": "P1809F7CD0C75ACF3" }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, "gridPos": { "h": 7, "w": 6, @@ -1139,6 +1173,44 @@ "show": false }, "maxDataPoints": 25, + "options": { + "calculate": false, + "calculation": {}, + "cellGap": 2, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "#b4ff00", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "Spectral", + "steps": 128 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "ge" + }, + "showValue": "never", + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "ms" + } + }, + "pluginVersion": "9.2.2", "reverseYBuckets": false, "targets": [ { @@ -1185,6 +1257,21 @@ "type": "prometheus", "uid": "P1809F7CD0C75ACF3" }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, "gridPos": { "h": 7, "w": 6, @@ -1199,6 +1286,44 @@ "show": false }, "maxDataPoints": 30, + "options": { + "calculate": false, + "calculation": {}, + "cellGap": 2, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "#b4ff00", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "RdYlGn", + "steps": 128 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "ge" + }, + "showValue": "never", + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "ms" + } + }, + "pluginVersion": "9.2.2", "reverseYBuckets": false, "targets": [ { @@ -1285,7 +1410,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.0.1", + "pluginVersion": "9.2.2", "targets": [ { "datasource": { @@ -1339,6 +1464,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1411,7 +1538,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1426,7 +1554,7 @@ }, "editorMode": "code", "exemplar": true, - "expr": "sum by (http_status_code, http_server_name) (\n rate(http_server_request_count{service_name=\"tableland:api\"}[10m])\n)", + "expr": "sum by (http_status_code, http_server_name) (rate(http_server_request_count_total{service_name=\"tableland:api\"}[10m]))", "interval": "", "legendFormat": "{{http_status_code}}-{{http_server_name}}", "range": true, @@ -1447,6 +1575,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1519,7 +1649,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1534,7 +1665,7 @@ }, "editorMode": "code", "exemplar": true, - "expr": "sum by (http_server_name) (\n rate(http_server_request_count{service_name=\"tableland:api\", http_server_name!=\"rpc\"}[5m])\n)", + "expr": "sum by (http_server_name) (\n rate(http_server_request_count_total{service_name=\"tableland:api\", http_server_name!=\"rpc\"}[5m])\n)", "interval": "", "legendFormat": "__auto", "range": true, @@ -1555,6 +1686,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1611,7 +1744,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1647,6 +1781,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1719,7 +1855,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1734,7 +1871,7 @@ }, "editorMode": "code", "exemplar": true, - "expr": "sum by (http_server_name) ( rate(http_server_response_content_length[$__rate_interval]))", + "expr": "sum by (http_server_name) ( rate(http_server_response_content_length_total[$__rate_interval]))", "interval": "", "legendFormat": "{{http_status_code}}", "range": true, @@ -1755,6 +1892,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1811,7 +1950,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1824,10 +1964,12 @@ "type": "prometheus", "uid": "P1809F7CD0C75ACF3" }, + "editorMode": "code", "exemplar": true, - "expr": "sum by (method) (\n rate(tableland_mesa_call_count{service_name=\"tableland:api\"}[5m])\n)\n", + "expr": "sum by (method) (rate(tableland_mesa_call_latency_count{service_name=\"tableland:api\"}[5m]))\n", "interval": "", "legendFormat": "{{method}}", + "range": true, "refId": "A" } ], @@ -1846,6 +1988,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1904,7 +2048,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1966,6 +2111,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2021,7 +2168,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -2034,10 +2182,12 @@ "type": "prometheus", "uid": "P1809F7CD0C75ACF3" }, + "editorMode": "code", "exemplar": true, - "expr": "sum by (method) (\n rate(tableland_sqlstore_call_count{service_name=\"tableland:api\"}[5m])\n)", + "expr": "sum by (method) (\n rate(tableland_sqlstore_call_latency_count{service_name=\"tableland:api\"}[5m])\n)", "interval": "", "legendFormat": "{{method}}", + "range": true, "refId": "A" } ], @@ -2056,6 +2206,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2114,7 +2266,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -2151,6 +2304,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2209,7 +2364,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -2259,6 +2415,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2317,7 +2475,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -2332,7 +2491,7 @@ }, "editorMode": "code", "exemplar": false, - "expr": "histogram_quantile(0.95, sum(rate(db_sql_latency_bucket{name=~\"processor|systemstore\"}[$__rate_interval])) by (chain_id, name, le))", + "expr": "histogram_quantile(0.95, sum(rate(db_sql_latency_milliseconds_bucket{name=~\"processor|systemstore\"}[$__rate_interval])) by (chain_id, name, le))", "format": "heatmap", "instant": false, "interval": "", @@ -2345,7 +2504,7 @@ "uid": "P1809F7CD0C75ACF3" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, sum(rate(db_sql_latency_bucket{name=~\"userstore\"}[$__rate_interval])) by (chain_id, name, le))", + "expr": "histogram_quantile(0.95, sum(rate(db_sql_latency_milliseconds_bucket{name=~\"userstore\"}[$__rate_interval])) by (chain_id, name, le))", "hide": false, "legendFormat": "{{name}}", "range": true, @@ -2431,7 +2590,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -2506,6 +2666,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2562,7 +2724,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "multi", @@ -2577,7 +2740,7 @@ }, "editorMode": "code", "exemplar": true, - "expr": "process_runtime_go_mem_heap_inuse", + "expr": "process_runtime_go_mem_heap_inuse_bytes", "interval": "", "legendFormat": "{{job}}", "range": true, @@ -2599,6 +2762,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2655,7 +2820,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "multi", @@ -2692,6 +2858,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2748,7 +2916,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "multi", @@ -2785,6 +2954,8 @@ "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2841,7 +3012,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "multi", @@ -2868,20 +3040,20 @@ } ], "refresh": "10s", - "schemaVersion": 36, + "schemaVersion": 37, "style": "dark", "tags": [], "templating": { "list": [] }, "time": { - "from": "now-5m", + "from": "now-15m", "to": "now" }, "timepicker": {}, "timezone": "", "title": "Validator", "uid": "2Le7qt_7z", - "version": 18, + "version": 9, "weekStart": "" } \ No newline at end of file From b4839337bf612a1a7b8a2b82ee0bc83f6bf6a760 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 9 Dec 2022 16:48:03 -0300 Subject: [PATCH 071/101] lint Signed-off-by: Ignacio Hagopian --- pkg/metrics/instrumenting.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/metrics/instrumenting.go b/pkg/metrics/instrumenting.go index 2ae1263f..87aba97d 100644 --- a/pkg/metrics/instrumenting.go +++ b/pkg/metrics/instrumenting.go @@ -156,7 +156,8 @@ func startCollectingMemoryMetrics() error { func aggregatorSelector(ik metric.InstrumentKind) aggregation.Aggregation { switch ik { - case metric.InstrumentKindSyncCounter, metric.InstrumentKindSyncUpDownCounter, metric.InstrumentKindAsyncCounter, metric.InstrumentKindAsyncUpDownCounter: + case metric.InstrumentKindSyncCounter, metric.InstrumentKindSyncUpDownCounter, + metric.InstrumentKindAsyncCounter, metric.InstrumentKindAsyncUpDownCounter: return aggregation.Sum{} case metric.InstrumentKindAsyncGauge: return aggregation.LastValue{} From 9df906d45f870c09d346e97f66487b1b4d551549 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 13 Dec 2022 16:33:02 -0300 Subject: [PATCH 072/101] controller: only write content type on json bodies [testnetdeploy] Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 5993dd53..89a503d3 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -26,11 +26,11 @@ func NewSystemController(svc system.SystemService) *SystemController { // GetReceiptByTransactionHash handles request asking for a transaction receipt. func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { - rw.Header().Set("Content-Type", "application/json") ctx := r.Context() paramTxnHash := mux.Vars(r)["transactionHash"] if _, err := common.ParseHexOrString(paramTxnHash); err != nil { + rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusBadRequest) log.Ctx(ctx).Error().Err(err).Msg("invalid transaction hash") _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Invalid transaction hash"}) @@ -40,6 +40,7 @@ func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r receipt, exists, err := c.systemService.GetReceiptByTransactionHash(ctx, txnHash) if err != nil { + rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusBadRequest) log.Ctx(ctx).Error().Err(err).Msg("get receipt by transaction hash") _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Get receipt by transaction hash failed"}) @@ -62,6 +63,8 @@ func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r receiptResponse.Error_ = *receipt.Error receiptResponse.ErrorEventIdx = int32(*receipt.ErrorEventIdx) } + + rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusOK) _ = json.NewEncoder(rw).Encode(receiptResponse) } @@ -69,11 +72,11 @@ func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r // GetTable handles the GET /chain/{chainID}/tables/{tableId} call. func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() - rw.Header().Set("Content-type", "application/json") vars := mux.Vars(r) id, err := tables.NewTableID(vars["tableId"]) if err != nil { + rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusBadRequest) log.Ctx(ctx). Error(). @@ -89,6 +92,7 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { metadata, err := c.systemService.GetTableMetadata(ctx, id) if err == system.ErrTableNotFound { if !isAPIV1 { + rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusOK) _ = json.NewEncoder(rw).Encode(metadata) return @@ -97,6 +101,7 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { return } if err != nil { + rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusInternalServerError) log.Ctx(ctx). Error(). @@ -136,6 +141,7 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { } copy(metadataV1.Schema.TableConstraints, metadata.Schema.TableConstraints) + rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusOK) enc := json.NewEncoder(rw) enc.SetEscapeHTML(false) From 1bdb38f08fdd374e91cc6f7538affaecb70e9b03 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 19 Dec 2022 11:22:42 -0300 Subject: [PATCH 073/101] healthbot: do not use relaying Signed-off-by: Ignacio Hagopian --- cmd/healthbot/config.go | 7 +- cmd/healthbot/counterprobe/counterprobe.go | 95 ++++++------------- .../counterprobe/counterprobe_test.go | 16 +++- cmd/healthbot/main.go | 23 ++++- pkg/client/chains.go | 40 ++++---- pkg/client/legacy/client.go | 2 +- pkg/client/v1/client.go | 2 +- 7 files changed, 87 insertions(+), 98 deletions(-) diff --git a/cmd/healthbot/config.go b/cmd/healthbot/config.go index 91cb7105..2ef19251 100644 --- a/cmd/healthbot/config.go +++ b/cmd/healthbot/config.go @@ -22,17 +22,16 @@ type config struct { Human bool `default:"false"` Debug bool `default:"false"` } - Target string `default:""` Chains []ChainConfig } // ChainConfig contains probe configuration for a particular chain. type ChainConfig struct { - Name string - Probe struct { + ChainID int + WalletPrivateKey string + Probe struct { CheckInterval string `default:"15s"` ReceiptTimeout string `default:"20s"` - SIWE string `default:""` Tablename string `default:""` } } diff --git a/cmd/healthbot/counterprobe/counterprobe.go b/cmd/healthbot/counterprobe/counterprobe.go index 037d4759..6aa8712e 100644 --- a/cmd/healthbot/counterprobe/counterprobe.go +++ b/cmd/healthbot/counterprobe/counterprobe.go @@ -4,17 +4,14 @@ import ( "context" "errors" "fmt" - "net/url" "sync" "time" "github.com/rs/zerolog" logger "github.com/rs/zerolog/log" - "github.com/textileio/go-tableland/internal/router/controllers/legacy" + clientV1 "github.com/textileio/go-tableland/pkg/client/v1" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric/instrument/syncint64" - - "github.com/ethereum/go-ethereum/rpc" ) const ( @@ -24,14 +21,13 @@ const ( // CounterProbe allows running an e2e probe for a pre-minted table // that has a counter column. type CounterProbe struct { - log zerolog.Logger + log zerolog.Logger + client *clientV1.Client checkInterval time.Duration receiptTimeout time.Duration tableName string - rpcClient *rpc.Client - lock sync.RWMutex mLastCounterValue int64 mLastCheck time.Time @@ -43,8 +39,7 @@ type CounterProbe struct { // New returns a *CounterProbe. func New( chainName string, - endpoint string, - siwe string, + client *clientV1.Client, tableName string, checkInterval time.Duration, receiptTimeout time.Duration, @@ -55,24 +50,16 @@ func New( Logger() if receiptTimeout == 0 { - return nil, fmt.Errorf("receipt timeout can't be zero") + return nil, errors.New("receipt timeout can't be zero") } if len(tableName) == 0 { return nil, errors.New("tablename is empty") } - if _, err := url.ParseQuery(endpoint); err != nil { - return nil, fmt.Errorf("invalid endpoint target: %s", err) - } - rpcClient, err := rpc.Dial(endpoint) - if err != nil { - return nil, fmt.Errorf("creating jsonrpc client: %s", err) - } - rpcClient.SetHeader("Authorization", "Bearer "+siwe) cp := &CounterProbe{ log: log, checkInterval: checkInterval, - rpcClient: rpcClient, + client: client, tableName: tableName, receiptTimeout: receiptTimeout, } @@ -149,57 +136,35 @@ func (cp *CounterProbe) healthCheck(ctx context.Context) (int64, error) { } func (cp *CounterProbe) increaseCounterValue(ctx context.Context) error { - updateCounterReq := legacy.RelayWriteQueryRequest{ - Statement: fmt.Sprintf("update %s set counter=counter+1", cp.tableName), - } - var updateCounterRes legacy.RelayWriteQueryResponse - if err := cp.rpcClient.CallContext(ctx, &updateCounterRes, "tableland_relayWriteQuery", updateCounterReq); err != nil { - return fmt.Errorf("calling tableland_runReadQuery: %s", err) - } - - getReceiptRequest := legacy.GetReceiptRequest{ - TxnHash: updateCounterRes.Transaction.Hash, + txnHash, err := cp.client.Write(ctx, fmt.Sprintf("update %s set counter=counter+1", cp.tableName)) + if err != nil { + return fmt.Errorf("calling client Write: %s", err) } start := time.Now() - deadline := time.Now().Add(cp.receiptTimeout) - for time.Now().Before(deadline) { - var getReceiptResponse legacy.GetReceiptResponse - if err := cp.rpcClient.CallContext(ctx, &getReceiptResponse, "tableland_getReceipt", getReceiptRequest); err != nil { - return fmt.Errorf("calling tableland_getReceipt: %s", err) - } - if getReceiptResponse.Ok { - if getReceiptResponse.Receipt.Error != "" { - return fmt.Errorf("receipt found but has an error %s", getReceiptResponse.Receipt.Error) - } - cp.log.Info().Int64("duration", time.Since(start).Milliseconds()).Msg("receipt confirmed") - return nil - } - time.Sleep(time.Second * 5) - } - - return fmt.Errorf("timed out waiting for receipt %s", getReceiptRequest.TxnHash) -} - -func (cp *CounterProbe) getCurrentCounterValue(ctx context.Context) (int64, error) { - output := "table" - getCounterReq := legacy.RunReadQueryRequest{ - Statement: fmt.Sprintf("select * from %s", cp.tableName), - Output: &output, - } - - type data struct { - Rows [][]int64 `json:"rows"` - } - var getCounterRes struct { - Result data `json:"data"` + receipt, ok, err := cp.client.Receipt(ctx, txnHash, clientV1.WaitFor(cp.receiptTimeout)) + if err != nil { + return fmt.Errorf("calling tableland_getReceipt: %s", err) } - if err := cp.rpcClient.CallContext(ctx, &getCounterRes, "tableland_runReadQuery", getCounterReq); err != nil { - return 0, fmt.Errorf("calling tableland_runSQL: %s", err) + if !ok { + return fmt.Errorf("waiting for receipt %s timed out", txnHash) } - if len(getCounterRes.Result.Rows) != 1 || len(getCounterRes.Result.Rows[0]) != 1 { - return 0, fmt.Errorf("unexpected response format") + if receipt.Error_ != "" { + return fmt.Errorf("receipt found but has an error %s", receipt.Error_) } + cp.log.Info().Int64("duration", time.Since(start).Milliseconds()).Msg("receipt confirmed") + return nil +} - return getCounterRes.Result.Rows[0][0], nil +func (cp *CounterProbe) getCurrentCounterValue(ctx context.Context) (int64, error) { + var counter int64 + if err := cp.client.Read( + ctx, + fmt.Sprintf("select counter from %s", cp.tableName), + &counter, + clientV1.ReadExtract(), + clientV1.ReadUnwrap()); err != nil { + return 0, fmt.Errorf("calling read query: %s", err) + } + return counter, nil } diff --git a/cmd/healthbot/counterprobe/counterprobe_test.go b/cmd/healthbot/counterprobe/counterprobe_test.go index 2cb43447..b4eec194 100644 --- a/cmd/healthbot/counterprobe/counterprobe_test.go +++ b/cmd/healthbot/counterprobe/counterprobe_test.go @@ -6,15 +6,23 @@ import ( "time" "github.com/stretchr/testify/require" + "github.com/textileio/go-tableland/pkg/client" + clientV1 "github.com/textileio/go-tableland/pkg/client/v1" + "github.com/textileio/go-tableland/pkg/wallet" ) func TestProduction(t *testing.T) { t.SkipNow() - siwe := "fillme" - endpoint := "https://testnet.tableland.network/rpc" - tblname := "Runbook_24" - cp, err := New("optimism-mainnet", endpoint, siwe, tblname, time.Second, time.Second*10) + ctx := context.Background() + wallet, err := wallet.NewWallet("FILL ME") + require.NoError(t, err) + + chain := client.Chains[client.ChainIDs.Optimism] + client, err := clientV1.NewClient(ctx, wallet, clientV1.NewClientChain(chain)) + require.NoError(t, err) + + cp, err := New("optimism-mainnet", client, "Runbook_24", time.Second, time.Second*10) require.NoError(t, err) value, err := cp.healthCheck(context.Background()) diff --git a/cmd/healthbot/main.go b/cmd/healthbot/main.go index 54679f2a..0aa6a99d 100644 --- a/cmd/healthbot/main.go +++ b/cmd/healthbot/main.go @@ -11,8 +11,11 @@ import ( "github.com/rs/zerolog/log" "github.com/textileio/go-tableland/buildinfo" "github.com/textileio/go-tableland/cmd/healthbot/counterprobe" + "github.com/textileio/go-tableland/pkg/client" + clientV1 "github.com/textileio/go-tableland/pkg/client/v1" "github.com/textileio/go-tableland/pkg/logging" "github.com/textileio/go-tableland/pkg/metrics" + "github.com/textileio/go-tableland/pkg/wallet" ) func main() { @@ -36,10 +39,24 @@ func main() { log.Fatal().Err(err).Msgf("receipt timeout has invalid format: %s", chainCfg.Probe.ReceiptTimeout) } + wallet, err := wallet.NewWallet(chainCfg.WalletPrivateKey) + if err != nil { + log.Fatal().Err(err).Msg("unable to create wallet from private key string") + } + + chain, ok := client.Chains[client.ChainID(chainCfg.ChainID)] + if !ok { + log.Fatal().Int("chain_id", chainCfg.ChainID).Msg("the chain id isn't supported in the Tableland client") + } + + client, err := clientV1.NewClient(ctx, wallet, clientV1.NewClientChain(chain)) + if err != nil { + log.Fatal().Err(err).Msg("error creating tbl client") + } + cp, err := counterprobe.New( - chainCfg.Name, - cfg.Target, - chainCfg.Probe.SIWE, + chain.Name, + client, chainCfg.Probe.Tablename, checkInterval, receiptTimeout) diff --git a/pkg/client/chains.go b/pkg/client/chains.go index 224b99d6..52a600d3 100644 --- a/pkg/client/chains.go +++ b/pkg/client/chains.go @@ -40,64 +40,64 @@ var ChainIDs = struct { type Chain struct { Endpoint string ID ChainID + Name string ContractAddr common.Address } // Chains is the connection info for all chains supported by Tableland. -var Chains = struct { - Ethereum Chain - Optimism Chain - Polygon Chain - Arbitrum Chain - EthereumGoerli Chain - OptimismGoerli Chain - ArbitrumGoerli Chain - PolygonMumbai Chain - Local Chain -}{ - Ethereum: Chain{ +var Chains = map[ChainID]Chain{ + ChainIDs.Ethereum: { Endpoint: mainnetURL, ID: ChainIDs.Ethereum, + Name: "Ethereum", ContractAddr: common.HexToAddress("0x012969f7e3439a9B04025b5a049EB9BAD82A8C12"), }, - Optimism: Chain{ + ChainIDs.Optimism: { Endpoint: mainnetURL, ID: ChainIDs.Optimism, + Name: "Optimism", ContractAddr: common.HexToAddress("0xfad44BF5B843dE943a09D4f3E84949A11d3aa3e6"), }, - Polygon: Chain{ + ChainIDs.Polygon: { Endpoint: mainnetURL, ID: ChainIDs.Polygon, + Name: "Polygon", ContractAddr: common.HexToAddress("0x5c4e6A9e5C1e1BF445A062006faF19EA6c49aFeA"), }, - Arbitrum: Chain{ + ChainIDs.Arbitrum: { Endpoint: mainnetURL, ID: ChainIDs.Arbitrum, + Name: "Arbitrum", ContractAddr: common.HexToAddress("0x9aBd75E8640871A5a20d3B4eE6330a04c962aFfd"), }, - EthereumGoerli: Chain{ + ChainIDs.EthereumGoerli: { Endpoint: testnetURL, ID: ChainIDs.EthereumGoerli, + Name: "Ethereum Goerli", ContractAddr: common.HexToAddress("0xDA8EA22d092307874f30A1F277D1388dca0BA97a"), }, - OptimismGoerli: Chain{ + ChainIDs.OptimismGoerli: { Endpoint: testnetURL, ID: ChainIDs.OptimismGoerli, + Name: "Optimism Goerli", ContractAddr: common.HexToAddress("0xC72E8a7Be04f2469f8C2dB3F1BdF69A7D516aBbA"), }, - ArbitrumGoerli: Chain{ + ChainIDs.ArbitrumGoerli: { Endpoint: testnetURL, ID: ChainIDs.ArbitrumGoerli, + Name: "Arbitrum Goerli", ContractAddr: common.HexToAddress("0x033f69e8d119205089Ab15D340F5b797732f646b"), }, - PolygonMumbai: Chain{ + ChainIDs.PolygonMumbai: { Endpoint: testnetURL, ID: ChainIDs.PolygonMumbai, + Name: "Polygon Mumbai", ContractAddr: common.HexToAddress("0x4b48841d4b32C4650E4ABc117A03FE8B51f38F68"), }, - Local: Chain{ + ChainIDs.Local: { Endpoint: localURL, ID: ChainIDs.Local, + Name: "Local", ContractAddr: common.HexToAddress("0xe7f1725e7734ce288f8367e1bb143e90bb3f0512"), }, } diff --git a/pkg/client/legacy/client.go b/pkg/client/legacy/client.go index dbfc5927..13804268 100644 --- a/pkg/client/legacy/client.go +++ b/pkg/client/legacy/client.go @@ -23,7 +23,7 @@ import ( "github.com/textileio/go-tableland/pkg/wallet" ) -var defaultChain = client.Chains.PolygonMumbai +var defaultChain = client.Chains[client.ChainIDs.PolygonMumbai] // TxnReceipt is a Tableland event processing receipt. // TODO(json-rpc): remove client_legacy package when support is dropped. diff --git a/pkg/client/v1/client.go b/pkg/client/v1/client.go index a5c5ce9b..674779bc 100644 --- a/pkg/client/v1/client.go +++ b/pkg/client/v1/client.go @@ -21,7 +21,7 @@ import ( "github.com/textileio/go-tableland/pkg/wallet" ) -var defaultChain = client.Chains.PolygonMumbai +var defaultChain = client.Chains[client.ChainIDs.PolygonMumbai] // Client is the Tableland client. type Client struct { From e7bc600032379c21c01fa98c89f5bfe6f4d58438 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 19 Dec 2022 14:52:34 -0300 Subject: [PATCH 074/101] docker/deployed: fix env_example and config.json files Signed-off-by: Ignacio Hagopian --- .../staging/healthbot/.env_healthbot.example | 2 +- docker/deployed/staging/healthbot/config.json | 4 ++-- .../testnet/healthbot/.env_healthbot.example | 8 ++++---- docker/deployed/testnet/healthbot/config.json | 18 +++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docker/deployed/staging/healthbot/.env_healthbot.example b/docker/deployed/staging/healthbot/.env_healthbot.example index 1f179f8e..fae7a781 100644 --- a/docker/deployed/staging/healthbot/.env_healthbot.example +++ b/docker/deployed/staging/healthbot/.env_healthbot.example @@ -1,2 +1,2 @@ -HEALTHBOT_OPTIMISM_GOERLI_SIWE= +HEALTHBOT_OPTIMISM_GOERLI_PRIVATE_KEY= HEALTHBOT_OPTIMISM_GOERLI_TABLE= \ No newline at end of file diff --git a/docker/deployed/staging/healthbot/config.json b/docker/deployed/staging/healthbot/config.json index c93e6636..981da2bf 100644 --- a/docker/deployed/staging/healthbot/config.json +++ b/docker/deployed/staging/healthbot/config.json @@ -9,11 +9,11 @@ "Target": "https://staging.tableland.network/rpc", "Chains": [ { - "Name": "optimism-goerli", + "ChainID": 5, + "WalletPrivateKey": "${HEALTHBOT_OPTIMISM_GOERLI_PRIVATE_KEY}", "Probe": { "CheckInterval": "360s", "ReceiptTimeout": "20s", - "SIWE": "${HEALTHBOT_OPTIMISM_GOERLI_SIWE}", "Tablename": "${HEALTHBOT_OPTIMISM_GOERLI_TABLE}" } } diff --git a/docker/deployed/testnet/healthbot/.env_healthbot.example b/docker/deployed/testnet/healthbot/.env_healthbot.example index 18859e85..a4116f96 100644 --- a/docker/deployed/testnet/healthbot/.env_healthbot.example +++ b/docker/deployed/testnet/healthbot/.env_healthbot.example @@ -1,9 +1,9 @@ -HEALTHBOT_ETHEREUM_GOERLI_SIWE= +HEALTHBOT_ETHEREUM_GOERLI_PRIVATE_KEY= HEALTHBOT_ETHEREUM_GOERLI_TABLE= -HEALTHBOT_POLYGON_MUMBAI_SIWE= +HEALTHBOT_POLYGON_MUMBAI_PRIVATE_KEY= HEALTHBOT_POLYGON_MUMBAI_TABLE= -HEALTHBOT_ARBITRUM_GOERLI_SIWE= +HEALTHBOT_ARBITRUM_GOERLI_PRIVATE_KEY= HEALTHBOT_ARBITRUM_GOERLI_TABLE= -HEALTHBOT_OPTIMISM_GOERLI_SIWE= +HEALTHBOT_OPTIMISM_GOERLI_PRIVATE_KEY= HEALTHBOT_OPTIMISM_GOERLI_TABLE= diff --git a/docker/deployed/testnet/healthbot/config.json b/docker/deployed/testnet/healthbot/config.json index a36ac256..112404f2 100644 --- a/docker/deployed/testnet/healthbot/config.json +++ b/docker/deployed/testnet/healthbot/config.json @@ -6,41 +6,41 @@ "Human": false, "Debug": true }, - "Target": "https://testnet.tableland.network/rpc", + "Target": "https://testnets.tableland.network/rpc", "Chains": [ { - "Name": "arbitrum-goerli", + "Name": 421613, + "WalletPrivateKey": "${HEALTHBOT_ARBITRUM_GOERLI_PRIVATE_KEY}", "Probe": { "CheckInterval": "360s", "ReceiptTimeout": "25s", - "SIWE": "${HEALTHBOT_ARBITRUM_GOERLI_SIWE}", "Tablename": "${HEALTHBOT_ARBITRUM_GOERLI_TABLE}" } }, { - "Name": "ethereum-goerli", + "ChainID": 5, + "WalletPrivateKey": "${HEALTHBOT_ETHEREUM_GOERLI_PRIVATE_KEY}", "Probe": { "CheckInterval": "1h", "ReceiptTimeout": "90s", - "SIWE": "${HEALTHBOT_ETHEREUM_GOERLI_SIWE}", "Tablename": "${HEALTHBOT_ETHEREUM_GOERLI_TABLE}" } }, { - "Name": "polygon-mumbai", + "ChainID": 80001, + "WalletPrivateKey": "${HEALTHBOT_POLYGON_MUMBAI_PRIVATE_KEY}", "Probe": { "CheckInterval": "240s", "ReceiptTimeout": "40s", - "SIWE": "${HEALTHBOT_POLYGON_MUMBAI_SIWE}", "Tablename": "${HEALTHBOT_POLYGON_MUMBAI_TABLE}" } }, { - "Name": "optimism-goerli", + "ChainID": 420, + "WalletPrivateKey": "${HEALTHBOT_OPTIMISM_GOERLI_PRIVATE_KEY}", "Probe": { "CheckInterval": "360s", "ReceiptTimeout": "25s", - "SIWE": "${HEALTHBOT_OPTIMISM_GOERLI_SIWE}", "Tablename": "${HEALTHBOT_OPTIMISM_GOERLI_TABLE}" } } From 38e538fbfa056b1fc296eace14f26601eb6c5eb4 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 26 Dec 2022 13:54:03 -0300 Subject: [PATCH 075/101] healthbot: remove Targets from config files Signed-off-by: Ignacio Hagopian --- docker/deployed/staging/healthbot/config.json | 1 - docker/deployed/testnet/healthbot/config.json | 1 - 2 files changed, 2 deletions(-) diff --git a/docker/deployed/staging/healthbot/config.json b/docker/deployed/staging/healthbot/config.json index 981da2bf..8598c10e 100644 --- a/docker/deployed/staging/healthbot/config.json +++ b/docker/deployed/staging/healthbot/config.json @@ -6,7 +6,6 @@ "Human": false, "Debug": true }, - "Target": "https://staging.tableland.network/rpc", "Chains": [ { "ChainID": 5, diff --git a/docker/deployed/testnet/healthbot/config.json b/docker/deployed/testnet/healthbot/config.json index 112404f2..d7ffbdf8 100644 --- a/docker/deployed/testnet/healthbot/config.json +++ b/docker/deployed/testnet/healthbot/config.json @@ -6,7 +6,6 @@ "Human": false, "Debug": true }, - "Target": "https://testnets.tableland.network/rpc", "Chains": [ { "Name": 421613, From aaea82f0d4a353be81941cefbf6bff163bec34f8 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 15 Dec 2022 14:29:57 -0300 Subject: [PATCH 076/101] internal/router: unify infra controller Signed-off-by: Ignacio Hagopian --- internal/router/controllers/infra.go | 10 +--------- internal/router/router.go | 11 ++++------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/internal/router/controllers/infra.go b/internal/router/controllers/infra.go index b670ea3b..99bd9b3b 100644 --- a/internal/router/controllers/infra.go +++ b/internal/router/controllers/infra.go @@ -8,16 +8,8 @@ import ( "github.com/textileio/go-tableland/internal/router/controllers/apiv1" ) -// InfraController defines the HTTP handlers for infrastructure APIs. -type InfraController struct{} - -// NewInfraController creates a new InfraController. -func NewInfraController() *InfraController { - return &InfraController{} -} - // Version returns git information of the running binary. -func (c *InfraController) Version(rw http.ResponseWriter, _ *http.Request) { +func (c *UserController) Version(rw http.ResponseWriter, _ *http.Request) { rw.Header().Set("Content-type", "application/json") summary := buildinfo.GetSummary() rw.WriteHeader(http.StatusOK) diff --git a/internal/router/router.go b/internal/router/router.go index 9791d66f..ff7b96c0 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -31,7 +31,6 @@ func ConfiguredRouter( userCtrl := controllers.NewUserController(tableland) systemCtrl := controllers.NewSystemController(systemService) - infraCtrl := controllers.NewInfraController() // General router configuration. router := newRouter() @@ -51,10 +50,10 @@ func ConfiguredRouter( // TODO(json-rpc): remove this when dropping support. // APIs Legacy (REST + JSON-RPC) - configureLegacyRoutes(router, server, supportedChainIDs, rateLim, systemCtrl, userCtrl, infraCtrl) + configureLegacyRoutes(router, server, supportedChainIDs, rateLim, systemCtrl, userCtrl) // APIs V1 - if err := configureAPIV1Routes(router, supportedChainIDs, rateLim, systemCtrl, userCtrl, infraCtrl); err != nil { + if err := configureAPIV1Routes(router, supportedChainIDs, rateLim, systemCtrl, userCtrl); err != nil { return nil, fmt.Errorf("configuring API v1: %s", err) } @@ -68,7 +67,6 @@ func configureLegacyRoutes( rateLim mux.MiddlewareFunc, systemCtrl *controllers.SystemController, userCtrl *controllers.UserController, - infraCtrl *controllers.InfraController, ) { router.post("/rpc", func(rw http.ResponseWriter, r *http.Request) { server.ServeHTTP(rw, r) @@ -82,7 +80,7 @@ func configureLegacyRoutes( router.get("/schema/{table_name}", systemCtrl.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint router.get("/query", userCtrl.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint - router.get("/version", infraCtrl.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint + router.get("/version", userCtrl.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint // Health endpoint configuration. router.get("/healthz", controllers.HealthHandler) @@ -95,7 +93,6 @@ func configureAPIV1Routes( rateLim mux.MiddlewareFunc, systemCtrl *controllers.SystemController, userCtrl *controllers.UserController, - infraCtrl *controllers.InfraController, ) error { handlers := map[string]struct { handler http.HandlerFunc @@ -114,7 +111,7 @@ func configureAPIV1Routes( []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim}, }, "Version": { - infraCtrl.Version, + userCtrl.Version, []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, }, "Health": { From 27d57f7284faba745766c2793f88cb6c6f1ac599 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 12 Dec 2022 11:03:35 -0300 Subject: [PATCH 077/101] internal/router: unify system controller Signed-off-by: Ignacio Hagopian --- internal/router/controllers/system.go | 18 ++++---------- internal/router/controllers/system_test.go | 18 +++++++------- internal/router/controllers/user.go | 11 ++++++--- internal/router/controllers/user_test.go | 28 +++++++++++----------- internal/router/router.go | 24 ++++++++----------- 5 files changed, 45 insertions(+), 54 deletions(-) diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go index 89a503d3..4d3819f2 100644 --- a/internal/router/controllers/system.go +++ b/internal/router/controllers/system.go @@ -14,16 +14,6 @@ import ( "github.com/textileio/go-tableland/pkg/tables" ) -// SystemController defines the HTTP handlers for interacting with system operations. -type SystemController struct { - systemService system.SystemService -} - -// NewSystemController creates a new SystemController. -func NewSystemController(svc system.SystemService) *SystemController { - return &SystemController{svc} -} - // GetReceiptByTransactionHash handles request asking for a transaction receipt. func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -70,7 +60,7 @@ func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r } // GetTable handles the GET /chain/{chainID}/tables/{tableId} call. -func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { +func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := mux.Vars(r) @@ -150,7 +140,7 @@ func (c *SystemController) GetTable(rw http.ResponseWriter, r *http.Request) { // GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. // TODO(json-rpc): delete when dropping support. -func (c *SystemController) GetTablesByController(rw http.ResponseWriter, r *http.Request) { +func (c *UserController) GetTablesByController(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() rw.Header().Set("Content-type", "application/json") vars := mux.Vars(r) @@ -193,7 +183,7 @@ func (c *SystemController) GetTablesByController(rw http.ResponseWriter, r *http // GetTablesByStructureHash handles the GET /chain/{id}/tables/structure/{hash} call. // TODO(json-rpc): delete when dropping support. -func (c *SystemController) GetTablesByStructureHash(rw http.ResponseWriter, r *http.Request) { +func (c *UserController) GetTablesByStructureHash(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() rw.Header().Set("Content-type", "application/json") @@ -233,7 +223,7 @@ func (c *SystemController) GetTablesByStructureHash(rw http.ResponseWriter, r *h // GetSchemaByTableName handles the GET /schema/{table_name} call. // TODO(json-rpc): delete when droppping support. -func (c *SystemController) GetSchemaByTableName(rw http.ResponseWriter, r *http.Request) { +func (c *UserController) GetSchemaByTableName(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() rw.Header().Set("Content-type", "application/json") diff --git a/internal/router/controllers/system_test.go b/internal/router/controllers/system_test.go index d48b3adb..98d4227e 100644 --- a/internal/router/controllers/system_test.go +++ b/internal/router/controllers/system_test.go @@ -11,11 +11,11 @@ import ( systemimpl "github.com/textileio/go-tableland/internal/system/impl" ) -func TestSystemControllerMock(t *testing.T) { +func TestGetTablesByMocked(t *testing.T) { t.Parallel() systemService := systemimpl.NewSystemMockService() - systemController := NewSystemController(systemService) + ctrl := NewUserController(nil, systemService) t.Run("get table metadata", func(t *testing.T) { t.Parallel() @@ -23,7 +23,7 @@ func TestSystemControllerMock(t *testing.T) { require.NoError(t, err) router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/{tableId}", systemController.GetTable) + router.HandleFunc("/chain/{chainID}/tables/{tableId}", ctrl.GetTable) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -46,7 +46,7 @@ func TestSystemControllerMock(t *testing.T) { require.NoError(t, err) router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/controller/{hash}", systemController.GetTablesByController) + router.HandleFunc("/chain/{chainID}/tables/controller/{hash}", ctrl.GetTablesByController) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -73,7 +73,7 @@ func TestSystemControllerMock(t *testing.T) { require.NoError(t, err) router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/structure/{hash}", systemController.GetTablesByStructureHash) + router.HandleFunc("/chain/{chainID}/tables/structure/{hash}", ctrl.GetTablesByStructureHash) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -100,7 +100,7 @@ func TestSystemControllerMock(t *testing.T) { require.NoError(t, err) router := mux.NewRouter() - router.HandleFunc("/schema/{table_name}", systemController.GetSchemaByTableName) + router.HandleFunc("/schema/{table_name}", ctrl.GetSchemaByTableName) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -126,7 +126,7 @@ func TestSystemControllerMock(t *testing.T) { }) } -func TestInvalidID(t *testing.T) { +func TestGetTableWithInvalidID(t *testing.T) { t.Parallel() id := "invalid integer" @@ -135,7 +135,7 @@ func TestInvalidID(t *testing.T) { require.NoError(t, err) systemService := systemimpl.NewSystemMockService() - systemController := NewSystemController(systemService) + systemController := NewUserController(nil, systemService) router := mux.NewRouter() router.HandleFunc("/tables/{id}", systemController.GetTable) @@ -156,7 +156,7 @@ func TestTableNotFoundMock(t *testing.T) { require.NoError(t, err) systemService := systemimpl.NewSystemMockErrService() - systemController := NewSystemController(systemService) + systemController := NewUserController(nil, systemService) router := mux.NewRouter() router.HandleFunc("/tables/{tableId}", systemController.GetTable) diff --git a/internal/router/controllers/user.go b/internal/router/controllers/user.go index c456d1f7..69ac6aee 100644 --- a/internal/router/controllers/user.go +++ b/internal/router/controllers/user.go @@ -13,6 +13,7 @@ import ( "github.com/rs/zerolog/log" "github.com/textileio/go-tableland/internal/formatter" "github.com/textileio/go-tableland/internal/router/middlewares" + "github.com/textileio/go-tableland/internal/system" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/errors" "github.com/textileio/go-tableland/pkg/tables" @@ -26,12 +27,16 @@ type SQLRunner interface { // UserController defines the HTTP handlers for interacting with user tables. type UserController struct { - runner SQLRunner + runner SQLRunner + systemService system.SystemService } // NewUserController creates a new UserController. -func NewUserController(runner SQLRunner) *UserController { - return &UserController{runner} +func NewUserController(runner SQLRunner, svc system.SystemService) *UserController { + return &UserController{ + runner: runner, + systemService: svc, + } } // MetadataConfig defines columns should be mapped to erc721 metadata diff --git a/internal/router/controllers/user_test.go b/internal/router/controllers/user_test.go index 41cb9acf..722e009c 100644 --- a/internal/router/controllers/user_test.go +++ b/internal/router/controllers/user_test.go @@ -14,13 +14,13 @@ import ( "github.com/textileio/go-tableland/mocks" ) -func TestUserController(t *testing.T) { +func TestGetTableRow(t *testing.T) { t.Parallel() req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1", nil) require.NoError(t, err) - userController := NewUserController(newTableRowRunnerMock(t)) + userController := NewUserController(newTableRowRunnerMock(t), nil) router := mux.NewRouter() router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow) @@ -33,13 +33,13 @@ func TestUserController(t *testing.T) { require.JSONEq(t, expJSON, rr.Body.String()) } -func TestUserControllerERC721Metadata(t *testing.T) { +func TestERC721Metadata(t *testing.T) { t.Parallel() req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1?format=erc721&name=id&image=image&description=description&external_url=external_url&attributes[0][column]=base&attributes[0][trait_type]=Base&attributes[1][column]=eyes&attributes[1][trait_type]=Eyes&attributes[2][column]=mouth&attributes[2][trait_type]=Mouth&attributes[3][column]=level&attributes[3][trait_type]=Level&attributes[4][column]=stamina&attributes[4][trait_type]=Stamina&attributes[5][column]=personality&attributes[5][trait_type]=Personality&attributes[6][column]=aqua_power&attributes[6][display_type]=boost_number&attributes[6][trait_type]=Aqua%20Power&attributes[7][column]=stamina_increase&attributes[7][display_type]=boost_percentage&attributes[7][trait_type]=Stamina%20Increase&attributes[8][column]=generation&attributes[8][display_type]=number&attributes[8][trait_type]=Generation", nil) // nolint require.NoError(t, err) - userController := NewUserController(newTableRowRunnerMock(t)) + userController := NewUserController(newTableRowRunnerMock(t), nil) router := mux.NewRouter() router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow) @@ -52,7 +52,7 @@ func TestUserControllerERC721Metadata(t *testing.T) { require.JSONEq(t, expJSON, rr.Body.String()) } -func TestUserControllerBadQuery(t *testing.T) { +func TestBadQuery(t *testing.T) { t.Parallel() r := mocks.NewSQLRunner(t) @@ -61,7 +61,7 @@ func TestUserControllerBadQuery(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/invalid_column/0", nil) require.NoError(t, err) - userController := NewUserController(r) + userController := NewUserController(r, nil) router := mux.NewRouter() router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow) @@ -75,7 +75,7 @@ func TestUserControllerBadQuery(t *testing.T) { require.JSONEq(t, expJSON, rr.Body.String()) } -func TestUserControllerRowNotFound(t *testing.T) { +func TestRowNotFound(t *testing.T) { t.Parallel() r := mocks.NewSQLRunner(t) @@ -104,7 +104,7 @@ func TestUserControllerRowNotFound(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1", nil) require.NoError(t, err) - userController := NewUserController(r) + userController := NewUserController(r, nil) router := mux.NewRouter() router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow) @@ -118,7 +118,7 @@ func TestUserControllerRowNotFound(t *testing.T) { require.JSONEq(t, expJSON, rr.Body.String()) } -func TestUserControllerQuery(t *testing.T) { +func TestQuery(t *testing.T) { r := mocks.NewSQLRunner(t) r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return( &tableland.TableData{ @@ -148,7 +148,7 @@ func TestUserControllerQuery(t *testing.T) { nil, ) - userController := NewUserController(r) + userController := NewUserController(r, nil) router := mux.NewRouter() router.HandleFunc("/query", userController.GetTableQuery) @@ -186,7 +186,7 @@ func TestUserControllerQuery(t *testing.T) { } } -func TestUserControllerLegacyQuery(t *testing.T) { +func TestLegacyQuery(t *testing.T) { r := mocks.NewSQLRunner(t) r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return( &tableland.TableData{ @@ -208,7 +208,7 @@ func TestUserControllerLegacyQuery(t *testing.T) { nil, ) - userController := NewUserController(r) + userController := NewUserController(r, nil) router := mux.NewRouter() router.HandleFunc("/query", userController.GetTableQuery) @@ -237,7 +237,7 @@ func TestUserControllerLegacyQuery(t *testing.T) { } } -func TestUserControllerQueryExtracted(t *testing.T) { +func TestQueryExtracted(t *testing.T) { r := mocks.NewSQLRunner(t) r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return( &tableland.TableData{ @@ -251,7 +251,7 @@ func TestUserControllerQueryExtracted(t *testing.T) { nil, ) - userController := NewUserController(r) + userController := NewUserController(r, nil) router := mux.NewRouter() router.HandleFunc("/query", userController.GetTableQuery) diff --git a/internal/router/router.go b/internal/router/router.go index ff7b96c0..0c7d554e 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -28,9 +28,7 @@ func ConfiguredRouter( if err := server.RegisterName("tableland", rpcService); err != nil { return nil, fmt.Errorf("failed to register a json-rpc service: %s", err) } - userCtrl := controllers.NewUserController(tableland) - - systemCtrl := controllers.NewSystemController(systemService) + userCtrl := controllers.NewUserController(tableland, systemService) // General router configuration. router := newRouter() @@ -50,10 +48,10 @@ func ConfiguredRouter( // TODO(json-rpc): remove this when dropping support. // APIs Legacy (REST + JSON-RPC) - configureLegacyRoutes(router, server, supportedChainIDs, rateLim, systemCtrl, userCtrl) + configureLegacyRoutes(router, server, supportedChainIDs, rateLim, userCtrl) // APIs V1 - if err := configureAPIV1Routes(router, supportedChainIDs, rateLim, systemCtrl, userCtrl); err != nil { + if err := configureAPIV1Routes(router, supportedChainIDs, rateLim, userCtrl); err != nil { return nil, fmt.Errorf("configuring API v1: %s", err) } @@ -65,7 +63,6 @@ func configureLegacyRoutes( server *rpc.Server, supportedChainIDs []tableland.ChainID, rateLim mux.MiddlewareFunc, - systemCtrl *controllers.SystemController, userCtrl *controllers.UserController, ) { router.post("/rpc", func(rw http.ResponseWriter, r *http.Request) { @@ -73,11 +70,11 @@ func configureLegacyRoutes( }, middlewares.WithLogging, middlewares.OtelHTTP("rpc"), middlewares.Authentication, rateLim) // Gateway configuration. - router.get("/chain/{chainId}/tables/{tableId}", systemCtrl.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint - router.get("/chain/{chainId}/tables/{id}/{key}/{value}", userCtrl.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint - router.get("/chain/{chainId}/tables/controller/{address}", systemCtrl.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint - router.get("/chain/{chainId}/tables/structure/{hash}", systemCtrl.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint - router.get("/schema/{table_name}", systemCtrl.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint + router.get("/chain/{chainId}/tables/{tableId}", userCtrl.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/{id}/{key}/{value}", userCtrl.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/controller/{address}", userCtrl.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/structure/{hash}", userCtrl.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/schema/{table_name}", userCtrl.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint router.get("/query", userCtrl.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint router.get("/version", userCtrl.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint @@ -91,7 +88,6 @@ func configureAPIV1Routes( router *Router, supportedChainIDs []tableland.ChainID, rateLim mux.MiddlewareFunc, - systemCtrl *controllers.SystemController, userCtrl *controllers.UserController, ) error { handlers := map[string]struct { @@ -103,11 +99,11 @@ func configureAPIV1Routes( []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, }, "ReceiptByTransactionHash": { - systemCtrl.GetReceiptByTransactionHash, + userCtrl.GetReceiptByTransactionHash, []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim}, }, "GetTableById": { - systemCtrl.GetTable, + userCtrl.GetTable, []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim}, }, "Version": { From 4b56dc80202de7d6b3ff03a910c875ffbb0bdaab Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 12 Dec 2022 11:10:06 -0300 Subject: [PATCH 078/101] improve namings Signed-off-by: Ignacio Hagopian --- .../controllers/{user.go => controller.go} | 286 ++++++++++++++++++ .../{user_test.go => controller_test.go} | 189 +++++++++++- internal/router/controllers/infra.go | 26 -- internal/router/controllers/system_test.go | 171 ----------- internal/router/router.go | 7 +- 5 files changed, 465 insertions(+), 214 deletions(-) rename internal/router/controllers/{user.go => controller.go} (57%) rename internal/router/controllers/{user_test.go => controller_test.go} (67%) delete mode 100644 internal/router/controllers/infra.go delete mode 100644 internal/router/controllers/system_test.go diff --git a/internal/router/controllers/user.go b/internal/router/controllers/controller.go similarity index 57% rename from internal/router/controllers/user.go rename to internal/router/controllers/controller.go index 69ac6aee..9a6f867d 100644 --- a/internal/router/controllers/user.go +++ b/internal/router/controllers/controller.go @@ -6,12 +6,16 @@ import ( "fmt" "net/http" "strconv" + "strings" "time" + "github.com/ethereum/go-ethereum/common" "github.com/gorilla/mux" "github.com/hetiansu5/urlquery" "github.com/rs/zerolog/log" + "github.com/textileio/go-tableland/buildinfo" "github.com/textileio/go-tableland/internal/formatter" + "github.com/textileio/go-tableland/internal/router/controllers/apiv1" "github.com/textileio/go-tableland/internal/router/middlewares" "github.com/textileio/go-tableland/internal/system" "github.com/textileio/go-tableland/internal/tableland" @@ -215,6 +219,288 @@ func (c *UserController) GetTableRow(rw http.ResponseWriter, r *http.Request) { } } +// Version returns git information of the running binary. +func (c *UserController) Version(rw http.ResponseWriter, _ *http.Request) { + rw.Header().Set("Content-type", "application/json") + summary := buildinfo.GetSummary() + rw.WriteHeader(http.StatusOK) + + _ = json.NewEncoder(rw).Encode(apiv1.VersionInfo{ + Version: int32(summary.Version), + GitCommit: summary.GitCommit, + GitBranch: summary.GitBranch, + GitState: summary.GitState, + GitSummary: summary.GitSummary, + BuildDate: summary.BuildDate, + BinaryVersion: summary.BinaryVersion, + }) +} + +// GetReceiptByTransactionHash handles request asking for a transaction receipt. +func (c *UserController) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + ctx := r.Context() + + paramTxnHash := mux.Vars(r)["transactionHash"] + if _, err := common.ParseHexOrString(paramTxnHash); err != nil { + rw.WriteHeader(http.StatusBadRequest) + log.Ctx(ctx).Error().Err(err).Msg("invalid transaction hash") + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Invalid transaction hash"}) + return + } + txnHash := common.HexToHash(paramTxnHash) + + receipt, exists, err := c.systemService.GetReceiptByTransactionHash(ctx, txnHash) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + log.Ctx(ctx).Error().Err(err).Msg("get receipt by transaction hash") + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Get receipt by transaction hash failed"}) + return + } + if !exists { + rw.WriteHeader(http.StatusNotFound) + return + } + + receiptResponse := apiv1.TransactionReceipt{ + TransactionHash: paramTxnHash, + BlockNumber: receipt.BlockNumber, + ChainId: int32(receipt.ChainID), + } + if receipt.TableID != nil { + receiptResponse.TableId = receipt.TableID.String() + } + if receipt.Error != nil { + receiptResponse.Error_ = *receipt.Error + receiptResponse.ErrorEventIdx = int32(*receipt.ErrorEventIdx) + } + rw.WriteHeader(http.StatusOK) + _ = json.NewEncoder(rw).Encode(receiptResponse) +} + +// GetTable handles the GET /chain/{chainID}/tables/{tableId} call. +func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + rw.Header().Set("Content-type", "application/json") + vars := mux.Vars(r) + + id, err := tables.NewTableID(vars["tableId"]) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + log.Ctx(ctx). + Error(). + Err(err). + Msg("invalid id format") + + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Invalid id format"}) + return + } + + isAPIV1 := strings.HasPrefix(r.RequestURI, "/api/v1/tables") + + metadata, err := c.systemService.GetTableMetadata(ctx, id) + if err == system.ErrTableNotFound { + if !isAPIV1 { + rw.WriteHeader(http.StatusOK) + _ = json.NewEncoder(rw).Encode(metadata) + return + } + rw.WriteHeader(http.StatusNotFound) + return + } + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + log.Ctx(ctx). + Error(). + Err(err). + Str("id", id.String()). + Msg("failed to fetch metadata") + + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Failed to fetch metadata"}) + return + } + + metadataV1 := apiv1.Table{ + Name: metadata.Name, + ExternalUrl: metadata.ExternalURL, + AnimationUrl: metadata.AnimationURL, + Image: metadata.Image, + Attributes: make([]apiv1.TableAttributes, len(metadata.Attributes)), + Schema: &apiv1.Schema{ + Columns: make([]apiv1.Column, len(metadata.Schema.Columns)), + TableConstraints: make([]string, len(metadata.Schema.TableConstraints)), + }, + } + for i, attr := range metadata.Attributes { + metadataV1.Attributes[i] = apiv1.TableAttributes{ + DisplayType: attr.DisplayType, + TraitType: attr.TraitType, + Value: attr.Value, + } + } + for i, schemaColumn := range metadata.Schema.Columns { + metadataV1.Schema.Columns[i] = apiv1.Column{ + Name: schemaColumn.Name, + Type_: schemaColumn.Type, + Constraints: make([]string, len(schemaColumn.Constraints)), + } + copy(metadataV1.Schema.Columns[i].Constraints, schemaColumn.Constraints) + } + copy(metadataV1.Schema.TableConstraints, metadata.Schema.TableConstraints) + + rw.WriteHeader(http.StatusOK) + + _ = json.NewEncoder(rw).Encode(metadataV1) +} + +// GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. +// TODO(json-rpc): delete when dropping support. +func (c *UserController) GetTablesByController(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + rw.Header().Set("Content-type", "application/json") + vars := mux.Vars(r) + + controller := vars["address"] + tables, err := c.systemService.GetTablesByController(ctx, controller) + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + log.Ctx(ctx). + Error(). + Err(err). + Str("request_address", controller). + Msg("failed to fetch tables") + + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Failed to fetch tables"}) + return + } + + // This struct is used since we don't want to return an ID field. + // The Name will be {optional-prefix}_{chainId}_{tableId}. + // Not doing `omitempty` in tableland.Table since + // that feels hacky. Looks safer to define a separate type here at the handler level. + type tableNameIDUnified struct { + Controller string `json:"controller"` + Name string `json:"name"` + Structure string `json:"structure"` + } + retTables := make([]tableNameIDUnified, len(tables)) + for i, t := range tables { + retTables[i] = tableNameIDUnified{ + Controller: t.Controller, + Name: t.Name(), + Structure: t.Structure, + } + } + + rw.WriteHeader(http.StatusOK) + _ = json.NewEncoder(rw).Encode(retTables) +} + +// GetTablesByStructureHash handles the GET /chain/{id}/tables/structure/{hash} call. +// TODO(json-rpc): delete when dropping support. +func (c *UserController) GetTablesByStructureHash(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + rw.Header().Set("Content-type", "application/json") + vars := mux.Vars(r) + + hash := vars["hash"] + tables, err := c.systemService.GetTablesByStructure(ctx, hash) + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + log.Ctx(ctx). + Error(). + Err(err). + Str("hash", hash). + Msg("failed to fetch tables") + + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Failed to fetch tables"}) + return + } + + type tableNameIDUnified struct { + Controller string `json:"controller"` + Name string `json:"name"` + Structure string `json:"structure"` + } + retTables := make([]tableNameIDUnified, len(tables)) + for i, t := range tables { + retTables[i] = tableNameIDUnified{ + Controller: t.Controller, + Name: t.Name(), + Structure: t.Structure, + } + } + + rw.WriteHeader(http.StatusOK) + _ = json.NewEncoder(rw).Encode(retTables) +} + +// GetSchemaByTableName handles the GET /schema/{table_name} call. +// TODO(json-rpc): delete when droppping support. +func (c *UserController) GetSchemaByTableName(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + rw.Header().Set("Content-type", "application/json") + vars := mux.Vars(r) + + name := vars["table_name"] + schema, err := c.systemService.GetSchemaByTableName(ctx, name) + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + log.Ctx(ctx). + Error(). + Err(err). + Str("table_name", name). + Msg("failed to fetch tables") + + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Failed to get schema from table"}) + return + } + + if len(schema.Columns) == 0 { + rw.WriteHeader(http.StatusInternalServerError) + log.Ctx(ctx). + Warn(). + Str("name", name). + Msg("table does not exist") + + _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Table does not exist"}) + return + } + + type Column struct { + Name string `json:"name"` + Type string `json:"type"` + Constraints []string `json:"constraints"` + } + + type response struct { + Columns []Column `json:"columns"` + TableConstraints []string `json:"table_constraints"` + } + + columns := make([]Column, len(schema.Columns)) + for i, col := range schema.Columns { + columns[i] = Column{ + Name: col.Name, + Type: col.Type, + Constraints: col.Constraints, + } + } + + rw.WriteHeader(http.StatusOK) + _ = json.NewEncoder(rw).Encode(response{ + Columns: columns, + TableConstraints: schema.TableConstraints, + }) +} + +// HealthHandler serves health check requests. +func HealthHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + // GetTableQuery handles the GET /query?s=[statement] call. // Use mode=columns|rows|json|lines query param to control output format. func (c *UserController) GetTableQuery(rw http.ResponseWriter, r *http.Request) { diff --git a/internal/router/controllers/user_test.go b/internal/router/controllers/controller_test.go similarity index 67% rename from internal/router/controllers/user_test.go rename to internal/router/controllers/controller_test.go index 722e009c..4984076f 100644 --- a/internal/router/controllers/user_test.go +++ b/internal/router/controllers/controller_test.go @@ -2,6 +2,7 @@ package controllers import ( "errors" + "fmt" "net/http" "net/http/httptest" "strings" @@ -10,6 +11,7 @@ import ( "github.com/gorilla/mux" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + systemimpl "github.com/textileio/go-tableland/internal/system/impl" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/mocks" ) @@ -20,10 +22,10 @@ func TestGetTableRow(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1", nil) require.NoError(t, err) - userController := NewUserController(newTableRowRunnerMock(t), nil) + ctrl := NewUserController(newTableRowRunnerMock(t), nil) router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow) + router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", ctrl.GetTableRow) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -39,10 +41,10 @@ func TestERC721Metadata(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1?format=erc721&name=id&image=image&description=description&external_url=external_url&attributes[0][column]=base&attributes[0][trait_type]=Base&attributes[1][column]=eyes&attributes[1][trait_type]=Eyes&attributes[2][column]=mouth&attributes[2][trait_type]=Mouth&attributes[3][column]=level&attributes[3][trait_type]=Level&attributes[4][column]=stamina&attributes[4][trait_type]=Stamina&attributes[5][column]=personality&attributes[5][trait_type]=Personality&attributes[6][column]=aqua_power&attributes[6][display_type]=boost_number&attributes[6][trait_type]=Aqua%20Power&attributes[7][column]=stamina_increase&attributes[7][display_type]=boost_percentage&attributes[7][trait_type]=Stamina%20Increase&attributes[8][column]=generation&attributes[8][display_type]=number&attributes[8][trait_type]=Generation", nil) // nolint require.NoError(t, err) - userController := NewUserController(newTableRowRunnerMock(t), nil) + ctrl := NewUserController(newTableRowRunnerMock(t), nil) router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow) + router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", ctrl.GetTableRow) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -61,10 +63,10 @@ func TestBadQuery(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/invalid_column/0", nil) require.NoError(t, err) - userController := NewUserController(r, nil) + ctrl := NewUserController(r, nil) router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow) + router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", ctrl.GetTableRow) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -104,10 +106,10 @@ func TestRowNotFound(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1", nil) require.NoError(t, err) - userController := NewUserController(r, nil) + ctrl := NewUserController(r, nil) router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", userController.GetTableRow) + router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", ctrl.GetTableRow) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) @@ -148,10 +150,10 @@ func TestQuery(t *testing.T) { nil, ) - userController := NewUserController(r, nil) + ctrl := NewUserController(r, nil) router := mux.NewRouter() - router.HandleFunc("/query", userController.GetTableQuery) + router.HandleFunc("/query", ctrl.GetTableQuery) // Table output req, err := http.NewRequest("GET", "/query?s=select%20*%20from%20foo%3B&output=table", nil) @@ -208,10 +210,10 @@ func TestLegacyQuery(t *testing.T) { nil, ) - userController := NewUserController(r, nil) + ctrl := NewUserController(r, nil) router := mux.NewRouter() - router.HandleFunc("/query", userController.GetTableQuery) + router.HandleFunc("/query", ctrl.GetTableQuery) // Mode = json req, err := http.NewRequest("GET", "/query?s=select%20*%20from%20foo%3B&mode=json", nil) @@ -251,10 +253,10 @@ func TestQueryExtracted(t *testing.T) { nil, ) - userController := NewUserController(r, nil) + ctrl := NewUserController(r, nil) router := mux.NewRouter() - router.HandleFunc("/query", userController.GetTableQuery) + router.HandleFunc("/query", ctrl.GetTableQuery) // Extracted object output req, err := http.NewRequest("GET", "/query?s=select%20*%20from%20foo%3B&output=objects&extract=true", nil) @@ -280,6 +282,165 @@ func TestQueryExtracted(t *testing.T) { } } +func TestGetTablesByMocked(t *testing.T) { + t.Parallel() + + systemService := systemimpl.NewSystemMockService() + ctrl := NewUserController(nil, systemService) + + t.Run("get table metadata", func(t *testing.T) { + t.Parallel() + req, err := http.NewRequest("GET", "/chain/1337/tables/100", nil) + require.NoError(t, err) + + router := mux.NewRouter() + router.HandleFunc("/chain/{chainID}/tables/{tableId}", ctrl.GetTable) + + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + + //nolint + expJSON := `{ + "name":"name-1", + "external_url":"https://tableland.network/tables/100", + "image":"https://bafkreifhuhrjhzbj4onqgbrmhpysk2mop2jimvdvfut6taiyzt2yqzt43a.ipfs.dweb.link", + "attributes":[{"display_type":"date","trait_type":"created","value":1546360800}], + "schema":{"columns":[{"name":"foo","type":"text"}]} + }` + require.JSONEq(t, expJSON, rr.Body.String()) + }) + + t.Run("get tables by controller", func(t *testing.T) { + t.Parallel() + req, err := http.NewRequest("GET", "/chain/1337/tables/controller/0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", nil) + require.NoError(t, err) + + router := mux.NewRouter() + router.HandleFunc("/chain/{chainID}/tables/controller/{hash}", ctrl.GetTablesByController) + + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + + //nolint + expJSON := `[ + { + "controller":"0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", + "name":"test_1337_0", + "structure":"0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99ee" + }, + { + "controller":"0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", + "name":"test2_1337_1", + "structure":"0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99ee" + }]` + require.JSONEq(t, expJSON, rr.Body.String()) + }) + + t.Run("get tables by structure", func(t *testing.T) { + t.Parallel() + req, err := http.NewRequest("GET", "/chain/1337/tables/structure/0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99eek", nil) // nolint + require.NoError(t, err) + + router := mux.NewRouter() + router.HandleFunc("/chain/{chainID}/tables/structure/{hash}", ctrl.GetTablesByStructureHash) + + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + + //nolint + expJSON := `[ + { + "controller":"0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", + "name":"test_1337_0", + "structure":"0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99ee" + }, + { + "controller":"0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", + "name":"test2_1337_1", + "structure":"0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99ee" + }]` + require.JSONEq(t, expJSON, rr.Body.String()) + }) + + t.Run("get schema by table name", func(t *testing.T) { + t.Parallel() + req, err := http.NewRequest("GET", "/schema/test_1337_0", nil) // nolint + require.NoError(t, err) + + router := mux.NewRouter() + router.HandleFunc("/schema/{table_name}", ctrl.GetSchemaByTableName) + + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + + //nolint + expJSON := `{ + "columns": [ + { + "name" : "a", + "type" : "int", + "constraints" : ["PRIMARY KEY"] + }, + { + "name" : "b", + "type" : "text", + "constraints" : ["DEFAULT ''"] + } + ], + "table_constraints": ["CHECK check (a > 0)"] + }` + require.JSONEq(t, expJSON, rr.Body.String()) + }) +} + +func TestGetTableWithInvalidID(t *testing.T) { + t.Parallel() + + id := "invalid integer" + path := fmt.Sprintf("/tables/%s", id) + req, err := http.NewRequest("GET", path, nil) + require.NoError(t, err) + + systemService := systemimpl.NewSystemMockService() + systemController := NewUserController(nil, systemService) + + router := mux.NewRouter() + router.HandleFunc("/tables/{id}", systemController.GetTable) + + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + + require.Equal(t, http.StatusBadRequest, rr.Code) + + expJSON := `{"message": "Invalid id format"}` + require.JSONEq(t, expJSON, rr.Body.String()) +} + +func TestTableNotFoundMock(t *testing.T) { + t.Parallel() + + req, err := http.NewRequest("GET", "/tables/100", nil) + require.NoError(t, err) + + systemService := systemimpl.NewSystemMockErrService() + systemController := NewUserController(nil, systemService) + + router := mux.NewRouter() + router.HandleFunc("/tables/{tableId}", systemController.GetTable) + + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + + require.Equal(t, http.StatusInternalServerError, rr.Code) + + expJSON := `{"message": "Failed to fetch metadata"}` + require.JSONEq(t, expJSON, rr.Body.String()) +} + func newTableRowRunnerMock(t *testing.T) SQLRunner { r := mocks.NewSQLRunner(t) r.EXPECT().RunReadQuery(mock.Anything, mock.Anything).Return( diff --git a/internal/router/controllers/infra.go b/internal/router/controllers/infra.go deleted file mode 100644 index 99bd9b3b..00000000 --- a/internal/router/controllers/infra.go +++ /dev/null @@ -1,26 +0,0 @@ -package controllers - -import ( - "encoding/json" - "net/http" - - "github.com/textileio/go-tableland/buildinfo" - "github.com/textileio/go-tableland/internal/router/controllers/apiv1" -) - -// Version returns git information of the running binary. -func (c *UserController) Version(rw http.ResponseWriter, _ *http.Request) { - rw.Header().Set("Content-type", "application/json") - summary := buildinfo.GetSummary() - rw.WriteHeader(http.StatusOK) - - _ = json.NewEncoder(rw).Encode(apiv1.VersionInfo{ - Version: int32(summary.Version), - GitCommit: summary.GitCommit, - GitBranch: summary.GitBranch, - GitState: summary.GitState, - GitSummary: summary.GitSummary, - BuildDate: summary.BuildDate, - BinaryVersion: summary.BinaryVersion, - }) -} diff --git a/internal/router/controllers/system_test.go b/internal/router/controllers/system_test.go deleted file mode 100644 index 98d4227e..00000000 --- a/internal/router/controllers/system_test.go +++ /dev/null @@ -1,171 +0,0 @@ -package controllers - -import ( - "fmt" - "net/http" - "net/http/httptest" - "testing" - - "github.com/gorilla/mux" - "github.com/stretchr/testify/require" - systemimpl "github.com/textileio/go-tableland/internal/system/impl" -) - -func TestGetTablesByMocked(t *testing.T) { - t.Parallel() - - systemService := systemimpl.NewSystemMockService() - ctrl := NewUserController(nil, systemService) - - t.Run("get table metadata", func(t *testing.T) { - t.Parallel() - req, err := http.NewRequest("GET", "/chain/1337/tables/100", nil) - require.NoError(t, err) - - router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/{tableId}", ctrl.GetTable) - - rr := httptest.NewRecorder() - router.ServeHTTP(rr, req) - require.Equal(t, http.StatusOK, rr.Code) - - //nolint - expJSON := `{ - "name":"name-1", - "external_url":"https://tableland.network/tables/100", - "image":"https://bafkreifhuhrjhzbj4onqgbrmhpysk2mop2jimvdvfut6taiyzt2yqzt43a.ipfs.dweb.link", - "attributes":[{"display_type":"date","trait_type":"created","value":1546360800}], - "schema":{"columns":[{"name":"foo","type":"text"}]} - }` - require.JSONEq(t, expJSON, rr.Body.String()) - }) - - t.Run("get tables by controller", func(t *testing.T) { - t.Parallel() - req, err := http.NewRequest("GET", "/chain/1337/tables/controller/0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", nil) - require.NoError(t, err) - - router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/controller/{hash}", ctrl.GetTablesByController) - - rr := httptest.NewRecorder() - router.ServeHTTP(rr, req) - require.Equal(t, http.StatusOK, rr.Code) - - //nolint - expJSON := `[ - { - "controller":"0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", - "name":"test_1337_0", - "structure":"0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99ee" - }, - { - "controller":"0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", - "name":"test2_1337_1", - "structure":"0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99ee" - }]` - require.JSONEq(t, expJSON, rr.Body.String()) - }) - - t.Run("get tables by structure", func(t *testing.T) { - t.Parallel() - req, err := http.NewRequest("GET", "/chain/1337/tables/structure/0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99eek", nil) // nolint - require.NoError(t, err) - - router := mux.NewRouter() - router.HandleFunc("/chain/{chainID}/tables/structure/{hash}", ctrl.GetTablesByStructureHash) - - rr := httptest.NewRecorder() - router.ServeHTTP(rr, req) - require.Equal(t, http.StatusOK, rr.Code) - - //nolint - expJSON := `[ - { - "controller":"0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", - "name":"test_1337_0", - "structure":"0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99ee" - }, - { - "controller":"0x2a891118Cf3a8FdeBb00109ea3ed4E33B82D960f", - "name":"test2_1337_1", - "structure":"0605f6c6705c7c1257edb2d61d94a03ad15f1d253a5a75525c6da8cda34a99ee" - }]` - require.JSONEq(t, expJSON, rr.Body.String()) - }) - - t.Run("get schema by table name", func(t *testing.T) { - t.Parallel() - req, err := http.NewRequest("GET", "/schema/test_1337_0", nil) // nolint - require.NoError(t, err) - - router := mux.NewRouter() - router.HandleFunc("/schema/{table_name}", ctrl.GetSchemaByTableName) - - rr := httptest.NewRecorder() - router.ServeHTTP(rr, req) - require.Equal(t, http.StatusOK, rr.Code) - - //nolint - expJSON := `{ - "columns": [ - { - "name" : "a", - "type" : "int", - "constraints" : ["PRIMARY KEY"] - }, - { - "name" : "b", - "type" : "text", - "constraints" : ["DEFAULT ''"] - } - ], - "table_constraints": ["CHECK check (a > 0)"] - }` - require.JSONEq(t, expJSON, rr.Body.String()) - }) -} - -func TestGetTableWithInvalidID(t *testing.T) { - t.Parallel() - - id := "invalid integer" - path := fmt.Sprintf("/tables/%s", id) - req, err := http.NewRequest("GET", path, nil) - require.NoError(t, err) - - systemService := systemimpl.NewSystemMockService() - systemController := NewUserController(nil, systemService) - - router := mux.NewRouter() - router.HandleFunc("/tables/{id}", systemController.GetTable) - - rr := httptest.NewRecorder() - router.ServeHTTP(rr, req) - - require.Equal(t, http.StatusBadRequest, rr.Code) - - expJSON := `{"message": "Invalid id format"}` - require.JSONEq(t, expJSON, rr.Body.String()) -} - -func TestTableNotFoundMock(t *testing.T) { - t.Parallel() - - req, err := http.NewRequest("GET", "/tables/100", nil) - require.NoError(t, err) - - systemService := systemimpl.NewSystemMockErrService() - systemController := NewUserController(nil, systemService) - - router := mux.NewRouter() - router.HandleFunc("/tables/{tableId}", systemController.GetTable) - - rr := httptest.NewRecorder() - router.ServeHTTP(rr, req) - - require.Equal(t, http.StatusInternalServerError, rr.Code) - - expJSON := `{"message": "Failed to fetch metadata"}` - require.JSONEq(t, expJSON, rr.Body.String()) -} diff --git a/internal/router/router.go b/internal/router/router.go index 0c7d554e..94abc704 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -28,7 +28,6 @@ func ConfiguredRouter( if err := server.RegisterName("tableland", rpcService); err != nil { return nil, fmt.Errorf("failed to register a json-rpc service: %s", err) } - userCtrl := controllers.NewUserController(tableland, systemService) // General router configuration. router := newRouter() @@ -46,12 +45,14 @@ func ConfiguredRouter( return nil, fmt.Errorf("creating rate limit controller middleware: %s", err) } + ctrl := controllers.NewUserController(tableland, systemService) + // TODO(json-rpc): remove this when dropping support. // APIs Legacy (REST + JSON-RPC) - configureLegacyRoutes(router, server, supportedChainIDs, rateLim, userCtrl) + configureLegacyRoutes(router, server, supportedChainIDs, rateLim, ctrl) // APIs V1 - if err := configureAPIV1Routes(router, supportedChainIDs, rateLim, userCtrl); err != nil { + if err := configureAPIV1Routes(router, supportedChainIDs, rateLim, ctrl); err != nil { return nil, fmt.Errorf("configuring API v1: %s", err) } From 1fcd6f6565c180245c5a9fe0708a6234ca11acc9 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 15 Dec 2022 14:32:50 -0300 Subject: [PATCH 079/101] rebase fixes Signed-off-by: Ignacio Hagopian --- internal/router/controllers/controller.go | 11 +- internal/router/controllers/system.go | 287 ---------------------- 2 files changed, 8 insertions(+), 290 deletions(-) delete mode 100644 internal/router/controllers/system.go diff --git a/internal/router/controllers/controller.go b/internal/router/controllers/controller.go index 9a6f867d..867f3b9a 100644 --- a/internal/router/controllers/controller.go +++ b/internal/router/controllers/controller.go @@ -238,11 +238,11 @@ func (c *UserController) Version(rw http.ResponseWriter, _ *http.Request) { // GetReceiptByTransactionHash handles request asking for a transaction receipt. func (c *UserController) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { - rw.Header().Set("Content-Type", "application/json") ctx := r.Context() paramTxnHash := mux.Vars(r)["transactionHash"] if _, err := common.ParseHexOrString(paramTxnHash); err != nil { + rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusBadRequest) log.Ctx(ctx).Error().Err(err).Msg("invalid transaction hash") _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Invalid transaction hash"}) @@ -252,6 +252,7 @@ func (c *UserController) GetReceiptByTransactionHash(rw http.ResponseWriter, r * receipt, exists, err := c.systemService.GetReceiptByTransactionHash(ctx, txnHash) if err != nil { + rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusBadRequest) log.Ctx(ctx).Error().Err(err).Msg("get receipt by transaction hash") _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Get receipt by transaction hash failed"}) @@ -274,6 +275,8 @@ func (c *UserController) GetReceiptByTransactionHash(rw http.ResponseWriter, r * receiptResponse.Error_ = *receipt.Error receiptResponse.ErrorEventIdx = int32(*receipt.ErrorEventIdx) } + + rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusOK) _ = json.NewEncoder(rw).Encode(receiptResponse) } @@ -281,11 +284,11 @@ func (c *UserController) GetReceiptByTransactionHash(rw http.ResponseWriter, r * // GetTable handles the GET /chain/{chainID}/tables/{tableId} call. func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() - rw.Header().Set("Content-type", "application/json") vars := mux.Vars(r) id, err := tables.NewTableID(vars["tableId"]) if err != nil { + rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusBadRequest) log.Ctx(ctx). Error(). @@ -301,6 +304,7 @@ func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { metadata, err := c.systemService.GetTableMetadata(ctx, id) if err == system.ErrTableNotFound { if !isAPIV1 { + rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusOK) _ = json.NewEncoder(rw).Encode(metadata) return @@ -309,6 +313,7 @@ func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { return } if err != nil { + rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusInternalServerError) log.Ctx(ctx). Error(). @@ -348,8 +353,8 @@ func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { } copy(metadataV1.Schema.TableConstraints, metadata.Schema.TableConstraints) + rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(metadataV1) } diff --git a/internal/router/controllers/system.go b/internal/router/controllers/system.go deleted file mode 100644 index 4d3819f2..00000000 --- a/internal/router/controllers/system.go +++ /dev/null @@ -1,287 +0,0 @@ -package controllers - -import ( - "encoding/json" - "net/http" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/gorilla/mux" - "github.com/rs/zerolog/log" - "github.com/textileio/go-tableland/internal/router/controllers/apiv1" - "github.com/textileio/go-tableland/internal/system" - "github.com/textileio/go-tableland/pkg/errors" - "github.com/textileio/go-tableland/pkg/tables" -) - -// GetReceiptByTransactionHash handles request asking for a transaction receipt. -func (c *SystemController) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - paramTxnHash := mux.Vars(r)["transactionHash"] - if _, err := common.ParseHexOrString(paramTxnHash); err != nil { - rw.Header().Set("Content-Type", "application/json") - rw.WriteHeader(http.StatusBadRequest) - log.Ctx(ctx).Error().Err(err).Msg("invalid transaction hash") - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Invalid transaction hash"}) - return - } - txnHash := common.HexToHash(paramTxnHash) - - receipt, exists, err := c.systemService.GetReceiptByTransactionHash(ctx, txnHash) - if err != nil { - rw.Header().Set("Content-Type", "application/json") - rw.WriteHeader(http.StatusBadRequest) - log.Ctx(ctx).Error().Err(err).Msg("get receipt by transaction hash") - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Get receipt by transaction hash failed"}) - return - } - if !exists { - rw.WriteHeader(http.StatusNotFound) - return - } - - receiptResponse := apiv1.TransactionReceipt{ - TransactionHash: paramTxnHash, - BlockNumber: receipt.BlockNumber, - ChainId: int32(receipt.ChainID), - } - if receipt.TableID != nil { - receiptResponse.TableId = receipt.TableID.String() - } - if receipt.Error != nil { - receiptResponse.Error_ = *receipt.Error - receiptResponse.ErrorEventIdx = int32(*receipt.ErrorEventIdx) - } - - rw.Header().Set("Content-Type", "application/json") - rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(receiptResponse) -} - -// GetTable handles the GET /chain/{chainID}/tables/{tableId} call. -func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - vars := mux.Vars(r) - - id, err := tables.NewTableID(vars["tableId"]) - if err != nil { - rw.Header().Set("Content-type", "application/json") - rw.WriteHeader(http.StatusBadRequest) - log.Ctx(ctx). - Error(). - Err(err). - Msg("invalid id format") - - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Invalid id format"}) - return - } - - isAPIV1 := strings.HasPrefix(r.RequestURI, "/api/v1/tables") - - metadata, err := c.systemService.GetTableMetadata(ctx, id) - if err == system.ErrTableNotFound { - if !isAPIV1 { - rw.Header().Set("Content-type", "application/json") - rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(metadata) - return - } - rw.WriteHeader(http.StatusNotFound) - return - } - if err != nil { - rw.Header().Set("Content-type", "application/json") - rw.WriteHeader(http.StatusInternalServerError) - log.Ctx(ctx). - Error(). - Err(err). - Str("id", id.String()). - Msg("failed to fetch metadata") - - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Failed to fetch metadata"}) - return - } - - metadataV1 := apiv1.Table{ - Name: metadata.Name, - ExternalUrl: metadata.ExternalURL, - AnimationUrl: metadata.AnimationURL, - Image: metadata.Image, - Attributes: make([]apiv1.TableAttributes, len(metadata.Attributes)), - Schema: &apiv1.Schema{ - Columns: make([]apiv1.Column, len(metadata.Schema.Columns)), - TableConstraints: make([]string, len(metadata.Schema.TableConstraints)), - }, - } - for i, attr := range metadata.Attributes { - metadataV1.Attributes[i] = apiv1.TableAttributes{ - DisplayType: attr.DisplayType, - TraitType: attr.TraitType, - Value: attr.Value, - } - } - for i, schemaColumn := range metadata.Schema.Columns { - metadataV1.Schema.Columns[i] = apiv1.Column{ - Name: schemaColumn.Name, - Type_: schemaColumn.Type, - Constraints: make([]string, len(schemaColumn.Constraints)), - } - copy(metadataV1.Schema.Columns[i].Constraints, schemaColumn.Constraints) - } - copy(metadataV1.Schema.TableConstraints, metadata.Schema.TableConstraints) - - rw.Header().Set("Content-type", "application/json") - rw.WriteHeader(http.StatusOK) - enc := json.NewEncoder(rw) - enc.SetEscapeHTML(false) - _ = enc.Encode(metadataV1) -} - -// GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. -// TODO(json-rpc): delete when dropping support. -func (c *UserController) GetTablesByController(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - rw.Header().Set("Content-type", "application/json") - vars := mux.Vars(r) - - controller := vars["address"] - tables, err := c.systemService.GetTablesByController(ctx, controller) - if err != nil { - rw.WriteHeader(http.StatusInternalServerError) - log.Ctx(ctx). - Error(). - Err(err). - Str("request_address", controller). - Msg("failed to fetch tables") - - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Failed to fetch tables"}) - return - } - - // This struct is used since we don't want to return an ID field. - // The Name will be {optional-prefix}_{chainId}_{tableId}. - // Not doing `omitempty` in tableland.Table since - // that feels hacky. Looks safer to define a separate type here at the handler level. - type tableNameIDUnified struct { - Controller string `json:"controller"` - Name string `json:"name"` - Structure string `json:"structure"` - } - retTables := make([]tableNameIDUnified, len(tables)) - for i, t := range tables { - retTables[i] = tableNameIDUnified{ - Controller: t.Controller, - Name: t.Name(), - Structure: t.Structure, - } - } - - rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(retTables) -} - -// GetTablesByStructureHash handles the GET /chain/{id}/tables/structure/{hash} call. -// TODO(json-rpc): delete when dropping support. -func (c *UserController) GetTablesByStructureHash(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - rw.Header().Set("Content-type", "application/json") - vars := mux.Vars(r) - - hash := vars["hash"] - tables, err := c.systemService.GetTablesByStructure(ctx, hash) - if err != nil { - rw.WriteHeader(http.StatusInternalServerError) - log.Ctx(ctx). - Error(). - Err(err). - Str("hash", hash). - Msg("failed to fetch tables") - - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Failed to fetch tables"}) - return - } - - type tableNameIDUnified struct { - Controller string `json:"controller"` - Name string `json:"name"` - Structure string `json:"structure"` - } - retTables := make([]tableNameIDUnified, len(tables)) - for i, t := range tables { - retTables[i] = tableNameIDUnified{ - Controller: t.Controller, - Name: t.Name(), - Structure: t.Structure, - } - } - - rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(retTables) -} - -// GetSchemaByTableName handles the GET /schema/{table_name} call. -// TODO(json-rpc): delete when droppping support. -func (c *UserController) GetSchemaByTableName(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - rw.Header().Set("Content-type", "application/json") - vars := mux.Vars(r) - - name := vars["table_name"] - schema, err := c.systemService.GetSchemaByTableName(ctx, name) - if err != nil { - rw.WriteHeader(http.StatusInternalServerError) - log.Ctx(ctx). - Error(). - Err(err). - Str("table_name", name). - Msg("failed to fetch tables") - - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Failed to get schema from table"}) - return - } - - if len(schema.Columns) == 0 { - rw.WriteHeader(http.StatusInternalServerError) - log.Ctx(ctx). - Warn(). - Str("name", name). - Msg("table does not exist") - - _ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "Table does not exist"}) - return - } - - type Column struct { - Name string `json:"name"` - Type string `json:"type"` - Constraints []string `json:"constraints"` - } - - type response struct { - Columns []Column `json:"columns"` - TableConstraints []string `json:"table_constraints"` - } - - columns := make([]Column, len(schema.Columns)) - for i, col := range schema.Columns { - columns[i] = Column{ - Name: col.Name, - Type: col.Type, - Constraints: col.Constraints, - } - } - - rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(response{ - Columns: columns, - TableConstraints: schema.TableConstraints, - }) -} - -// HealthHandler serves health check requests. -func HealthHandler(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) -} From b5d0a7de5e24c92d4b0f032a792be8f16e59b318 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 15 Dec 2022 14:38:16 -0300 Subject: [PATCH 080/101] last nit renaming Signed-off-by: Ignacio Hagopian --- internal/router/controllers/controller.go | 28 +++++++++---------- .../router/controllers/controller_test.go | 20 ++++++------- internal/router/router.go | 20 ++++++------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/internal/router/controllers/controller.go b/internal/router/controllers/controller.go index 867f3b9a..1797385d 100644 --- a/internal/router/controllers/controller.go +++ b/internal/router/controllers/controller.go @@ -29,15 +29,15 @@ type SQLRunner interface { RunReadQuery(ctx context.Context, stmt string) (*tableland.TableData, error) } -// UserController defines the HTTP handlers for interacting with user tables. -type UserController struct { +// Controller defines the HTTP handlers for interacting with user tables. +type Controller struct { runner SQLRunner systemService system.SystemService } -// NewUserController creates a new UserController. -func NewUserController(runner SQLRunner, svc system.SystemService) *UserController { - return &UserController{ +// NewController creates a new Controller. +func NewController(runner SQLRunner, svc system.SystemService) *Controller { + return &Controller{ runner: runner, systemService: svc, } @@ -138,7 +138,7 @@ func userRowToMap(cols []tableland.Column, row []*tableland.ColumnValue) map[str // GetTableRow handles the GET /chain/{chainID}/tables/{id}/{key}/{value} call. // Use format=erc721 query param to generate JSON for ERC721 metadata. // TODO(json-rpc): delete method when dropping support. -func (c *UserController) GetTableRow(rw http.ResponseWriter, r *http.Request) { +func (c *Controller) GetTableRow(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) format := r.URL.Query().Get("format") @@ -220,7 +220,7 @@ func (c *UserController) GetTableRow(rw http.ResponseWriter, r *http.Request) { } // Version returns git information of the running binary. -func (c *UserController) Version(rw http.ResponseWriter, _ *http.Request) { +func (c *Controller) Version(rw http.ResponseWriter, _ *http.Request) { rw.Header().Set("Content-type", "application/json") summary := buildinfo.GetSummary() rw.WriteHeader(http.StatusOK) @@ -237,7 +237,7 @@ func (c *UserController) Version(rw http.ResponseWriter, _ *http.Request) { } // GetReceiptByTransactionHash handles request asking for a transaction receipt. -func (c *UserController) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { +func (c *Controller) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() paramTxnHash := mux.Vars(r)["transactionHash"] @@ -282,7 +282,7 @@ func (c *UserController) GetReceiptByTransactionHash(rw http.ResponseWriter, r * } // GetTable handles the GET /chain/{chainID}/tables/{tableId} call. -func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { +func (c *Controller) GetTable(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := mux.Vars(r) @@ -360,7 +360,7 @@ func (c *UserController) GetTable(rw http.ResponseWriter, r *http.Request) { // GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. // TODO(json-rpc): delete when dropping support. -func (c *UserController) GetTablesByController(rw http.ResponseWriter, r *http.Request) { +func (c *Controller) GetTablesByController(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() rw.Header().Set("Content-type", "application/json") vars := mux.Vars(r) @@ -403,7 +403,7 @@ func (c *UserController) GetTablesByController(rw http.ResponseWriter, r *http.R // GetTablesByStructureHash handles the GET /chain/{id}/tables/structure/{hash} call. // TODO(json-rpc): delete when dropping support. -func (c *UserController) GetTablesByStructureHash(rw http.ResponseWriter, r *http.Request) { +func (c *Controller) GetTablesByStructureHash(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() rw.Header().Set("Content-type", "application/json") @@ -443,7 +443,7 @@ func (c *UserController) GetTablesByStructureHash(rw http.ResponseWriter, r *htt // GetSchemaByTableName handles the GET /schema/{table_name} call. // TODO(json-rpc): delete when droppping support. -func (c *UserController) GetSchemaByTableName(rw http.ResponseWriter, r *http.Request) { +func (c *Controller) GetSchemaByTableName(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() rw.Header().Set("Content-type", "application/json") @@ -508,7 +508,7 @@ func HealthHandler(w http.ResponseWriter, _ *http.Request) { // GetTableQuery handles the GET /query?s=[statement] call. // Use mode=columns|rows|json|lines query param to control output format. -func (c *UserController) GetTableQuery(rw http.ResponseWriter, r *http.Request) { +func (c *Controller) GetTableQuery(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-Type", "application/json") stm := r.URL.Query().Get("s") // TODO(json-rpc): remove query parameter "s" when dropping support. @@ -549,7 +549,7 @@ func (c *UserController) GetTableQuery(rw http.ResponseWriter, r *http.Request) _, _ = rw.Write(formatted) } -func (c *UserController) runReadRequest( +func (c *Controller) runReadRequest( ctx context.Context, stm string, rw http.ResponseWriter, diff --git a/internal/router/controllers/controller_test.go b/internal/router/controllers/controller_test.go index 4984076f..7fb8ecd0 100644 --- a/internal/router/controllers/controller_test.go +++ b/internal/router/controllers/controller_test.go @@ -22,7 +22,7 @@ func TestGetTableRow(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1", nil) require.NoError(t, err) - ctrl := NewUserController(newTableRowRunnerMock(t), nil) + ctrl := NewController(newTableRowRunnerMock(t), nil) router := mux.NewRouter() router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", ctrl.GetTableRow) @@ -41,7 +41,7 @@ func TestERC721Metadata(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1?format=erc721&name=id&image=image&description=description&external_url=external_url&attributes[0][column]=base&attributes[0][trait_type]=Base&attributes[1][column]=eyes&attributes[1][trait_type]=Eyes&attributes[2][column]=mouth&attributes[2][trait_type]=Mouth&attributes[3][column]=level&attributes[3][trait_type]=Level&attributes[4][column]=stamina&attributes[4][trait_type]=Stamina&attributes[5][column]=personality&attributes[5][trait_type]=Personality&attributes[6][column]=aqua_power&attributes[6][display_type]=boost_number&attributes[6][trait_type]=Aqua%20Power&attributes[7][column]=stamina_increase&attributes[7][display_type]=boost_percentage&attributes[7][trait_type]=Stamina%20Increase&attributes[8][column]=generation&attributes[8][display_type]=number&attributes[8][trait_type]=Generation", nil) // nolint require.NoError(t, err) - ctrl := NewUserController(newTableRowRunnerMock(t), nil) + ctrl := NewController(newTableRowRunnerMock(t), nil) router := mux.NewRouter() router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", ctrl.GetTableRow) @@ -63,7 +63,7 @@ func TestBadQuery(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/invalid_column/0", nil) require.NoError(t, err) - ctrl := NewUserController(r, nil) + ctrl := NewController(r, nil) router := mux.NewRouter() router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", ctrl.GetTableRow) @@ -106,7 +106,7 @@ func TestRowNotFound(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1", nil) require.NoError(t, err) - ctrl := NewUserController(r, nil) + ctrl := NewController(r, nil) router := mux.NewRouter() router.HandleFunc("/chain/{chainID}/tables/{id}/{key}/{value}", ctrl.GetTableRow) @@ -150,7 +150,7 @@ func TestQuery(t *testing.T) { nil, ) - ctrl := NewUserController(r, nil) + ctrl := NewController(r, nil) router := mux.NewRouter() router.HandleFunc("/query", ctrl.GetTableQuery) @@ -210,7 +210,7 @@ func TestLegacyQuery(t *testing.T) { nil, ) - ctrl := NewUserController(r, nil) + ctrl := NewController(r, nil) router := mux.NewRouter() router.HandleFunc("/query", ctrl.GetTableQuery) @@ -253,7 +253,7 @@ func TestQueryExtracted(t *testing.T) { nil, ) - ctrl := NewUserController(r, nil) + ctrl := NewController(r, nil) router := mux.NewRouter() router.HandleFunc("/query", ctrl.GetTableQuery) @@ -286,7 +286,7 @@ func TestGetTablesByMocked(t *testing.T) { t.Parallel() systemService := systemimpl.NewSystemMockService() - ctrl := NewUserController(nil, systemService) + ctrl := NewController(nil, systemService) t.Run("get table metadata", func(t *testing.T) { t.Parallel() @@ -406,7 +406,7 @@ func TestGetTableWithInvalidID(t *testing.T) { require.NoError(t, err) systemService := systemimpl.NewSystemMockService() - systemController := NewUserController(nil, systemService) + systemController := NewController(nil, systemService) router := mux.NewRouter() router.HandleFunc("/tables/{id}", systemController.GetTable) @@ -427,7 +427,7 @@ func TestTableNotFoundMock(t *testing.T) { require.NoError(t, err) systemService := systemimpl.NewSystemMockErrService() - systemController := NewUserController(nil, systemService) + systemController := NewController(nil, systemService) router := mux.NewRouter() router.HandleFunc("/tables/{tableId}", systemController.GetTable) diff --git a/internal/router/router.go b/internal/router/router.go index 94abc704..d139c77e 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -45,7 +45,7 @@ func ConfiguredRouter( return nil, fmt.Errorf("creating rate limit controller middleware: %s", err) } - ctrl := controllers.NewUserController(tableland, systemService) + ctrl := controllers.NewController(tableland, systemService) // TODO(json-rpc): remove this when dropping support. // APIs Legacy (REST + JSON-RPC) @@ -64,21 +64,21 @@ func configureLegacyRoutes( server *rpc.Server, supportedChainIDs []tableland.ChainID, rateLim mux.MiddlewareFunc, - userCtrl *controllers.UserController, + ctrl *controllers.Controller, ) { router.post("/rpc", func(rw http.ResponseWriter, r *http.Request) { server.ServeHTTP(rw, r) }, middlewares.WithLogging, middlewares.OtelHTTP("rpc"), middlewares.Authentication, rateLim) // Gateway configuration. - router.get("/chain/{chainId}/tables/{tableId}", userCtrl.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint - router.get("/chain/{chainId}/tables/{id}/{key}/{value}", userCtrl.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint - router.get("/chain/{chainId}/tables/controller/{address}", userCtrl.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint - router.get("/chain/{chainId}/tables/structure/{hash}", userCtrl.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint - router.get("/schema/{table_name}", userCtrl.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint + router.get("/chain/{chainId}/tables/{tableId}", ctrl.GetTable, middlewares.WithLogging, middlewares.OtelHTTP("GetTable"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/{id}/{key}/{value}", ctrl.GetTableRow, middlewares.WithLogging, middlewares.OtelHTTP("GetTableRow"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/controller/{address}", ctrl.GetTablesByController, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByController"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/chain/{chainId}/tables/structure/{hash}", ctrl.GetTablesByStructureHash, middlewares.WithLogging, middlewares.OtelHTTP("GetTablesByStructureHash"), middlewares.RESTChainID(supportedChainIDs), rateLim) // nolint + router.get("/schema/{table_name}", ctrl.GetSchemaByTableName, middlewares.WithLogging, middlewares.OtelHTTP("GetSchemaFromTableName"), rateLim) // nolint - router.get("/query", userCtrl.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint - router.get("/version", userCtrl.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint + router.get("/query", ctrl.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint + router.get("/version", ctrl.Version, middlewares.WithLogging, middlewares.OtelHTTP("Version"), rateLim) // nolint // Health endpoint configuration. router.get("/healthz", controllers.HealthHandler) @@ -89,7 +89,7 @@ func configureAPIV1Routes( router *Router, supportedChainIDs []tableland.ChainID, rateLim mux.MiddlewareFunc, - userCtrl *controllers.UserController, + userCtrl *controllers.Controller, ) error { handlers := map[string]struct { handler http.HandlerFunc From fabb69e67a2f19ef35d990674eb92e0b5cbb7bd7 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 23 Dec 2022 10:38:33 -0300 Subject: [PATCH 081/101] controllers: disable html escaping in GetTable Signed-off-by: Ignacio Hagopian --- internal/router/controllers/controller.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/router/controllers/controller.go b/internal/router/controllers/controller.go index 1797385d..2999831b 100644 --- a/internal/router/controllers/controller.go +++ b/internal/router/controllers/controller.go @@ -355,7 +355,9 @@ func (c *Controller) GetTable(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-type", "application/json") rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(metadataV1) + enc := json.NewEncoder(rw) + enc.SetEscapeHTML(false) + _ = enc.Encode(metadataV1) } // GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. From 5435b8ad8e4c649f4929a010df69e8f9c8cd5fbf Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 13 Dec 2022 16:59:05 -0300 Subject: [PATCH 082/101] ci: generate binaries Signed-off-by: Ignacio Hagopian --- .github/workflows/binaries.yml | 61 ++++++++++++++++++++++++++++++++++ .github/workflows/deploy.yml | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/binaries.yml diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml new file mode 100644 index 00000000..27370ab2 --- /dev/null +++ b/.github/workflows/binaries.yml @@ -0,0 +1,61 @@ +name: Generate binaries +on: + release: + types: + - created +jobs: + binaries: + strategy: + matrix: + include: + - os: ubuntu-latest + asset_name: api-linux-amd64.tar.gz + compress_cmd: tar -czvf + build_cmd: docker run -v $PWD:/data golang:1.19 bash -c "cd /data && go build ./cmd/api" + - os: windows-latest + asset_name: api-windows-amd64.zip + compress_cmd: tar.exe -a -c -f + build_cmd: go build -o api ./cmd/api + - os: macos-latest + asset_name: api-darwin-amd64.tar.gz + compress_cmd: tar -czvf + build_cmd: go build -o api ./cmd/api + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: v1.19.x + - name: Build binary + run: ${{ matrix.build_cmd }} + - name: Pack output + run: ${{ matrix.compress_cmd }} ${{ matrix.asset_name }} api + - name: Upload binary + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ${{ matrix.asset_name }} + asset_name: ${{ matrix.asset_name }} + tag: ${{ github.ref_name }} + overwrite: true + docker: + runs-on: ubuntu-latest + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v3 + with: + file: ./cmd/api/Dockerfile + push: true + tags: textile/tableland:latest,textile/tableland:${{ github.ref_name }} + platforms: linux/amd64, linux/arm64 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7df6c4bd..2f76533d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,7 +14,7 @@ on: jobs: deploy: - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[stagingdeploy]') || contains(github.event.head_commit.message, '[testnetdeploy]') || contains(github.event.head_commit.message, '[mainnetdeploy]') + if: contains(github.event.head_commit.message, '[stagingdeploy]') || contains(github.event.head_commit.message, '[testnetdeploy]') || contains(github.event.head_commit.message, '[mainnetdeploy]') name: Deploy runs-on: ubuntu-latest steps: From a13193d31a9d959cf2c984ea8e0e0d3d29a166cc Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 22 Dec 2022 11:29:18 -0300 Subject: [PATCH 083/101] pkg/parsing: include tests for resolving parsed write queries Signed-off-by: Ignacio Hagopian --- pkg/parsing/impl/validator_test.go | 143 +++++++++++++++++++++++++---- 1 file changed, 127 insertions(+), 16 deletions(-) diff --git a/pkg/parsing/impl/validator_test.go b/pkg/parsing/impl/validator_test.go index b70ef327..d777e0f0 100644 --- a/pkg/parsing/impl/validator_test.go +++ b/pkg/parsing/impl/validator_test.go @@ -793,12 +793,13 @@ func TestGetGrantStatementRolesAndPrivileges(t *testing.T) { func TestWriteStatementAddWhereClause(t *testing.T) { t.Parallel() - testCase := []struct { + type subTest struct { name string query string whereClause string expQuery string - }{ + } + testCase := []subTest{ { name: "no-where-clause", query: "UPDATE foo_1337_10 SET id = 1", @@ -814,24 +815,26 @@ func TestWriteStatementAddWhereClause(t *testing.T) { } for _, tc := range testCase { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() + t.Run(tc.name, func(tc subTest) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() - parser := newParser(t, []string{"system_", "registry"}) - mss, err := parser.ValidateMutatingQuery(tc.query, 1337) - require.NoError(t, err) - require.Len(t, mss, 1) + parser := newParser(t, []string{"system_", "registry"}) + mss, err := parser.ValidateMutatingQuery(tc.query, 1337) + require.NoError(t, err) + require.Len(t, mss, 1) - ws, ok := mss[0].(parsing.WriteStmt) - require.True(t, ok) + ws, ok := mss[0].(parsing.WriteStmt) + require.True(t, ok) - err = ws.AddWhereClause(tc.whereClause) - require.NoError(t, err) + err = ws.AddWhereClause(tc.whereClause) + require.NoError(t, err) - sql, err := ws.GetQuery() - require.NoError(t, err) - require.Equal(t, tc.expQuery, sql) - }) + sql, err := ws.GetQuery() + require.NoError(t, err) + require.Equal(t, tc.expQuery, sql) + } + }(tc)) } } @@ -891,6 +894,114 @@ func TestWriteStatementAddReturningClause(t *testing.T) { }) } +type WriteQueryResolver interface { + GetTxnHash() string + GetBlockNumber() uint64 +} + +func TestCustomFunctionResolveWriteQuery(t *testing.T) { + t.Parallel() + + type testCase struct { + name string + query string + wqr WriteQueryResolver + mustFail bool + expQueries []string + } + tests := []testCase{ + { + name: "insert with custom functions", + query: "insert into foo_1337_1 values (txn_hash(), block_num())", + wqr: newWriteQueryResolver("0xDEADBEEF", 100), + expQueries: []string{"insert into foo_1337_1 values ('0xDEADBEEF', 100)"}, + }, + { + name: "update with custom functions", + query: "update foo_1337_1 SET a=txn_hash(), b=block_num() where c in (block_num(), block_num()+1)", + wqr: newWriteQueryResolver("0xDEADBEEF", 100), + expQueries: []string{"update foo_1337_1 SET a='0xDEADBEEF', b=100 where c in (100, 100+1)"}, + }, + { + name: "delete with custom functions", + query: "delete from foo_1337_1 where a=block_num() and b=txn_hash()", + wqr: newWriteQueryResolver("0xDEADBEEF", 100), + expQueries: []string{"delete from foo_1337_1 where a=100 and b='0xDEADBEEF'"}, + }, + { + name: "multiple queries", + query: "insert into foo_1337_1 values (txn_hash()); delete from foo_1337_1 where a=block_num()", + wqr: newWriteQueryResolver("0xDEADBEEF", 100), + expQueries: []string{ + "insert into foo_1337_1 values ('0xDEADBEEF')", + "delete from foo_1337_1 where a=100", + }, + }, + { + name: "block_num() with integer argument", + query: "delete from foo_1337_1 where a=block_num(1337)", + wqr: newWriteQueryResolver("0xDEADBEEF", 100), + mustFail: true, + }, + { + name: "block_num() with string argument", + query: "delete from foo_1337_1 where a=block_num('foo')", + wqr: newWriteQueryResolver("0xDEADBEEF", 100), + mustFail: true, + }, + { + name: "txn_hash() with an integer argument", + query: "insert into foo_1337_1 values (txn_hash(1))", + wqr: newWriteQueryResolver("0xDEADBEEF", 100), + mustFail: true, + }, + { + name: "txn_hash() with a string argument", + query: "insert into foo_1337_1 values (txn_hash('foo'))", + wqr: newWriteQueryResolver("0xDEADBEEF", 100), + mustFail: true, + }, + } + + for _, it := range tests { + t.Run(it.name, func(tc testCase) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + + parser := newParser(t, []string{"system_", "registry"}) + mutStmts, err := parser.ValidateMutatingQuery(tc.query, tableland.ChainID(100)) + require.NoError(t, err) + + for i, stmt := range mutStmts { + q, err := stmt.GetQuery(tc.wqr) + if tc.mustFail { + require.Error(t, err) + return + } + require.Equal(t, tc.expQueries[i], q) + } + } + }(it)) + } +} + +type writeQueryResolver struct { + txnHash string + blockNumber uint64 +} + +func newWriteQueryResolver(txnHash string, blockNumber uint64) *writeQueryResolver { + return &writeQueryResolver{txnHash: txnHash, blockNumber: blockNumber} +} + +func (wqr *writeQueryResolver) GetTxnHash() string { + return wqr.txnHash +} + +func (wqr *writeQueryResolver) GetBlockNumber() uint64 { + return wqr.blockNumber +} + func newParser(t *testing.T, prefixes []string, opts ...parsing.Option) parsing.SQLValidator { t.Helper() p, err := parser.New(prefixes, opts...) From d7806845525211b73afdf9e2c1191e99c457d352 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 22 Dec 2022 11:29:19 -0300 Subject: [PATCH 084/101] pkg/eventprocessor: include custom functions e2e tests Signed-off-by: Ignacio Hagopian --- .../impl/executor/impl/executor_test.go | 38 ++++-- .../impl/txnscope_runsql_customfuncs_test.go | 123 ++++++++++++++++++ .../executor/impl/txnscope_runsql_test.go | 103 ++++++++------- .../impl/txnscope_setcontroller_test.go | 8 +- .../executor/impl/txnscope_transfer_test.go | 6 +- 5 files changed, 218 insertions(+), 60 deletions(-) create mode 100644 pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go diff --git a/pkg/eventprocessor/impl/executor/impl/executor_test.go b/pkg/eventprocessor/impl/executor/impl/executor_test.go index ffb99551..b0c643aa 100644 --- a/pkg/eventprocessor/impl/executor/impl/executor_test.go +++ b/pkg/eventprocessor/impl/executor/impl/executor_test.go @@ -26,7 +26,7 @@ func TestReceiptExists(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithTable(t, 0) + ex, _ := newExecutorWithIntegerTable(t, 0) txnHash := "0x0000000000000000000000000000000000000000000000000000000000001234" @@ -148,27 +148,41 @@ func TestMultiEventTxnBlock(t *testing.T) { { // Check 1) and 3). require.True(t, existsTableWithName(t, dbURI, "bar_1337_100")) - require.Equal(t, 2, tableRowCountT100(t, dbURI, "select count(*) from bar_1337_100")) + require.Equal(t, 2, tableReadInteger(t, dbURI, "select count(*) from bar_1337_100")) // Check 2). require.False(t, existsTableWithName(t, dbURI, "foo_1337_101")) } } -func tableRowCountT100(t *testing.T, dbURI string, query string) int { +func tableReadInteger(t *testing.T, dbURI string, query string) int { t.Helper() db, err := sql.Open("sqlite3", dbURI) require.NoError(t, err) row := db.QueryRowContext(context.Background(), query) - var rowCount int - if err = row.Scan(&rowCount); err == sql.ErrNoRows { + var integer int + if err = row.Scan(&integer); err == sql.ErrNoRows { return 0 } require.NoError(t, err) - return rowCount + return integer +} + +func tableReadString(t *testing.T, dbURI string, query string) string { + t.Helper() + + db, err := sql.Open("sqlite3", dbURI) + require.NoError(t, err) + + row := db.QueryRowContext(context.Background(), query) + + var str string + require.NoError(t, row.Scan(&str)) + + return str } func existsTableWithName(t *testing.T, dbURI string, tableName string) bool { @@ -205,7 +219,15 @@ func newExecutor(t *testing.T, rowsLimit int) (*Executor, string) { return exec, dbURI } -func newExecutorWithTable(t *testing.T, rowsLimit int) (*Executor, string) { +func newExecutorWithStringTable(t *testing.T, rowsLimit int) (*Executor, string) { + return newExecutorWithTable(t, rowsLimit, "create table foo_1337 (zar text)") +} + +func newExecutorWithIntegerTable(t *testing.T, rowsLimit int) (*Executor, string) { + return newExecutorWithTable(t, rowsLimit, "create table foo_1337 (zar int)") +} + +func newExecutorWithTable(t *testing.T, rowsLimit int, createStmt string) (*Executor, string) { t.Helper() ex, dbURI := newExecutor(t, rowsLimit) @@ -225,7 +247,7 @@ func newExecutorWithTable(t *testing.T, rowsLimit int) (*Executor, string) { ðereum.ContractCreateTable{ Owner: common.HexToAddress("0xb451cee4A42A652Fe77d373BAe66D42fd6B8D8FF"), TableId: id.ToBigInt(), - Statement: "create table foo_1337 (zar text)", + Statement: createStmt, }, }, }) diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go new file mode 100644 index 00000000..334b2865 --- /dev/null +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go @@ -0,0 +1,123 @@ +package impl + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCustomFunctionsWriteQuery(t *testing.T) { + t.Parallel() + type subTest struct { + name string + query string + mustFail bool + newExecutorWithTable func() (*Executor, string) + assertExpectation func(dbURI string, txnHash string) + } + + checkTxnHash := func(dbURI string, txnHash string) { + require.Equal(t, txnHash, tableReadString(t, dbURI, "select * from foo_1337_100")) + } + checkBlockNumberEq1 := func(dbURI string, txnHash string) { + require.Equal(t, 1, tableReadInteger(t, dbURI, "select * from foo_1337_100")) + } + newExecutorWithIntegerTable := func() (*Executor, string) { return newExecutorWithIntegerTable(t, 0) } + newExecutorWithStringTable := func() (*Executor, string) { return newExecutorWithStringTable(t, 0) } + + subTests := []subTest{ + // txn_hash() + { + name: "txn_hash() lowercase", + query: "insert into foo_1337_100 values (txn_hash())", + newExecutorWithTable: newExecutorWithStringTable, + assertExpectation: checkTxnHash, + }, + { + name: "txn_hash() mixed case", + query: "insert into foo_1337_100 values (TxN_HaSh())", + newExecutorWithTable: newExecutorWithStringTable, + assertExpectation: checkTxnHash, + }, + { + name: "txn_hash() upper case", + query: "insert into foo_1337_100 values (TXN_HASH())", + newExecutorWithTable: newExecutorWithStringTable, + assertExpectation: checkTxnHash, + }, + { + name: "txn_hash() with integer argument", + query: "insert into foo_1337_100 values (txn_hash(1))", + newExecutorWithTable: newExecutorWithStringTable, + mustFail: true, + }, + { + name: "txn_hash() with string argument", + query: "insert into foo_1337_100 values (txn_hash('i must not have arguments'))", + newExecutorWithTable: newExecutorWithStringTable, + mustFail: true, + }, + + // block_num() + { + name: "block_num() lower case", + query: "insert into foo_1337_100 values (block_num())", + newExecutorWithTable: newExecutorWithIntegerTable, + assertExpectation: checkBlockNumberEq1, + }, + { + name: "block_num() mixed case", + query: "insert into foo_1337_100 values (BlOcK_nUm())", + newExecutorWithTable: newExecutorWithIntegerTable, + assertExpectation: checkBlockNumberEq1, + }, + { + name: "block_num() upper case", + query: "insert into foo_1337_100 values (BLOCK_NUM())", + newExecutorWithTable: newExecutorWithIntegerTable, + assertExpectation: checkBlockNumberEq1, + }, + { + // block_num() must be valid **only** for read queries. + name: "block_num() with integer argument", + query: "insert into foo_1337_100 values (block_num(1337))", + newExecutorWithTable: newExecutorWithIntegerTable, + mustFail: true, + }, + { + name: "block_num() with string argument", + query: "insert into foo_1337_100 values (block_num('nope'))", + newExecutorWithTable: newExecutorWithIntegerTable, + mustFail: true, + }, + } + + for _, test := range subTests { + t.Run(test.name, func(test subTest) func(t *testing.T) { + return func(t *testing.T) { + ctx := context.Background() + ex, dbURI := test.newExecutorWithTable() + + bs, err := ex.NewBlockScope(ctx, 0) + require.NoError(t, err) + + txnHash, res, err := execTxnWithRunSQLEvents(t, bs, []string{test.query}) + if test.mustFail { + require.Error(t, err) + } + require.NoError(t, err) + require.NotNil(t, res.TableID) + require.Equal(t, int64(100), res.TableID.ToBigInt().Int64()) + + require.NoError(t, bs.Commit()) + require.NoError(t, bs.Close()) + require.NoError(t, ex.Close(ctx)) + + require.Equal(t, 1, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) + + test.assertExpectation(dbURI, txnHash.Hex()) + } + }(test)) + } +} diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go index 1f4189a7..b9658cc4 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go @@ -2,10 +2,13 @@ package impl import ( "context" + "encoding/binary" "fmt" "math/big" + "math/rand" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed" @@ -22,7 +25,7 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -33,14 +36,14 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { require.NoError(t, bs.Close()) require.NoError(t, ex.Close(ctx)) - require.Equal(t, 1, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100")) + require.Equal(t, 1, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) }) t.Run("multiple inserts", func(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -54,20 +57,20 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { require.NoError(t, ex.Close(ctx)) // 3 txns each with one event with a total of 4 inserts. - require.Equal(t, 4, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100")) + require.Equal(t, 4, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) }) t.Run("multiple with single failure", func(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) assertExecTxnWithRunSQLEvents(t, bs, []string{`insert into foo_1337_100 values ('onez')`}) - res, err := execTxnWithRunSQLEvents(t, bs, []string{`insert into foo_1337_100 values ('twoz');insert into foo_1337_101 values ('threez')`}) //nolint + _, res, err := execTxnWithRunSQLEvents(t, bs, []string{`insert into foo_1337_100 values ('twoz');insert into foo_1337_101 values ('threez')`}) //nolint require.NoError(t, err) require.NotNil(t, res.Error) require.Equal(t, 0, *res.ErrorEventIdx) @@ -84,14 +87,14 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { // We check that we see 2 inserted rows, from the first and third transaction. // Despite the first query of the second transaction was correct, it must be rollbacked since the second // query wasn't. - require.Equal(t, 2, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100")) + require.Equal(t, 2, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) }) t.Run("with abrupt close", func(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -106,14 +109,14 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { // The opened batch wasn't txnp.CloseBatch(), but we simply // closed the whole store. This should rollback any ongoing // opened batch and leave db state correctly. - require.Equal(t, 0, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100")) + require.Equal(t, 0, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) }) t.Run("one grant", func(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -143,7 +146,7 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -190,7 +193,7 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -227,7 +230,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithTable(t, 0) + ex, _ := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -236,7 +239,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { assertExecTxnWithSetController(t, bs, "0x1") policy := ethereum.ITablelandControllerPolicy{AllowInsert: false} - res, err := execTxnWithRunSQLEventsAndPolicy( + _, res, err := execTxnWithRunSQLEventsAndPolicy( t, bs, []string{`insert into foo_1337_100 values ('one');`}, policy) require.NoError(t, err) require.Contains(t, *res.Error, "insert is not allowed by policy") @@ -246,7 +249,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithTable(t, 0) + ex, _ := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -256,7 +259,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { require.NoError(t, err) policy := ethereum.ITablelandControllerPolicy{AllowUpdate: false} - res, err := execTxnWithRunSQLEventsAndPolicy( + _, res, err := execTxnWithRunSQLEventsAndPolicy( t, bs, []string{`update foo_1337_100 set zar = 'three';`}, policy) require.NoError(t, err) require.Contains(t, *res.Error, "update is not allowed by policy") @@ -266,7 +269,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithTable(t, 0) + ex, _ := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -276,7 +279,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { require.NoError(t, err) policy := ethereum.ITablelandControllerPolicy{AllowDelete: false} - res, err := execTxnWithRunSQLEventsAndPolicy( + _, res, err := execTxnWithRunSQLEventsAndPolicy( t, bs, []string{`DELETE FROM foo_1337_100`}, policy) require.NoError(t, err) require.Contains(t, *res.Error, "delete is not allowed by policy") @@ -286,7 +289,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithTable(t, 0) + ex, _ := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -297,7 +300,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { policy := ethereum.ITablelandControllerPolicy{AllowUpdate: true, UpdatableColumns: []string{"zaz"}} // tries to update zar and not zaz - res, err := execTxnWithRunSQLEventsAndPolicy( + _, res, err := execTxnWithRunSQLEventsAndPolicy( t, bs, []string{`update foo_1337_100 set zar = 'three';`}, policy) require.NoError(t, err) require.Contains(t, *res.Error, "column zar is not allowed") @@ -307,7 +310,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -327,7 +330,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { UpdatableColumns: []string{"zar"}, } // send an update that updates all rows with a policy to restricts the update - res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{`update foo_1337_100 set zar = 'three'`}, policy) + _, res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{`update foo_1337_100 set zar = 'three'`}, policy) require.NoError(t, err) require.Nil(t, res.Error) require.Nil(t, res.ErrorEventIdx) @@ -337,7 +340,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { require.NoError(t, ex.Close(ctx)) // there should be only one row updated - require.Equal(t, 1, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100 WHERE zar = 'three'")) + require.Equal(t, 1, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100 WHERE zar = 'three'")) }) } @@ -346,14 +349,14 @@ func TestRunSQL_RowCountLimit(t *testing.T) { ctx := context.Background() rowLimit := 10 - ex, dbURI := newExecutorWithTable(t, rowLimit) + ex, dbURI := newExecutorWithIntegerTable(t, rowLimit) // Helper func to insert a row and return the result. insertRow := func(t *testing.T) *string { bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) - res, err := execTxnWithRunSQLEvents(t, bs, []string{`insert into foo_1337_100 values ('one')`}) + _, res, err := execTxnWithRunSQLEvents(t, bs, []string{`insert into foo_1337_100 values ('one')`}) require.NoError(t, err) if res.Error == nil { require.NoError(t, bs.Commit()) @@ -366,7 +369,7 @@ func TestRunSQL_RowCountLimit(t *testing.T) { for i := 0; i < rowLimit; i++ { require.Nil(t, insertRow(t)) } - require.Equal(t, rowLimit, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100")) + require.Equal(t, rowLimit, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) // The next insert should fail. err := insertRow(t) @@ -383,7 +386,7 @@ func TestWithCheck(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -392,7 +395,7 @@ func TestWithCheck(t *testing.T) { assertExecTxnWithSetController(t, bs, "0x1") policy := ethereum.ITablelandControllerPolicy{AllowInsert: true, WithCheck: "zar = 'two'"} - res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{`insert into foo_1337_100 values ('one')`}, policy) + _, res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{`insert into foo_1337_100 values ('one')`}, policy) require.NoError(t, err) require.Contains(t, *res.Error, "number of affected rows 1 does not match auditing count 0") @@ -400,14 +403,14 @@ func TestWithCheck(t *testing.T) { require.NoError(t, bs.Close()) require.NoError(t, ex.Close(ctx)) - require.Equal(t, 0, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100")) + require.Equal(t, 0, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) }) t.Run("update with check not satistifed", func(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) { bs, err := ex.NewBlockScope(ctx, 0) @@ -424,7 +427,7 @@ func TestWithCheck(t *testing.T) { require.NoError(t, err) policy := ethereum.ITablelandControllerPolicy{AllowUpdate: true, WithCheck: "zar = 'two'"} - res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{`update foo_1337_100 SET zar = 'three'`}, policy) + _, res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{`update foo_1337_100 SET zar = 'three'`}, policy) require.NoError(t, err) require.Contains(t, *res.Error, "number of affected rows 1 does not match auditing count 0") @@ -433,15 +436,15 @@ func TestWithCheck(t *testing.T) { } require.NoError(t, ex.Close(ctx)) - require.Equal(t, 1, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100 WHERE zar = 'one'")) - require.Equal(t, 0, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100 WHERE zar = 'three'")) + require.Equal(t, 1, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100 WHERE zar = 'one'")) + require.Equal(t, 0, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100 WHERE zar = 'three'")) }) t.Run("insert with check satistifed", func(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -452,7 +455,7 @@ func TestWithCheck(t *testing.T) { policy := ethereum.ITablelandControllerPolicy{AllowInsert: true, WithCheck: "zar in ('one', 'two')"} q := `insert into foo_1337_100 values ('one');` q += `insert into foo_1337_100 values ('two')` - res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{q}, policy) + _, res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{q}, policy) require.NoError(t, err) require.Nil(t, res.Error) require.Nil(t, res.ErrorEventIdx) @@ -461,7 +464,7 @@ func TestWithCheck(t *testing.T) { require.NoError(t, bs.Close()) require.NoError(t, ex.Close(ctx)) - require.Equal(t, 2, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100")) + require.Equal(t, 2, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) }) t.Run("row count limit-withcheck", func(t *testing.T) { @@ -469,7 +472,7 @@ func TestWithCheck(t *testing.T) { ctx := context.Background() rowLimit := 10 - ex, dbURI := newExecutorWithTable(t, rowLimit) + ex, dbURI := newExecutorWithIntegerTable(t, rowLimit) { bs, err := ex.NewBlockScope(ctx, 0) @@ -485,7 +488,7 @@ func TestWithCheck(t *testing.T) { require.NoError(t, err) policy := ethereum.ITablelandControllerPolicy{AllowInsert: true, WithCheck: "zar in ('one')"} - res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{`insert into foo_1337_100 values ('one')`}, policy) + _, res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, []string{`insert into foo_1337_100 values ('one')`}, policy) require.NoError(t, err) if res.Error == nil { require.NoError(t, bs.Commit()) @@ -498,7 +501,7 @@ func TestWithCheck(t *testing.T) { for i := 0; i < rowLimit; i++ { require.Nil(t, insertRow(t)) } - require.Equal(t, rowLimit, tableRowCountT100(t, dbURI, "select count(*) from foo_1337_100")) + require.Equal(t, rowLimit, tableReadInteger(t, dbURI, "select count(*) from foo_1337_100")) // The next insert should fail. err := insertRow(t) @@ -508,20 +511,22 @@ func TestWithCheck(t *testing.T) { }) } -func assertExecTxnWithRunSQLEvents(t *testing.T, bs executor.BlockScope, stmts []string) { +func assertExecTxnWithRunSQLEvents(t *testing.T, bs executor.BlockScope, stmts []string) common.Hash { t.Helper() - res, err := execTxnWithRunSQLEvents(t, bs, stmts) + txnHash, res, err := execTxnWithRunSQLEvents(t, bs, stmts) require.NoError(t, err) require.NotNil(t, res.TableID) require.Equal(t, int64(100), res.TableID.ToBigInt().Int64()) + + return txnHash } func execTxnWithRunSQLEvents( t *testing.T, bs executor.BlockScope, stmts []string, -) (executor.TxnExecutionResult, error) { +) (common.Hash, executor.TxnExecutionResult, error) { t.Helper() policy := ethereum.ITablelandControllerPolicy{ @@ -532,7 +537,8 @@ func execTxnWithRunSQLEvents( WithCheck: "", UpdatableColumns: nil, } - return execTxnWithRunSQLEventsAndPolicy(t, bs, stmts, policy) + txnHash, res, err := execTxnWithRunSQLEventsAndPolicy(t, bs, stmts, policy) + return txnHash, res, err } func execTxnWithRunSQLEventsAndPolicy( @@ -540,7 +546,7 @@ func execTxnWithRunSQLEventsAndPolicy( bs executor.BlockScope, stmts []string, policy ethereum.ITablelandControllerPolicy, -) (executor.TxnExecutionResult, error) { +) (common.Hash, executor.TxnExecutionResult, error) { t.Helper() events := make([]interface{}, len(stmts)) @@ -552,5 +558,12 @@ func execTxnWithRunSQLEventsAndPolicy( Policy: policy, } } - return bs.ExecuteTxnEvents(context.Background(), eventfeed.TxnEvents{Events: events}) + + var hashBytes [common.HashLength]byte + binary.LittleEndian.PutUint64(hashBytes[:], rand.Uint64()) + txnHash := common.BytesToHash(hashBytes[:]) + + txnResult, err := bs.ExecuteTxnEvents(context.Background(), eventfeed.TxnEvents{TxnHash: txnHash, Events: events}) + + return txnHash, txnResult, err } diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_setcontroller_test.go b/pkg/eventprocessor/impl/executor/impl/txnscope_setcontroller_test.go index f42e0c0f..059b2165 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_setcontroller_test.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_setcontroller_test.go @@ -20,7 +20,7 @@ func TestSetController(t *testing.T) { t.Run("controller is not set default", func(t *testing.T) { t.Parallel() - _, dbURI := newExecutorWithTable(t, 0) + _, dbURI := newExecutorWithIntegerTable(t, 0) // Let's test first that the controller is not set (it's the default behavior) db, err := sql.Open("sqlite3", dbURI) @@ -31,7 +31,7 @@ func TestSetController(t *testing.T) { t.Run("foreign key constraint", func(t *testing.T) { t.Parallel() - ex, _ := newExecutorWithTable(t, 0) + ex, _ := newExecutorWithIntegerTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -47,7 +47,7 @@ func TestSetController(t *testing.T) { t.Run("set unset controller", func(t *testing.T) { t.Parallel() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) // sets bs, err := ex.NewBlockScope(ctx, 0) @@ -77,7 +77,7 @@ func TestSetController(t *testing.T) { t.Run("upsert", func(t *testing.T) { t.Parallel() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) { bs, err := ex.NewBlockScope(ctx, 0) diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_transfer_test.go b/pkg/eventprocessor/impl/executor/impl/txnscope_transfer_test.go index c9ac9c85..b70b231f 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_transfer_test.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_transfer_test.go @@ -17,10 +17,10 @@ func TestTransfer(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithTable(t, 0) + ex, dbURI := newExecutorWithIntegerTable(t, 0) require.Equal(t, 1, - tableRowCountT100( + tableReadInteger( t, dbURI, fmt.Sprintf( @@ -43,7 +43,7 @@ func TestTransfer(t *testing.T) { require.NoError(t, ex.Close(ctx)) require.Equal(t, 1, - tableRowCountT100( + tableReadInteger( t, dbURI, fmt.Sprintf( From 16110d8a9a58423a9815ca1dfb9a73050b5c38ae Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 22 Dec 2022 11:29:19 -0300 Subject: [PATCH 085/101] pkg/parsing: include tests for custom functions in read queries Signed-off-by: Ignacio Hagopian --- pkg/parsing/impl/validator_test.go | 85 +++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 13 deletions(-) diff --git a/pkg/parsing/impl/validator_test.go b/pkg/parsing/impl/validator_test.go index d777e0f0..e9d28cb2 100644 --- a/pkg/parsing/impl/validator_test.go +++ b/pkg/parsing/impl/validator_test.go @@ -894,9 +894,53 @@ func TestWriteStatementAddReturningClause(t *testing.T) { }) } -type WriteQueryResolver interface { - GetTxnHash() string - GetBlockNumber() uint64 +func TestCustomFunctionResolveReadQuery(t *testing.T) { + t.Parallel() + + type testCase struct { + name string + query string + rqr ReadQueryResolver + mustFail bool + expQuery string + } + + rqr := newReadQueryResolver(map[tableland.ChainID]uint64{ + tableland.ChainID(1337): 1001, + tableland.ChainID(1338): 1002, + tableland.ChainID(1339): 1003, + }) + tests := []testCase{ + { + name: "select with block_num(*)", + query: "select block_num(1337), block_num(1338) from foo_1337_1 where a = block_num(1339)", + expQuery: "select 1001, 1002 from foo_1337_1 where a = 1003", + }, + { + name: "select with block_num(*) for chainID that doesn't exist", + query: "select block_num(1337) from foo_1337_1 where a = block_num(1336)", + mustFail: true, + }, + } + + for _, it := range tests { + t.Run(it.name, func(tc testCase) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + + parser := newParser(t, []string{"system_", "registry"}) + stmt, err := parser.ValidateReadQuery(tc.query) + require.NoError(t, err) + + q, err := stmt.GetQuery(rqr) + if tc.mustFail { + require.Error(t, err) + return + } + require.Equal(t, tc.expQuery, q) + } + }(it)) + } } func TestCustomFunctionResolveWriteQuery(t *testing.T) { @@ -905,33 +949,30 @@ func TestCustomFunctionResolveWriteQuery(t *testing.T) { type testCase struct { name string query string - wqr WriteQueryResolver mustFail bool expQueries []string } + + wqr := newWriteQueryResolver("0xDEADBEEF", 100) tests := []testCase{ { name: "insert with custom functions", query: "insert into foo_1337_1 values (txn_hash(), block_num())", - wqr: newWriteQueryResolver("0xDEADBEEF", 100), expQueries: []string{"insert into foo_1337_1 values ('0xDEADBEEF', 100)"}, }, { name: "update with custom functions", query: "update foo_1337_1 SET a=txn_hash(), b=block_num() where c in (block_num(), block_num()+1)", - wqr: newWriteQueryResolver("0xDEADBEEF", 100), expQueries: []string{"update foo_1337_1 SET a='0xDEADBEEF', b=100 where c in (100, 100+1)"}, }, { name: "delete with custom functions", query: "delete from foo_1337_1 where a=block_num() and b=txn_hash()", - wqr: newWriteQueryResolver("0xDEADBEEF", 100), expQueries: []string{"delete from foo_1337_1 where a=100 and b='0xDEADBEEF'"}, }, { name: "multiple queries", query: "insert into foo_1337_1 values (txn_hash()); delete from foo_1337_1 where a=block_num()", - wqr: newWriteQueryResolver("0xDEADBEEF", 100), expQueries: []string{ "insert into foo_1337_1 values ('0xDEADBEEF')", "delete from foo_1337_1 where a=100", @@ -940,25 +981,21 @@ func TestCustomFunctionResolveWriteQuery(t *testing.T) { { name: "block_num() with integer argument", query: "delete from foo_1337_1 where a=block_num(1337)", - wqr: newWriteQueryResolver("0xDEADBEEF", 100), mustFail: true, }, { name: "block_num() with string argument", query: "delete from foo_1337_1 where a=block_num('foo')", - wqr: newWriteQueryResolver("0xDEADBEEF", 100), mustFail: true, }, { name: "txn_hash() with an integer argument", query: "insert into foo_1337_1 values (txn_hash(1))", - wqr: newWriteQueryResolver("0xDEADBEEF", 100), mustFail: true, }, { name: "txn_hash() with a string argument", query: "insert into foo_1337_1 values (txn_hash('foo'))", - wqr: newWriteQueryResolver("0xDEADBEEF", 100), mustFail: true, }, } @@ -973,7 +1010,7 @@ func TestCustomFunctionResolveWriteQuery(t *testing.T) { require.NoError(t, err) for i, stmt := range mutStmts { - q, err := stmt.GetQuery(tc.wqr) + q, err := stmt.GetQuery(wqr) if tc.mustFail { require.Error(t, err) return @@ -985,6 +1022,15 @@ func TestCustomFunctionResolveWriteQuery(t *testing.T) { } } +type WriteQueryResolver interface { + GetTxnHash() string + GetBlockNumber() uint64 +} + +type ReadQueryResolver interface { + GetBlockNumber() uint64 +} + type writeQueryResolver struct { txnHash string blockNumber uint64 @@ -1002,6 +1048,19 @@ func (wqr *writeQueryResolver) GetBlockNumber() uint64 { return wqr.blockNumber } +type readQueryResolver struct { + chainBlockNumbers map[tableland.ChainID]uint64 +} + +func newReadQueryResolver(chainBlockNumbers map[tableland.ChainID]uint64) *readQueryResolver { + return &readQueryResolver{chainBlockNumbers: chainBlockNumbers} +} + +func (wqr *readQueryResolver) GetBlockNumber(chainID tableland.ChainID) (uint64, bool) { + blockNumber, ok := wqr.chainBlockNumbers[chainID] + return blockNumber, ok +} + func newParser(t *testing.T, prefixes []string, opts ...parsing.Option) parsing.SQLValidator { t.Helper() p, err := parser.New(prefixes, opts...) From dc8ea3c18e3fc976a6824aee734984fd3cd46dec Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 22 Dec 2022 11:29:20 -0300 Subject: [PATCH 086/101] pkg/readqueryresolver: create helper method for user store Signed-off-by: Ignacio Hagopian --- pkg/readqueryresolver/readqueryresolver.go | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 pkg/readqueryresolver/readqueryresolver.go diff --git a/pkg/readqueryresolver/readqueryresolver.go b/pkg/readqueryresolver/readqueryresolver.go new file mode 100644 index 00000000..be0f3fec --- /dev/null +++ b/pkg/readqueryresolver/readqueryresolver.go @@ -0,0 +1,27 @@ +package readqueryresolver + +import ( + "github.com/textileio/go-tableland/internal/tableland" + "github.com/textileio/go-tableland/pkg/eventprocessor" +) + +type ReadQueryResolver struct { + leb map[tableland.ChainID]func() int64 +} + +func New(chainStacks map[tableland.ChainID]eventprocessor.EventProcessor) *ReadQueryResolver { + leb := make(map[tableland.ChainID]func() int64, len(chainStacks)) + for chainID, ep := range chainStacks { + leb[chainID] = ep.GetLastExecutedBlockNumber + } + return &ReadQueryResolver{leb: leb} +} + +func (rqr *ReadQueryResolver) GetBlockNumber(chainID tableland.ChainID) (int64, bool) { + r, ok := rqr.leb[chainID] + if !ok { + return 0, false + } + + return r(), true +} From 75fb249d57addb45de9b54dd280e1068be1effc5 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 22 Dec 2022 11:29:20 -0300 Subject: [PATCH 087/101] pkg/parsing: improve tests Signed-off-by: Ignacio Hagopian --- pkg/parsing/impl/validator_test.go | 36 +++++++++++------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/pkg/parsing/impl/validator_test.go b/pkg/parsing/impl/validator_test.go index e9d28cb2..c46e17bc 100644 --- a/pkg/parsing/impl/validator_test.go +++ b/pkg/parsing/impl/validator_test.go @@ -116,7 +116,7 @@ func TestReadRunSQL(t *testing.T) { if tc.expErrType == nil { require.NoError(t, err) require.NotNil(t, rs) - q, err := rs.GetQuery() + q, err := rs.GetQuery(nil) require.NoError(t, err) require.Equal(t, tc.query, q) return @@ -728,7 +728,7 @@ func TestGetWriteStatements(t *testing.T) { require.NoError(t, err) for i := range stmts { - query, err := stmts[i].GetQuery() + query, err := stmts[i].GetQuery(nil) require.NoError(t, err) require.Equal(t, tc.expectedStmts[i], query) } @@ -779,7 +779,7 @@ func TestGetGrantStatementRolesAndPrivileges(t *testing.T) { for i := range stmts { gs, ok := stmts[i].(parsing.GrantStmt) require.True(t, ok) - q, err := gs.GetQuery() + q, err := gs.GetQuery(nil) require.NoError(t, err) require.Equal(t, tc.expectedStmt, q) require.Equal(t, tc.roles, gs.GetRoles()) @@ -830,7 +830,7 @@ func TestWriteStatementAddWhereClause(t *testing.T) { err = ws.AddWhereClause(tc.whereClause) require.NoError(t, err) - sql, err := ws.GetQuery() + sql, err := ws.GetQuery(nil) require.NoError(t, err) require.Equal(t, tc.expQuery, sql) } @@ -854,7 +854,7 @@ func TestWriteStatementAddReturningClause(t *testing.T) { err = ws.AddReturningClause() require.NoError(t, err) - sql, err := ws.GetQuery() + sql, err := ws.GetQuery(nil) require.NoError(t, err) require.Equal(t, "insert into foo_1337_1 values ('bar') returning (rowid)", sql) }) @@ -873,7 +873,7 @@ func TestWriteStatementAddReturningClause(t *testing.T) { err = ws.AddReturningClause() require.NoError(t, err) - sql, err := ws.GetQuery() + sql, err := ws.GetQuery(nil) require.NoError(t, err) require.Equal(t, "update foo_1337_1 set foo = 'bar' returning (rowid)", sql) }) @@ -900,12 +900,11 @@ func TestCustomFunctionResolveReadQuery(t *testing.T) { type testCase struct { name string query string - rqr ReadQueryResolver mustFail bool expQuery string } - rqr := newReadQueryResolver(map[tableland.ChainID]uint64{ + rqr := newReadQueryResolver(map[tableland.ChainID]int64{ tableland.ChainID(1337): 1001, tableland.ChainID(1338): 1002, tableland.ChainID(1339): 1003, @@ -1022,21 +1021,12 @@ func TestCustomFunctionResolveWriteQuery(t *testing.T) { } } -type WriteQueryResolver interface { - GetTxnHash() string - GetBlockNumber() uint64 -} - -type ReadQueryResolver interface { - GetBlockNumber() uint64 -} - type writeQueryResolver struct { txnHash string - blockNumber uint64 + blockNumber int64 } -func newWriteQueryResolver(txnHash string, blockNumber uint64) *writeQueryResolver { +func newWriteQueryResolver(txnHash string, blockNumber int64) *writeQueryResolver { return &writeQueryResolver{txnHash: txnHash, blockNumber: blockNumber} } @@ -1044,19 +1034,19 @@ func (wqr *writeQueryResolver) GetTxnHash() string { return wqr.txnHash } -func (wqr *writeQueryResolver) GetBlockNumber() uint64 { +func (wqr *writeQueryResolver) GetBlockNumber() int64 { return wqr.blockNumber } type readQueryResolver struct { - chainBlockNumbers map[tableland.ChainID]uint64 + chainBlockNumbers map[tableland.ChainID]int64 } -func newReadQueryResolver(chainBlockNumbers map[tableland.ChainID]uint64) *readQueryResolver { +func newReadQueryResolver(chainBlockNumbers map[tableland.ChainID]int64) *readQueryResolver { return &readQueryResolver{chainBlockNumbers: chainBlockNumbers} } -func (wqr *readQueryResolver) GetBlockNumber(chainID tableland.ChainID) (uint64, bool) { +func (wqr *readQueryResolver) GetBlockNumber(chainID tableland.ChainID) (int64, bool) { blockNumber, ok := wqr.chainBlockNumbers[chainID] return blockNumber, ok } From 2a9c0ae0e02c4ba2ea22a7a974a383a98078de69 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 22 Dec 2022 11:29:20 -0300 Subject: [PATCH 088/101] pkg/eventprocessor: use in-memory last height to avoid hitting the database Signed-off-by: Ignacio Hagopian --- pkg/eventprocessor/eventprocessor.go | 3 +-- pkg/eventprocessor/impl/eventprocessor.go | 11 +++-------- pkg/telemetry/chainscollector/chainscollector.go | 6 +----- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/pkg/eventprocessor/eventprocessor.go b/pkg/eventprocessor/eventprocessor.go index fea1c5dc..cb8ae3cd 100644 --- a/pkg/eventprocessor/eventprocessor.go +++ b/pkg/eventprocessor/eventprocessor.go @@ -1,7 +1,6 @@ package eventprocessor import ( - "context" "fmt" "time" @@ -67,7 +66,7 @@ func WithHashCalcStep(step int64) Option { // EventProcessor processes events from a smart-contract. type EventProcessor interface { - GetLastExecutedBlockNumber(context.Context) (int64, error) + GetLastExecutedBlockNumber() int64 Start() error Stop() } diff --git a/pkg/eventprocessor/impl/eventprocessor.go b/pkg/eventprocessor/impl/eventprocessor.go index 0226ab2f..a9fcb452 100644 --- a/pkg/eventprocessor/impl/eventprocessor.go +++ b/pkg/eventprocessor/impl/eventprocessor.go @@ -113,13 +113,8 @@ func (ep *EventProcessor) Start() error { } // GetLastExecutedBlockNumber returns the last executed block number. -func (ep *EventProcessor) GetLastExecutedBlockNumber(ctx context.Context) (int64, error) { - blockNumber, err := ep.executor.GetLastExecutedBlockNumber(ctx) - if err != nil { - return 0, fmt.Errorf("get last executed block number: %s", err) - } - - return blockNumber, nil +func (ep *EventProcessor) GetLastExecutedBlockNumber() int64 { + return ep.mLastProcessedHeight.Load() } // Stop stops processing new events. @@ -318,7 +313,7 @@ func (ep *EventProcessor) calculateHash(ctx context.Context, bs executor.BlockSc if err := telemetry.Collect(ctx, telemetry.StateHashMetric{ Version: telemetry.StateHashMetricV1, ChainID: int64(stateHash.ChainID), - BlockNumber: stateHash.BlockNumber, + BlockNumber: int64(stateHash.BlockNumber), Hash: stateHash.Hash, }); err != nil { return fmt.Errorf("calculating hash for current block: %s", err) diff --git a/pkg/telemetry/chainscollector/chainscollector.go b/pkg/telemetry/chainscollector/chainscollector.go index 0bd09646..c15bf429 100644 --- a/pkg/telemetry/chainscollector/chainscollector.go +++ b/pkg/telemetry/chainscollector/chainscollector.go @@ -47,11 +47,7 @@ func (cc *ChainsCollector) Start(ctx context.Context) { LastProcessedBlockNumbers: make(map[tableland.ChainID]int64, len(cc.chainStacks)), } for chainID, chainStack := range cc.chainStacks { - blockNumber, err := chainStack.EventProcessor.GetLastExecutedBlockNumber(ctx) - if err != nil { - cc.log.Error().Err(err).Msg("get last executed block number") - continue - } + blockNumber := chainStack.EventProcessor.GetLastExecutedBlockNumber() metric.LastProcessedBlockNumbers[chainID] = blockNumber } if err := telemetry.Collect(ctx, metric); err != nil { From 20d6a84312d41a8115dbf58aac10316687c6afee Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 22 Dec 2022 11:29:21 -0300 Subject: [PATCH 089/101] pkg/parsing: remove existing Stmt base abstraction since the only remaining method has different signature for children Signed-off-by: Ignacio Hagopian --- pkg/parsing/impl/validator.go | 21 +++++++++++++++------ pkg/parsing/query_validator.go | 25 +++++++++++++++++++------ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/pkg/parsing/impl/validator.go b/pkg/parsing/impl/validator.go index 36792fd5..85ae04de 100644 --- a/pkg/parsing/impl/validator.go +++ b/pkg/parsing/impl/validator.go @@ -206,7 +206,7 @@ func (pp *QueryValidator) ValidateReadQuery(query string) (parsing.ReadStmt, err } return &readStmt{ - query: query, + statement: ast.Statements[0], }, nil } @@ -220,8 +220,12 @@ type mutatingStmt struct { var _ parsing.MutatingStmt = (*mutatingStmt)(nil) -func (s *mutatingStmt) GetQuery() (string, error) { - return s.node.String(), nil +func (s *mutatingStmt) GetQuery(resolver parsing.WriteQueryResolver) (string, error) { + query, err := s.node.Resolve(resolver) + if err != nil { + return "", fmt.Errorf("resolving write query: %s", err) + } + return query, nil } func (s *mutatingStmt) GetPrefix() string { @@ -344,13 +348,18 @@ func (gs *grantStmt) GetPrivileges() tableland.Privileges { } type readStmt struct { - query string + statement sqlparser.Statement } var _ parsing.ReadStmt = (*readStmt)(nil) -func (s *readStmt) GetQuery() (string, error) { - return s.query, nil +func (s *readStmt) GetQuery(resolver parsing.ReadQueryResolver) (string, error) { + query, err := s.statement.Resolve(resolver) + if err != nil { + return "", fmt.Errorf("resolving sql query: %s", err) + } + + return query, nil } func (pp *QueryValidator) validateWriteQuery(stmt sqlparser.WriteStatement) (*sqlparser.ValidatedTable, error) { diff --git a/pkg/parsing/query_validator.go b/pkg/parsing/query_validator.go index 21c4e68c..43d91cd2 100644 --- a/pkg/parsing/query_validator.go +++ b/pkg/parsing/query_validator.go @@ -9,16 +9,25 @@ import ( "github.com/textileio/go-tableland/pkg/tables" ) -// Stmt represents any valid read or mutating query. -type Stmt interface { - GetQuery() (string, error) +// WriteQueryResolver resolves Tablealand Custom Functions for a write statement. +type WriteQueryResolver interface { + // GetTxnHash returns the transaction hash of the transaction containing the query being processed. + GetTxnHash() string + + // GetBlockNumber returns the block number of the block containing query being processed. + GetBlockNumber() int64 +} + +// ReadQueryResolver resolves Tablealand Custom Functions for a read statement. +type ReadQueryResolver interface { + // GetBlockNumber returns the last known block number for the provided chainID. If the chainID isn't known, + // it returns (0, false). + GetBlockNumber(chainID tableland.ChainID) (int64, bool) } // MutatingStmt represents mutating statement, that is either // a SugaredWriteStmt or a SugaredGrantStmt. type MutatingStmt interface { - Stmt - // GetPrefix returns the prefix of the table, if any. e.g: "insert into foo_4_100" -> "foo". // Since the prefix is optional, it can return "". GetPrefix() string @@ -30,6 +39,9 @@ type MutatingStmt interface { // GetDBTableName returns the database table name. GetDBTableName() string + + // GetQuery returns an executable stringification of a mutating statements with resolved custom functions. + GetQuery(WriteQueryResolver) (string, error) } // ReadStmt is an already parsed read statement that satisfies all @@ -37,7 +49,8 @@ type MutatingStmt interface { // with correct assumptions about parsing validity and being a read statement // (select). type ReadStmt interface { - Stmt + // GetQuery returns an executable stringification of a mutating statements with resolved custom functions. + GetQuery(ReadQueryResolver) (string, error) } // WriteStmt is an already parsed write statement that satisfies all From eedc0a5081583e3b64f3428dabaa1d14e17d05a0 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 22 Dec 2022 11:29:21 -0300 Subject: [PATCH 090/101] wire custom function resolving Signed-off-by: Ignacio Hagopian --- cmd/api/main.go | 7 +- internal/tableland/impl/mesa_test.go | 5 +- .../impl/eventprocessor_test.go | 4 +- .../impl/executor/impl/blockscope.go | 25 +++++- .../impl/executor/impl/txnscope.go | 4 +- .../impl/executor/impl/txnscope_runsql.go | 4 +- pkg/sqlstore/impl/user/store.go | 10 ++- tests/fullstack/fullstack.go | 84 ++++++++++--------- 8 files changed, 91 insertions(+), 52 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index db2bb093..33fdb3cf 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -35,6 +35,7 @@ import ( nonceimpl "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/parsing" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" + "github.com/textileio/go-tableland/pkg/readqueryresolver" "github.com/textileio/go-tableland/pkg/sqlstore" sqlstoreimpl "github.com/textileio/go-tableland/pkg/sqlstore/impl" "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" @@ -94,7 +95,11 @@ func main() { } // User store. - userStore, err := user.New(databaseURL) + eps := make(map[tableland.ChainID]eventprocessor.EventProcessor, len(chainStacks)) + for chainID, stack := range chainStacks { + eps[chainID] = stack.EventProcessor + } + userStore, err := user.New(databaseURL, readqueryresolver.New(eps)) if err != nil { log.Fatal().Err(err).Msg("creating user store") } diff --git a/internal/tableland/impl/mesa_test.go b/internal/tableland/impl/mesa_test.go index 3f8d045a..0cbd42ea 100644 --- a/internal/tableland/impl/mesa_test.go +++ b/internal/tableland/impl/mesa_test.go @@ -23,6 +23,7 @@ import ( "github.com/stretchr/testify/require" "github.com/textileio/go-tableland/internal/chains" "github.com/textileio/go-tableland/internal/tableland" + "github.com/textileio/go-tableland/pkg/eventprocessor" "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed" efimpl "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed/impl" epimpl "github.com/textileio/go-tableland/pkg/eventprocessor/impl" @@ -30,6 +31,7 @@ import ( "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/parsing" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" + rqresolver "github.com/textileio/go-tableland/pkg/readqueryresolver" "github.com/textileio/go-tableland/pkg/sqlstore" "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" @@ -958,7 +960,8 @@ func (b *tablelandSetupBuilder) build(t *testing.T) *tablelandSetup { require.NoError(t, err) t.Cleanup(func() { ep.Stop() }) - userStore, err := user.New(dbURI) + userStore, err := user.New( + dbURI, rqresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{tableland.ChainID(1337): ep})) require.NoError(t, err) return &tablelandSetup{ diff --git a/pkg/eventprocessor/impl/eventprocessor_test.go b/pkg/eventprocessor/impl/eventprocessor_test.go index 2740644f..5db06a28 100644 --- a/pkg/eventprocessor/impl/eventprocessor_test.go +++ b/pkg/eventprocessor/impl/eventprocessor_test.go @@ -16,6 +16,7 @@ import ( efimpl "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed/impl" executor "github.com/textileio/go-tableland/pkg/eventprocessor/impl/executor/impl" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" + rqresolver "github.com/textileio/go-tableland/pkg/readqueryresolver" "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" "github.com/textileio/go-tableland/pkg/tables" @@ -372,7 +373,8 @@ func setup(t *testing.T) ( } require.NoError(t, err) - userStore, err := user.New(dbURI) + userStore, err := user.New( + dbURI, rqresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{chainID: ep})) require.NoError(t, err) tableReader := func(readQuery string) []int64 { diff --git a/pkg/eventprocessor/impl/executor/impl/blockscope.go b/pkg/eventprocessor/impl/executor/impl/blockscope.go index 2387567f..fff11fb5 100644 --- a/pkg/eventprocessor/impl/executor/impl/blockscope.go +++ b/pkg/eventprocessor/impl/executor/impl/blockscope.go @@ -75,9 +75,13 @@ func (bs *blockScope) ExecuteTxnEvents( } ts := &txnScope{ - parser: bs.parser, - acl: bs.acl, scopeVars: bs.scopeVars, + + parser: bs.parser, + queryResolver: newWriteQueryResolver(evmTxn.TxnHash.Hex(), bs.scopeVars.BlockNumber), + + acl: bs.acl, + log: logger.With(). Str("component", "txnscope"). Int64("chain_id", int64(bs.scopeVars.ChainID)). @@ -234,3 +238,20 @@ func (bs *blockScope) Commit() error { } return nil } + +type writeQueryResolver struct { + txnHash string + blockNumber int64 +} + +func newWriteQueryResolver(txnHash string, blockNumber int64) *writeQueryResolver { + return &writeQueryResolver{txnHash: txnHash, blockNumber: blockNumber} +} + +func (wqr *writeQueryResolver) GetTxnHash() string { + return wqr.txnHash +} + +func (wqr *writeQueryResolver) GetBlockNumber() int64 { + return wqr.blockNumber +} diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope.go b/pkg/eventprocessor/impl/executor/impl/txnscope.go index e556264c..6288d213 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope.go @@ -34,7 +34,9 @@ func (e *errQueryExecution) Error() string { type txnScope struct { log zerolog.Logger - parser parsing.SQLValidator + parser parsing.SQLValidator + queryResolver parsing.WriteQueryResolver + acl tableland.ACL scopeVars scopeVars diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go index 5e0387be..ac8b55c0 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go @@ -243,7 +243,7 @@ func (ts *txnScope) executeWriteStmt( } if policy.WithCheck() == "" { - query, err := ws.GetQuery() + query, err := ws.GetQuery(ts.queryResolver) if err != nil { return fmt.Errorf("get query query: %s", err) } @@ -281,7 +281,7 @@ func (ts *txnScope) executeWriteStmt( ts.log.Warn().Err(err).Msg("add returning clause called on delete") } - query, err := ws.GetQuery() + query, err := ws.GetQuery(ts.queryResolver) if err != nil { return fmt.Errorf("get query: %s", err) } diff --git a/pkg/sqlstore/impl/user/store.go b/pkg/sqlstore/impl/user/store.go index c1355b61..97830c46 100644 --- a/pkg/sqlstore/impl/user/store.go +++ b/pkg/sqlstore/impl/user/store.go @@ -18,11 +18,12 @@ var log = logger.With().Str("component", "userstore").Logger() // UserStore provides access to the db store. type UserStore struct { - db *sql.DB + db *sql.DB + resolver parsing.ReadQueryResolver } // New creates a new UserStore. -func New(dbURI string) (*UserStore, error) { +func New(dbURI string, resolver parsing.ReadQueryResolver) (*UserStore, error) { attrs := append([]attribute.KeyValue{attribute.String("name", "userstore")}, metrics.BaseAttrs...) db, err := otelsql.Open("sqlite3", dbURI, otelsql.WithAttributes(attrs...)) if err != nil { @@ -32,13 +33,14 @@ func New(dbURI string) (*UserStore, error) { return nil, fmt.Errorf("registering dbstats: %s", err) } return &UserStore{ - db: db, + db: db, + resolver: resolver, }, nil } // Read executes a read statement on the db. func (db *UserStore) Read(ctx context.Context, rq parsing.ReadStmt) (*tableland.TableData, error) { - query, err := rq.GetQuery() + query, err := rq.GetQuery(db.resolver) if err != nil { return nil, fmt.Errorf("get query: %s", err) } diff --git a/tests/fullstack/fullstack.go b/tests/fullstack/fullstack.go index e3fa9a46..1724d4ce 100644 --- a/tests/fullstack/fullstack.go +++ b/tests/fullstack/fullstack.go @@ -19,6 +19,7 @@ import ( systemimpl "github.com/textileio/go-tableland/internal/system/impl" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/internal/tableland/impl" + "github.com/textileio/go-tableland/pkg/eventprocessor" "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed" efimpl "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed/impl" epimpl "github.com/textileio/go-tableland/pkg/eventprocessor/impl" @@ -26,6 +27,7 @@ import ( nonceimpl "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/parsing" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" + rqresolver "github.com/textileio/go-tableland/pkg/readqueryresolver" "github.com/textileio/go-tableland/pkg/sqlstore" sqlstoreimplsystem "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" @@ -84,12 +86,6 @@ func CreateFullStack(t *testing.T, deps Deps) FullStack { require.NoError(t, err) } - userStore := deps.UserStore - if userStore == nil { - userStore, err = user.New(dbURI) - require.NoError(t, err) - } - backend, addr, contract, transactOpts, sk := testutil.Setup(t) wallet, err := wallet.NewWallet(hex.EncodeToString(crypto.FromECDSA(sk))) @@ -104,16 +100,57 @@ func CreateFullStack(t *testing.T, deps Deps) FullStack { ) require.NoError(t, err) + db, err := sql.Open("sqlite3", dbURI) + require.NoError(t, err) + db.SetMaxOpenConns(1) + + acl := deps.ACL + if acl == nil { + acl = &aclHalfMock{systemStore} + } + + ex, err := executor.NewExecutor(1337, db, parser, 0, acl) + require.NoError(t, err) + // Spin up dependencies needed for the EventProcessor. + // i.e: Executor, Parser, and EventFeed (connected to the EVM chain) + ef, err := efimpl.New( + systemStore, + ChainID, + backend, + addr, + eventfeed.WithNewHeadPollFreq(time.Millisecond), + eventfeed.WithMinBlockDepth(0)) + require.NoError(t, err) + + // Create EventProcessor for our test. + ep, err := epimpl.New(parser, ex, ef, 1337) + require.NoError(t, err) + + err = ep.Start() + require.NoError(t, err) + t.Cleanup(func() { + ep.Stop() + }) + chainStacks := map[tableland.ChainID]chains.ChainStack{ 1337: { Store: systemStore, Registry: registry, AllowTransactionRelay: true, + EventProcessor: ep, }, } tbl := deps.Tableland if tbl == nil { + userStore := deps.UserStore + if userStore == nil { + userStore, err = user.New( + dbURI, + rqresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{tableland.ChainID(1337): ep}), + ) + require.NoError(t, err) + } tbl = impl.NewTablelandMesa(parser, userStore, chainStacks) tbl, err = impl.NewInstrumentedTablelandMesa(tbl) require.NoError(t, err) @@ -137,44 +174,11 @@ func CreateFullStack(t *testing.T, deps Deps) FullStack { require.NoError(t, err) } - acl := deps.ACL - if acl == nil { - acl = &aclHalfMock{systemStore} - } - - db, err := sql.Open("sqlite3", dbURI) - require.NoError(t, err) - db.SetMaxOpenConns(1) - - ex, err := executor.NewExecutor(1337, db, parser, 0, acl) - require.NoError(t, err) - router, err := router.ConfiguredRouter(tbl, systemService, 10, time.Second, []tableland.ChainID{ChainID}) require.NoError(t, err) server := httptest.NewServer(router.Handler()) - - // Spin up dependencies needed for the EventProcessor. - // i.e: Executor, Parser, and EventFeed (connected to the EVM chain) - ef, err := efimpl.New( - systemStore, - ChainID, - backend, - addr, - eventfeed.WithNewHeadPollFreq(time.Millisecond), - eventfeed.WithMinBlockDepth(0)) - require.NoError(t, err) - - // Create EventProcessor for our test. - ep, err := epimpl.New(parser, ex, ef, 1337) - require.NoError(t, err) - - err = ep.Start() - require.NoError(t, err) - t.Cleanup(func() { - ep.Stop() - server.Close() - }) + t.Cleanup(server.Close) return FullStack{ Backend: backend, From 2fa9a7f41df27deba17cfae287fff8666a2841a0 Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Thu, 29 Dec 2022 12:34:56 -0300 Subject: [PATCH 091/101] connects with the parser Signed-off-by: Bruno Calza --- cmd/api/main.go | 4 +- go.mod | 2 +- go.sum | 4 +- internal/tableland/impl/mesa_test.go | 6 +- pkg/eventprocessor/impl/eventprocessor.go | 2 +- .../impl/eventprocessor_test.go | 4 +- .../impl/executor/impl/blockscope.go | 14 +- .../impl/executor/impl/executor_test.go | 2 +- .../impl/executor/impl/txnscope.go | 5 +- .../impl/executor/impl/txnscope_runsql.go | 5 +- .../impl/txnscope_runsql_customfuncs_test.go | 12 +- .../executor/impl/txnscope_runsql_test.go | 35 ++-- pkg/parsing/impl/validator.go | 20 +- pkg/parsing/impl/validator_test.go | 179 +----------------- pkg/parsing/query_validator.go | 21 +- pkg/readqueryresolver/readqueryresolver.go | 27 --- .../readstatementresolver.go | 30 +++ pkg/sqlstore/impl/user/store.go | 5 +- tests/fullstack/fullstack.go | 4 +- 19 files changed, 96 insertions(+), 285 deletions(-) delete mode 100644 pkg/readqueryresolver/readqueryresolver.go create mode 100644 pkg/readstatementresolver/readstatementresolver.go diff --git a/cmd/api/main.go b/cmd/api/main.go index 33fdb3cf..d11de87c 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -35,7 +35,7 @@ import ( nonceimpl "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/parsing" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" - "github.com/textileio/go-tableland/pkg/readqueryresolver" + "github.com/textileio/go-tableland/pkg/readstatementresolver" "github.com/textileio/go-tableland/pkg/sqlstore" sqlstoreimpl "github.com/textileio/go-tableland/pkg/sqlstore/impl" "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" @@ -99,7 +99,7 @@ func main() { for chainID, stack := range chainStacks { eps[chainID] = stack.EventProcessor } - userStore, err := user.New(databaseURL, readqueryresolver.New(eps)) + userStore, err := user.New(databaseURL, readstatementresolver.New(eps)) if err != nil { log.Fatal().Err(err).Msg("creating user store") } diff --git a/go.mod b/go.mod index 4a6354a2..e893cd18 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/cobra v1.6.0 github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff github.com/stretchr/testify v1.8.1 - github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527 + github.com/tablelandnetwork/sqlparser v0.0.0-20221229133649-a34f5eedb409 github.com/textileio/cli v1.0.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 go.opentelemetry.io/otel v1.11.2 diff --git a/go.sum b/go.sum index 23431d98..89bad7f4 100644 --- a/go.sum +++ b/go.sum @@ -1316,8 +1316,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527 h1:cwTLUHmgeUSoV+cgvKfxG8zSjmCLTwrzBALjxVrPz/g= -github.com/tablelandnetwork/sqlparser v0.0.0-20221209125022-863bbd9f6527/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20221229133649-a34f5eedb409 h1:CHMbHuXZTY6e6g/2dy2diziFu86bYAoHtz+0lYqhrpI= +github.com/tablelandnetwork/sqlparser v0.0.0-20221229133649-a34f5eedb409/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/textileio/cli v1.0.2 h1:qSp/x4d/9SZ93TxhgZnE5okRKqzqHqrzAwKAPjuPw50= github.com/textileio/cli v1.0.2/go.mod h1:vTlCvvVyOmXXLwddCcBg3PDavfUsCkRBZoyr6Nu1lkc= diff --git a/internal/tableland/impl/mesa_test.go b/internal/tableland/impl/mesa_test.go index 0cbd42ea..68c8174a 100644 --- a/internal/tableland/impl/mesa_test.go +++ b/internal/tableland/impl/mesa_test.go @@ -31,7 +31,7 @@ import ( "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/parsing" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" - rqresolver "github.com/textileio/go-tableland/pkg/readqueryresolver" + rsresolver "github.com/textileio/go-tableland/pkg/readstatementresolver" "github.com/textileio/go-tableland/pkg/sqlstore" "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" @@ -961,13 +961,13 @@ func (b *tablelandSetupBuilder) build(t *testing.T) *tablelandSetup { t.Cleanup(func() { ep.Stop() }) userStore, err := user.New( - dbURI, rqresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{tableland.ChainID(1337): ep})) + dbURI, rsresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{1337: ep})) require.NoError(t, err) return &tablelandSetup{ ctx: ctx, - chainID: tableland.ChainID(1337), + chainID: 1337, // ethereum client ethClient: backend, diff --git a/pkg/eventprocessor/impl/eventprocessor.go b/pkg/eventprocessor/impl/eventprocessor.go index a9fcb452..d22205aa 100644 --- a/pkg/eventprocessor/impl/eventprocessor.go +++ b/pkg/eventprocessor/impl/eventprocessor.go @@ -313,7 +313,7 @@ func (ep *EventProcessor) calculateHash(ctx context.Context, bs executor.BlockSc if err := telemetry.Collect(ctx, telemetry.StateHashMetric{ Version: telemetry.StateHashMetricV1, ChainID: int64(stateHash.ChainID), - BlockNumber: int64(stateHash.BlockNumber), + BlockNumber: stateHash.BlockNumber, Hash: stateHash.Hash, }); err != nil { return fmt.Errorf("calculating hash for current block: %s", err) diff --git a/pkg/eventprocessor/impl/eventprocessor_test.go b/pkg/eventprocessor/impl/eventprocessor_test.go index 5db06a28..5385d765 100644 --- a/pkg/eventprocessor/impl/eventprocessor_test.go +++ b/pkg/eventprocessor/impl/eventprocessor_test.go @@ -16,7 +16,7 @@ import ( efimpl "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed/impl" executor "github.com/textileio/go-tableland/pkg/eventprocessor/impl/executor/impl" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" - rqresolver "github.com/textileio/go-tableland/pkg/readqueryresolver" + rsresolver "github.com/textileio/go-tableland/pkg/readstatementresolver" "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" "github.com/textileio/go-tableland/pkg/tables" @@ -374,7 +374,7 @@ func setup(t *testing.T) ( require.NoError(t, err) userStore, err := user.New( - dbURI, rqresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{chainID: ep})) + dbURI, rsresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{chainID: ep})) require.NoError(t, err) tableReader := func(readQuery string) []int64 { diff --git a/pkg/eventprocessor/impl/executor/impl/blockscope.go b/pkg/eventprocessor/impl/executor/impl/blockscope.go index fff11fb5..1bab319e 100644 --- a/pkg/eventprocessor/impl/executor/impl/blockscope.go +++ b/pkg/eventprocessor/impl/executor/impl/blockscope.go @@ -77,8 +77,8 @@ func (bs *blockScope) ExecuteTxnEvents( ts := &txnScope{ scopeVars: bs.scopeVars, - parser: bs.parser, - queryResolver: newWriteQueryResolver(evmTxn.TxnHash.Hex(), bs.scopeVars.BlockNumber), + parser: bs.parser, + statementResolver: newWriteStatementResolver(evmTxn.TxnHash.Hex(), bs.scopeVars.BlockNumber), acl: bs.acl, @@ -239,19 +239,19 @@ func (bs *blockScope) Commit() error { return nil } -type writeQueryResolver struct { +type writeStatmentResolver struct { txnHash string blockNumber int64 } -func newWriteQueryResolver(txnHash string, blockNumber int64) *writeQueryResolver { - return &writeQueryResolver{txnHash: txnHash, blockNumber: blockNumber} +func newWriteStatementResolver(txnHash string, blockNumber int64) *writeStatmentResolver { + return &writeStatmentResolver{txnHash: txnHash, blockNumber: blockNumber} } -func (wqr *writeQueryResolver) GetTxnHash() string { +func (wqr *writeStatmentResolver) GetTxnHash() string { return wqr.txnHash } -func (wqr *writeQueryResolver) GetBlockNumber() int64 { +func (wqr *writeStatmentResolver) GetBlockNumber() int64 { return wqr.blockNumber } diff --git a/pkg/eventprocessor/impl/executor/impl/executor_test.go b/pkg/eventprocessor/impl/executor/impl/executor_test.go index b0c643aa..89e0991f 100644 --- a/pkg/eventprocessor/impl/executor/impl/executor_test.go +++ b/pkg/eventprocessor/impl/executor/impl/executor_test.go @@ -223,7 +223,7 @@ func newExecutorWithStringTable(t *testing.T, rowsLimit int) (*Executor, string) return newExecutorWithTable(t, rowsLimit, "create table foo_1337 (zar text)") } -func newExecutorWithIntegerTable(t *testing.T, rowsLimit int) (*Executor, string) { +func newExecutorWithIntegerTable(t *testing.T, rowsLimit int) (*Executor, string) { //nolint return newExecutorWithTable(t, rowsLimit, "create table foo_1337 (zar int)") } diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope.go b/pkg/eventprocessor/impl/executor/impl/txnscope.go index 6288d213..98604b7f 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/rs/zerolog" + "github.com/tablelandnetwork/sqlparser" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/eventprocessor/eventfeed" "github.com/textileio/go-tableland/pkg/eventprocessor/impl/executor" @@ -34,8 +35,8 @@ func (e *errQueryExecution) Error() string { type txnScope struct { log zerolog.Logger - parser parsing.SQLValidator - queryResolver parsing.WriteQueryResolver + parser parsing.SQLValidator + statementResolver sqlparser.WriteStatementResolver acl tableland.ACL scopeVars scopeVars diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go index ac8b55c0..3c78ba97 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go @@ -243,7 +243,7 @@ func (ts *txnScope) executeWriteStmt( } if policy.WithCheck() == "" { - query, err := ws.GetQuery(ts.queryResolver) + query, err := ws.GetQuery(ts.statementResolver) if err != nil { return fmt.Errorf("get query query: %s", err) } @@ -281,7 +281,7 @@ func (ts *txnScope) executeWriteStmt( ts.log.Warn().Err(err).Msg("add returning clause called on delete") } - query, err := ws.GetQuery(ts.queryResolver) + query, err := ws.GetQuery(ts.statementResolver) if err != nil { return fmt.Errorf("get query: %s", err) } @@ -322,7 +322,6 @@ func (ts *txnScope) checkAffectedRowsAgainstAuditingQuery( } return fmt.Errorf("checking affected rows query exec: %s", err) } - if count != affectedRowsCount { return &errQueryExecution{ Code: "POLICY_WITH_CHECK", diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go index 334b2865..a97a0c78 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go @@ -78,13 +78,6 @@ func TestCustomFunctionsWriteQuery(t *testing.T) { newExecutorWithTable: newExecutorWithIntegerTable, assertExpectation: checkBlockNumberEq1, }, - { - // block_num() must be valid **only** for read queries. - name: "block_num() with integer argument", - query: "insert into foo_1337_100 values (block_num(1337))", - newExecutorWithTable: newExecutorWithIntegerTable, - mustFail: true, - }, { name: "block_num() with string argument", query: "insert into foo_1337_100 values (block_num('nope'))", @@ -99,12 +92,13 @@ func TestCustomFunctionsWriteQuery(t *testing.T) { ctx := context.Background() ex, dbURI := test.newExecutorWithTable() - bs, err := ex.NewBlockScope(ctx, 0) + bs, err := ex.NewBlockScope(ctx, 1) require.NoError(t, err) txnHash, res, err := execTxnWithRunSQLEvents(t, bs, []string{test.query}) if test.mustFail { - require.Error(t, err) + require.NotNil(t, res.Error) + return } require.NoError(t, err) require.NotNil(t, res.TableID) diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go index b9658cc4..cbf44204 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go @@ -25,7 +25,7 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithIntegerTable(t, 0) + ex, dbURI := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -43,7 +43,7 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithIntegerTable(t, 0) + ex, dbURI := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -64,7 +64,7 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithIntegerTable(t, 0) + ex, dbURI := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -94,7 +94,7 @@ func TestRunSQL_OneEventPerTxn(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithIntegerTable(t, 0) + ex, dbURI := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -230,7 +230,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithIntegerTable(t, 0) + ex, _ := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -249,7 +249,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithIntegerTable(t, 0) + ex, _ := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -269,7 +269,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithIntegerTable(t, 0) + ex, _ := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -289,7 +289,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, _ := newExecutorWithIntegerTable(t, 0) + ex, _ := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -310,7 +310,7 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithIntegerTable(t, 0) + ex, dbURI := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -349,7 +349,7 @@ func TestRunSQL_RowCountLimit(t *testing.T) { ctx := context.Background() rowLimit := 10 - ex, dbURI := newExecutorWithIntegerTable(t, rowLimit) + ex, dbURI := newExecutorWithStringTable(t, rowLimit) // Helper func to insert a row and return the result. insertRow := func(t *testing.T) *string { @@ -386,7 +386,7 @@ func TestWithCheck(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithIntegerTable(t, 0) + ex, dbURI := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -410,7 +410,7 @@ func TestWithCheck(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithIntegerTable(t, 0) + ex, dbURI := newExecutorWithStringTable(t, 0) { bs, err := ex.NewBlockScope(ctx, 0) @@ -444,7 +444,7 @@ func TestWithCheck(t *testing.T) { t.Parallel() ctx := context.Background() - ex, dbURI := newExecutorWithIntegerTable(t, 0) + ex, dbURI := newExecutorWithStringTable(t, 0) bs, err := ex.NewBlockScope(ctx, 0) require.NoError(t, err) @@ -472,7 +472,7 @@ func TestWithCheck(t *testing.T) { ctx := context.Background() rowLimit := 10 - ex, dbURI := newExecutorWithIntegerTable(t, rowLimit) + ex, dbURI := newExecutorWithStringTable(t, rowLimit) { bs, err := ex.NewBlockScope(ctx, 0) @@ -511,15 +511,13 @@ func TestWithCheck(t *testing.T) { }) } -func assertExecTxnWithRunSQLEvents(t *testing.T, bs executor.BlockScope, stmts []string) common.Hash { +func assertExecTxnWithRunSQLEvents(t *testing.T, bs executor.BlockScope, stmts []string) { t.Helper() - txnHash, res, err := execTxnWithRunSQLEvents(t, bs, stmts) + _, res, err := execTxnWithRunSQLEvents(t, bs, stmts) require.NoError(t, err) require.NotNil(t, res.TableID) require.Equal(t, int64(100), res.TableID.ToBigInt().Int64()) - - return txnHash } func execTxnWithRunSQLEvents( @@ -564,6 +562,5 @@ func execTxnWithRunSQLEventsAndPolicy( txnHash := common.BytesToHash(hashBytes[:]) txnResult, err := bs.ExecuteTxnEvents(context.Background(), eventfeed.TxnEvents{TxnHash: txnHash, Events: events}) - return txnHash, txnResult, err } diff --git a/pkg/parsing/impl/validator.go b/pkg/parsing/impl/validator.go index 85ae04de..128ff754 100644 --- a/pkg/parsing/impl/validator.go +++ b/pkg/parsing/impl/validator.go @@ -220,12 +220,16 @@ type mutatingStmt struct { var _ parsing.MutatingStmt = (*mutatingStmt)(nil) -func (s *mutatingStmt) GetQuery(resolver parsing.WriteQueryResolver) (string, error) { - query, err := s.node.Resolve(resolver) - if err != nil { - return "", fmt.Errorf("resolving write query: %s", err) +func (s *mutatingStmt) GetQuery(resolver sqlparser.WriteStatementResolver) (string, error) { + if writeStmt, ok := s.node.(sqlparser.WriteStatement); ok { + query, err := writeStmt.Resolve(resolver) + if err != nil { + return "", fmt.Errorf("resolving write statement: %s", err) + } + return query, nil } - return query, nil + + return s.node.String(), nil } func (s *mutatingStmt) GetPrefix() string { @@ -353,10 +357,10 @@ type readStmt struct { var _ parsing.ReadStmt = (*readStmt)(nil) -func (s *readStmt) GetQuery(resolver parsing.ReadQueryResolver) (string, error) { - query, err := s.statement.Resolve(resolver) +func (s *readStmt) GetQuery(resolver sqlparser.ReadStatementResolver) (string, error) { + query, err := s.statement.(sqlparser.ReadStatement).Resolve(resolver) if err != nil { - return "", fmt.Errorf("resolving sql query: %s", err) + return "", fmt.Errorf("resolving read statement: %s", err) } return query, nil diff --git a/pkg/parsing/impl/validator_test.go b/pkg/parsing/impl/validator_test.go index c46e17bc..f56f412f 100644 --- a/pkg/parsing/impl/validator_test.go +++ b/pkg/parsing/impl/validator_test.go @@ -45,7 +45,7 @@ func TestReadRunSQL(t *testing.T) { // Allow joins and sub-queries { name: "with join", - query: "select * from foo_1 join bar_2 on a=b", + query: "select * from foo_1 join bar_2 on a = b", expErrType: nil, }, { @@ -59,24 +59,8 @@ func TestReadRunSQL(t *testing.T) { expErrType: nil, }, { - name: "select with complex subqueries in function arguments", - query: `select - json_object( - 'name', '#' || rigs.id, - 'external_url', 'https://rigs.tableland.xyz/' || rigs.id, - 'attributes', json_array( - json_object('trait_type', 'Fleet', 'value', rigs.fleet), - json_object('trait_type', 'Chassis', 'value', rigs.chassis), - json_object('trait_type', 'Wheels', 'value', rigs.wheels), - json_object('trait_type', 'Background', 'value', rigs.background), - json_object('trait_type', ( - select name from badges_2 where badges.rig_id = rigs.id and position = 1 limit 1 - ), 'value', ( - select image from badges_2 where badges.rig_id = rigs.id and position = 1 limit 1 - )) - ) - ) - from rigs_1;`, + name: "select with complex subqueries in function arguments", + query: `select json_object('name', '#' || rigs.id, 'external_url', 'https://rigs.tableland.xyz/' || rigs.id, 'attributes', json_array(json_object('trait_type', 'Fleet', 'value', rigs.fleet), json_object('trait_type', 'Chassis', 'value', rigs.chassis), json_object('trait_type', 'Wheels', 'value', rigs.wheels), json_object('trait_type', 'Background', 'value', rigs.background), json_object('trait_type', (select name from badges_2 where badges.rig_id = rigs.id and position = 1 limit 1), 'value', (select image from badges_2 where badges.rig_id = rigs.id and position = 1 limit 1)))) from rigs_1`, // nolint expErrType: nil, }, @@ -894,163 +878,6 @@ func TestWriteStatementAddReturningClause(t *testing.T) { }) } -func TestCustomFunctionResolveReadQuery(t *testing.T) { - t.Parallel() - - type testCase struct { - name string - query string - mustFail bool - expQuery string - } - - rqr := newReadQueryResolver(map[tableland.ChainID]int64{ - tableland.ChainID(1337): 1001, - tableland.ChainID(1338): 1002, - tableland.ChainID(1339): 1003, - }) - tests := []testCase{ - { - name: "select with block_num(*)", - query: "select block_num(1337), block_num(1338) from foo_1337_1 where a = block_num(1339)", - expQuery: "select 1001, 1002 from foo_1337_1 where a = 1003", - }, - { - name: "select with block_num(*) for chainID that doesn't exist", - query: "select block_num(1337) from foo_1337_1 where a = block_num(1336)", - mustFail: true, - }, - } - - for _, it := range tests { - t.Run(it.name, func(tc testCase) func(t *testing.T) { - return func(t *testing.T) { - t.Parallel() - - parser := newParser(t, []string{"system_", "registry"}) - stmt, err := parser.ValidateReadQuery(tc.query) - require.NoError(t, err) - - q, err := stmt.GetQuery(rqr) - if tc.mustFail { - require.Error(t, err) - return - } - require.Equal(t, tc.expQuery, q) - } - }(it)) - } -} - -func TestCustomFunctionResolveWriteQuery(t *testing.T) { - t.Parallel() - - type testCase struct { - name string - query string - mustFail bool - expQueries []string - } - - wqr := newWriteQueryResolver("0xDEADBEEF", 100) - tests := []testCase{ - { - name: "insert with custom functions", - query: "insert into foo_1337_1 values (txn_hash(), block_num())", - expQueries: []string{"insert into foo_1337_1 values ('0xDEADBEEF', 100)"}, - }, - { - name: "update with custom functions", - query: "update foo_1337_1 SET a=txn_hash(), b=block_num() where c in (block_num(), block_num()+1)", - expQueries: []string{"update foo_1337_1 SET a='0xDEADBEEF', b=100 where c in (100, 100+1)"}, - }, - { - name: "delete with custom functions", - query: "delete from foo_1337_1 where a=block_num() and b=txn_hash()", - expQueries: []string{"delete from foo_1337_1 where a=100 and b='0xDEADBEEF'"}, - }, - { - name: "multiple queries", - query: "insert into foo_1337_1 values (txn_hash()); delete from foo_1337_1 where a=block_num()", - expQueries: []string{ - "insert into foo_1337_1 values ('0xDEADBEEF')", - "delete from foo_1337_1 where a=100", - }, - }, - { - name: "block_num() with integer argument", - query: "delete from foo_1337_1 where a=block_num(1337)", - mustFail: true, - }, - { - name: "block_num() with string argument", - query: "delete from foo_1337_1 where a=block_num('foo')", - mustFail: true, - }, - { - name: "txn_hash() with an integer argument", - query: "insert into foo_1337_1 values (txn_hash(1))", - mustFail: true, - }, - { - name: "txn_hash() with a string argument", - query: "insert into foo_1337_1 values (txn_hash('foo'))", - mustFail: true, - }, - } - - for _, it := range tests { - t.Run(it.name, func(tc testCase) func(t *testing.T) { - return func(t *testing.T) { - t.Parallel() - - parser := newParser(t, []string{"system_", "registry"}) - mutStmts, err := parser.ValidateMutatingQuery(tc.query, tableland.ChainID(100)) - require.NoError(t, err) - - for i, stmt := range mutStmts { - q, err := stmt.GetQuery(wqr) - if tc.mustFail { - require.Error(t, err) - return - } - require.Equal(t, tc.expQueries[i], q) - } - } - }(it)) - } -} - -type writeQueryResolver struct { - txnHash string - blockNumber int64 -} - -func newWriteQueryResolver(txnHash string, blockNumber int64) *writeQueryResolver { - return &writeQueryResolver{txnHash: txnHash, blockNumber: blockNumber} -} - -func (wqr *writeQueryResolver) GetTxnHash() string { - return wqr.txnHash -} - -func (wqr *writeQueryResolver) GetBlockNumber() int64 { - return wqr.blockNumber -} - -type readQueryResolver struct { - chainBlockNumbers map[tableland.ChainID]int64 -} - -func newReadQueryResolver(chainBlockNumbers map[tableland.ChainID]int64) *readQueryResolver { - return &readQueryResolver{chainBlockNumbers: chainBlockNumbers} -} - -func (wqr *readQueryResolver) GetBlockNumber(chainID tableland.ChainID) (int64, bool) { - blockNumber, ok := wqr.chainBlockNumbers[chainID] - return blockNumber, ok -} - func newParser(t *testing.T, prefixes []string, opts ...parsing.Option) parsing.SQLValidator { t.Helper() p, err := parser.New(prefixes, opts...) diff --git a/pkg/parsing/query_validator.go b/pkg/parsing/query_validator.go index 43d91cd2..ce2cd322 100644 --- a/pkg/parsing/query_validator.go +++ b/pkg/parsing/query_validator.go @@ -5,26 +5,11 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/tablelandnetwork/sqlparser" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/tables" ) -// WriteQueryResolver resolves Tablealand Custom Functions for a write statement. -type WriteQueryResolver interface { - // GetTxnHash returns the transaction hash of the transaction containing the query being processed. - GetTxnHash() string - - // GetBlockNumber returns the block number of the block containing query being processed. - GetBlockNumber() int64 -} - -// ReadQueryResolver resolves Tablealand Custom Functions for a read statement. -type ReadQueryResolver interface { - // GetBlockNumber returns the last known block number for the provided chainID. If the chainID isn't known, - // it returns (0, false). - GetBlockNumber(chainID tableland.ChainID) (int64, bool) -} - // MutatingStmt represents mutating statement, that is either // a SugaredWriteStmt or a SugaredGrantStmt. type MutatingStmt interface { @@ -41,7 +26,7 @@ type MutatingStmt interface { GetDBTableName() string // GetQuery returns an executable stringification of a mutating statements with resolved custom functions. - GetQuery(WriteQueryResolver) (string, error) + GetQuery(sqlparser.WriteStatementResolver) (string, error) } // ReadStmt is an already parsed read statement that satisfies all @@ -50,7 +35,7 @@ type MutatingStmt interface { // (select). type ReadStmt interface { // GetQuery returns an executable stringification of a mutating statements with resolved custom functions. - GetQuery(ReadQueryResolver) (string, error) + GetQuery(sqlparser.ReadStatementResolver) (string, error) } // WriteStmt is an already parsed write statement that satisfies all diff --git a/pkg/readqueryresolver/readqueryresolver.go b/pkg/readqueryresolver/readqueryresolver.go deleted file mode 100644 index be0f3fec..00000000 --- a/pkg/readqueryresolver/readqueryresolver.go +++ /dev/null @@ -1,27 +0,0 @@ -package readqueryresolver - -import ( - "github.com/textileio/go-tableland/internal/tableland" - "github.com/textileio/go-tableland/pkg/eventprocessor" -) - -type ReadQueryResolver struct { - leb map[tableland.ChainID]func() int64 -} - -func New(chainStacks map[tableland.ChainID]eventprocessor.EventProcessor) *ReadQueryResolver { - leb := make(map[tableland.ChainID]func() int64, len(chainStacks)) - for chainID, ep := range chainStacks { - leb[chainID] = ep.GetLastExecutedBlockNumber - } - return &ReadQueryResolver{leb: leb} -} - -func (rqr *ReadQueryResolver) GetBlockNumber(chainID tableland.ChainID) (int64, bool) { - r, ok := rqr.leb[chainID] - if !ok { - return 0, false - } - - return r(), true -} diff --git a/pkg/readstatementresolver/readstatementresolver.go b/pkg/readstatementresolver/readstatementresolver.go new file mode 100644 index 00000000..95cc59ab --- /dev/null +++ b/pkg/readstatementresolver/readstatementresolver.go @@ -0,0 +1,30 @@ +package readstatementresolver + +import ( + "github.com/textileio/go-tableland/internal/tableland" + "github.com/textileio/go-tableland/pkg/eventprocessor" +) + +// ReadStatementResolver implements the interface for custom functions resolution of read statements. +type ReadStatementResolver struct { + leb map[tableland.ChainID]func() int64 +} + +// New creates a new ReadStatementResolver. +func New(chainStacks map[tableland.ChainID]eventprocessor.EventProcessor) *ReadStatementResolver { + leb := make(map[tableland.ChainID]func() int64, len(chainStacks)) + for chainID, ep := range chainStacks { + leb[chainID] = ep.GetLastExecutedBlockNumber + } + return &ReadStatementResolver{leb: leb} +} + +// GetBlockNumber returns the block number for a given chain id. +func (rqr *ReadStatementResolver) GetBlockNumber(chainID int64) (int64, bool) { + r, ok := rqr.leb[tableland.ChainID(chainID)] + if !ok { + return 0, false + } + + return r(), true +} diff --git a/pkg/sqlstore/impl/user/store.go b/pkg/sqlstore/impl/user/store.go index 97830c46..0b12c969 100644 --- a/pkg/sqlstore/impl/user/store.go +++ b/pkg/sqlstore/impl/user/store.go @@ -8,6 +8,7 @@ import ( "github.com/XSAM/otelsql" _ "github.com/mattn/go-sqlite3" // sqlite3 driver logger "github.com/rs/zerolog/log" + "github.com/tablelandnetwork/sqlparser" "github.com/textileio/go-tableland/internal/tableland" "github.com/textileio/go-tableland/pkg/metrics" "github.com/textileio/go-tableland/pkg/parsing" @@ -19,11 +20,11 @@ var log = logger.With().Str("component", "userstore").Logger() // UserStore provides access to the db store. type UserStore struct { db *sql.DB - resolver parsing.ReadQueryResolver + resolver sqlparser.ReadStatementResolver } // New creates a new UserStore. -func New(dbURI string, resolver parsing.ReadQueryResolver) (*UserStore, error) { +func New(dbURI string, resolver sqlparser.ReadStatementResolver) (*UserStore, error) { attrs := append([]attribute.KeyValue{attribute.String("name", "userstore")}, metrics.BaseAttrs...) db, err := otelsql.Open("sqlite3", dbURI, otelsql.WithAttributes(attrs...)) if err != nil { diff --git a/tests/fullstack/fullstack.go b/tests/fullstack/fullstack.go index 1724d4ce..9a55525d 100644 --- a/tests/fullstack/fullstack.go +++ b/tests/fullstack/fullstack.go @@ -27,7 +27,7 @@ import ( nonceimpl "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/parsing" parserimpl "github.com/textileio/go-tableland/pkg/parsing/impl" - rqresolver "github.com/textileio/go-tableland/pkg/readqueryresolver" + rsresolver "github.com/textileio/go-tableland/pkg/readstatementresolver" "github.com/textileio/go-tableland/pkg/sqlstore" sqlstoreimplsystem "github.com/textileio/go-tableland/pkg/sqlstore/impl/system" "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" @@ -147,7 +147,7 @@ func CreateFullStack(t *testing.T, deps Deps) FullStack { if userStore == nil { userStore, err = user.New( dbURI, - rqresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{tableland.ChainID(1337): ep}), + rsresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{1337: ep}), ) require.NoError(t, err) } From dd989c988f65612eca3146411d925cffe6f65369 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 29 Dec 2022 15:53:44 -0300 Subject: [PATCH 092/101] updates parser latest version [testnetdeploy] Signed-off-by: Ignacio Hagopian --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e893cd18..f755f8b7 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/cobra v1.6.0 github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff github.com/stretchr/testify v1.8.1 - github.com/tablelandnetwork/sqlparser v0.0.0-20221229133649-a34f5eedb409 + github.com/tablelandnetwork/sqlparser v0.0.0-20221229184339-ab2ed64c97b0 github.com/textileio/cli v1.0.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 go.opentelemetry.io/otel v1.11.2 diff --git a/go.sum b/go.sum index 89bad7f4..3b8758ae 100644 --- a/go.sum +++ b/go.sum @@ -1316,8 +1316,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tablelandnetwork/sqlparser v0.0.0-20221229133649-a34f5eedb409 h1:CHMbHuXZTY6e6g/2dy2diziFu86bYAoHtz+0lYqhrpI= -github.com/tablelandnetwork/sqlparser v0.0.0-20221229133649-a34f5eedb409/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20221229184339-ab2ed64c97b0 h1:Gkr89OqiqH1TCSve9sbsziBHl3ex+4nZZynIQS9IQs8= +github.com/tablelandnetwork/sqlparser v0.0.0-20221229184339-ab2ed64c97b0/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/textileio/cli v1.0.2 h1:qSp/x4d/9SZ93TxhgZnE5okRKqzqHqrzAwKAPjuPw50= github.com/textileio/cli v1.0.2/go.mod h1:vTlCvvVyOmXXLwddCcBg3PDavfUsCkRBZoyr6Nu1lkc= From 5736259bac7326176af9cc08d4b17c5c39bde764 Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Fri, 30 Dec 2022 13:30:57 -0300 Subject: [PATCH 093/101] updates parser with new custom function implementation [testnetdeploy] Signed-off-by: Bruno Calza --- go.mod | 2 +- go.sum | 4 ++-- pkg/eventprocessor/impl/executor/impl/txnscope.go | 2 +- .../impl/executor/impl/txnscope_runsql.go | 10 ++++++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index f755f8b7..56395eac 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/cobra v1.6.0 github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff github.com/stretchr/testify v1.8.1 - github.com/tablelandnetwork/sqlparser v0.0.0-20221229184339-ab2ed64c97b0 + github.com/tablelandnetwork/sqlparser v0.0.0-20221230162331-b318f234cefd github.com/textileio/cli v1.0.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 go.opentelemetry.io/otel v1.11.2 diff --git a/go.sum b/go.sum index 3b8758ae..d6639182 100644 --- a/go.sum +++ b/go.sum @@ -1316,8 +1316,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tablelandnetwork/sqlparser v0.0.0-20221229184339-ab2ed64c97b0 h1:Gkr89OqiqH1TCSve9sbsziBHl3ex+4nZZynIQS9IQs8= -github.com/tablelandnetwork/sqlparser v0.0.0-20221229184339-ab2ed64c97b0/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20221230162331-b318f234cefd h1:AbpyzqlTban/UqJTrotlpWC9q/ePGU4qsrvqjoiLmG4= +github.com/tablelandnetwork/sqlparser v0.0.0-20221230162331-b318f234cefd/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/textileio/cli v1.0.2 h1:qSp/x4d/9SZ93TxhgZnE5okRKqzqHqrzAwKAPjuPw50= github.com/textileio/cli v1.0.2/go.mod h1:vTlCvvVyOmXXLwddCcBg3PDavfUsCkRBZoyr6Nu1lkc= diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope.go b/pkg/eventprocessor/impl/executor/impl/txnscope.go index 98604b7f..5181e401 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope.go @@ -18,7 +18,7 @@ import ( var tableIDIsEmpty = "table id is empty" // errQueryExecution is an error returned when the query execution failed -// with a cause related to th query itself. Retrying the execution of this query +// with a cause related to the query itself. Retrying the execution of this query // will always return an error (e.g: inserting a string in an integer column). // A query execution failure due to the database being down or any other infrastructure // problem isn't an ErrQueryExecution error. diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go index 3c78ba97..4d127900 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go @@ -245,7 +245,10 @@ func (ts *txnScope) executeWriteStmt( if policy.WithCheck() == "" { query, err := ws.GetQuery(ts.statementResolver) if err != nil { - return fmt.Errorf("get query query: %s", err) + return &errQueryExecution{ + Code: "QUERY_RESOLUTION", + Msg: err.Error(), + } } cmdTag, err := ts.txn.ExecContext(ctx, query) if err != nil { @@ -283,7 +286,10 @@ func (ts *txnScope) executeWriteStmt( query, err := ws.GetQuery(ts.statementResolver) if err != nil { - return fmt.Errorf("get query: %s", err) + return &errQueryExecution{ + Code: "QUERY_RESOLUTION", + Msg: err.Error(), + } } affectedRowIDs, err := ts.executeQueryAndGetAffectedRows(ctx, query) From dfcbe1c72b4dff66760a042bfdcbaa45e9572884 Mon Sep 17 00:00:00 2001 From: Joe Wagner Date: Mon, 2 Jan 2023 17:32:50 -0700 Subject: [PATCH 094/101] add remote workflow trigger binaries.yml --- .github/workflows/binaries.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 27370ab2..dbe5188b 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -59,3 +59,27 @@ jobs: push: true tags: textile/tableland:latest,textile/tableland:${{ github.ref_name }} platforms: linux/amd64, linux/arm64 + js-release: + runs-on: ubuntu-latest + steps: + - name: PR to publish this release via the npm package + uses: actions/github-script@v6 + with: + # TODO: I think we will need a token with greater permission than this, + # maybe TEXTILEIO_MACHINE_ACCESS_TOKEN will work? + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: 'tablelandnetwork', + repo: 'js-validator', + workflow_id: 'release-pr.yml', + ref: 'main', + inputs: { + release_version: ${{ github.ref_name }} + } + }).catch(error => error).then(response => { + core.debug(response); + if (response.status !== 204) { + core.setFailed(`create workflow_dispatch received status code ${response.status}`); + } + }); From 666764bfceec5ff1895185618d3325a482041fb8 Mon Sep 17 00:00:00 2001 From: Joe Wagner Date: Tue, 3 Jan 2023 10:44:16 -0700 Subject: [PATCH 095/101] Change binary workflow token name --- .github/workflows/binaries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index dbe5188b..5d3b3c62 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -67,7 +67,7 @@ jobs: with: # TODO: I think we will need a token with greater permission than this, # maybe TEXTILEIO_MACHINE_ACCESS_TOKEN will work? - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.TEXTILEIO_MACHINE_ACCESS_TOKEN }} script: | await github.rest.actions.createWorkflowDispatch({ owner: 'tablelandnetwork', From d7b181b286191703aea5ea5544f63fb98616879a Mon Sep 17 00:00:00 2001 From: Joe Wagner Date: Tue, 3 Jan 2023 15:05:07 -0700 Subject: [PATCH 096/101] Cleanup and fixes to js-release workflow job --- .github/workflows/binaries.yml | 47 +++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 5d3b3c62..503694c7 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -61,25 +61,48 @@ jobs: platforms: linux/amd64, linux/arm64 js-release: runs-on: ubuntu-latest + if: ${{ success() }} + needs: [binaries] steps: + - run: echo "release_version ${{ github.ref_name }}" + - name: PR to publish this release via the npm package uses: actions/github-script@v6 with: - # TODO: I think we will need a token with greater permission than this, - # maybe TEXTILEIO_MACHINE_ACCESS_TOKEN will work? github-token: ${{ secrets.TEXTILEIO_MACHINE_ACCESS_TOKEN }} script: | - await github.rest.actions.createWorkflowDispatch({ - owner: 'tablelandnetwork', - repo: 'js-validator', - workflow_id: 'release-pr.yml', - ref: 'main', - inputs: { - release_version: ${{ github.ref_name }} + // This triggers the release-pr workflow in the js-validator repo + // which will create a pull request in that repo to update the binaries + // on npm with this release + try { + // TODO: switch back to 'tablelandnetwork' + const ownerOrg = 'joewagner'; + + // if the tag/release has a preceeding "v" we want to remove + // it and match standard symantics in the js ecosystem + let version = '${{ github.ref_name }}'; + if (/^v[0-9]/.test(version)) { + version = version.slice(1); } - }).catch(error => error).then(response => { - core.debug(response); + + const options = { + owner: ownerOrg, + repo: 'js-validator', + workflow_id: 'release-pr.yml', + ref: 'main', + inputs: { + release_version: version + } + }; + + console.log(options); + + const response = await github.rest.actions.createWorkflowDispatch(options); + if (response.status !== 204) { core.setFailed(`create workflow_dispatch received status code ${response.status}`); } - }); + } catch(err) { + console.log(err); + core.setFailed(err.message); + } From fac4e191f50b48d938b46e7af134c21307b7defc Mon Sep 17 00:00:00 2001 From: Joe Wagner Date: Wed, 4 Jan 2023 17:24:40 -0700 Subject: [PATCH 097/101] Fix org name in binaries workflow --- .github/workflows/binaries.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 503694c7..2abc2142 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -75,8 +75,7 @@ jobs: // which will create a pull request in that repo to update the binaries // on npm with this release try { - // TODO: switch back to 'tablelandnetwork' - const ownerOrg = 'joewagner'; + const ownerOrg = 'tablelandnetwork'; // if the tag/release has a preceeding "v" we want to remove // it and match standard symantics in the js ecosystem From 5dd1920af0ae2f28ad6a39a78471137f6de859ff Mon Sep 17 00:00:00 2001 From: Joe Wagner Date: Fri, 13 Jan 2023 12:16:17 -0700 Subject: [PATCH 098/101] Fix name of remote workflow in binaries.yml --- .github/workflows/binaries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 2abc2142..4c02c06e 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -87,7 +87,7 @@ jobs: const options = { owner: ownerOrg, repo: 'js-validator', - workflow_id: 'release-pr.yml', + workflow_id: 'validator-update-pr.yml', ref: 'main', inputs: { release_version: version From c186a1b4ca9cea9fe8b2e80fe20bc62e08ddf793 Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Tue, 3 Jan 2023 18:32:06 -0300 Subject: [PATCH 099/101] fix: get schema was not parsing statements with autoincrement [testnetdeploy] Signed-off-by: Bruno Calza --- internal/system/impl/sqlstore_test.go | 6 +++--- pkg/sqlstore/impl/system/store.go | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/system/impl/sqlstore_test.go b/internal/system/impl/sqlstore_test.go index 786df02a..fa0440db 100644 --- a/internal/system/impl/sqlstore_test.go +++ b/internal/system/impl/sqlstore_test.go @@ -128,7 +128,7 @@ func TestGetSchemaByTableName(t *testing.T) { ðereum.ContractCreateTable{ TableId: big.NewInt(42), Owner: common.HexToAddress("0xb451cee4A42A652Fe77d373BAe66D42fd6B8D8FF"), - Statement: "create table foo_1337 (a int primary key, b text not null default 'foo' unique, check (a > 0))", + Statement: "create table foo_1337 (a integer primary key, b text not null default 'foo' unique, check (a > 0))", }, }, }) @@ -148,9 +148,9 @@ func TestGetSchemaByTableName(t *testing.T) { require.Len(t, schema.TableConstraints, 1) require.Equal(t, "a", schema.Columns[0].Name) - require.Equal(t, "int", schema.Columns[0].Type) + require.Equal(t, "integer", schema.Columns[0].Type) require.Len(t, schema.Columns[0].Constraints, 1) - require.Equal(t, "primary key", schema.Columns[0].Constraints[0]) + require.Equal(t, "primary key autoincrement", schema.Columns[0].Constraints[0]) require.Equal(t, "b", schema.Columns[1].Name) require.Equal(t, "text", schema.Columns[1].Type) diff --git a/pkg/sqlstore/impl/system/store.go b/pkg/sqlstore/impl/system/store.go index a0aef69f..473c14fe 100644 --- a/pkg/sqlstore/impl/system/store.go +++ b/pkg/sqlstore/impl/system/store.go @@ -246,6 +246,10 @@ func (s *SystemStore) GetSchemaByTableName(ctx context.Context, name string) (sq return sqlstore.TableSchema{}, fmt.Errorf("failed to get the table: %s", err) } + if strings.Contains(strings.ToLower(createStmt), "autoincrement") { + createStmt = strings.Replace(createStmt, "autoincrement", "", -1) + } + index := strings.LastIndex(strings.ToLower(createStmt), "strict") ast, err := sqlparser.Parse(createStmt[:index]) if err != nil { From 6f491763639eea533307d9facba55631431ec07a Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 17 Jan 2023 10:02:29 -0300 Subject: [PATCH 100/101] update deps [testnetdeploy] Signed-off-by: Ignacio Hagopian --- go.mod | 46 ++++---- go.sum | 326 ++++++++------------------------------------------------- 2 files changed, 70 insertions(+), 302 deletions(-) diff --git a/go.mod b/go.mod index 56395eac..d31105f7 100644 --- a/go.mod +++ b/go.mod @@ -1,42 +1,44 @@ module github.com/textileio/go-tableland -go 1.17 +go 1.18 require ( - cloud.google.com/go/bigquery v1.42.0 - cloud.google.com/go/logging v1.5.0 - github.com/XSAM/otelsql v0.17.0 - github.com/ethereum/go-ethereum v1.10.25 + cloud.google.com/go/bigquery v1.45.0 + cloud.google.com/go/logging v1.6.1 + github.com/XSAM/otelsql v0.17.1 + github.com/ethereum/go-ethereum v1.10.26 github.com/golang-migrate/migrate/v4 v4.15.2 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 github.com/hetiansu5/urlquery v1.2.7 github.com/json-iterator/go v1.1.12 - github.com/klauspost/compress v1.15.11 + github.com/klauspost/compress v1.15.14 github.com/mattn/go-sqlite3 v1.14.16 github.com/omeid/uconfig v1.2.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 github.com/rs/zerolog v1.28.0 github.com/sethvargo/go-limiter v0.7.2 - github.com/spf13/cobra v1.6.0 + github.com/spf13/cobra v1.6.1 github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff github.com/stretchr/testify v1.8.1 github.com/tablelandnetwork/sqlparser v0.0.0-20221230162331-b318f234cefd github.com/textileio/cli v1.0.2 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 go.opentelemetry.io/otel v1.11.2 go.opentelemetry.io/otel/exporters/prometheus v0.34.0 go.opentelemetry.io/otel/metric v0.34.0 go.opentelemetry.io/otel/sdk/metric v0.34.0 go.uber.org/atomic v1.10.0 - golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f + golang.org/x/sync v0.1.0 ) require ( - cloud.google.com/go v0.102.1 // indirect - cloud.google.com/go/compute v1.7.0 // indirect - cloud.google.com/go/iam v0.3.0 // indirect + cloud.google.com/go v0.107.0 // indirect + cloud.google.com/go/compute v1.13.0 // indirect + cloud.google.com/go/compute/metadata v0.2.1 // indirect + cloud.google.com/go/iam v0.8.0 // indirect + cloud.google.com/go/longrunning v0.3.0 // indirect github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -57,8 +59,8 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect - github.com/googleapis/gax-go/v2 v2.5.1 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect + github.com/googleapis/gax-go/v2 v2.7.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -96,21 +98,21 @@ require ( github.com/textileio/go-log/v2 v2.1.3-gke-2 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect - go.opencensus.io v0.23.0 // indirect + go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel/sdk v1.11.2 // indirect go.opentelemetry.io/otel/trace v1.11.2 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.0 // indirect golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e // indirect - golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect - golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect + golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect + golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect - google.golang.org/api v0.95.0 // indirect + golang.org/x/text v0.4.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.103.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f // indirect - google.golang.org/grpc v1.48.0 // indirect + google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd // indirect + google.golang.org/grpc v1.51.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect diff --git a/go.sum b/go.sum index d6639182..2a3d0824 100644 --- a/go.sum +++ b/go.sum @@ -3,13 +3,11 @@ bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= @@ -31,59 +29,46 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1 h1:vpK6iQWv/2uUeFJth4/cBHsQAGjn1iIE6AAlxipRaA0= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0 h1:JuTk8po4bCKRwObdT0zLb1K0BGkGHJdtgs2GK3j2Gws= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/datacatalog v1.3.0 h1:3llKXv7cC1acsWjvWmG0NQQkYVSVgunMSfVk7h6zz8Q= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/bigquery v1.45.0 h1:DdniQAaoQU7A/L9l6UrSBX/e0BUS2vmwC9Ll/LUQbUY= +cloud.google.com/go/bigquery v1.45.0/go.mod h1:frTreZmdFlTornn7K+IsIBrvCqQP0XccOvUjEker3AM= +cloud.google.com/go/compute v1.13.0 h1:AYrLkB8NPdDRslNp4Jxmzrhdr03fUAIDbiGFjLWowoU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/datacatalog v1.8.1 h1:8R4W1f3YINUhK/QldgGLH8L4mu4/bsOIz5eeyD+eH1w= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/logging v1.5.0 h1:DcR52smaYLgeK9KPzJlBJyyBYqW/EGKiuRRl8boL1s4= -cloud.google.com/go/logging v1.5.0/go.mod h1:c/57U/aLdzSFuBtvbtFduG1Ii54uSm95HOBnp58P7/U= +cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/logging v1.6.1 h1:ZBsZK+JG+oCDT+vaxwqF2egKNRjz8soXiS6Xv79benI= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= cloud.google.com/go/spanner v1.28.0/go.mod h1:7m6mtQZn/hMbMfx62ct5EWrGND4DNqkXyrmBPRS+OJo= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0 h1:wWRIaDURQA8xxHguFCshYepGlrWIrbBnAmc7wfg07qY= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= +cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= @@ -103,10 +88,8 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= -github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= @@ -142,8 +125,8 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIO github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= -github.com/XSAM/otelsql v0.17.0 h1:eq9yWwFY6t+nruMmjzhbdbkIo+HnUTziimkBbIqNKwM= -github.com/XSAM/otelsql v0.17.0/go.mod h1:zGN8fF5r7Xclr92eMl8JM8pYquSWV8Kjf2fUeWvpd3Y= +github.com/XSAM/otelsql v0.17.1 h1:f1BtwEuCz5+MflACiZXWM2xodkqb1lNzHJFbgLsDt3g= +github.com/XSAM/otelsql v0.17.1/go.mod h1:wmphbucQO1BrOo4v7jRsOgcYEpO9nZI4AwVkVtRsUp8= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -154,9 +137,7 @@ github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:C github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/apache/arrow/go/arrow v0.0.0-20210818145353-234c94e4ce64/go.mod h1:2qMFB56yOP3KzkB3PbYZ4AlUFg3a88F67TIx5lB/WwY= github.com/apache/arrow/go/arrow v0.0.0-20211013220434-5962184e7a30/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -166,16 +147,12 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= github.com/aws/aws-sdk-go-v2 v1.8.0/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0= github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= github.com/aws/aws-sdk-go-v2/config v1.6.0/go.mod h1:TNtBVmka80lRPk5+S9ZqVfFszOQAGJJ9KbT3EM3CHNU= github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw= -github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= github.com/aws/aws-sdk-go-v2/credentials v1.3.2/go.mod h1:PACKuTJdt6AlXvEq8rFI4eDmoqDFC5DpVKQbWysaDgM= github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.4.0/go.mod h1:Mj/U8OpDbcVcoctrYwA2bak8k/HFPdcLzI/vaiXMwuM= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.4.0/go.mod h1:eHwXu2+uE/T6gpnYWwBwqoeqRf9IXyCcolyOWDRAErQ= @@ -184,21 +161,16 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.2.0/go.mod h1:Q5jATQc+f1MfZp3PDMhn6 github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.2.2/go.mod h1:EASdTcM1lGhUe1/p4gkojHwlGJkeoRjjr1sRCzup3Is= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.3.0/go.mod h1:v8ygadNyATSm6elwJ/4gzJwcFhri9RqS8skgHKiwXPU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.2.2/go.mod h1:NXmNI41bdEsJMrD0v9rUvbGCB5GwdBEpKvUvIY3vTFg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.5.2/go.mod h1:QuL2Ym8BkrLmN4lUofXYq6000/i5jPjosCNK//t6gak= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.7.2/go.mod h1:np7TMuJNT83O0oDOSF8i4dF3dvGqA6hPYYo6YYkzgRA= -github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= github.com/aws/aws-sdk-go-v2/service/s3 v1.12.0/go.mod h1:6J++A5xpo7QDsIeSqPK4UHqMSyPOCopa+zKtqAMhqVQ= github.com/aws/aws-sdk-go-v2/service/s3 v1.16.1/go.mod h1:CQe/KvWV1AqRc65KqeJjrLzr5X2ijnFTTVzJW0VBRCI= -github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sso v1.3.2/go.mod h1:J21I6kF+d/6XHVk7kp/cx9YVD2TMD2TbLwtRGVcinXo= github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk= -github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/aws-sdk-go-v2/service/sts v1.6.1/go.mod h1:hLZ/AnkIKHLuPGjEiyghNEdvJ2PP0MgOxcmv9EBJ4xs= github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g= -github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= @@ -219,20 +191,16 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -240,8 +208,6 @@ github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -259,7 +225,6 @@ github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -277,8 +242,6 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= -github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -401,7 +364,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= @@ -409,7 +371,6 @@ github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1S github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= -github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -421,26 +382,19 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= -github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dhui/dktest v0.3.10/go.mod h1:h5Enh0nG3Qbo9WjNFRrwmKUaePEBhXMOygbz3Ww7Sz0= -github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.13+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= @@ -452,11 +406,8 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -472,20 +423,16 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= -github.com/ethereum/go-ethereum v1.10.18/go.mod h1:RD3NhcSBjZpj3k+SnQq24wBrmnmie78P5R/P62iNBD8= -github.com/ethereum/go-ethereum v1.10.25 h1:5dFrKJDnYf8L6/5o42abCE6a9yJm9cs4EJVRyYMr55s= -github.com/ethereum/go-ethereum v1.10.25/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= +github.com/ethereum/go-ethereum v1.10.26 h1:i/7d9RBBwiXCEuyduBQzJw/mKmnvzsN14jqBmytw72s= +github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= -github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -500,18 +447,11 @@ github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0 github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= -github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= -github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= @@ -558,9 +498,7 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -598,7 +536,6 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= @@ -611,12 +548,10 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= -github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-migrate/migrate/v4 v4.15.2 h1:vU+M05vs6jWHKDdmE1Ecwj0BznygFc4QsdRe2E/L7kc= github.com/golang-migrate/migrate/v4 v4.15.2/go.mod h1:f2toGLkYqD3JH+Todi4aZ2ZdbeUNx4sIwiOK96rE9Lw= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -654,16 +589,13 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -678,7 +610,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= @@ -687,7 +618,6 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -717,23 +647,17 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1 h1:kBRZU0PSuI7PspsSb/ChWoVResUcwNVIdpB049pKTiw= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= @@ -747,7 +671,6 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -764,7 +687,6 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= -github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= @@ -796,8 +718,6 @@ github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -809,17 +729,6 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= -github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= -github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= -github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= -github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= -github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= -github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= -github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= @@ -867,8 +776,6 @@ github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= -github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -892,17 +799,14 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= -github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= @@ -911,18 +815,14 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= -github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= -github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/klauspost/compress v1.15.14 h1:i7WCKDToww0wA+9qrUZ1xOjp218vfFo3nTU6UHp+gOc= +github.com/klauspost/compress v1.15.14/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -939,11 +839,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4= -github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -965,13 +860,10 @@ github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsI github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= -github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= @@ -985,19 +877,16 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -1018,7 +907,6 @@ github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxd github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= -github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= @@ -1037,11 +925,9 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= @@ -1049,8 +935,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -1117,20 +1001,14 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -1143,7 +1021,6 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -1196,7 +1073,6 @@ github.com/relvacode/iso8601 v1.1.0 h1:2nV8sp0eOjpoKQ2vD3xSDygsjAx37NHG2UlZiCkDH github.com/relvacode/iso8601 v1.1.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -1205,7 +1081,6 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -1225,9 +1100,6 @@ github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sethvargo/go-limiter v0.7.2 h1:FgC4N7RMpV5gMrUdda15FaFTkQ/L4fEqM7seXMs4oO8= github.com/sethvargo/go-limiter v0.7.2/go.mod h1:C0kbSFbiriE5k2FFOe18M1YZbAR2Fiwf72uGu0CXCcU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= @@ -1266,8 +1138,8 @@ github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKv github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= -github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1284,7 +1156,6 @@ github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff h1:jBz/gRYeRf2MjtxtdTHUX3PbIYFJD2S7TViBrhGWbPA= github.com/spruceid/siwe-go v0.2.1-0.20220804171946-fc1b0374f4ff/go.mod h1:X+Fj7GsCyLAjfrjkGzgoiRsoAh8+bz4fSz2N3jwN9bc= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1295,7 +1166,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1309,11 +1179,9 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tablelandnetwork/sqlparser v0.0.0-20221230162331-b318f234cefd h1:AbpyzqlTban/UqJTrotlpWC9q/ePGU4qsrvqjoiLmG4= @@ -1326,7 +1194,6 @@ github.com/textileio/go-log/v2 v2.1.3-gke-2/go.mod h1:DwACkjFS3kjZZR/4Spx3aPfSsc github.com/textileio/opentelemetry-go-contrib/instrumentation/net/http/otelhttp v0.26.1-0.20220407173812-deccbe316725 h1:a6cvZKwHxznhOK3feagpqKbWlhfP5XLXxRlf5pnE1hA= github.com/textileio/opentelemetry-go-contrib/instrumentation/net/http/otelhttp v0.26.1-0.20220407173812-deccbe316725/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= @@ -1336,19 +1203,13 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y= -github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= @@ -1357,7 +1218,6 @@ github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmF github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= @@ -1368,17 +1228,14 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= @@ -1404,9 +1261,9 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= @@ -1414,7 +1271,6 @@ go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzox go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ= go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= -go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0= go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= @@ -1426,13 +1282,11 @@ go.opentelemetry.io/otel/exporters/prometheus v0.34.0 h1:L5D+HxdaC/ORB47ribbTBbk go.opentelemetry.io/otel/exporters/prometheus v0.34.0/go.mod h1:6gUoJyfhoWqF0tOLaY0ZmKgkQRcvEQx6p5rVlKHp3s4= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw= -go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= go.opentelemetry.io/otel/metric v0.34.0 h1:MCPoQxcg/26EuuJwpYN1mZTeCYAUGx8ABxfW07YkjP8= go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= -go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= go.opentelemetry.io/otel/sdk v1.11.2 h1:GF4JoaEx7iihdMFu30sOyRx52HDHOkl9xQ8SMqNXUiU= go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU= go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= @@ -1443,7 +1297,6 @@ go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16g go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE= go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= -go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= @@ -1481,16 +1334,13 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -1511,7 +1361,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1545,8 +1394,6 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1589,10 +1436,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1600,7 +1445,6 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -1609,24 +1453,17 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1647,13 +1484,8 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1666,8 +1498,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1712,7 +1544,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1735,9 +1566,7 @@ golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1765,7 +1594,6 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1787,27 +1615,16 @@ golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1823,15 +1640,15 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= @@ -1875,11 +1692,9 @@ golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1916,23 +1731,18 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= @@ -1969,20 +1779,8 @@ google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0 h1:d1c24AAS01DYqXreBeuVV7ewY/U8Mnhh47pwtsgVtYg= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2000,7 +1798,6 @@ google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -2008,7 +1805,6 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= @@ -2041,7 +1837,6 @@ google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= @@ -2065,32 +1860,10 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f h1:wwbo0UziciPT4Dsca+bmplW53QNAl7tiUOw7FfAcsf8= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd h1:OjndDrsik+Gt+e6fs45z9AxiewiKyLKYpA45W5Kpkks= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2123,13 +1896,9 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2144,7 +1913,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= @@ -2174,7 +1942,6 @@ gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -2205,7 +1972,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= From 5272681de228fe2a51ebab9f76af0b25c442db3d Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 17 Jan 2023 10:20:49 -0300 Subject: [PATCH 101/101] gha: fix deployment action Signed-off-by: Ignacio Hagopian --- .github/workflows/deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2f76533d..35820664 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,7 +14,7 @@ on: jobs: deploy: - if: contains(github.event.head_commit.message, '[stagingdeploy]') || contains(github.event.head_commit.message, '[testnetdeploy]') || contains(github.event.head_commit.message, '[mainnetdeploy]') + if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[stagingdeploy]') || contains(github.event.head_commit.message, '[testnetdeploy]') || contains(github.event.head_commit.message, '[mainnetdeploy]') name: Deploy runs-on: ubuntu-latest steps: @@ -55,7 +55,7 @@ jobs: for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" - - if: github.ref == 'refs/heads/main'|| contains(github.event.head_commit.message, '[testnetdeploy]') + - if: github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[testnetdeploy]') name: Deploy testnet uses: appleboy/ssh-action@master with: @@ -78,7 +78,7 @@ jobs: for i in 1 2 3 4; do [ $(curl --insecure --silent https://127.0.0.1/api/v1/version | jq .git_commit) = "\"${{ steps.prep.outputs.sha_short}}\"" ] && break || (if [ $i = 4 ]; then exit -1; else sleep 5; fi ) done echo "All healthy!" - - if: github.event_name == 'release' || github.ref == 'refs/heads/main' || contains(github.event.head_commit.message, '[mainnetdeploy]') + - if: github.event_name == 'release' || contains(github.event.head_commit.message, '[mainnetdeploy]') name: Deploy mainnet uses: appleboy/ssh-action@master with: