diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml new file mode 100644 index 00000000..4c02c06e --- /dev/null +++ b/.github/workflows/binaries.yml @@ -0,0 +1,107 @@ +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 + 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: + github-token: ${{ secrets.TEXTILEIO_MACHINE_ACCESS_TOKEN }} + script: | + // 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 { + const ownerOrg = 'tablelandnetwork'; + + // 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); + } + + const options = { + owner: ownerOrg, + repo: 'js-validator', + workflow_id: 'validator-update-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); + } diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 27194652..35820664 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,11 @@ 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: ${{ steps.prep.outputs.vm_host }} + host: ${{ secrets.STAGING_VM_HOST }} username: validator key: ${{ env.vm_ssh_key }} port: 22 @@ -53,12 +46,57 @@ jobs: cd go-tableland git fetch && git checkout -f ${{ github.sha }} cd docker - - HEALTHBOT_ENABLED=true make ${{ steps.prep.outputs.deployment }}-up + + 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 + 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]') + name: Deploy testnet + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.TESTNET_V2_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 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. + sleep 5; + 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' || contains(github.event.head_commit.message, '[mainnetdeploy]') + name: Deploy mainnet + 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/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/.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 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/Makefile b/Makefile index 74b304be..4e919e4c 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,21 @@ 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 +.PHONY: lint + +# OpenAPI +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} + 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: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} && \ + mv go/* . && \ + 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/cmd/api/main.go b/cmd/api/main.go index aac6c739..d11de87c 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -35,6 +35,8 @@ 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/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" "github.com/textileio/go-tableland/pkg/sqlstore/impl/user" @@ -93,13 +95,17 @@ 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, readstatementresolver.New(eps)) if err != nil { log.Fatal().Err(err).Msg("creating user store") } // 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,28 +474,57 @@ 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) { - rateLimInterval, err := time.ParseDuration(httpConfig.RateLimInterval) + instrUserStore, err := sqlstoreimpl.NewInstrumentedUserStore(userStore) if err != nil { - return nil, fmt.Errorf("parsing http ratelimiter interval: %s", err) + 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) } - router := router.ConfiguredRouter( + 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, gatewayConfig.ExternalURIPrefix, gatewayConfig.MetadataRendererURI, - gatewayConfig.AnimationRendererURI, + 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( + mesaService, + systemService, httpConfig.MaxRequestPerInterval, rateLimInterval, - parser, - userStore, - chainStacks, + supportedChainIDs, ) + if err != nil { + return nil, fmt.Errorf("configuring router: %s", err) + } server := &http.Server{ Addr: ":" + httpConfig.Port, 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 7d7d7473..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/rpcservice" + 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 := rpcservice.RelayWriteQueryRequest{ - Statement: fmt.Sprintf("update %s set counter=counter+1", cp.tableName), - } - var updateCounterRes rpcservice.RelayWriteQueryResponse - if err := cp.rpcClient.CallContext(ctx, &updateCounterRes, "tableland_relayWriteQuery", updateCounterReq); err != nil { - return fmt.Errorf("calling tableland_runReadQuery: %s", err) - } - - getReceiptRequest := rpcservice.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 rpcservice.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 := rpcservice.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/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)") } diff --git a/docker/Makefile b/docker/Makefile index 8ea088c4..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 @@ -46,4 +41,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 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/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..11b73390 --- /dev/null +++ b/docker/deployed/mainnet/api/config.json @@ -0,0 +1,167 @@ +{ + "Impl": "mesa", + "HTTP": { + "Port": "8080", + "RateLimInterval": "1s", + "MaxRequestPerInterval": 10, + "TLSCert": "${VALIDATOR_TLS_CERT}", + "TLSKey": "${VALIDATOR_TLS_KEY}" + }, + "Gateway": { + "ExternalURIPrefix": "https://tableland.network", + "MetadataRendererURI": "https://render.tableland.xyz", + "AnimationRendererURI": "https://render.tableland.xyz/anim" + }, + "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-mainnet-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/mainnet/grafana/.env_grafana.example b/docker/deployed/mainnet/grafana/.env_grafana.example new file mode 100644 index 00000000..0b6e7eb0 --- /dev/null +++ b/docker/deployed/mainnet/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/docker/deployed/mainnet/grafana/data/.gitkeep b/docker/deployed/mainnet/grafana/data/.gitkeep new file mode 100644 index 00000000..e69de29b 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 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/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..8598c10e 100644 --- a/docker/deployed/staging/healthbot/config.json +++ b/docker/deployed/staging/healthbot/config.json @@ -6,14 +6,13 @@ "Human": false, "Debug": true }, - "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/api/config.json b/docker/deployed/testnet/api/config.json index 5b99ef2d..b668e8e2 100644 --- a/docker/deployed/testnet/api/config.json +++ b/docker/deployed/testnet/api/config.json @@ -8,9 +8,9 @@ "TLSKey": "${VALIDATOR_TLS_KEY}" }, "Gateway": { - "ExternalURIPrefix": "https://testnet.tableland.network", - "MetadataRendererURI": "https://render.tableland.xyz", - "AnimationRendererURI": "https://render.tableland.xyz/anim" + "ExternalURIPrefix": "https://testnets.tableland.network", + "MetadataRendererURI": "https://testnets.render.tableland.xyz", + "AnimationRendererURI": "https://testnets.render.tableland.xyz/anim" }, "DB": { "Port": "5432" @@ -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" @@ -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, 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/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..d7ffbdf8 100644 --- a/docker/deployed/testnet/healthbot/config.json +++ b/docker/deployed/testnet/healthbot/config.json @@ -6,41 +6,40 @@ "Human": false, "Debug": true }, - "Target": "https://testnet.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}" } } 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 diff --git a/go.mod b/go.mod index 9b3b5f46..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.16.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/mattn/go-sqlite3 v1.14.15 + 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.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 + github.com/spf13/cobra v1.6.1 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-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.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/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 @@ -56,9 +58,9 @@ 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/googleapis/enterprise-certificate-proxy v0.1.0 // indirect - github.com/googleapis/gax-go/v2 v2.5.1 // indirect + github.com/google/go-cmp v0.5.9 // 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 @@ -78,7 +80,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 @@ -90,27 +92,27 @@ 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 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.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 44854ec0..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.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.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,15 +610,14 @@ 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= 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= @@ -716,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= @@ -746,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= @@ -763,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= @@ -795,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= @@ -808,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= @@ -866,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= @@ -891,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= @@ -910,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= @@ -938,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= @@ -964,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= @@ -984,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.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +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/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= @@ -1017,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= @@ -1036,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= @@ -1048,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= @@ -1116,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= @@ -1142,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= @@ -1155,14 +1033,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= @@ -1194,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= @@ -1203,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= @@ -1223,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= @@ -1264,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= @@ -1279,22 +1153,19 @@ 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= -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= 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= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1303,19 +1174,18 @@ 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= 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-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-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= @@ -1324,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= @@ -1334,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= @@ -1355,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= @@ -1366,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= @@ -1402,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= @@ -1412,40 +1271,34 @@ 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.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.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.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.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= @@ -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= 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 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_query.go b/internal/router/controllers/apiv1/api_query.go new file mode 100644 index 00000000..0d2ccd80 --- /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 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/api_receipt.go b/internal/router/controllers/apiv1/api_receipt.go new file mode 100644 index 00000000..81177b33 --- /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 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/api_tables.go b/internal/router/controllers/apiv1/api_tables.go new file mode 100644 index 00000000..fced67cc --- /dev/null +++ b/internal/router/controllers/apiv1/api_tables.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 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/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_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..83060b06 --- /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:"table_constraints,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..08a21d59 --- /dev/null +++ b/internal/router/controllers/apiv1/model_table.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 Table struct { + + Name string `json:"name,omitempty"` + + ExternalUrl string `json:"external_url,omitempty"` + + AnimationUrl string `json:"animation_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..e519d6b6 --- /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 interface{} `json:"value,omitempty"` +} 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..bf8d16e1 --- /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:"table_id,omitempty"` + + TransactionHash string `json:"transaction_hash,omitempty"` + + BlockNumber int64 `json:"block_number,omitempty"` + + ChainId int32 `json:"chain_id,omitempty"` + + Error_ string `json:"error,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 new file mode 100644 index 00000000..d460bc98 --- /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 int32 `json:"version,omitempty"` + + GitCommit string `json:"git_commit,omitempty"` + + GitBranch string `json:"git_branch,omitempty"` + + GitState string `json:"git_state,omitempty"` + + GitSummary string `json:"git_summary,omitempty"` + + BuildDate string `json:"build_date,omitempty"` + + BinaryVersion string `json:"binary_version,omitempty"` +} diff --git a/internal/router/controllers/apiv1/routers.go b/internal/router/controllers/apiv1/routers.go new file mode 100644 index 00000000..f61e6894 --- /dev/null +++ b/internal/router/controllers/apiv1/routers.go @@ -0,0 +1,92 @@ +/* + * 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{ + "Health", + strings.ToUpper("Get"), + "/api/v1/health", + Health, + }, + + Route{ + "QueryByStatement", + strings.ToUpper("Get"), + "/api/v1/query", + QueryByStatement, + }, + + Route{ + "ReceiptByTransactionHash", + strings.ToUpper("Get"), + "/api/v1/receipt/{chainId}/{transactionHash}", + ReceiptByTransactionHash, + }, + + Route{ + "GetTableById", + strings.ToUpper("Get"), + "/api/v1/tables/{chainId}/{tableId}", + GetTableById, + }, + + Route{ + "Version", + strings.ToUpper("Get"), + "/api/v1/version", + Version, + }, +} diff --git a/internal/router/controllers/user.go b/internal/router/controllers/controller.go similarity index 51% rename from internal/router/controllers/user.go rename to internal/router/controllers/controller.go index ba5e87a1..2999831b 100644 --- a/internal/router/controllers/user.go +++ b/internal/router/controllers/controller.go @@ -6,13 +6,18 @@ 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" "github.com/textileio/go-tableland/pkg/errors" "github.com/textileio/go-tableland/pkg/tables" @@ -24,14 +29,18 @@ 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 { - runner SQLRunner +// 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) *UserController { - return &UserController{runner} +// NewController creates a new Controller. +func NewController(runner SQLRunner, svc system.SystemService) *Controller { + return &Controller{ + runner: runner, + systemService: svc, + } } // MetadataConfig defines columns should be mapped to erc721 metadata @@ -128,7 +137,8 @@ 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. -func (c *UserController) GetTableRow(rw http.ResponseWriter, r *http.Request) { +// TODO(json-rpc): delete method when dropping support. +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") @@ -209,12 +219,305 @@ func (c *UserController) GetTableRow(rw http.ResponseWriter, r *http.Request) { } } +// Version returns git information of the running binary. +func (c *Controller) 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 *Controller) 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 *Controller) 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 *Controller) 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 *Controller) 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 *Controller) 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) { +func (c *Controller) 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 { @@ -248,7 +551,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, @@ -299,7 +602,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/internal/router/controllers/user_test.go b/internal/router/controllers/controller_test.go similarity index 66% rename from internal/router/controllers/user_test.go rename to internal/router/controllers/controller_test.go index 41cb9acf..7fb8ecd0 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,20 +11,21 @@ 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" ) -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)) + ctrl := NewController(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) @@ -33,16 +35,16 @@ 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)) + ctrl := NewController(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) @@ -52,7 +54,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,10 +63,10 @@ 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) + ctrl := NewController(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) @@ -75,7 +77,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,10 +106,10 @@ func TestUserControllerRowNotFound(t *testing.T) { req, err := http.NewRequest("GET", "/chain/69/tables/100/id/1", nil) require.NoError(t, err) - userController := NewUserController(r) + ctrl := NewController(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) @@ -118,7 +120,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,10 +150,10 @@ func TestUserControllerQuery(t *testing.T) { nil, ) - userController := NewUserController(r) + ctrl := NewController(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) @@ -186,7 +188,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,10 +210,10 @@ func TestUserControllerLegacyQuery(t *testing.T) { nil, ) - userController := NewUserController(r) + ctrl := NewController(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) @@ -237,7 +239,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,10 +253,10 @@ func TestUserControllerQueryExtracted(t *testing.T) { nil, ) - userController := NewUserController(r) + ctrl := NewController(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 TestUserControllerQueryExtracted(t *testing.T) { } } +func TestGetTablesByMocked(t *testing.T) { + t.Parallel() + + systemService := systemimpl.NewSystemMockService() + ctrl := NewController(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 := NewController(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 := NewController(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 3ae77b1b..00000000 --- a/internal/router/controllers/infra.go +++ /dev/null @@ -1,24 +0,0 @@ -package controllers - -import ( - "encoding/json" - "net/http" - - "github.com/textileio/go-tableland/buildinfo" -) - -// 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) { - rw.Header().Set("Content-type", "application/json") - summary := buildinfo.GetSummary() - rw.WriteHeader(http.StatusOK) - _ = json.NewEncoder(rw).Encode(summary) -} diff --git a/internal/router/rpcservice/rpcservice.go b/internal/router/controllers/legacy/rpcservice.go similarity index 99% rename from internal/router/rpcservice/rpcservice.go rename to internal/router/controllers/legacy/rpcservice.go index c1d939a4..f3a44e8d 100644 --- a/internal/router/rpcservice/rpcservice.go +++ b/internal/router/controllers/legacy/rpcservice.go @@ -1,4 +1,4 @@ -package rpcservice +package legacy import ( "context" 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/system.go deleted file mode 100644 index 3bec5313..00000000 --- a/internal/router/controllers/system.go +++ /dev/null @@ -1,199 +0,0 @@ -package controllers - -import ( - "encoding/json" - "net/http" - - "github.com/gorilla/mux" - "github.com/rs/zerolog/log" - "github.com/textileio/go-tableland/internal/system" - "github.com/textileio/go-tableland/pkg/errors" - "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} -} - -// GetTable handles the GET /chain/{chainID}/tables/{id} 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["id"]) - 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 - } - - metadata, err := c.systemService.GetTableMetadata(ctx, id) - 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 - } - - rw.WriteHeader(http.StatusOK) - enc := json.NewEncoder(rw) - enc.SetEscapeHTML(false) - _ = enc.Encode(metadata) -} - -// GetTablesByController handles the GET /chain/{chainID}/tables/controller/{address} call. -func (c *SystemController) 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. -func (c *SystemController) 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. -func (c *SystemController) 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, - }) -} diff --git a/internal/router/controllers/system_test.go b/internal/router/controllers/system_test.go deleted file mode 100644 index 2b7c7db6..00000000 --- a/internal/router/controllers/system_test.go +++ /dev/null @@ -1,170 +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 TestSystemControllerMock(t *testing.T) { - t.Parallel() - - systemService := systemimpl.NewSystemMockService() - systemController := NewSystemController(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/{id}", systemController.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}] - }` - 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}", systemController.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}", systemController.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}", systemController.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 TestInvalidID(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 := NewSystemController(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 := NewSystemController(systemService) - - router := mux.NewRouter() - router.HandleFunc("/tables/{id}", 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/middlewares/rest.go b/internal/router/middlewares/rest.go index 59bf10d8..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 26a12c82..d139c77e 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -1,109 +1,154 @@ 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/controllers/apiv1" + "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/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 { - instrUserStore, err := sqlstoreimpl.NewInstrumentedUserStore(userStore) - if err != nil { - log.Fatal().Err(err).Msg("creating instrumented user store") - } - - mesaService := impl.NewTablelandMesa(parser, instrUserStore, chainStacks) - mesaService, err = impl.NewInstrumentedTablelandMesa(mesaService) - if err != nil { - log.Fatal().Err(err).Msg("instrumenting mesa") - } - rpcService := rpcservice.NewRPCService(mesaService) - userController := controllers.NewUserController(mesaService) - + supportedChainIDs []tableland.ChainID, +) (*Router, error) { + rpcService := legacy.NewRPCService(tableland) 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() - - 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 { - log.Fatal().Err(err).Msg("creating system store") - } - systemService, err := systemimpl.NewInstrumentedSystemSQLStoreService(sysStore) - if err != nil { - log.Fatal().Err(err).Msg("instrumenting system sql store") - } - 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{ 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 { - log.Fatal().Err(err).Msg("creating rate limit controller middleware") + return nil, fmt.Errorf("creating rate limit controller middleware: %s", err) + } + + ctrl := controllers.NewController(tableland, systemService) + + // TODO(json-rpc): remove this when dropping support. + // APIs Legacy (REST + JSON-RPC) + configureLegacyRoutes(router, server, supportedChainIDs, rateLim, ctrl) + + // APIs V1 + if err := configureAPIV1Routes(router, supportedChainIDs, rateLim, ctrl); err != nil { + return nil, fmt.Errorf("configuring API v1: %s", err) } - router.Post("/rpc", func(rw http.ResponseWriter, r *http.Request) { + return router, nil +} + +func configureLegacyRoutes( + router *Router, + server *rpc.Server, + supportedChainIDs []tableland.ChainID, + rateLim mux.MiddlewareFunc, + 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/{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}", 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", userController.GetTableQuery, middlewares.WithLogging, middlewares.OtelHTTP("GetTableQuery"), rateLim) // nolint - router.Get("/version", infraController.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", healthHandler) - router.Get("/health", healthHandler) - - return router + router.get("/healthz", controllers.HealthHandler) + router.get("/health", controllers.HealthHandler) } -func healthHandler(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) +func configureAPIV1Routes( + router *Router, + supportedChainIDs []tableland.ChainID, + rateLim mux.MiddlewareFunc, + userCtrl *controllers.Controller, +) error { + handlers := map[string]struct { + handler http.HandlerFunc + middlewares []mux.MiddlewareFunc + }{ + "QueryByStatement": { + userCtrl.GetTableQuery, + []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, + }, + "ReceiptByTransactionHash": { + userCtrl.GetReceiptByTransactionHash, + []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim}, + }, + "GetTableById": { + userCtrl.GetTable, + []mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim}, + }, + "Version": { + userCtrl.Version, + []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, + }, + "Health": { + controllers.HealthHandler, + []mux.MiddlewareFunc{middlewares.WithLogging, rateLim}, + }, + } + + var specRoutesCount int + if err := apiv1.NewRouter().Walk(func(route *mux.Route, _ *mux.Router, _ []*mux.Route) error { + 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++ + endpoint, ok := handlers[routeName] + if !ok { + return fmt.Errorf("route with name %s not found in handler", routeName) + } + pathTemplate, err := route.GetPathTemplate() + if err != nil { + return fmt.Errorf("get path template: %s", err) + } + + router.get( + pathTemplate, + endpoint.handler, + append(endpoint.middlewares, middlewares.OtelHTTP(routeName))..., + ) + 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. @@ -111,36 +156,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...) } diff --git a/internal/system/impl/mock.go b/internal/system/impl/mock.go index 99710fcc..17edb5c6 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{ @@ -33,6 +48,9 @@ func (*SystemMockService) GetTableMetadata(_ context.Context, id tables.TableID) Value: 1546360800, }, }, + Schema: sqlstore.TableSchema{ + Columns: []sqlstore.ColumnSchema{{Name: "foo", Type: "text"}}, + }, }, nil } @@ -109,6 +127,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..723ccf46 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" @@ -109,11 +110,16 @@ func (s *SystemSQLStoreService) GetTableMetadata( ExternalURL: fmt.Sprintf("%s/chain/%d/tables/%s", s.extURLPrefix, chainID, id), Image: s.emptyMetadataImage(), Message: "Table not found", - }, nil + }, system.ErrTableNotFound + } + 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), @@ -124,9 +130,42 @@ func (s *SystemSQLStoreService) GetTableMetadata( Value: table.CreatedAt.Unix(), }, }, + Schema: schema, }, nil } +// GetReceiptByTransactionHash returns a receipt by transaction hash. +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..86ecbdc6 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,28 @@ 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 +74,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/impl/sqlstore_test.go b/internal/system/impl/sqlstore_test.go index 37e3b244..fa0440db 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" @@ -127,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))", }, }, }) @@ -147,18 +148,18 @@ 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) 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) { @@ -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) diff --git a/internal/system/system.go b/internal/system/system.go index 36d3a73d..a3ee19aa 100644 --- a/internal/system/system.go +++ b/internal/system/system.go @@ -2,15 +2,22 @@ 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" ) +// ErrTableNotFound indicates that the table doesn't exist. +var ErrTableNotFound = errors.New("table not found") + // 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) 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/internal/tableland/impl/mesa_test.go b/internal/tableland/impl/mesa_test.go index 6e7ff2b9..68c8174a 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" + 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" @@ -64,27 +66,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. @@ -979,13 +960,14 @@ 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, 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/internal/tableland/impl/testdata/any_queries.csv b/internal/tableland/impl/testdata/any_queries.csv deleted file mode 100644 index e803f7fe..00000000 --- a/internal/tableland/impl/testdata/any_queries.csv +++ /dev/null @@ -1,4 +0,0 @@ -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]]}" 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/client/chains.go b/pkg/client/chains.go index e21dc13d..52a600d3 100644 --- a/pkg/client/chains.go +++ b/pkg/client/chains.go @@ -5,7 +5,8 @@ import ( ) const ( - testnetURL = "https://testnet.tableland.network" + mainnetURL = "https://tableland.network" + testnetURL = "https://testnets.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, } @@ -39,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{ - Endpoint: testnetURL, +var Chains = map[ChainID]Chain{ + ChainIDs.Ethereum: { + Endpoint: mainnetURL, ID: ChainIDs.Ethereum, + Name: "Ethereum", ContractAddr: common.HexToAddress("0x012969f7e3439a9B04025b5a049EB9BAD82A8C12"), }, - Optimism: Chain{ - Endpoint: testnetURL, + ChainIDs.Optimism: { + Endpoint: mainnetURL, ID: ChainIDs.Optimism, + Name: "Optimism", ContractAddr: common.HexToAddress("0xfad44BF5B843dE943a09D4f3E84949A11d3aa3e6"), }, - Polygon: Chain{ - Endpoint: testnetURL, + ChainIDs.Polygon: { + Endpoint: mainnetURL, ID: ChainIDs.Polygon, + Name: "Polygon", ContractAddr: common.HexToAddress("0x5c4e6A9e5C1e1BF445A062006faF19EA6c49aFeA"), }, - EthereumGoerli: Chain{ + ChainIDs.Arbitrum: { + Endpoint: mainnetURL, + ID: ChainIDs.Arbitrum, + Name: "Arbitrum", + ContractAddr: common.HexToAddress("0x9aBd75E8640871A5a20d3B4eE6330a04c962aFfd"), + }, + 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"), }, - Arbitrum: Chain{ - Endpoint: testnetURL, - ID: ChainIDs.Arbitrum, - ContractAddr: common.HexToAddress("0x9aBd75E8640871A5a20d3B4eE6330a04c962aFfd"), - }, - 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"), }, } @@ -106,7 +107,8 @@ func (c Chain) CanRelayWrites() bool { return c.ID != ChainIDs.Ethereum && c.ID != ChainIDs.Optimism && c.ID != ChainIDs.Polygon } -var infuraURLs = map[ChainID]string{ +// InfuraURLs contains the URLs for supported chains for Infura. +var InfuraURLs = map[ChainID]string{ ChainIDs.EthereumGoerli: "https://goerli.infura.io/v3/%s", ChainIDs.Ethereum: "https://mainnet.infura.io/v3/%s", ChainIDs.OptimismGoerli: "https://optimism-goerli.infura.io/v3/%s", @@ -117,7 +119,8 @@ var infuraURLs = map[ChainID]string{ ChainIDs.Polygon: "https://polygon-mainnet.infura.io/v3/%s", } -var alchemyURLs = map[ChainID]string{ +// 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", ChainIDs.OptimismGoerli: "https://opt-goerli.g.alchemy.com/v2/%s", @@ -128,6 +131,7 @@ var alchemyURLs = map[ChainID]string{ ChainIDs.Polygon: "https://polygon-mainnet.g.alchemy.com/v2/%s", } -var localURLs = map[ChainID]string{ +// LocalURLs contains the URLs for a local network. +var LocalURLs = map[ChainID]string{ ChainIDs.Local: "http://localhost:8545", } diff --git a/pkg/client/client.go b/pkg/client/legacy/client.go similarity index 88% rename from pkg/client/client.go rename to pkg/client/legacy/client.go index 4bf0314d..13804268 100644 --- a/pkg/client/client.go +++ b/pkg/client/legacy/client.go @@ -1,4 +1,4 @@ -package client +package clientlegacy import ( "context" @@ -13,8 +13,9 @@ 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/client" "github.com/textileio/go-tableland/pkg/nonce/impl" "github.com/textileio/go-tableland/pkg/siwe" "github.com/textileio/go-tableland/pkg/tables" @@ -22,16 +23,17 @@ import ( "github.com/textileio/go-tableland/pkg/wallet" ) -var defaultChain = 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. 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"` + 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. @@ -76,13 +78,13 @@ type Client struct { tblRPC *rpc.Client tblHTTP *http.Client tblContract *ethereum.Client - chain Chain + chain client.Chain relayWrites bool wallet *wallet.Wallet } type config struct { - chain *Chain + chain *client.Chain relayWrites *bool infuraAPIKey string alchemyAPIKey string @@ -94,7 +96,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 } @@ -251,8 +253,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 +292,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 +305,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 +314,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 +322,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 +357,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 +377,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 +387,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 +436,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 +447,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) } @@ -455,7 +457,7 @@ func (c *Client) getReceipt(ctx context.Context, txnHash string) (*TxnReceipt, b } receipt := TxnReceipt{ - ChainID: ChainID(res.Receipt.ChainID), + ChainID: client.ChainID(res.Receipt.ChainID), TxnHash: res.Receipt.TxnHash, BlockNumber: res.Receipt.BlockNumber, Error: res.Receipt.Error, @@ -497,19 +499,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/legacy/client_test.go similarity index 58% rename from pkg/client/client_test.go rename to pkg/client/legacy/client_test.go index 2b195dce..d2ca915a 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/legacy/client_test.go @@ -1,36 +1,16 @@ -package client +package clientlegacy 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/pkg/client" + "github.com/textileio/go-tableland/tests/fullstack" ) func TestCreate(t *testing.T) { @@ -148,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) @@ -179,95 +140,25 @@ 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) + stack := fullstack.CreateFullStack(t, fullstack.Deps{}) - 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, - }, + c := client.Chain{ + Endpoint: stack.Server.URL, + ID: client.ChainID(fullstack.ChainID), + ContractAddr: stack.Address, } - router := router.ConfiguredRouter( - "https://testnet.tableland.network", - "https://render.tableland.xyz", - "", - 10, - time.Second, - parser, - userStore, - chainStack, - ) - - server := httptest.NewServer(router.Handler()) - - c := Chain{ - Endpoint: server.URL, - ID: ChainID(1337), - ContractAddr: addr, - } - - 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) @@ -277,7 +168,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) @@ -290,7 +181,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 { @@ -311,7 +202,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/pkg/client/v1/client.go b/pkg/client/v1/client.go new file mode 100644 index 00000000..674779bc --- /dev/null +++ b/pkg/client/v1/client.go @@ -0,0 +1,188 @@ +package v1 + +import ( + "context" + "errors" + "fmt" + "math/big" + "net/http" + "net/url" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "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" + "github.com/textileio/go-tableland/pkg/tables/impl/ethereum" + "github.com/textileio/go-tableland/pkg/wallet" +) + +var defaultChain = client.Chains[client.ChainIDs.PolygonMumbai] + +// Client is the Tableland client. +type Client struct { + tblHTTP *http.Client + tblContract *ethereum.Client + chain client.Chain + wallet *wallet.Wallet + parser parsing.SQLValidator + baseURL *url.URL +} + +type config struct { + chain *client.Chain + 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 + } +} + +// 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) + } + + 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) + } + + parserOpts := []parsing.Option{ + parsing.WithMaxReadQuerySize(35000), + parsing.WithMaxWriteQuerySize(35000), + } + + parser, err := parserimpl.New([]string{ + "sqlite_", + systemimpl.SystemTablesPrefix, + systemimpl.RegistryTableName, + }, parserOpts...) + if err != nil { + return nil, fmt.Errorf("new parser: %s", err) + } + + baseURL, err := url.Parse(config.chain.Endpoint) + if err != nil { + return nil, fmt.Errorf("invalid endpoint URL: %s", err) + } + + return &Client{ + tblHTTP: &http.Client{ + Timeout: time.Second * 30, + }, + tblContract: tblContract, + chain: *config.chain, + wallet: wallet, + parser: parser, + baseURL: baseURL, + }, nil +} + +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") +} + +// 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/v1/client_test.go b/pkg/client/v1/client_test.go new file mode 100644 index 00000000..d0c7737d --- /dev/null +++ b/pkg/client/v1/client_test.go @@ -0,0 +1,234 @@ +package v1 + +import ( + "context" + "fmt" + "testing" + "time" + + "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) { + calls := setup(t) + requireCreate(t, calls) +} + +func TestWrite(t *testing.T) { + calls := setup(t) + tableName := requireCreate(t, calls) + requireWrite(t, calls, tableName) +} + +func TestRead(t *testing.T) { + t.Run("status 200", func(t *testing.T) { + calls := setup(t) + tableName := requireCreate(t, calls) + hash := requireWrite(t, calls, tableName) + requireReceipt(t, calls, hash, WaitFor(time.Second*10)) + + type result struct { + Bar string `json:"bar"` + } + + res0 := []result{} + 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", tableName), &res1, ReadFormat(Table)) + require.Len(t, res1, 2) + + res2 := result{} + 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", tableName), &res3, ReadExtract()) + require.Len(t, res3, 1) + require.Equal(t, "baz", res3[0]) + + res4 := "" + calls.query(fmt.Sprintf("select * from %s", tableName), &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) + }) +} + +func TestGetReceipt(t *testing.T) { + t.Run("status 200", func(t *testing.T) { + calls := setup(t) + 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) + _, _, 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.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) { + calls := setup(t) + info, err := calls.version() + require.NoError(t, err) + + require.Equal(t, int32(0), 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) { + calls := setup(t) + healthy, err := calls.health() + require.NoError(t, err) + require.True(t, healthy) +} + +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 tableName +} + +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 +} + +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) + return res +} + +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) + receipt func(txnHash string, options ...ReceiptOption) (*apiv1.TransactionReceipt, bool) + getTableByID func(tableID TableID) *apiv1.Table + version func() (*apiv1.VersionInfo, error) + health func() (bool, error) +} + +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) + + ctx := context.Background() + return clientCalls{ + client: client, + 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 + }, + query: func(query string, target interface{}, opts ...ReadOption) { + err := client.Read(ctx, query, target, opts...) + require.NoError(t, err) + }, + write: func(query string) string { + hash, err := client.Write(ctx, query) + require.NoError(t, err) + stack.Backend.Commit() + return hash + }, + 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 TableID) *apiv1.Table { + table, err := client.GetTable(ctx, tableID) + require.NoError(t, err) + return table + }, + version: func() (*apiv1.VersionInfo, error) { + return client.Version(ctx) + }, + health: func() (bool, error) { + return client.CheckHealth(ctx) + }, + } +} diff --git a/pkg/client/v1/health.go b/pkg/client/v1/health.go new file mode 100644 index 00000000..ebe79e54 --- /dev/null +++ b/pkg/client/v1/health.go @@ -0,0 +1,23 @@ +package v1 + +import ( + "context" + "fmt" + "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 := 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) + } + res, err := c.tblHTTP.Do(req) + if err != nil { + return false, fmt.Errorf("http get error: %s", err) + } + defer func() { _ = res.Body.Close() }() + + return res.StatusCode == http.StatusOK, nil +} diff --git a/pkg/client/v1/queryhelpers.go b/pkg/client/v1/queryhelpers.go new file mode 100644 index 00000000..1dd32000 --- /dev/null +++ b/pkg/client/v1/queryhelpers.go @@ -0,0 +1,25 @@ +package v1 + +import ( + "fmt" + + "github.com/textileio/go-tableland/internal/tableland" +) + +// Hash validates the provided create table statement and returns its hash. +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) + } + return stmt.GetStructureHash(), nil +} + +// Validate validates a write query, returning the table id. +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) + } + return NewTableID(stmts[0].GetTableID().String()) +} diff --git a/pkg/client/v1/readquery.go b/pkg/client/v1/readquery.go new file mode 100644 index 00000000..de226f59 --- /dev/null +++ b/pkg/client/v1/readquery.go @@ -0,0 +1,101 @@ +package v1 + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" +) + +// 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) + +// ReadFormat sets the output format. Default is Objects. +func ReadFormat(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 + } +} + +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 + for _, opt := range opts { + opt(¶ms) + } + + url := c.baseURL.ResolveReference(queryURL) + 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() + + 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 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) + } + + 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/v1/receipt.go b/pkg/client/v1/receipt.go new file mode 100644 index 00000000..541d2ce8 --- /dev/null +++ b/pkg/client/v1/receipt.go @@ -0,0 +1,90 @@ +package v1 + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "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 := 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) + } + response, err := c.tblHTTP.Do(req) + if err != nil { + return nil, false, fmt.Errorf("calling get receipt by transaction hash: %s", err) + } + defer func() { _ = response.Body.Close() }() + 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 (status: %d, body: %s)", response.StatusCode, 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/v1/table.go b/pkg/client/v1/table.go new file mode 100644 index 00000000..8d71f238 --- /dev/null +++ b/pkg/client/v1/table.go @@ -0,0 +1,43 @@ +package v1 + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + + "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 := 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) + } + response, err := c.tblHTTP.Do(req) + if err != nil { + return nil, fmt.Errorf("calling get tables by id: %s", err) + } + defer func() { _ = response.Body.Close() }() + 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/client/v1/version.go b/pkg/client/v1/version.go new file mode 100644 index 00000000..6bf319bd --- /dev/null +++ b/pkg/client/v1/version.go @@ -0,0 +1,36 @@ +package v1 + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + "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 := fmt.Sprintf("%s/api/v1/version", c.baseURL) + + req, err := http.NewRequestWithContext(ctx, "GET", url, 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 func() { _ = res.Body.Close() }() + + bb, _ := io.ReadAll(res.Body) + + var versionInfo apiv1.VersionInfo + if err := json.NewDecoder(bytes.NewReader(bb)).Decode(&versionInfo); err != nil { + return nil, fmt.Errorf("decoding version info: %s", err) + } + + return &versionInfo, nil +} diff --git a/pkg/client/v1/writequery.go b/pkg/client/v1/writequery.go new file mode 100644 index 00000000..17ed2d34 --- /dev/null +++ b/pkg/client/v1/writequery.go @@ -0,0 +1,83 @@ +package v1 + +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 + 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(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 +} 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..d22205aa 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. diff --git a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go index df2332cb..ef15ffe7 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: "08af7e7055f266ea75d3b06350c47a52cfa59843", + 10: "2bce2d62e7f5eeadc4736f470ca2959b871e5d91", + 69: "643af9ad784444242c6ef415727203941a720197", + 137: "b5fb42f3538738ab5856abf9e3b2e38d82378ca4", + 420: "184800f533f4edd186853a85829fad8bc7802c4e", + 80001: "9336d3a3a36e57a86e4f95d3464048c954e46bc6", + 421613: "073727932afcee9a5dba19f43c023689ca855dc2", } historyDBURI := getHistoryDBURI(t) diff --git a/pkg/eventprocessor/impl/eventprocessor_test.go b/pkg/eventprocessor/impl/eventprocessor_test.go index 2740644f..5385d765 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" + 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" @@ -372,7 +373,8 @@ func setup(t *testing.T) ( } require.NoError(t, err) - userStore, err := user.New(dbURI) + userStore, err := user.New( + 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 2387567f..1bab319e 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, + statementResolver: newWriteStatementResolver(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 writeStatmentResolver struct { + txnHash string + blockNumber int64 +} + +func newWriteStatementResolver(txnHash string, blockNumber int64) *writeStatmentResolver { + return &writeStatmentResolver{txnHash: txnHash, blockNumber: blockNumber} +} + +func (wqr *writeStatmentResolver) GetTxnHash() string { + return wqr.txnHash +} + +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 ffb99551..89e0991f 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) { //nolint + 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.go b/pkg/eventprocessor/impl/executor/impl/txnscope.go index e556264c..5181e401 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" @@ -17,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. @@ -34,7 +35,9 @@ func (e *errQueryExecution) Error() string { type txnScope struct { log zerolog.Logger - parser parsing.SQLValidator + 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 5e0387be..4d127900 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go @@ -243,9 +243,12 @@ func (ts *txnScope) executeWriteStmt( } if policy.WithCheck() == "" { - query, err := ws.GetQuery() + 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 { @@ -281,9 +284,12 @@ 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.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) @@ -322,7 +328,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 new file mode 100644 index 00000000..a97a0c78 --- /dev/null +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_customfuncs_test.go @@ -0,0 +1,117 @@ +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, + }, + { + 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, 1) + require.NoError(t, err) + + txnHash, res, err := execTxnWithRunSQLEvents(t, bs, []string{test.query}) + if test.mustFail { + require.NotNil(t, res.Error) + return + } + 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..cbf44204 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 := newExecutorWithStringTable(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 := newExecutorWithStringTable(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 := newExecutorWithStringTable(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 := newExecutorWithStringTable(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, _ := newExecutorWithStringTable(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, _ := newExecutorWithStringTable(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, _ := newExecutorWithStringTable(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, _ := newExecutorWithStringTable(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 := newExecutorWithStringTable(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 := newExecutorWithStringTable(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 := newExecutorWithStringTable(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 := newExecutorWithStringTable(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 := newExecutorWithStringTable(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 := newExecutorWithStringTable(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) @@ -511,7 +514,7 @@ func TestWithCheck(t *testing.T) { func assertExecTxnWithRunSQLEvents(t *testing.T, bs executor.BlockScope, stmts []string) { t.Helper() - 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()) @@ -521,7 +524,7 @@ 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 +535,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 +544,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 +556,11 @@ 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( diff --git a/pkg/metrics/instrumenting.go b/pkg/metrics/instrumenting.go index 0d0909a8..87aba97d 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,19 @@ 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") +} diff --git a/pkg/parsing/impl/validator.go b/pkg/parsing/impl/validator.go index 97677566..128ff754 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, } @@ -219,42 +206,10 @@ func (pp *QueryValidator) ValidateReadQuery(query string) (parsing.ReadStmt, err } return &readStmt{ - query: query, + statement: ast.Statements[0], }, 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} @@ -265,7 +220,15 @@ type mutatingStmt struct { var _ parsing.MutatingStmt = (*mutatingStmt)(nil) -func (s *mutatingStmt) GetQuery() (string, error) { +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 s.node.String(), nil } @@ -389,33 +352,66 @@ 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 sqlparser.ReadStatementResolver) (string, error) { + query, err := s.statement.(sqlparser.ReadStatement).Resolve(resolver) + if err != nil { + return "", fmt.Errorf("resolving read statement: %s", err) + } + + return 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) + } + + 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 stmt.GetTable().String(), nil + 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 6d6d83bd..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, }, @@ -116,7 +100,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 @@ -166,7 +150,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 +160,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 +249,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 +441,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", @@ -588,9 +574,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 +588,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 +603,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"}, }, }, } @@ -726,7 +712,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) } @@ -777,7 +763,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()) @@ -791,12 +777,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", @@ -812,24 +799,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(nil) + require.NoError(t, err) + require.Equal(t, tc.expQuery, sql) + } + }(tc)) } } @@ -849,7 +838,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) }) @@ -868,7 +857,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) }) @@ -942,6 +931,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 +950,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..ce2cd322 100644 --- a/pkg/parsing/query_validator.go +++ b/pkg/parsing/query_validator.go @@ -5,20 +5,14 @@ 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" ) -// Stmt represents any valid read or mutating query. -type Stmt interface { - GetQuery() (string, error) -} - // 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 +24,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(sqlparser.WriteStatementResolver) (string, error) } // ReadStmt is an already parsed read statement that satisfies all @@ -37,7 +34,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(sqlparser.ReadStatementResolver) (string, error) } // WriteStmt is an already parsed write statement that satisfies all @@ -204,6 +202,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 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/system/store.go b/pkg/sqlstore/impl/system/store.go index b7f3b2f0..473c14fe 100644 --- a/pkg/sqlstore/impl/system/store.go +++ b/pkg/sqlstore/impl/system/store.go @@ -246,7 +246,11 @@ 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") + 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 { return sqlstore.TableSchema{}, fmt.Errorf("failed to parse create stmt: %s", err) @@ -257,15 +261,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, } diff --git a/pkg/sqlstore/impl/user/store.go b/pkg/sqlstore/impl/user/store.go index c1355b61..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" @@ -18,11 +19,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 sqlparser.ReadStatementResolver } // New creates a new UserStore. -func New(dbURI string) (*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 { @@ -32,13 +34,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/pkg/sqlstore/table.go b/pkg/sqlstore/table.go index 620faf63..45e32486 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 `json:"schema"` } // TableMetadataAttribute represents the table metadata attribute. @@ -62,3 +63,15 @@ type SystemACL struct { CreatedAt time.Time UpdatedAt *time.Time } + +// Receipt represents a Tableland receipt. +type Receipt struct { + ChainID tableland.ChainID + BlockNumber int64 + IndexInBlock int64 + TxnHash string + + TableID *tables.TableID + Error *string + ErrorEventIdx *int +} 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 { diff --git a/tableland-openapi-spec.yaml b/tableland-openapi-spec.yaml deleted file mode 100644 index a9675b42..00000000 --- a/tableland-openapi-spec.yaml +++ /dev/null @@ -1,609 +0,0 @@ -openapi: 3.0.0 -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. - - * The `getReceipt` method allows you to get the receipt of a chain transaction to know if it was executed, and the execution details. - - * 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}: - get: - summary: Get all tables controlled by an ETH address - parameters: - - in: path - name: chainID - schema: - type: integer - 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 - schema: - type: string - required: true - description: hash of the schema of the table - 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/{id}: - get: - summary: Get the metadata associated with a table - parameters: - - in: path - name: chainID - schema: - type: integer - 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 - content: - application/json: - schema: - type: "object" - required: - - message - example: - message: "Failed to fetch metadata" - "400": - description: Bad Request - content: - application/json: - schema: - type: "object" - required: - - message - example: - message: "Invalid id format" - /schema/{tableName}: - get: - summary: Get the schema of a table by its full name - parameters: - - in: path - name: tableName - schema: - type: string - required: true - description: The full name of the table - responses: - "200": - description: Successful response - content: - application/json: - schema: - type: object - 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}: - get: - summary: Get a read query with the statement in the `s` querystring parameter - parameters: - - in: query - name: readStatement - description: The SQL statement describing the read query - required: true - responses: - "200": - description: Successful response - 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 - -components: - securitySchemes: - bearerAuth: # arbitrary name for the security scheme - type: http - scheme: bearer - bearerFormat: SIWE - schemas: - runReadQuery: - 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: - 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: - type: "string" - validateCreateTable: - 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: - - "create_statement" - properties: - create_statement: - type: "string" - validateWriteQuery: - 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: - type: "string" - getReceipt: - 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: - - "txn_hash" - properties: - txn_hash: - type: "string" - setController: - 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: - - "controller" - - "token_id" - properties: - controller: - type: "string" - token_id: - type: "string" diff --git a/tests/fullstack/fullstack.go b/tests/fullstack/fullstack.go new file mode 100644 index 00000000..9a55525d --- /dev/null +++ b/tests/fullstack/fullstack.go @@ -0,0 +1,211 @@ +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" + "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" + 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" + "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 +} + +// CreateFullStack creates a running validator with the provided dependencies, or defaults otherwise. +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) + } + + 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), + ) + 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, + rsresolver.New(map[tableland.ChainID]eventprocessor.EventProcessor{1337: ep}), + ) + require.NoError(t, err) + } + 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) + } + + router, err := router.ConfiguredRouter(tbl, systemService, 10, time.Second, []tableland.ChainID{ChainID}) + require.NoError(t, err) + + server := httptest.NewServer(router.Handler()) + t.Cleanup(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 +}