├── .github └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .goreleaser.yml ├── .swagger-codegen-ignore ├── .swagger-codegen └── VERSION ├── .travis.yml ├── LICENSE ├── README.md ├── apiactions ├── default.go ├── processing.go └── validation.go ├── auth └── auth.go ├── cmd ├── api.go ├── block.go ├── daemon.go ├── db.go ├── e2e.go ├── root.go ├── run.go ├── serve.go └── version.go ├── config ├── README.md ├── access.go ├── config.go └── default │ └── chainqueryconfig.toml ├── daemon ├── daemon.go ├── jobs │ ├── certificatesync.go │ ├── certificatesync_test.go │ ├── chainsync.go │ ├── chainvalidation.go │ ├── claimcntsync.go │ ├── claimtriesync.go │ ├── mempoolsync.go │ ├── outputfixsync.go │ └── valuesync.go ├── processing │ ├── address.go │ ├── block.go │ ├── claim.go │ ├── claim_test.go │ ├── metadata.go │ ├── outpoint.go │ └── transaction.go └── upgrademanager │ ├── script.go │ └── upgrade.go ├── datastore └── datastore.go ├── db ├── apiinit.go ├── chainquery_schema.sql ├── init.go ├── logger.go ├── query.go └── query_test.go ├── dev.sh ├── docker ├── Dockerfile ├── build.sh ├── healthcheck.sh ├── my.cnf └── start.sh ├── docs ├── assets │ ├── css │ │ ├── bootstrap-responsive.css │ │ ├── bootstrap.css │ │ └── style.css │ ├── images │ │ └── logo.png │ └── js │ │ ├── bootstrap.js │ │ ├── jquery-1.8.3.min.js │ │ └── main.js ├── index.html ├── models │ ├── AddressSummary.html │ ├── TableSize.html │ └── TableStatus.html └── operations │ ├── DefaultApi.html │ ├── QueryApi.html │ └── StatApi.html ├── e2e ├── chainqueryconfig.toml ├── channel.go ├── claim.go ├── docker-compose.yml ├── e2e.go ├── e2e.sh ├── finder.go ├── metadata.go ├── prepare_e2e.sh ├── script.go └── transaction.go ├── global └── global.go ├── go.mod ├── go.sum ├── lbrycrd ├── client.go ├── reponse.go ├── request.go ├── script.go └── script_test.go ├── main.go ├── main.js ├── meta └── meta.go ├── metrics └── metrics.go ├── migration ├── 000_init_schema.sql ├── 001_supports.sql ├── 002_decimals.sql ├── 003_dht_tracking.sql ├── 004_new_indices.sql ├── 005_remove_foreign_keys.sql ├── 006_add_height_index.sql ├── 007_more_decimals.sql ├── 008_schema_fix.sql ├── 009_certificate_validation.sql ├── 010_triggers.sql ├── 011_add_license.sql ├── 012_store_last_height.sql ├── 013_add_input_vin.sql ├── 014_yay_new_metadata.sql ├── 015_adjust_column_sizes.sql ├── 016_transaction_hashes_adjustment.sql ├── 017_claim_owner.sql ├── 018_cert_sync_index.sql ├── 019_raw_tx.sql ├── 020_content_type.sql ├── 021_claim_reference.sql ├── 022_align_claim_id.sql ├── 023_sdhash_index.sql ├── 024_claims_in_channel.sql ├── 025_outputindices.sql ├── 026_purchases.sql ├── 027_signed_supports.sql ├── 028_liscense_url.sql ├── 029_support_index.sql ├── 030_json_field.sql ├── 031_drop_unused_columns.sql ├── 032_drop_block_txhashes.sql ├── 032_drop_transaction_cols.sql ├── 033_vin_vout_changes.sql ├── 034_support_uniq_index.sql ├── 035_add_tx_count.sql └── bindata.go ├── model ├── abnormal_claim.go ├── address.go ├── application_status.go ├── block.go ├── boil_queries.go ├── boil_table_names.go ├── boil_types.go ├── boil_view_names.go ├── claim.go ├── claim_in_list.go ├── claim_tag.go ├── input.go ├── job_status.go ├── mysql_upsert.go ├── output.go ├── purchase.go ├── support.go ├── tag.go ├── transaction.go └── transaction_address.go ├── notifications ├── events.go └── notifications.go ├── package.json ├── scripts ├── build.sh ├── coverage.sh ├── cron_update_master.sh ├── deploy.sh ├── gen_apis.sh ├── gen_models.sh ├── lint.sh ├── regtest.sh ├── release.sh └── test.sh ├── sockety └── sockety.go ├── sqlboiler.toml ├── swagger ├── apiserver │ ├── .swagger-codegen-ignore │ ├── .swagger-codegen │ │ └── VERSION │ ├── api │ │ └── swagger.yaml │ ├── go │ │ ├── README.md │ │ ├── address_summary.go │ │ ├── logger.go │ │ ├── query_api.go │ │ ├── routers.go │ │ ├── stat_api.go │ │ ├── table_size.go │ │ └── table_status.go │ └── main.go ├── chainquery.yaml ├── clients │ ├── goclient │ │ ├── .gitignore │ │ ├── .swagger-codegen-ignore │ │ ├── .swagger-codegen │ │ │ └── VERSION │ │ ├── .travis.yml │ │ ├── README.md │ │ ├── address_summary.go │ │ ├── api │ │ │ └── swagger.yaml │ │ ├── api_client.go │ │ ├── api_response.go │ │ ├── configuration.go │ │ ├── default_api.go │ │ ├── docs │ │ │ ├── AddressSummary.md │ │ │ ├── DefaultApi.md │ │ │ ├── QueryApi.md │ │ │ ├── StatApi.md │ │ │ ├── TableSize.md │ │ │ └── TableStatus.md │ │ ├── git_push.sh │ │ ├── query_api.go │ │ ├── stat_api.go │ │ ├── table_size.go │ │ └── table_status.go │ └── pythonclient │ │ ├── .gitignore │ │ ├── .swagger-codegen-ignore │ │ ├── .swagger-codegen │ │ └── VERSION │ │ ├── .travis.yml │ │ ├── README.md │ │ ├── docs │ │ ├── AddressSummary.md │ │ ├── DefaultApi.md │ │ ├── QueryApi.md │ │ ├── StatApi.md │ │ ├── TableSize.md │ │ └── TableStatus.md │ │ ├── git_push.sh │ │ ├── requirements.txt │ │ ├── setup.py │ │ ├── swagger_client │ │ ├── __init__.py │ │ ├── api │ │ │ ├── __init__.py │ │ │ ├── default_api.py │ │ │ ├── query_api.py │ │ │ └── stat_api.py │ │ ├── api_client.py │ │ ├── configuration.py │ │ ├── models │ │ │ ├── __init__.py │ │ │ ├── address_summary.py │ │ │ ├── table_size.py │ │ │ └── table_status.py │ │ └── rest.py │ │ ├── test-requirements.txt │ │ ├── test │ │ ├── __init__.py │ │ ├── test_address_summary.py │ │ ├── test_default_api.py │ │ ├── test_query_api.py │ │ ├── test_stat_api.py │ │ ├── test_table_size.py │ │ └── test_table_status.py │ │ └── tox.ini └── modules │ └── go-server │ ├── README.mustache │ ├── controller-api.mustache │ ├── logger.mustache │ ├── main.mustache │ ├── model.mustache │ ├── partial_header.mustache │ ├── routers.mustache │ └── swagger.mustache ├── twilio └── twilio.go └── util ├── utility.go ├── utility_test.go └── worker.go /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [master] 14 | schedule: 15 | - cron: '0 10 * * 2' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['go', 'python', 'javascript'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v2 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | 39 | # If this run was triggered by a pull request event, then checkout 40 | # the head of the pull request instead of the merge commit. 41 | - run: git checkout HEAD^2 42 | if: ${{ github.event_name == 'pull_request' }} 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | /bin 4 | /persist 5 | /data 6 | swagger-codegen-cli.jar 7 | chainqueryconfig.toml 8 | !e2e/chainqueryconfig.toml 9 | cover.out 10 | .cover 11 | .DS_Store 12 | swagger/.DSStore 13 | swagger/apiserver/go/*_api.go 14 | chainquery.log 15 | #/migration/bindata.go -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # This is an example goreleaser.yaml file with some sane defaults. 2 | # Make sure to check the documentation at http://goreleaser.com 3 | builds: 4 | - env: 5 | - CGO_ENABLED=0 6 | goos: 7 | - linux 8 | - darwin 9 | - windows 10 | goarch: 11 | - 386 12 | - amd64 13 | ldflags: 14 | - -X "{{ .Env.IMPORTPATH }}/meta.semVersion={{ .Tag }}" -X "{{ .Env.IMPORTPATH }}/meta.version={{ .Env.VERSIONSHORT }}" -X "{{ .Env.IMPORTPATH }}/meta.versionLong={{ .Env.VERSIONLONG }}" -X "{{ .Env.IMPORTPATH }}/meta.commitMsg={{ .Env.COMMITMSG }}" 15 | archives: 16 | - id: zip 17 | name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}' 18 | replacements: 19 | darwin: Darwin 20 | linux: Linux 21 | windows: Windows 22 | 386: i386 23 | amd64: x86_64 24 | format: zip 25 | - files: 26 | - LICENSE 27 | checksum: 28 | name_template: 'checksums.txt' 29 | snapshot: 30 | name_template: "{{ .Tag }}-next" 31 | changelog: 32 | sort: asc 33 | filters: 34 | exclude: 35 | - '^docs:' 36 | - '^test:' 37 | 38 | -------------------------------------------------------------------------------- /.swagger-codegen-ignore: -------------------------------------------------------------------------------- 1 | # Swagger Codegen Ignore 2 | # Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /.swagger-codegen/VERSION: -------------------------------------------------------------------------------- 1 | unset -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | dist: focal 3 | language: go 4 | 5 | # Only the last two Go releases are supported by the Go team with security 6 | # updates. Any versions older than that should be considered deprecated. 7 | # Don't bother testing with them. tip builds your code with the latest 8 | # development version of Go. This can warn you that your code will break 9 | # in the next version of Go. Don't worry! Later we declare that test runs 10 | # are allowed to fail on Go tip. 11 | go: 1.19.x 12 | 13 | # Skip the install step. Don't `go get` dependencies. Only build with the 14 | # code in vendor/ 15 | install: true 16 | 17 | cache: 18 | directories: 19 | - $HOME/.cache/go-build 20 | - $HOME/gopath/pkg/mod 21 | 22 | services: 23 | - mysql 24 | - docker 25 | 26 | before_install: 27 | - sudo sed -i '/^\[mysqld\]/a log_bin_trust_function_creators = 1' /etc/mysql/mysql.conf.d/mysqld.cnf 28 | - mysql -u root -e 'CREATE DATABASE IF NOT EXISTS chainquery;' 29 | - mysql -u root -e "CREATE USER 'chainquery'@'localhost' IDENTIFIED BY 'chainquery';" 30 | - mysql -u root -e "GRANT ALL ON chainquery.* TO 'chainquery'@'localhost';" 31 | - sudo service mysql restart 32 | 33 | 34 | # Anything in before_script that returns a nonzero exit code will 35 | # flunk the build and immediately stop. It's sorta like having 36 | # set -e enabled in bash. 37 | before_script: 38 | # All the .go files, excluding vendor/ and model (auto generated) 39 | - GO_FILES=$(find . -iname '*.go' -type f | grep -v /vendor/ | grep -v /model/ | grep -v /swagger/ | grep -v /migration/) 40 | 41 | 42 | # script always run to completion (set +e). All of these code checks are must haves 43 | # in a modern Go project. 44 | script: 45 | # Build Chainquery successfully 46 | - ./scripts/build.sh 47 | # Fail if a .go file hasn't been formatted with gofmt 48 | - gofmt -s -l -d $GO_FILES #List diff for debugging 49 | - test -z $(gofmt -s -l -d $GO_FILES) 50 | - ./scripts/lint.sh 51 | # Run unit tests 52 | - ./scripts/test.sh 53 | # end to end testing 54 | - ./e2e/e2e.sh 55 | # check model generation... 56 | - ./bin/chainquery serve db && ./scripts/gen_models.sh 57 | # matches what was committed 58 | - go mod tidy 59 | - git diff --exit-code 60 | 61 | deploy: 62 | # uploads per commit builds 63 | - provider: s3 64 | bucket: "build.lbry.io" 65 | access_key_id: $AWS_ACCESS_KEY_ID 66 | secret_access_key: $AWS_SECRET_ACCESS_KEY 67 | skip_cleanup: true 68 | local-dir: bin 69 | upload-dir: "chainquery/branch-${TRAVIS_BRANCH}/commit-${TRAVIS_COMMIT:0:7}/build-${TRAVIS_BUILD_NUMBER}" 70 | on: 71 | all_branches: true 72 | # upload latest successful build per branch 73 | - provider: s3 74 | bucket: "build.lbry.io" 75 | access_key_id: $AWS_ACCESS_KEY_ID 76 | secret_access_key: $AWS_SECRET_ACCESS_KEY 77 | skip_cleanup: true 78 | local-dir: bin 79 | upload-dir: "chainquery/branch-${TRAVIS_BRANCH}" 80 | on: 81 | all_branches: true 82 | # Docker images - must be after upload 83 | - provider: script 84 | skip_cleanup: true 85 | script: ./docker/build.sh $TRAVIS_BRANCH 86 | on: 87 | all_branches: true 88 | condition: $TRAVIS_OS_NAME = linux 89 | 90 | notifications: 91 | webhooks: https://chainquery.odysee.tv/api/autoupdate -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2020 LBRY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /apiactions/processing.go: -------------------------------------------------------------------------------- 1 | package apiactions 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/lbryio/chainquery/auth" 7 | "github.com/lbryio/chainquery/daemon/jobs" 8 | "github.com/lbryio/chainquery/daemon/processing" 9 | "github.com/lbryio/chainquery/lbrycrd" 10 | "github.com/lbryio/chainquery/model" 11 | 12 | "github.com/lbryio/lbry.go/v2/extras/api" 13 | "github.com/lbryio/lbry.go/v2/extras/errors" 14 | 15 | v "github.com/lbryio/ozzo-validation" 16 | "github.com/sirupsen/logrus" 17 | "github.com/volatiletech/sqlboiler/v4/queries/qm" 18 | ) 19 | 20 | // ProcessBlocks processed a specific block or range of blocks if authorized. 21 | func ProcessBlocks(r *http.Request) api.Response { 22 | params := struct { 23 | Block *uint64 24 | From *uint64 25 | To *uint64 26 | Key string 27 | }{} 28 | 29 | err := api.FormValues(r, ¶ms, []*v.FieldRules{ 30 | v.Field(¶ms.Block), 31 | v.Field(¶ms.From), 32 | v.Field(¶ms.To), 33 | v.Field(¶ms.Key), 34 | }) 35 | if err != nil { 36 | return api.Response{Error: err, Status: http.StatusBadRequest} 37 | } 38 | 39 | if !auth.IsAuthorized(params.Key) { 40 | return api.Response{Error: errors.Err("not authorized"), Status: http.StatusUnauthorized} 41 | } 42 | 43 | if params.Block != nil { 44 | err = processBlocks(params.Block, nil, nil) 45 | } else if params.To != nil { 46 | err = processBlocks(nil, params.From, params.To) 47 | } else { 48 | err = processBlocks(nil, params.From, nil) 49 | } 50 | 51 | if err != nil { 52 | return api.Response{Error: err} 53 | } 54 | 55 | return api.Response{Data: "OK"} 56 | 57 | } 58 | 59 | func processBlocks(block, from, to *uint64) error { 60 | if block != nil { 61 | from = block 62 | end := *block 63 | to = &end 64 | } else { 65 | if from == nil { 66 | start := uint64(0) 67 | from = &start 68 | } 69 | if to == nil { 70 | currHeight, err := lbrycrd.GetBlockCount() 71 | if err != nil { 72 | return errors.Err(err) 73 | } 74 | to = currHeight 75 | } 76 | } 77 | 78 | for *from <= *to { 79 | processing.RunBlockProcessing(nil, *from) 80 | *from++ 81 | } 82 | return nil 83 | } 84 | 85 | // SyncName syncs the claims for a give name with the lbrycrd claimtrie ( effective amount, valid at height, and bidstate). 86 | func SyncName(r *http.Request) api.Response { 87 | 88 | params := struct { 89 | Name string 90 | Key string 91 | }{} 92 | 93 | err := api.FormValues(r, ¶ms, []*v.FieldRules{ 94 | v.Field(¶ms.Name), 95 | v.Field(¶ms.Key), 96 | }) 97 | if err != nil { 98 | return api.Response{Error: err, Status: http.StatusBadRequest} 99 | } 100 | 101 | if !auth.IsAuthorized(params.Key) { 102 | return api.Response{Error: errors.Err("not authorized"), Status: http.StatusUnauthorized} 103 | } 104 | 105 | claims, err := model.Claims(qm.Where(model.ClaimColumns.Name+"=?", params.Name), qm.Limit(1)).AllG() 106 | if err != nil { 107 | return api.Response{Error: errors.Err(err)} 108 | } 109 | 110 | count, err := lbrycrd.GetBlockCount() 111 | if err != nil { 112 | logrus.Error("ClaimTrieSyncAsync: Error getting block height", err) 113 | return api.Response{Error: errors.Err(err)} 114 | } 115 | 116 | err = jobs.SyncClaims(claims) 117 | if err != nil { 118 | return api.Response{Error: errors.Err(err)} 119 | } 120 | 121 | err = jobs.SetControllingClaimForNames(claims, *count) 122 | if err != nil { 123 | return api.Response{Error: errors.Err(err)} 124 | } 125 | 126 | return api.Response{Data: "ok"} 127 | 128 | } 129 | -------------------------------------------------------------------------------- /apiactions/validation.go: -------------------------------------------------------------------------------- 1 | package apiactions 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/lbryio/chainquery/auth" 7 | "github.com/lbryio/chainquery/daemon/jobs" 8 | 9 | "github.com/lbryio/lbry.go/v2/extras/api" 10 | "github.com/lbryio/lbry.go/v2/extras/errors" 11 | 12 | v "github.com/lbryio/ozzo-validation" 13 | ) 14 | 15 | //SyncAddressBalance will synchronize the balances for all addresses in chainquery. 16 | func SyncAddressBalance(r *http.Request) api.Response { 17 | params := struct { 18 | Key string 19 | }{} 20 | 21 | err := api.FormValues(r, ¶ms, []*v.FieldRules{ 22 | v.Field(¶ms.Key), 23 | }) 24 | if err != nil { 25 | return api.Response{Error: err, Status: http.StatusBadRequest} 26 | } 27 | 28 | if !auth.IsAuthorized(params.Key) { 29 | return api.Response{Error: errors.Err("not authorized"), Status: http.StatusUnauthorized} 30 | } 31 | 32 | rowsAffected, err := jobs.SyncAddressBalances() 33 | if err != nil { 34 | return api.Response{Error: err} 35 | } 36 | 37 | return api.Response{Data: rowsAffected} 38 | 39 | } 40 | 41 | //SyncTransactionValue will synchronize the value of all transactions in chainquery. 42 | func SyncTransactionValue(r *http.Request) api.Response { 43 | params := struct { 44 | Key string 45 | }{} 46 | 47 | err := api.FormValues(r, ¶ms, []*v.FieldRules{ 48 | v.Field(¶ms.Key), 49 | }) 50 | if err != nil { 51 | return api.Response{Error: err, Status: http.StatusBadRequest} 52 | } 53 | 54 | if !auth.IsAuthorized(params.Key) { 55 | return api.Response{Error: errors.Err("not authorized"), Status: http.StatusUnauthorized} 56 | } 57 | 58 | rowsAffected, err := jobs.SyncTransactionValue() 59 | if err != nil { 60 | return api.Response{Error: err} 61 | } 62 | 63 | return api.Response{Data: rowsAffected} 64 | 65 | } 66 | 67 | // ValidateChainData validates a range of blocks ensure that the block,Txs, and the same number of outputs,inputs exist. 68 | //If a difference in data is identified it will return an array identifying where there are differences. 69 | func ValidateChainData(r *http.Request) api.Response { 70 | params := struct { 71 | From uint64 72 | To *uint64 73 | Key string 74 | }{} 75 | 76 | err := api.FormValues(r, ¶ms, []*v.FieldRules{ 77 | v.Field(¶ms.From, v.Required), 78 | v.Field(¶ms.To), 79 | v.Field(¶ms.Key), 80 | }) 81 | if err != nil { 82 | return api.Response{Error: err, Status: http.StatusBadRequest} 83 | } 84 | 85 | if !auth.IsAuthorized(params.Key) { 86 | return api.Response{Error: errors.Err("not authorized"), Status: http.StatusUnauthorized} 87 | } 88 | 89 | var missing []jobs.BlockData 90 | if params.To != nil { 91 | missing, err = jobs.ValidateChainRange(¶ms.From, params.To) 92 | } else { 93 | missing, err = jobs.ValidateChainRange(¶ms.From, nil) 94 | } 95 | 96 | if err != nil { 97 | return api.Response{Error: err} 98 | } 99 | 100 | return api.Response{Data: missing} 101 | } 102 | -------------------------------------------------------------------------------- /auth/auth.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | //APIKeys holds the keys for authorized api access 4 | var APIKeys []string 5 | 6 | //IsAuthorized checks that the provided key matches the keys provided via the configuration. 7 | func IsAuthorized(key string) bool { 8 | for _, k := range APIKeys { 9 | if k == key { 10 | return true 11 | } 12 | } 13 | 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /cmd/api.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/lbryio/chainquery/apiactions" 7 | "github.com/lbryio/chainquery/config" 8 | "github.com/lbryio/chainquery/db" 9 | "github.com/lbryio/chainquery/lbrycrd" 10 | swagger "github.com/lbryio/chainquery/swagger/apiserver" 11 | "github.com/lbryio/chainquery/twilio" 12 | 13 | "github.com/spf13/cobra" 14 | ) 15 | 16 | func init() { 17 | rootCmd.AddCommand(apiCmd) 18 | } 19 | 20 | var apiCmd = &cobra.Command{ 21 | Use: "api", 22 | Short: "Start only the api server", 23 | Long: `This runs the API Server for chainquery only. The daemon does not run, however, the db is still required and all APIs are available.`, 24 | Run: func(cmd *cobra.Command, args []string) { 25 | config.InitSlack() 26 | twilio.InitTwilio() 27 | apiactions.AutoUpdateCommand = config.GetAutoUpdateCommand() 28 | //Main Chainquery DB connection 29 | dbInstance, err := db.Init(config.GetMySQLDSN(), config.GetDebugQueryMode()) 30 | if err != nil { 31 | log.Panic(err) 32 | } 33 | defer db.CloseDB(dbInstance) 34 | 35 | lbrycrdClient := lbrycrd.Init() 36 | defer lbrycrdClient.Shutdown() 37 | swagger.InitApiServer(config.GetAPIHostAndPort()) 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /cmd/block.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "strconv" 7 | "time" 8 | 9 | "github.com/lbryio/chainquery/config" 10 | "github.com/lbryio/chainquery/daemon/processing" 11 | "github.com/lbryio/chainquery/db" 12 | "github.com/lbryio/chainquery/lbrycrd" 13 | "github.com/lbryio/chainquery/model" 14 | "github.com/lbryio/chainquery/util" 15 | 16 | "github.com/lbryio/lbry.go/v2/extras/errors" 17 | 18 | "github.com/pkg/profile" 19 | "github.com/sirupsen/logrus" 20 | "github.com/spf13/cobra" 21 | "github.com/spf13/viper" 22 | ) 23 | 24 | func init() { 25 | rootCmd.AddCommand(blockCmd) 26 | } 27 | 28 | var blockCmd = &cobra.Command{ 29 | Use: "block", 30 | Short: "Processes a specific block height", 31 | Long: `This is useful for testing locally. You can just sync a particular problematic block. 32 | This will remove the block from the database before syncing it.`, 33 | Run: func(cmd *cobra.Command, args []string) { 34 | if viper.GetBool("codeprofile") { 35 | defer profile.Start(profile.NoShutdownHook).Stop() 36 | } 37 | blockHeight, err := strconv.ParseInt(args[0], 10, 64) 38 | if err != nil { 39 | logrus.Panic(errors.Prefix("Could not parse block height passed", err)) 40 | } 41 | lbrycrdClient := lbrycrd.Init() 42 | defer lbrycrdClient.Shutdown() 43 | blockHash, err := lbrycrdClient.GetBlockHash(blockHeight) 44 | if err != nil { 45 | logrus.Panic(errors.Prefix(fmt.Sprintf("Could not get block hash @ height %d", blockHeight), err)) 46 | } 47 | //Main Chainquery DB connection 48 | dbInstance, err := db.Init(config.GetMySQLDSN(), config.GetDebugQueryMode()) 49 | if err != nil { 50 | logrus.Panic(err) 51 | } 52 | defer db.CloseDB(dbInstance) 53 | logrus.Infof("Running processor on block %d with hash %s", blockHeight, blockHash) 54 | block, err := model.Blocks(model.BlockWhere.Hash.EQ(blockHash.String())).OneG() 55 | if err != nil && !errors.Is(err, sql.ErrNoRows) { 56 | logrus.Panic(errors.Err(err)) 57 | } 58 | if block != nil { 59 | err = block.DeleteG() 60 | if err != nil { 61 | logrus.Fatal(errors.Err(err)) 62 | } 63 | logrus.Info("Block successfully removed") 64 | } 65 | jsonBlock, err := lbrycrd.GetBlock(blockHash.String()) 66 | if err != nil { 67 | logrus.Fatal(errors.Err(err)) 68 | } 69 | logrus.Info("processing block started") 70 | defer util.TimeTrack(time.Now(), "block processing", "always") 71 | _, err = processing.ProcessBlock(uint64(blockHeight), nil, jsonBlock) 72 | if err != nil { 73 | logrus.Fatal(errors.Err(err)) 74 | } 75 | logrus.Info("processing block finished") 76 | }, 77 | } 78 | -------------------------------------------------------------------------------- /cmd/daemon.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/lbryio/chainquery/apiactions" 7 | "github.com/lbryio/chainquery/config" 8 | "github.com/lbryio/chainquery/daemon" 9 | "github.com/lbryio/chainquery/db" 10 | "github.com/lbryio/chainquery/lbrycrd" 11 | "github.com/lbryio/chainquery/twilio" 12 | "github.com/spf13/cobra" 13 | ) 14 | 15 | func init() { 16 | serveCmd.AddCommand(daemonCmd) 17 | } 18 | 19 | var daemonCmd = &cobra.Command{ 20 | Use: "daemon", 21 | Short: "Run only Daemon routines", 22 | Long: `Run only Daemon routines, without the API Server. Check github.com/lbryio/chainquery#what-does-chainquery-consist-of`, 23 | Run: func(cmd *cobra.Command, args []string) { 24 | config.InitSlack() 25 | twilio.InitTwilio() 26 | apiactions.AutoUpdateCommand = config.GetAutoUpdateCommand() 27 | //Main Chainquery DB connection 28 | dbInstance, err := db.Init(config.GetMySQLDSN(), config.GetDebugQueryMode()) 29 | if err != nil { 30 | log.Panic(err) 31 | } 32 | defer db.CloseDB(dbInstance) 33 | 34 | lbrycrdClient := lbrycrd.Init() 35 | defer lbrycrdClient.Shutdown() 36 | daemon.DoYourThing() 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /cmd/db.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/lbryio/chainquery/config" 7 | "github.com/lbryio/chainquery/db" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | func init() { 12 | serveCmd.AddCommand(dbCmd) 13 | } 14 | 15 | var dbCmd = &cobra.Command{ 16 | Use: "db", 17 | Short: "Sets up the database", 18 | Long: `This will initialize the specified database schema`, 19 | Run: func(cmd *cobra.Command, args []string) { 20 | //Main Chainquery DB connection 21 | dbInstance, err := db.Init(config.GetMySQLDSN(), config.GetDebugQueryMode()) 22 | if err != nil { 23 | log.Panic(err) 24 | } 25 | db.CloseDB(dbInstance) 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /cmd/e2e.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/lbryio/chainquery/config" 7 | "github.com/lbryio/chainquery/db" 8 | "github.com/lbryio/chainquery/lbrycrd" 9 | 10 | "github.com/lbryio/chainquery/e2e" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | func init() { 15 | rootCmd.AddCommand(e2eCmd) 16 | } 17 | 18 | var e2eCmd = &cobra.Command{ 19 | Use: "e2e", 20 | Short: "Launch end to end tests", 21 | Long: `Launch end to end tests`, 22 | Run: func(cmd *cobra.Command, args []string) { 23 | //Main Chainquery DB connection 24 | dbInstance, err := db.Init(config.GetMySQLDSN(), config.GetDebugQueryMode()) 25 | if err != nil { 26 | log.Panic(err) 27 | } 28 | defer db.CloseDB(dbInstance) 29 | 30 | lbrycrdClient := lbrycrd.Init() 31 | defer lbrycrdClient.Shutdown() 32 | e2e.StartE2ETesting() 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "net/http" 8 | 9 | "github.com/lbryio/chainquery/config" 10 | log "github.com/sirupsen/logrus" 11 | "github.com/spf13/cobra" 12 | "github.com/spf13/viper" 13 | ) 14 | 15 | const ( // config setting keys 16 | configpathflag = "configpath" 17 | debugmodeflag = "debug" 18 | tracemodeflag = "trace" 19 | ) 20 | 21 | func init() { 22 | cobra.OnInitialize(config.InitializeConfiguration) 23 | log.SetFormatter(&log.TextFormatter{FullTimestamp: true}) 24 | http.DefaultClient.Timeout = config.GetDefaultClientTimeout() 25 | rootCmd.PersistentFlags().String(configpathflag, "", "Specify non-default location of the configuration of chainquery. The precedence is $HOME, working directory, and lastly the branch path to the default configuration 'path/to/chainquery/config/default/'") 26 | rootCmd.PersistentFlags().BoolP(debugmodeflag, "d", false, "turns on debug mode for the application command.") 27 | rootCmd.PersistentFlags().BoolP(tracemodeflag, "t", false, "turns on trace mode for the application command, very verbose logging.") 28 | err := viper.BindPFlags(rootCmd.PersistentFlags()) 29 | if err != nil { 30 | log.Panic(err) 31 | } 32 | } 33 | 34 | var rootCmd = &cobra.Command{ 35 | Use: "chainquery", 36 | Short: "Chainquery parses and syncs the LBRY blockchain data into structured SQL", 37 | Long: `Chainquery uses a MySQL server instance and a LBRYcrd instance to parse the blockchain 38 | into data that can be queried quickly and easily`, 39 | Args: cobra.MinimumNArgs(1), 40 | Run: func(cmd *cobra.Command, args []string) { 41 | 42 | }, 43 | } 44 | 45 | // Execute executes the root command and is the entry point of the application from main.go 46 | func Execute() { 47 | if err := rootCmd.Execute(); err != nil { 48 | fmt.Println(err) 49 | os.Exit(1) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cmd/run.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "log" 5 | "strings" 6 | "time" 7 | 8 | "github.com/lbryio/chainquery/config" 9 | "github.com/lbryio/chainquery/daemon/jobs" 10 | "github.com/lbryio/chainquery/db" 11 | "github.com/lbryio/chainquery/lbrycrd" 12 | "github.com/lbryio/lbry.go/v2/extras/errors" 13 | 14 | "github.com/pkg/profile" 15 | "github.com/sirupsen/logrus" 16 | "github.com/spf13/cobra" 17 | "github.com/spf13/viper" 18 | ) 19 | 20 | func init() { 21 | rootCmd.AddCommand(runCmd) 22 | } 23 | 24 | var jobsMap = map[string]func(){ 25 | "claimcount": func() { 26 | err := jobs.SyncClaimCntInChannel() 27 | if err != nil { 28 | logrus.Errorf("failure in running claimcount job: %s", errors.FullTrace(err)) 29 | } 30 | }, 31 | "claimtrie": jobs.ClaimTrieSync, 32 | "certificate": jobs.CertificateSync, 33 | "mempool": jobs.MempoolSync, 34 | "transactionvalue": jobs.TransactionValueSync, 35 | "chain": jobs.ChainSync, 36 | "outputfix": jobs.OutputFixSync, 37 | } 38 | 39 | var runCmd = &cobra.Command{ 40 | Use: "run", 41 | Short: "Runs Specific Chainquery Jobs", 42 | Long: `Allows for running different chainquery jobs without having to run the rest of the application`, 43 | Run: func(cmd *cobra.Command, args []string) { 44 | if viper.GetBool("codeprofile") { 45 | defer profile.Start(profile.NoShutdownHook).Stop() 46 | } 47 | job, ok := jobsMap[args[0]] 48 | if !ok { 49 | var jobs []string 50 | for job := range jobsMap { 51 | jobs = append(jobs, job) 52 | } 53 | logrus.Infof("Incorrect usage, should be: run . Possible jobs are: %s", strings.Join(jobs, ", ")) 54 | return 55 | } 56 | lbrycrdClient := lbrycrd.Init() 57 | defer lbrycrdClient.Shutdown() 58 | //Main Chainquery DB connection 59 | dbInstance, err := db.Init(config.GetMySQLDSN(), config.GetDebugQueryMode()) 60 | if err != nil { 61 | log.Panic(err) 62 | } 63 | logrus.Debugf("Starting job '%s'", args[0]) 64 | start := time.Now() 65 | job() 66 | logrus.Debugf("Finished job '%s', it took %s", args[0], time.Since(start)) 67 | 68 | db.CloseDB(dbInstance) 69 | }, 70 | } 71 | -------------------------------------------------------------------------------- /cmd/serve.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/lbryio/chainquery/apiactions" 7 | "github.com/lbryio/chainquery/config" 8 | "github.com/lbryio/chainquery/daemon" 9 | "github.com/lbryio/chainquery/db" 10 | "github.com/lbryio/chainquery/lbrycrd" 11 | swagger "github.com/lbryio/chainquery/swagger/apiserver" 12 | "github.com/lbryio/chainquery/twilio" 13 | 14 | "github.com/pkg/profile" 15 | "github.com/spf13/cobra" 16 | "github.com/spf13/viper" 17 | ) 18 | 19 | func init() { 20 | rootCmd.AddCommand(serveCmd) 21 | } 22 | 23 | var serveCmd = &cobra.Command{ 24 | Use: "serve", 25 | Short: "Run Daemon routines and the API Server", 26 | Long: `Run Daemon routines and the API Server, check github.com/lbryio/chainquery#what-does-chainquery-consist-of`, 27 | Args: cobra.OnlyValidArgs, 28 | Run: func(cmd *cobra.Command, args []string) { 29 | if viper.GetBool("codeprofile") { 30 | defer profile.Start(profile.NoShutdownHook).Stop() 31 | } 32 | config.InitSlack() 33 | twilio.InitTwilio() 34 | apiactions.AutoUpdateCommand = config.GetAutoUpdateCommand() 35 | //Main Chainquery DB connection 36 | dbInstance, err := db.Init(config.GetMySQLDSN(), config.GetDebugQueryMode()) 37 | if err != nil { 38 | log.Panic(err) 39 | } 40 | defer db.CloseDB(dbInstance) 41 | 42 | lbrycrdClient := lbrycrd.Init() 43 | defer lbrycrdClient.Shutdown() 44 | 45 | go swagger.InitApiServer(config.GetAPIHostAndPort()) 46 | daemon.DoYourThing() 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/lbryio/chainquery/meta" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | func init() { 10 | rootCmd.AddCommand(versionCmd) 11 | } 12 | 13 | var versionCmd = &cobra.Command{ 14 | Use: "version", 15 | Short: "Print the version number of Chainquery", 16 | Long: `All software has versions. This is Chainquery's`, 17 | Run: func(cmd *cobra.Command, args []string) { 18 | println("Semantic Version: ", meta.GetSemVersion()) 19 | println("Version: " + meta.GetVersion()) 20 | println("Version(long): " + meta.GetVersionLong()) 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /config/README.md: -------------------------------------------------------------------------------- 1 | #Chainquery Configuration 2 | 3 | The Chainquery application comes with a watched configuration that when updated will be updated live in the application. Please see the default[configuration](default/chainqueryconfig.toml)for details. More elaborate documentation is on the way. 4 | 5 | The order of precedence for where chainquery looks for a configuration file are `--configpath` flag, `$HOME/`, `.` working directory, and last `./config/default/` for running from src. 6 | 7 | Testi -------------------------------------------------------------------------------- /config/access.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/lbryio/lbry.go/v2/extras/errors" 7 | 8 | "github.com/sirupsen/logrus" 9 | "github.com/spf13/viper" 10 | ) 11 | 12 | // GetMySQLDSN gets the MySql DSN from viper configuration 13 | func GetMySQLDSN() string { 14 | return viper.GetString(mysqldsn) 15 | } 16 | 17 | //GetAPIMySQLDSN gets the API MySql DSN from viper. This intended to be another account with limited privileges 18 | //for the apis to prevent potential abuse. It should have read only privileges at a minimum. 19 | func GetAPIMySQLDSN() string { 20 | return viper.GetString(apimysqldsn) 21 | } 22 | 23 | // GetLBRYcrdURL gets the LBRYcrd URL from viper configuration 24 | func GetLBRYcrdURL() string { 25 | if viper.IsSet(lbrycrdurl) { 26 | return viper.GetString(lbrycrdurl) 27 | } 28 | url, err := getLbrycrdURLFromConfFile() 29 | if err != nil { 30 | err = errors.Prefix("LBRYcrd conf file error", err) 31 | logrus.Panic(err) 32 | } 33 | return url 34 | } 35 | 36 | // GetDefaultClientTimeout gets the default client timeout. 37 | func GetDefaultClientTimeout() time.Duration { 38 | return viper.GetDuration(defaultclienttimeout) 39 | } 40 | 41 | // GetDaemonMode gets the daemon mode from the viper configuration. See default toml file for different modes. 42 | func GetDaemonMode() int { 43 | return viper.GetInt(daemonmode) 44 | } 45 | 46 | // GetProcessingDelay gets the processing delay from the viper configuration. 47 | func GetProcessingDelay() time.Duration { 48 | return viper.GetDuration(processingdelay) * time.Millisecond 49 | } 50 | 51 | // GetDaemonDelay gets the deamon delay from the viper configuration 52 | func GetDaemonDelay() time.Duration { 53 | return viper.GetDuration(daemondelay) * time.Second 54 | } 55 | 56 | // GetAPIHostAndPort gets the host and port string the api server should bind and listen too. 57 | func GetAPIHostAndPort() string { 58 | return viper.GetString(apihostport) 59 | } 60 | 61 | // GetDebugMode returns true/false if the app is in debug mode. 62 | func GetDebugMode() bool { 63 | return viper.GetBool(debugmode) 64 | } 65 | 66 | // GetDebugQueryMode turns on SQLBoiler query output 67 | func GetDebugQueryMode() bool { 68 | return viper.GetBool(debugquerymode) 69 | } 70 | 71 | // GetAutoUpdateCommand returns the command that should be executed to trigger a self update of the software. 72 | func GetAutoUpdateCommand() string { 73 | return viper.GetString(autoupdatecommand) 74 | } 75 | -------------------------------------------------------------------------------- /daemon/jobs/claimcntsync.go: -------------------------------------------------------------------------------- 1 | package jobs 2 | -------------------------------------------------------------------------------- /daemon/jobs/outputfixsync.go: -------------------------------------------------------------------------------- 1 | package jobs 2 | 3 | import ( 4 | "runtime" 5 | "sync" 6 | "time" 7 | 8 | "github.com/lbryio/lbry.go/v2/extras/errors" 9 | 10 | "github.com/lbryio/chainquery/model" 11 | "github.com/sirupsen/logrus" 12 | "github.com/volatiletech/null/v8" 13 | "github.com/volatiletech/sqlboiler/v4/boil" 14 | "github.com/volatiletech/sqlboiler/v4/queries/qm" 15 | ) 16 | 17 | // const outputFixSyncJob = "outputfixsync" 18 | 19 | // OutputFixSync this will check for spent claims and update them if they are incorrectly marked spent. 20 | func OutputFixSync() { 21 | err := fixOutputs() 22 | if err != nil { 23 | logrus.Error("Fix Outputs Sync:", errors.FullTrace(err)) 24 | } 25 | } 26 | 27 | func fixOutputs() error { 28 | wg := sync.WaitGroup{} 29 | spentClaimsChan := make(chan *model.Claim, 100) 30 | errorsChan := make(chan error, runtime.NumCPU()) 31 | c := model.ClaimColumns 32 | for i := 0; i < runtime.NumCPU()-1; i++ { 33 | wg.Add(1) 34 | go func(spentClaims chan *model.Claim, errorsChan chan error) { 35 | defer wg.Done() 36 | for claim := range spentClaims { 37 | where := model.OutputWhere 38 | isSpent, err := model.Outputs( 39 | where.ClaimID.EQ(null.StringFrom(claim.ClaimID)), 40 | where.TransactionHash.EQ(claim.TransactionHashUpdate.String), 41 | where.Vout.EQ(claim.VoutUpdate.Uint), 42 | where.IsSpent.EQ(true)).ExistsG() 43 | if err != nil { 44 | errorsChan <- errors.Err(err) 45 | return 46 | } 47 | if !isSpent { 48 | logrus.Debugf("%s is not really spent", claim.ClaimID) 49 | claim.BidState = "Active" 50 | claim.ModifiedAt = time.Now() 51 | err := claim.UpdateG(boil.Whitelist(c.BidState, c.ModifiedAt)) 52 | if err != nil { 53 | errorsChan <- errors.Err(err) 54 | return 55 | } 56 | } 57 | } 58 | }(spentClaimsChan, errorsChan) 59 | } 60 | 61 | lastClaimRecordID := uint64(0) 62 | claims, err := model.Claims( 63 | qm.Select(c.ID, c.ClaimID, c.TransactionHashID, c.TransactionHashUpdate, c.VoutUpdate), 64 | model.ClaimWhere.BidState.EQ("Spent"), 65 | model.ClaimWhere.ID.GT(lastClaimRecordID), 66 | qm.Limit(15000)).AllG() 67 | if err != nil { 68 | return errors.Err(err) 69 | } 70 | 71 | for len(claims) != 0 { 72 | logrus.Debugf("enqueing claims from %d to %d", claims[0].ID, claims[len(claims)-1].ID) 73 | for _, claim := range claims { 74 | spentClaimsChan <- claim 75 | lastClaimRecordID = claim.ID 76 | } 77 | claims, err = model.Claims( 78 | qm.Select(c.ID, c.ClaimID, c.TransactionHashID, c.TransactionHashUpdate, c.VoutUpdate), 79 | model.ClaimWhere.BidState.EQ("Spent"), 80 | model.ClaimWhere.ID.GT(lastClaimRecordID), 81 | qm.Limit(15000)).AllG() 82 | if err != nil { 83 | return errors.Err(err) 84 | } 85 | } 86 | close(spentClaimsChan) 87 | wg.Wait() 88 | close(errorsChan) 89 | for e := range errorsChan { 90 | logrus.Errorf("a worker incurrred in an error: %s", e.Error()) 91 | } 92 | return nil 93 | } 94 | -------------------------------------------------------------------------------- /daemon/processing/claim_test.go: -------------------------------------------------------------------------------- 1 | package processing 2 | 3 | import ( 4 | "encoding/hex" 5 | "encoding/json" 6 | "testing" 7 | 8 | util "github.com/lbryio/lbry.go/v2/lbrycrd" 9 | legacy_pb "github.com/lbryio/types/v1/go" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | type claimIDMatch struct { 14 | ClaimID string 15 | TxHash string 16 | N uint 17 | } 18 | 19 | var claimIDTests = []claimIDMatch{ 20 | 21 | {"589bc4845caca70977332025990b2a1807732b44", 22 | "6a9dbe3084b86cec8aa519970d2245dfa15193294cab65819a0d96d455c2a5df", 23 | 1}, 24 | 25 | {"60d7ddcc211c381bad63b73415c2065b219258f2", 26 | "2850f854108d9fd1d9067cc51ef38664f320cda363741a5774f8c6f0c154a702", 27 | 1}, 28 | 29 | {"015a97bef520a8b121baec02f9fd36a9f7e8a17e", 30 | "6ec15e7a80205fe2fb08eb57a5e4866544db56d81ebfc21d16a19c01a3394779", 31 | 0}, 32 | 33 | {"ed15aff6c77d0ae46b542aced757b04f7ec4a507", 34 | "1cd52537daa096d5fa2b0d20cbcf907fb1a1dc22436f48902473d8af1f7ebe07", 35 | 0}, 36 | 37 | {"bef5806ebee8816bcc8d10684eeb5d0d7c906c87", 38 | "bde00b2ba8ca425fff0d814d12a67d0ce99950365eb21081011aaf4a8c5f3e8b", 39 | 0}, 40 | {"8b120c045300923062d82911868febffccb502bf", 41 | "de0a48529d193ae33402f9620a25d91d7f33e608022d5e32451acd1d30fe7933", 42 | 0}, 43 | {"84cae80fbe8e49eb45a69ea3af884016c58e8ccb", 44 | "caf6a81ec886ed2a930a16814f0fdd488a753b22a77f5fb67a11fd3b985edb15", 45 | 0}, 46 | {"0fa76228fe19362a1b0af300217990f061460312", 47 | "7f3be2ae728ce3a3b5deee57011db1d284276594164b712914acc2f41b3d7152", 48 | 1}, 49 | } 50 | 51 | func TestGetClaimIDFromOutput(t *testing.T) { 52 | 53 | for _, claimMatch := range claimIDTests { 54 | claimID, err := util.ClaimIDFromOutpoint(claimMatch.TxHash, int(claimMatch.N)) 55 | if err != nil { 56 | t.Error(err) 57 | } 58 | if claimID != claimMatch.ClaimID { 59 | t.Error("Expected ", claimMatch.ClaimID, " got ", claimID) 60 | } 61 | } 62 | } 63 | 64 | func TestGetCertificate(t *testing.T) { 65 | pkHex := "3056301006072a8648ce3d020106052b8104000a03420004f83982cd9cedb8fd6ec81524fceb0b79ec65725dca0f8b8499def4ad2f3cfafd406e15184c1e0607d3fea7f5a5ae787735a8917394e6de576d73084ce961666d" 66 | pkBytes, err := hex.DecodeString(pkHex) 67 | if err != nil { 68 | t.Error(err) 69 | } 70 | var certificate *legacy_pb.Certificate 71 | unknown := legacy_pb.Certificate_UNKNOWN_VERSION 72 | SECP256k1 := legacy_pb.KeyType_SECP256k1 73 | certificate = &legacy_pb.Certificate{ 74 | Version: &unknown, 75 | KeyType: &SECP256k1, 76 | PublicKey: pkBytes, 77 | } 78 | 79 | certBytes, err := json.Marshal(certificate) 80 | if err != nil { 81 | logrus.Error("Could not form json from certificate") 82 | } 83 | println(string(certBytes)) 84 | expected := `{"version":0,"keyType":3,"publicKey":"MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE+DmCzZztuP1uyBUk/OsLeexlcl3KD4uEmd70rS88+v1AbhUYTB4GB9P+p/Wlrnh3NaiRc5Tm3ldtcwhM6WFmbQ=="}` 85 | if string(certBytes) != expected { 86 | t.Error("values don't match") 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /daemon/processing/metadata.go: -------------------------------------------------------------------------------- 1 | package processing 2 | 3 | import ( 4 | json2 "encoding/json" 5 | 6 | "github.com/lbryio/lbry.go/v2/schema/stake" 7 | ) 8 | 9 | // value.stream.metadata.author 10 | // value.stream.metadata.title 11 | // value.stream.metadata.description 12 | // value.claimType 13 | // value.stream.source.contentType 14 | // value.stream.metadata.nsfw 15 | 16 | //Value holds the current structure for metadata as json that is ensures a major versions backwards compatibility. 17 | type Value struct { 18 | Claim *Claim `json:"Claim"` 19 | } 20 | 21 | //Claim holds the current Claim structure 22 | type Claim struct { 23 | ClaimType string `json:"claimType"` 24 | Stream *Stream `json:"stream"` 25 | } 26 | 27 | //Stream holds the metadata and source 28 | type Stream struct { 29 | Metadata *Metadata `json:"metadata"` 30 | Source *Source `json:"source"` 31 | } 32 | 33 | //Metadata holds information that is used via the table column it is assigned for backwards compatibility. 34 | type Metadata struct { 35 | Author string `json:"author"` 36 | Title string `json:"title"` 37 | Description string `json:"description"` 38 | NSFW bool `json:"nsfw"` 39 | } 40 | 41 | //Source holds the media type of the claim 42 | type Source struct { 43 | ContentType string `json:"contentType"` 44 | } 45 | 46 | const streamType = "streamType" 47 | const certificateType = "certificateType" 48 | 49 | //GetValueAsJSON returns the JSON string of the structure of claim metadata. 50 | func GetValueAsJSON(helper stake.StakeHelper) ([]byte, error) { 51 | var value Value 52 | if helper.GetStream() != nil { 53 | s := helper.GetStream() 54 | contentType := "" 55 | if s.GetSource() != nil { 56 | contentType = s.GetSource().GetMediaType() 57 | } 58 | nsfw := tagExists("mature", helper.Claim.GetTags()) 59 | value = Value{ 60 | &Claim{ 61 | streamType, 62 | &Stream{ 63 | &Metadata{ 64 | s.GetAuthor(), 65 | helper.Claim.GetTitle(), 66 | helper.Claim.GetDescription(), 67 | nsfw, 68 | }, 69 | &Source{ 70 | contentType, 71 | }, 72 | }, 73 | }, 74 | } 75 | } else if helper.Claim.GetChannel() != nil { 76 | value = Value{&Claim{certificateType, nil}} 77 | } 78 | 79 | json, err := json2.Marshal(value) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | return json, nil 85 | } 86 | 87 | func tagExists(tagName string, taglist []string) bool { 88 | for _, tag := range taglist { 89 | if tag == tagName { 90 | return true 91 | } 92 | } 93 | return false 94 | } 95 | -------------------------------------------------------------------------------- /db/apiinit.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "database/sql" 5 | "strconv" 6 | 7 | "github.com/lbryio/lbry.go/v2/extras/errors" 8 | 9 | "github.com/volatiletech/sqlboiler/v4/boil" 10 | ) 11 | 12 | //Executor used for chainquery db 13 | var chainquery boil.Executor 14 | 15 | // InitAPIQuery initializes the api chainquery db connection 16 | func InitAPIQuery(dsn string, debug bool) (*QueryLogger, error) { 17 | if dsn == "" { 18 | return nil, errors.Base("chainquery DSN was not provided.") 19 | } 20 | _, logWrapper, err := dbInitConnection(dsn, "mysql", debug) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | //Set chainquery global executor 26 | chainquery = logWrapper 27 | 28 | return logWrapper, nil 29 | } 30 | 31 | // Used to query the chainquery database... 32 | func apiQuery(query string, args ...interface{}) (*sql.Rows, error) { 33 | if chainquery == nil { 34 | return nil, errors.Base("no connection to chainquery database.") 35 | } 36 | return chainquery.Query(query, args...) 37 | } 38 | 39 | type rowSlice []*map[string]interface{} 40 | 41 | func jsonify(rows *sql.Rows) rowSlice { 42 | columns, err := rows.Columns() 43 | if err != nil { 44 | panic(err.Error()) 45 | } 46 | 47 | values := make([]interface{}, len(columns)) 48 | 49 | scanArgs := make([]interface{}, len(values)) 50 | for i := range values { 51 | scanArgs[i] = &values[i] 52 | } 53 | 54 | c := 0 55 | 56 | data := rowSlice{} 57 | 58 | for rows.Next() { 59 | results := make(map[string]interface{}) 60 | err = rows.Scan(scanArgs...) 61 | if err != nil { 62 | panic(err.Error()) 63 | } 64 | 65 | for i, value := range values { 66 | switch value := value.(type) { 67 | case nil: 68 | results[columns[i]] = nil 69 | 70 | case []byte: 71 | s := string(value) 72 | x, err := strconv.Atoi(s) 73 | 74 | if err != nil { 75 | results[columns[i]] = s 76 | } else { 77 | results[columns[i]] = x 78 | } 79 | 80 | default: 81 | results[columns[i]] = value 82 | } 83 | } 84 | data = append(data, &results) 85 | c++ 86 | } 87 | 88 | return data 89 | } 90 | -------------------------------------------------------------------------------- /db/init.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "github.com/lbryio/chainquery/migration" 5 | "github.com/lbryio/lbry.go/v2/extras/errors" 6 | 7 | _ "github.com/go-sql-driver/mysql" // import mysql 8 | "github.com/jmoiron/sqlx" 9 | _ "github.com/kevinburke/go-bindata/v4" // so it's detected by `dep ensure` 10 | migrate "github.com/rubenv/sql-migrate" 11 | log "github.com/sirupsen/logrus" 12 | "github.com/volatiletech/sqlboiler/v4/boil" 13 | ) 14 | 15 | // Init initializes a database connection based on the dsn provided. It also sets it as the global db connection. 16 | func Init(dsn string, debug bool) (*QueryLogger, error) { 17 | dsn += "?parseTime=1&collation=utf8mb4_unicode_ci&loc=Local" 18 | dbConn, err := sqlx.Connect("mysql", dsn) 19 | if err != nil { 20 | return nil, errors.Err(err) 21 | } 22 | 23 | err = dbConn.Ping() 24 | if err != nil { 25 | return nil, errors.Err(err) 26 | } 27 | 28 | logWrapper := &QueryLogger{DB: dbConn} 29 | if debug { 30 | boil.DebugMode = true 31 | } 32 | 33 | boil.SetDB(logWrapper) 34 | 35 | migrations := &migrate.AssetMigrationSource{ 36 | Asset: migration.Asset, 37 | AssetDir: migration.AssetDir, 38 | Dir: "migration", 39 | } 40 | n, migrationErr := migrate.Exec(dbConn.DB, "mysql", migrations, migrate.Up) 41 | if migrationErr != nil { 42 | return nil, errors.Err(migrationErr) 43 | } 44 | log.Printf("Applied %d migrations", n) 45 | 46 | return logWrapper, nil 47 | } 48 | 49 | func dbInitConnection(dsn string, driverName string, debug bool) (*sqlx.DB, *QueryLogger, error) { 50 | dsn += "?parseTime=1&collation=utf8mb4_unicode_ci&loc=Local" 51 | dbConn, err := sqlx.Connect(driverName, dsn) 52 | if err != nil { 53 | return nil, nil, errors.Err(err) 54 | } 55 | 56 | err = dbConn.Ping() 57 | if err != nil { 58 | return nil, nil, errors.Err(err) 59 | } 60 | 61 | logWrapper := &QueryLogger{DB: dbConn} 62 | if debug { 63 | logWrapper.Logger = log.StandardLogger() 64 | //boil.DebugMode = true // this just prints everything twice 65 | } 66 | 67 | return dbConn, logWrapper, nil 68 | } 69 | 70 | // CloseDB is a wrapper function to allow error handle when it is usually deferred. 71 | func CloseDB(db *QueryLogger) { 72 | if err := db.Close(); err != nil { 73 | log.Error("Closing DB Error: ", err) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /db/query.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "context" 5 | 6 | g "github.com/lbryio/chainquery/swagger/clients/goclient" 7 | "github.com/lbryio/chainquery/util" 8 | 9 | "github.com/lbryio/chainquery/meta" 10 | "github.com/volatiletech/sqlboiler/v4/boil" 11 | "github.com/volatiletech/sqlboiler/v4/queries" 12 | ) 13 | 14 | // AddressSummary summarizes information for an address from chainquery database 15 | type AddressSummary struct { 16 | ID uint64 `boil:"id"` 17 | Address string `boil:"address"` 18 | TotalReceived float64 `boil:"total_received"` 19 | TotalSent float64 `boil:"total_sent"` 20 | Balance float64 `boil:"balance"` 21 | } 22 | 23 | // GetTableStatus provides size information for the tables in the chainquery database 24 | func GetTableStatus() (*g.ChainqueryStatus, error) { 25 | stats := g.ChainqueryStatus{} 26 | rows, err := boil.GetDB().Query( 27 | `SELECT TABLE_NAME as "table",` + 28 | `SUM(TABLE_ROWS) as "rows" ` + 29 | `FROM INFORMATION_SCHEMA.TABLES ` + 30 | `WHERE TABLE_SCHEMA = "chainquery" ` + 31 | `GROUP BY TABLE_NAME;`) 32 | 33 | if err != nil { 34 | return nil, err 35 | } 36 | defer util.CloseRows(rows) 37 | var statrows []g.TableSize 38 | for rows.Next() { 39 | var stat g.TableSize 40 | err = rows.Scan(&stat.TableName, &stat.NrRows) 41 | if err != nil { 42 | return nil, err 43 | } 44 | statrows = append(statrows, stat) 45 | } 46 | 47 | stats.TableStatus = statrows 48 | stats.SemVersion = meta.GetSemVersion() 49 | stats.VersionShort = meta.GetVersion() 50 | stats.VersionLong = meta.GetVersionLong() 51 | stats.CommitMessage = meta.GetCommitMessage() 52 | 53 | return &stats, nil 54 | } 55 | 56 | // GetAddressSummary returns summary information of an address in the chainquery database. 57 | func GetAddressSummary(address string) (*AddressSummary, error) { 58 | var context context.Context 59 | addressSummary := AddressSummary{} 60 | err := queries.Raw( 61 | `SELECT address.address, `+ 62 | `SUM(ta.credit_amount) AS total_received, `+ 63 | `SUM(ta.debit_amount) AS total_sent,`+ 64 | `(SUM(ta.credit_amount) - SUM(ta.debit_amount)) AS balance `+ 65 | `FROM address LEFT JOIN transaction_address as ta ON ta.address_id = address.id `+ 66 | `WHERE address.address=? `+ 67 | `GROUP BY address.address `, address).BindG(context, &addressSummary) 68 | 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | return &addressSummary, nil 74 | 75 | } 76 | 77 | // APIQuery is the entry point from the API to chainquery. The results are turned into json. 78 | func APIQuery(query string, args ...interface{}) (interface{}, error) { 79 | rows, err := apiQuery(query, args...) 80 | if err != nil { 81 | return nil, err 82 | } 83 | defer util.CloseRows(rows) 84 | return jsonify(rows), nil 85 | 86 | } 87 | -------------------------------------------------------------------------------- /db/query_test.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/lbryio/chainquery/model" 8 | "github.com/lbryio/lbry.go/v2/extras/errors" 9 | 10 | "github.com/volatiletech/sqlboiler/v4/queries/qm" 11 | ) 12 | 13 | func TestMain(m *testing.M) { 14 | dbInstance, err := Init("chainquery:chainquery@tcp(localhost:3306)/chainquery", false) 15 | if err != nil { 16 | panic(errors.FullTrace(err)) 17 | } 18 | defer CloseDB(dbInstance) 19 | os.Exit(m.Run()) 20 | } 21 | 22 | func TestQueryGetAddressSummary(t *testing.T) { 23 | //Need to add setup here so it can connect to the db 24 | addresses, err := model.Addresses(qm.Limit(1000)).AllG() 25 | if err != nil { 26 | t.Error(err) 27 | } 28 | 29 | for i := range addresses { 30 | address := addresses[i] 31 | _, err := GetAddressSummary(address.Address) 32 | if err != nil { 33 | t.Error(err) 34 | } 35 | 36 | } 37 | } 38 | 39 | func TestQueryGetTableStatus(t *testing.T) { 40 | stats, err := GetTableStatus() 41 | if err != nil { 42 | t.Error(err) 43 | } 44 | println("TableName NrRows", len(stats.TableStatus)) 45 | for _, stat := range stats.TableStatus { 46 | println(stat.TableName, ":", stat.NrRows) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | APP_DIR="$DIR" 5 | 6 | ( 7 | 8 | [ -n "$(pgrep lbrycrdd)" ] && export LBRYCRD_CONNECT="from_conf" 9 | 10 | hash reflex 2>/dev/null || go get github.com/cespare/reflex 11 | hash reflex 2>/dev/null || { echo >&2 'Make sure $GOPATH/bin is in your $PATH'; exit 1; } 12 | 13 | go install github.com/kevinburke/go-bindata/v4/...@latest 14 | 15 | cd "$APP_DIR" 16 | 17 | reflex --decoration=none --start-service=true --regex='\.go$' --inverse-regex='migration/bindata\.go' -- sh -c "go generate && go run *.go serve" 18 | ) 19 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | ## Get the latest source and extract it for the app container. 2 | ## Design choices, two RUN layers intended to keep builds faster, the zipped 3 | FROM ubuntu:18.04 as prep 4 | LABEL MAINTAINER="beamer@lbry.io" 5 | RUN apt-get update && \ 6 | apt-get -y install unzip curl telnet wait-for-it && \ 7 | apt-get autoclean -y && \ 8 | rm -rf /var/lib/apt/lists/* 9 | WORKDIR / 10 | SHELL ["/bin/bash", "-o", "pipefail", "-c"] 11 | COPY ./start.sh start 12 | COPY ./healthcheck.sh healthcheck 13 | ARG VERSION="master" 14 | RUN curl -s -o /chainquery http://build.lbry.io/chainquery/branch-"${VERSION}"/chainquery && \ 15 | chmod +x /chainquery 16 | 17 | 18 | FROM ubuntu:18.04 as app 19 | RUN apt-get update && \ 20 | apt-get -y install telnet wait-for-it && \ 21 | apt-get autoclean -y && \ 22 | rm -rf /var/lib/apt/lists/* 23 | ARG VERSION="master" 24 | ADD https://raw.githubusercontent.com/lbryio/chainquery/"${VERSION}"/config/default/chainqueryconfig.toml /etc/lbry/chainqueryconfig.toml.orig 25 | RUN adduser chainquery --gecos GECOS --shell /bin/bash --disabled-password --home /home/chainquery && \ 26 | chown -R chainquery:chainquery /etc/lbry 27 | COPY --from=prep ./healthcheck /chainquery /start /usr/bin/ 28 | HEALTHCHECK --interval=1m --timeout=30s \ 29 | CMD healthcheck 30 | EXPOSE 6300 31 | USER chainquery 32 | STOPSIGNAL SIGINT 33 | CMD ["start"] -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $# -eq 0 ] 3 | then 4 | echo "No docker tag argument supplied. Use './build.sh '" 5 | exit 1 6 | fi 7 | echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin 8 | docker build --no-cache --build-arg VERSION=$1 --tag odyseeteam/chainquery:$1 ./docker 9 | docker push odyseeteam/chainquery:$1 -------------------------------------------------------------------------------- /docker/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | curl --fail http://localhost:6300/api/status || exit 1 -------------------------------------------------------------------------------- /docker/my.cnf: -------------------------------------------------------------------------------- 1 | # Default Homebrew MySQL server config 2 | [mysqld] 3 | # Only allow connections from localhost 4 | innodb_log_file_size=5G 5 | key_buffer_size=1G 6 | innodb_flush_log_at_trx_commit = 0 7 | innodb_autoinc_lock_mode=2 8 | innodb_buffer_pool_size=1G 9 | innodb_log_buffer_size=1G -------------------------------------------------------------------------------- /docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Config setup 4 | 5 | ## Setup Values 6 | DEBUGMODE=$(echo "debugmode=$DEBUGMODE") 7 | LBRYCRDURL=$(echo "lbrycrdurl=\"rpc://$RPC_USER:$RPC_PASSWORD@10.5.1.2:9245\"") 8 | MYSQLDSN=$(echo "mysqldsn=\"$MYSQL_USER:$MYSQL_PASSWORD@tcp($MYSQL_SERVER:3306)/$MYSQL_DATABASE\"") 9 | APIMYSQLDSN=$(echo "apimysqldsn=\"$MYSQL_USER:$MYSQL_PASSWORD@tcp($MYSQL_SERVER:3306)/$MYSQL_DATABASE\"") 10 | 11 | ## Setup Defaults 12 | DEBUGMODE_DEFAULT='#DEFAULT-debugmode=false' 13 | LBRYCRDURL_DEFAULT='#DEFAULT-lbrycrdurl="rpc://lbry:lbry@localhost:9245"' 14 | MYSQLDSN_DEFAULT='#DEFAULT-mysqldsn="chainquery:chainquery@tcp(localhost:3306)/chainquery"' 15 | APIMYSQLDSN_DEFAULT='#DEFAULT-apimysqldsn="chainquery:chainquery@tcp(localhost:3306)/chainquery"' 16 | 17 | ## Add setup value variable name to this list to get processed on container start 18 | CONFIG_SETTINGS=( 19 | DEBUGMODE 20 | LBRYCRDURL 21 | MYSQLDSN 22 | APIMYSQLDSN 23 | ) 24 | 25 | function set_configs() { 26 | ## Set configs on container start if not already set. 27 | for i in "${!CONFIG_SETTINGS[@]}"; do 28 | ## Indirect references http://tldp.org/LDP/abs/html/ivr.html 29 | eval FROM_STRING=\$"${CONFIG_SETTINGS[$i]}_DEFAULT" 30 | eval TO_STRING=\$${CONFIG_SETTINGS[$i]} 31 | ## TODO: Add a bit more magic to make sure that you're only configuring things if not set by config mounts. 32 | sed -i "s~$FROM_STRING~"$TO_STRING"~g" /etc/lbry/chainqueryconfig.toml 33 | done 34 | echo "Reading config for debugging." 35 | cat /etc/lbry/chainqueryconfig.toml 36 | } 37 | 38 | if [[ ! -f /etc/lbry/chainqueryconfig.toml ]]; then 39 | echo "[INFO]: Did not find chainqueryconfig.toml" 40 | echo " Installing default and configuring with provided environment variables if any." 41 | ## Install fresh copy of config file. 42 | echo "cp -v /etc/lbry/chainqueryconfig.toml.orig /etc/lbry/chainqueryconfig.toml" 43 | cp -v /etc/lbry/chainqueryconfig.toml.orig /etc/lbry/chainqueryconfig.toml 44 | ls -lAh /etc/lbry/ 45 | set_configs 46 | else 47 | echo "[INFO]: Found a copy of chainqueryconfig.toml in /etc/lbry" 48 | fi 49 | 50 | ## For now keeping this simple. Potentially eventually add all command args as envvars for the Dockerfile or use safe way to add args via docker-compose.yml 51 | chainquery serve --configpath "/etc/lbry/" -------------------------------------------------------------------------------- /docs/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdyseeTeam/chainquery/48c092515dea5cd1856e7c84ce8611ee9b66e210/docs/assets/images/logo.png -------------------------------------------------------------------------------- /docs/assets/js/main.js: -------------------------------------------------------------------------------- 1 | window.onhashchange = function() { 2 | choose(window.location.href.toString()); 3 | } 4 | 5 | var selectionImage; 6 | 7 | function choose(url) { 8 | var f = url.split("/").slice(-1)[0].split("?")[0]; 9 | if(f.match(/#/g) && f.match(/#/g).length > 0) { 10 | f = f.split("#")[0]; 11 | } 12 | $('div.non-sidebar').empty(); 13 | $('div.non-sidebar').load("operations/" + f + ".html", function(){ 14 | goToAnchor(); 15 | // rebind the models 16 | $(".model a").on("click", function(e){ 17 | e.preventDefault(); 18 | var model = $(this).parent().attr("data-model") 19 | var parentOffset = $(this).parent().offset(); 20 | var encodedWord = encodeURI(model); 21 | 22 | if(!selectionImage) { 23 | selectionImage = $('
').attr({ 24 | title: 'Model detail', 25 | target: '_blank', 26 | class: 'model-detail-popup' 27 | }).hide(); 28 | $('div.model-container').append(selectionImage); 29 | } 30 | 31 | selectionImage.load("models/" + encodedWord + ".html") 32 | selectionImage.attr('href',url.replace('{term}',encodeURI(model))).css({ 33 | left: e.pageX + 20, 34 | top: e.pageY - 10, 35 | position: "absolute" 36 | }).fadeIn(); 37 | }) 38 | }); 39 | 40 | $("body").on("click",function(e) { 41 | var target = $(e.target); 42 | if (target.parents(".model-detail-popup").length == 0 && target.parents('.model').length != 1) { 43 | if(document.querySelector('.model-detail-popup')) { 44 | document.querySelector('.model-detail-popup').style.display = 'none'; 45 | } 46 | } 47 | }); 48 | } 49 | 50 | function goToAnchor() { 51 | var doARead = $($('a')[0]).offset(); 52 | var anchorArr = window.location.href.toString().split("#"); 53 | if(anchorArr.length > 2) { 54 | var anchor = anchorArr[anchorArr.length-1]; 55 | window.scrollTo(0,$('a[name='+anchor+']').offset().top - 80); 56 | } 57 | } 58 | function resize() 59 | { 60 | $(".sidebar").css('height', $(window).height() -60); 61 | $("#content-window").css('height', $(window).height() -60); 62 | 63 | } 64 | $(function(){ 65 | window.onresize = resize; 66 | resize(); 67 | $(window).bind('hashchange', function() { 68 | choose(window.location.href.toString()); 69 | }); 70 | }); -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | REST API Resources 13 | 14 | 15 |
16 |
17 |

18 |
19 |
20 |
21 |
22 |
23 | 58 |
59 |
60 |

Getting Started

61 |

To begin using your fancy HTTP API, follow the steps below.

62 |

You can add some helpful tips, here

63 |
64 |
65 |
66 | 67 | -------------------------------------------------------------------------------- /docs/models/AddressSummary.html: -------------------------------------------------------------------------------- 1 | 2 |

AddressSummary

3 |
    4 |
  • Address : String 5 |
    6 |
  • 7 |
8 |
    9 |
  • TotalReceived : Double 10 |
    Total amount received by address from all transactions it was a part of. 11 |
  • 12 |
13 |
    14 |
  • TotalSent : Double 15 |
    Total amount sent from address for all transactions it was a part of. 16 |
  • 17 |
18 |
    19 |
  • Balance : Double 20 |
    The current balance of an address 21 |
  • 22 |
23 | -------------------------------------------------------------------------------- /docs/models/TableSize.html: -------------------------------------------------------------------------------- 1 | 2 |

TableSize

3 |
    4 |
  • TableName : String 5 |
    Name of the table being referenced. 6 |
  • 7 |
8 |
    9 |
  • NrRows : Long 10 |
    The number of rows in the referenced table 11 |
  • 12 |
13 | -------------------------------------------------------------------------------- /docs/models/TableStatus.html: -------------------------------------------------------------------------------- 1 | 2 |

TableStatus

3 |
    4 |
  • Status : List 5 |
    6 |
  • 7 |
8 | -------------------------------------------------------------------------------- /docs/operations/DefaultApi.html: -------------------------------------------------------------------------------- 1 |
2 |

3 |

This is the API

4 | 5 |

autoUpdate

6 |
7 |

8 |

takes a webhook as defined by https://docs.travis-ci.com/user/notifications/#Webhooks-Delivery-Format, validates the public key, chooses whether or not update the application. If so it shuts down the api, downloads the latest release from https://github.com/lbryio/chainquery/releases, replaces the binary and starts the api again.

9 |

URL

10 | http://0.0.0.0:6300/api/autoupdate 11 |

HTTP Method

12 | POST 13 |

Response Type

14 |
15 |

Parameters

16 |
    17 |
  • 18 | 19 | 20 | 21 | 22 | Body: 23 | payload 24 | Object(object) 25 | 26 |

    27 |
  • 28 |
29 |
30 | -------------------------------------------------------------------------------- /docs/operations/QueryApi.html: -------------------------------------------------------------------------------- 1 |
2 |

3 |

This is the API

4 | 5 |

sQL Query

6 |
7 |

8 |

API exposed for sending SQL queries directly against the chainquery database. Since this is an exposed API there are limits to its use. These limits include queries per hour, read-only, limited to 60 second timeout.

9 |

URL

10 | http://0.0.0.0:6300/api/sql 11 |

HTTP Method

12 | GET 13 |

Response Type

14 | 15 |

Parameters

16 |
    17 |
  • 18 | 19 | 20 | Path: 21 | 22 | 23 | query 24 | String 25 | 26 |

    The SQL query to be put against the chainquery database.

    27 |
  • 28 |
  • 29 | 30 | 31 | Path: 32 | 33 | 34 | values 35 | List(String) 36 | 37 |

    when passing in a query use '?' for values which will be replaced in order of appearance with this array.

    38 |
  • 39 |
40 |
41 | -------------------------------------------------------------------------------- /docs/operations/StatApi.html: -------------------------------------------------------------------------------- 1 |
2 |

3 |

This is the API

4 | 5 |

addressSummary

6 |
7 |

8 |

It returns sent, recieved, balance, and number of transactions it has been used in.

9 |

URL

10 | http://0.0.0.0:6300/api/addresssummary 11 |

HTTP Method

12 | GET 13 |

Response Type

14 | 15 |

Parameters

16 |
    17 |
  • 18 | 19 | Query: 20 | 21 | 22 | 23 | LbryAddress 24 | String 25 | 26 |

    A LbryAddress

    27 |
  • 28 |
29 |

chainQueryStatus

30 |
31 |

32 | 33 |

URL

34 | http://0.0.0.0:6300/api/status 35 |

HTTP Method

36 | GET 37 |

Response Type

38 | 39 |

Parameters

40 |
    41 |
42 |
43 | -------------------------------------------------------------------------------- /e2e/chainqueryconfig.toml: -------------------------------------------------------------------------------- 1 | lbrycrdurl="rpc://lbry:lbry@localhost:11337" 2 | mysqldsn="chainquery:chainquery@tcp(localhost:3306)/chainquery_e2e_test" 3 | blockchainname="lbrycrd_regtest" 4 | #debugmode=true 5 | #debugquerymode=true 6 | #profilemode=true 7 | #mysqlprofile=true 8 | -------------------------------------------------------------------------------- /e2e/channel.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "github.com/btcsuite/btcd/btcec" 5 | "github.com/lbryio/lbry.go/v2/extras/errors" 6 | "github.com/lbryio/lbry.go/v2/schema/keys" 7 | c "github.com/lbryio/lbry.go/v2/schema/stake" 8 | pb "github.com/lbryio/types/v2/go" 9 | ) 10 | 11 | func newChannel() (*c.StakeHelper, *btcec.PrivateKey, error) { 12 | claimChannel := new(pb.Claim_Channel) 13 | channel := new(pb.Channel) 14 | claimChannel.Channel = channel 15 | 16 | pbClaim := new(pb.Claim) 17 | pbClaim.Type = claimChannel 18 | 19 | privateKey, err := btcec.NewPrivateKey(btcec.S256()) 20 | if err != nil { 21 | return nil, nil, errors.Err(err) 22 | } 23 | pubkeyBytes, err := keys.PublicKeyToDER(privateKey.PubKey()) 24 | if err != nil { 25 | return nil, nil, errors.Err(err) 26 | } 27 | 28 | helper := c.StakeHelper{Claim: pbClaim} 29 | helper.Version = c.NoSig 30 | helper.Claim.GetChannel().PublicKey = pubkeyBytes 31 | helper.Claim.Tags = []string{"Foo", "Bar"} 32 | coverSrc := new(pb.Source) 33 | coverSrc.Url = "https://coverurl.com" 34 | helper.Claim.GetChannel().Cover = coverSrc 35 | helper.Claim.GetChannel().WebsiteUrl = "https://homepageurl.com" 36 | helper.Claim.Languages = []*pb.Language{{Language: pb.Language_en}} 37 | helper.Claim.Title = "title" 38 | helper.Claim.Description = "description" 39 | thumbnailSrc := new(pb.Source) 40 | thumbnailSrc.Url = "thumbnailurl.com" 41 | helper.Claim.Thumbnail = thumbnailSrc 42 | helper.Claim.Locations = []*pb.Location{{Country: pb.Location_US}} 43 | 44 | return &helper, privateKey, nil 45 | } 46 | 47 | func createChannel(name string) (*c.StakeHelper, *btcec.PrivateKey, error) { 48 | channel, key, err := newChannel() 49 | if err != nil { 50 | return nil, nil, err 51 | } 52 | 53 | rawTx, err := getEmptyTx(claimAmount) 54 | if err != nil { 55 | return nil, nil, err 56 | } 57 | err = addClaimToTx(rawTx, channel, name) 58 | if err != nil { 59 | return nil, nil, err 60 | } 61 | 62 | _, err = signTxAndSend(rawTx) 63 | if err != nil { 64 | return nil, nil, err 65 | } 66 | 67 | return channel, key, nil 68 | } 69 | -------------------------------------------------------------------------------- /e2e/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | 3 | services: 4 | ############# 5 | ## Lbrycrd ## 6 | ############# 7 | lbrycrd: 8 | image: lbry/lbrycrd:master 9 | restart: "no" 10 | ports: 11 | - "11336:29246" 12 | - "11337:29245" 13 | ## host volumes for persistent data such as wallet private keys. 14 | volumes: 15 | - "../persist/data:/data" 16 | environment: 17 | - RUN_MODE=regtest 18 | -------------------------------------------------------------------------------- /e2e/e2e.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | ./e2e/prepare_e2e.sh 5 | ./bin/chainquery e2e --configpath=$PWD/e2e 6 | echo $? 7 | cd e2e 8 | docker-compose stop lbrycrd 9 | if [ -d persist ]; then rm -r persist; fi #Remove this if you want to debug the lbrycrd data, debug docker or see files grabbed. 10 | echo "Finished e2e test" -------------------------------------------------------------------------------- /e2e/finder.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "github.com/btcsuite/btcd/btcjson" 5 | "github.com/lbryio/lbry.go/v2/extras/errors" 6 | ) 7 | 8 | type outputFinder struct { 9 | unspent []btcjson.ListUnspentResult 10 | lastChecked int 11 | } 12 | 13 | func newOutputFinder(unspentResults []btcjson.ListUnspentResult) *outputFinder { 14 | return &outputFinder{unspent: unspentResults, lastChecked: -1} 15 | } 16 | 17 | func (f *outputFinder) nextBatch(minAmount float64) ([]btcjson.ListUnspentResult, error) { 18 | var batch []btcjson.ListUnspentResult 19 | var lbcBatched float64 20 | for i, unspent := range f.unspent { 21 | if i > f.lastChecked { 22 | if unspent.Spendable { 23 | batch = append(batch, unspent) 24 | lbcBatched = lbcBatched + unspent.Amount 25 | } 26 | } 27 | if lbcBatched >= minAmount { 28 | f.lastChecked = i 29 | break 30 | } 31 | if i == len(f.unspent)-1 { 32 | return nil, errors.Err("Not enough unspent outputs to spend %d on supports.", minAmount) 33 | } 34 | } 35 | 36 | return batch, nil 37 | } 38 | -------------------------------------------------------------------------------- /e2e/prepare_e2e.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | echo 'Running e2e tests...' 5 | if [ -d persist ]; then rm -r persist; fi #Remove this if you want to debug the lbrycrd data, debug docker or see files grabbed. 6 | ./scripts/build.sh 7 | mysql -u root -e 'DROP DATABASE IF EXISTS chainquery_e2e_test;' 8 | mysql -u root -e 'CREATE DATABASE IF NOT EXISTS chainquery_e2e_test;' 9 | mysql -u root -e "GRANT ALL ON chainquery_e2e_test.* TO 'chainquery'@'localhost';" 10 | cd e2e 11 | docker-compose stop 12 | docker-compose rm -f 13 | if [ -d ../persist ]; then rm -r ../persist; fi 14 | mkdir ../persist 15 | echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin 16 | docker-compose pull 17 | docker-compose up -d lbrycrd 18 | docker ps 19 | sleep 20 20 | echo "Generating 800 blocks" 21 | docker-compose exec lbrycrd lbrycrd-cli --conf=/etc/lbry/lbrycrd.conf generate 800 -------------------------------------------------------------------------------- /e2e/script.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "github.com/btcsuite/btcd/txscript" 5 | "github.com/btcsuite/btcutil" 6 | "github.com/lbryio/lbry.go/v2/extras/errors" 7 | ) 8 | 9 | /* WILL NEED FOR FUTURE TESTS 10 | func getClaimSupportPayoutScript(name, claimid string, address btcutil.Address) ([]byte, error) { 11 | //OP_SUPPORT_CLAIM OP_2DROP OP_DROP OP_DUP OP_HASH160
OP_EQUALVERIFY OP_CHECKSIG 12 | 13 | pkscript, err := txscript.PayToAddrScript(address) 14 | if err != nil { 15 | return nil, errors.Err(err) 16 | } 17 | 18 | bytes, err := hex.DecodeString(claimid) 19 | if err != nil { 20 | return nil, errors.Err(err) 21 | } 22 | 23 | return txscript.NewScriptBuilder(). 24 | AddOp(txscript.OP_NOP7). //OP_SUPPORT_CLAIM 25 | AddData([]byte(name)). // 26 | AddData(util.ReverseBytes(bytes)). // 27 | AddOp(txscript.OP_2DROP). //OP_2DROP 28 | AddOp(txscript.OP_DROP). //OP_DROP 29 | AddOps(pkscript). //OP_DUP OP_HASH160
OP_EQUALVERIFY OP_CHECKSIG 30 | Script() 31 | 32 | }*/ 33 | 34 | func getClaimNamePayoutScript(name string, value []byte, address btcutil.Address) ([]byte, error) { 35 | //OP_CLAIM_NAME OP_2DROP OP_DROP OP_DUP OP_HASH160
OP_EQUALVERIFY OP_CHECKSIG 36 | 37 | pkscript, err := txscript.PayToAddrScript(address) 38 | if err != nil { 39 | return nil, errors.Err(err) 40 | } 41 | 42 | return txscript.NewScriptBuilder(). 43 | AddOp(txscript.OP_NOP6). //OP_SUPPORT_CLAIM 44 | AddData([]byte(name)). // 45 | AddData(value). // 46 | AddOp(txscript.OP_2DROP). //OP_2DROP 47 | AddOp(txscript.OP_DROP). //OP_DROP 48 | AddOps(pkscript). //OP_DUP OP_HASH160
OP_EQUALVERIFY OP_CHECKSIG 49 | Script() 50 | } 51 | -------------------------------------------------------------------------------- /e2e/transaction.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "github.com/lbryio/chainquery/lbrycrd" 5 | "github.com/lbryio/lbry.go/v2/extras/errors" 6 | 7 | "github.com/btcsuite/btcd/btcjson" 8 | "github.com/btcsuite/btcd/chaincfg/chainhash" 9 | "github.com/btcsuite/btcd/wire" 10 | "github.com/btcsuite/btcutil" 11 | ) 12 | 13 | func createBaseRawTx(inputs []btcjson.TransactionInput, change float64) (*wire.MsgTx, error) { 14 | addresses := make(map[btcutil.Address]btcutil.Amount) 15 | changeAddress, err := lbrycrd.LBRYcrdClient.GetNewAddress("") 16 | if err != nil { 17 | return nil, errors.Err(err) 18 | } 19 | changeAmount, err := btcutil.NewAmount(change) 20 | if err != nil { 21 | return nil, errors.Err(err) 22 | } 23 | addresses[changeAddress] = changeAmount 24 | lockTime := int64(0) 25 | return lbrycrd.LBRYcrdClient.CreateRawTransaction(inputs, addresses, &lockTime) 26 | } 27 | 28 | func getEmptyTx(totalOutputSpend float64) (*wire.MsgTx, error) { 29 | totalFees := 0.1 30 | unspentResults, err := lbrycrd.LBRYcrdClient.ListUnspentMin(1) 31 | if err != nil { 32 | return nil, errors.Err(err) 33 | } 34 | finder := newOutputFinder(unspentResults) 35 | 36 | outputs, err := finder.nextBatch(totalOutputSpend + totalFees) 37 | if err != nil { 38 | return nil, err 39 | } 40 | if len(outputs) == 0 { 41 | return nil, errors.Err("Not enough spendable outputs to create transaction") 42 | } 43 | inputs := make([]btcjson.TransactionInput, len(outputs)) 44 | var totalInputSpend float64 45 | for i, output := range outputs { 46 | inputs[i] = btcjson.TransactionInput{Txid: output.TxID, Vout: output.Vout} 47 | totalInputSpend = totalInputSpend + output.Amount 48 | } 49 | 50 | change := totalInputSpend - totalOutputSpend - totalFees 51 | return createBaseRawTx(inputs, change) 52 | } 53 | 54 | func signTxAndSend(rawTx *wire.MsgTx) (*chainhash.Hash, error) { 55 | signedTx, allInputsSigned, err := lbrycrd.LBRYcrdClient.SignRawTransactionWithWallet(rawTx) 56 | if err != nil { 57 | return nil, errors.Err(err) 58 | } 59 | if !allInputsSigned { 60 | return nil, errors.Err("Not all inputs for the tx could be signed!") 61 | } 62 | 63 | return lbrycrd.LBRYcrdClient.SendRawTransaction(signedTx, false) 64 | } 65 | -------------------------------------------------------------------------------- /global/global.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import "time" 4 | 5 | // DaemonSettings is a struct for holding the different settings of the daemon. 6 | type DaemonSettings struct { 7 | DaemonMode int 8 | ProcessingDelay time.Duration 9 | DaemonDelay time.Duration 10 | IsReIndex bool 11 | } 12 | 13 | // BlockChainName is the name of the blockchain. It is used to decode protobuf claims. 14 | var BlockChainName = "lbrycrd_main" 15 | 16 | const ( 17 | //StreamClaimType is a reference to claim table type column - stream claims 18 | StreamClaimType = "stream" 19 | //ChannelClaimType is a reference to claim table type column - channel claims 20 | ChannelClaimType = "channel" 21 | //ClaimListClaimType is a reference to claim table type column - list of claims 22 | ClaimListClaimType = "claimlist" 23 | //ClaimReferenceClaimType is a reference to claim table type column - reference to another claim 24 | ClaimReferenceClaimType = "claimreference" 25 | ) 26 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:generate go-bindata -o migration/bindata.go -nometadata -pkg migration -ignore bindata.go migration/ 4 | //go:generate go fmt ./migration/bindata.go 5 | //go:generate goimports -l ./migration/bindata.go 6 | 7 | import ( 8 | _ "github.com/kevinburke/go-bindata/v4" // so it's detected by `dep ensure` 9 | "github.com/lbryio/chainquery/cmd" 10 | ) 11 | 12 | func main() { 13 | cmd.Execute() 14 | } 15 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | var express = require("express") 2 | 3 | var app = express(); 4 | var docs_handler = express.static(__dirname + '/docs/'); 5 | app.use(docs_handler); 6 | // start the server 7 | app.listen(8002); 8 | -------------------------------------------------------------------------------- /meta/meta.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | // version and commitMsg get filled in using -ldflags when the binary gets built with /scripts/build.sh 4 | var semVersion string 5 | var version string 6 | var versionLong string 7 | var commitMsg string 8 | 9 | // GetVersion returns the version of the application. If it is tagged it will be the semver, otherwise it will contain 10 | // the number of commits since the last one, the short hash of the commit and whether or not the directory was dirty 11 | // at build time. 12 | func GetVersion() string { 13 | if version != "" { 14 | return version 15 | } 16 | 17 | return "unknown" 18 | } 19 | 20 | // GetVersionLong returns what GetVersion returns but will always return the long version. 21 | func GetVersionLong() string { 22 | if versionLong != "" { 23 | return versionLong 24 | } 25 | 26 | return "unknown" 27 | } 28 | 29 | // GetSemVersion returns the Semantic Version of the Chainquery Application. This field is set on deployment 30 | // with the tag vx.x.x 31 | func GetSemVersion() string { 32 | if semVersion != "" { 33 | return semVersion 34 | } 35 | 36 | return "unknown" 37 | } 38 | 39 | // GetCommitMessage returns the commit message of the commit used to build the binary. 40 | func GetCommitMessage() string { 41 | if commitMsg != "" { 42 | return commitMsg 43 | } 44 | 45 | return "unknown" 46 | } 47 | -------------------------------------------------------------------------------- /metrics/metrics.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/prometheus/client_golang/prometheus" 7 | "github.com/prometheus/client_golang/prometheus/promauto" 8 | ) 9 | 10 | var ( 11 | jobs = promauto.NewHistogramVec(prometheus.HistogramOpts{ 12 | Namespace: "chainquery", 13 | Subsystem: "jobs", 14 | Name: "duration", 15 | Help: "The durations of the individual job processing", 16 | }, []string{"job"}) 17 | 18 | // JobLoad metric for number of active calls by job 19 | JobLoad = promauto.NewGaugeVec(prometheus.GaugeOpts{ 20 | Namespace: "chainquery", 21 | Subsystem: "jobs", 22 | Name: "job_load", 23 | Help: "Number of active calls by job", 24 | }, []string{"job"}) 25 | 26 | // Notifications metric for total sent notifications by type 27 | Notifications = promauto.NewCounterVec(prometheus.CounterOpts{ 28 | Namespace: "chainquery", 29 | Subsystem: "notifications", 30 | Name: "total_sent", 31 | Help: "sent notifications by type", 32 | }, []string{"type"}) 33 | 34 | // ProcessingFailures metric for processing failure count by type 35 | ProcessingFailures = promauto.NewCounterVec(prometheus.CounterOpts{ 36 | Namespace: "chainquery", 37 | Subsystem: "processing", 38 | Name: "failures", 39 | Help: "processing failure count by type", 40 | }, []string{"type"}) 41 | 42 | processing = promauto.NewHistogramVec(prometheus.HistogramOpts{ 43 | Namespace: "chainquery", 44 | Subsystem: "processing", 45 | Name: "duration", 46 | Help: "The durations of the individual processing by type", 47 | }, []string{"type"}) 48 | 49 | // SocketyNotifications metric for processing failure count by type 50 | SocketyNotifications = promauto.NewCounterVec(prometheus.CounterOpts{ 51 | Namespace: "chainquery", 52 | Subsystem: "sockety", 53 | Name: "notifications", 54 | Help: "counter for sending sockety notifications as the blockchain sourcex", 55 | }, []string{"type", "category", "subcategory"}) 56 | ) 57 | 58 | //Job helper function to make tracking metric one line deferral 59 | func Job(start time.Time, name string) { 60 | duration := time.Since(start).Seconds() 61 | jobs.WithLabelValues(name).Observe(duration) 62 | } 63 | 64 | //Processing helper function to make tracking metric one line deferral 65 | func Processing(start time.Time, name string) { 66 | duration := time.Since(start).Seconds() 67 | processing.WithLabelValues(name).Observe(duration) 68 | } 69 | -------------------------------------------------------------------------------- /migration/001_supports.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE output ADD COLUMN `claim_id` CHAR(40) CHARACTER SET latin1 COLLATE latin1_general_ci; 5 | -- +migrate StatementEnd 6 | 7 | -- +migrate StatementBegin 8 | ALTER TABLE output ADD FOREIGN KEY `fk_claim` (`claim_id`) REFERENCES `claim` (`claim_id`) ON DELETE CASCADE ON UPDATE NO ACTION; 9 | -- +migrate StatementEnd 10 | 11 | -- +migrate StatementBegin 12 | ALTER TABLE support ADD COLUMN `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; 13 | -- +migrate StatementEnd 14 | 15 | -- +migrate StatementBegin 16 | ALTER TABLE support ADD COLUMN `modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; 17 | -- +migrate StatementEnd 18 | 19 | -- +migrate StatementBegin 20 | CREATE TABLE IF NOT EXISTS `job_status` 21 | ( 22 | `job_name` VARCHAR(40) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, 23 | `last_sync` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', 24 | `is_success` TINYINT(1) DEFAULT 0 NOT NULL, 25 | `error_message` TEXT, 26 | 27 | PRIMARY KEY `pk_jobstatus` (`job_name`) 28 | 29 | )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; 30 | -- +migrate StatementEnd 31 | -------------------------------------------------------------------------------- /migration/002_decimals.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE claim CHANGE COLUMN `effective_amount` `effective_amount` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 ; 3 | ALTER TABLE claim CHANGE COLUMN `fee` `fee` DOUBLE(58,8) NOT NULL DEFAULT '0.00000000' ; 4 | 5 | -------------------------------------------------------------------------------- /migration/003_dht_tracking.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | CREATE TABLE IF NOT EXISTS `claim_checkpoint` 4 | ( 5 | `id` SERIAL, 6 | `claim_id` CHAR(40) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, 7 | `checkpoint` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 8 | `is_available` TINYINT(1) NOT NULL, 9 | `head_available` TINYINT(1) NOT NULL, 10 | `s_d_available` TINYINT(1) NOT NULL, 11 | 12 | PRIMARY KEY `pk_claim_checkpoint` (`id`), 13 | INDEX `idx_claim_id` (`claim_id`), 14 | INDEX `idx_checkpoint` (`checkpoint`), 15 | INDEX `idx_is_available` (`is_available`) 16 | ); 17 | -- +migrate StatementEnd 18 | 19 | -- +migrate StatementBegin 20 | CREATE TABLE IF NOT EXISTS `peer` 21 | ( 22 | `node_id` CHAR(100) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, 23 | `known_i_p_list` TEXT CHARACTER SET latin1 COLLATE latin1_general_ci, 24 | 25 | PRIMARY KEY `pk_id` (`node_id`), 26 | CONSTRAINT `cnt_known_i_p_list` CHECK(`known_i_p_list` IS NULL OR JSON_VALID(`known_i_p_list`)) 27 | ); 28 | -- +migrate StatementEnd 29 | 30 | -- +migrate StatementBegin 31 | CREATE TABLE IF NOT EXISTS `peer_claim` 32 | ( 33 | `peer_id` CHAR(100) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, 34 | `claim_id` CHAR(40) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, 35 | `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 36 | `last_seen` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 37 | 38 | PRIMARY KEY `pk_peer_claim` (`peer_id`,`claim_id`), 39 | INDEX `idx_claim_id` (`claim_id`), 40 | INDEX `idx_created` (`created`), 41 | INDEX `idx_last_seen` (`last_seen`) 42 | 43 | ); 44 | -- +migrate StatementEnd 45 | 46 | -- +migrate StatementBegin 47 | CREATE TABLE IF NOT EXISTS `peer_claim_checkpoint` 48 | ( 49 | `id` SERIAL, 50 | `peer_id` CHAR(100) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, 51 | `claim_id` CHAR(40) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, 52 | `checkpoint` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 53 | `is_available` TINYINT(1) NOT NULL, 54 | 55 | PRIMARY KEY `pk_peer_claim_checkpoint` (`id`), 56 | INDEX `idx_peer_id` (`peer_id`), 57 | INDEX `idx_claim_id` (`claim_id`), 58 | INDEX `idx_checkpoint` (`checkpoint`), 59 | INDEX `idx_is_available` (`is_available`) 60 | 61 | ); 62 | -- +migrate StatementEnd 63 | 64 | 65 | -------------------------------------------------------------------------------- /migration/004_new_indices.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE `output` ADD INDEX `Idx_IsSpent` (`is_spent` ASC); 5 | -- +migrate StatementEnd 6 | 7 | -- +migrate StatementBegin 8 | ALTER TABLE `claim` ADD INDEX `Idx_FeeAddress` (`fee_address` ASC); 9 | -- +migrate StatementEnd 10 | 11 | -- +migrate StatementBegin 12 | ALTER TABLE `output` ADD INDEX `Idx_SpentOutput` (`transaction_hash` ASC, `vout` ASC, `is_spent` ASC) COMMENT 'used for grabbing spent outputs with joins'; 13 | -- +migrate StatementEnd 14 | 15 | -- +migrate StatementBegin 16 | ALTER TABLE `claim` ADD INDEX `Idx_ClaimOutpoint` (`transaction_by_hash_id` ASC, `vout` ASC) COMMENT 'used for match claim to output with joins'; 17 | -- +migrate StatementEnd 18 | 19 | -- +migrate StatementBegin 20 | ALTER TABLE `claim` ADD COLUMN `claim_address` VARCHAR(40) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL DEFAULT ''; 21 | -- +migrate StatementEnd 22 | 23 | -- +migrate StatementBegin 24 | ALTER TABLE `claim` ADD INDEX `Idx_ClaimAddress` (`claim_address`); 25 | -- +migrate StatementEnd 26 | -------------------------------------------------------------------------------- /migration/005_remove_foreign_keys.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim 5 | DROP FOREIGN KEY claim_ibfk_2; 6 | -- +migrate StatementEnd 7 | 8 | -- +migrate StatementBegin 9 | ALTER TABLE input 10 | DROP FOREIGN KEY input_ibfk_1; 11 | -- +migrate StatementEnd 12 | 13 | -- +migrate StatementBegin 14 | ALTER TABLE support 15 | DROP FOREIGN KEY support_ibfk_1, 16 | CHANGE COLUMN transaction_hash transaction_hash_id VARCHAR(70) CHARACTER SET 'latin1' COLLATE 'latin1_general_ci' NULL DEFAULT NULL, 17 | ADD CONSTRAINT fk_transaction 18 | FOREIGN KEY (transaction_hash_id) 19 | REFERENCES transaction (hash) 20 | ON DELETE CASCADE 21 | ON UPDATE NO ACTION; 22 | -- +migrate StatementEnd 23 | 24 | -- +migrate StatementBegin 25 | ALTER TABLE output 26 | DROP FOREIGN KEY output_ibfk_3, 27 | DROP FOREIGN KEY output_ibfk_2; 28 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/006_add_height_index.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE `claim` ADD INDEX `Idx_Height` (`height` ASC); 5 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/007_more_decimals.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE block CHANGE COLUMN difficulty difficulty DOUBLE(50,8) NOT NULL ; -------------------------------------------------------------------------------- /migration/008_schema_fix.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | DROP TABLE peer_claim_checkpoint; 5 | -- +migrate StatementEnd 6 | 7 | -- +migrate StatementBegin 8 | DROP TABLE claim_checkpoint; 9 | -- +migrate StatementEnd 10 | 11 | -- +migrate StatementBegin 12 | DROP TABLE peer_claim; 13 | -- +migrate StatementEnd 14 | 15 | -- +migrate StatementBegin 16 | DROP TABLE peer; 17 | -- +migrate StatementEnd 18 | 19 | -- +migrate StatementBegin 20 | DROP TABLE input_address; 21 | -- +migrate StatementEnd 22 | 23 | -- +migrate StatementBegin 24 | DROP TABLE output_address; 25 | -- +migrate StatementEnd 26 | 27 | -- +migrate StatementBegin 28 | ALTER TABLE address 29 | DROP COLUMN tag, 30 | DROP COLUMN tag_url, 31 | CHANGE COLUMN created created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 32 | CHANGE COLUMN modified modified_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; 33 | -- +migrate StatementEnd 34 | 35 | -- +migrate StatementBegin 36 | ALTER TABLE output 37 | DROP COLUMN hash160, 38 | CHANGE COLUMN created created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 39 | CHANGE COLUMN modified modified_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; 40 | -- +migrate StatementEnd 41 | 42 | -- +migrate StatementBegin 43 | ALTER TABLE transaction 44 | DROP COLUMN value, 45 | CHANGE COLUMN created created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 46 | CHANGE COLUMN modified modified_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; 47 | -- +migrate StatementEnd 48 | 49 | -- +migrate StatementBegin 50 | ALTER TABLE transaction_address 51 | DROP COLUMN latest_transaction_time; 52 | -- +migrate StatementEnd 53 | 54 | -- +migrate StatementBegin 55 | ALTER TABLE block 56 | DROP COLUMN median_time, 57 | DROP COLUMN target, 58 | CHANGE COLUMN created created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 59 | CHANGE COLUMN modified modified_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; 60 | -- +migrate StatementEnd 61 | 62 | -- +migrate StatementBegin 63 | ALTER TABLE unknown_claim 64 | RENAME TO abnormal_claim, 65 | ADD COLUMN created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 66 | ADD COLUMN modified_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; 67 | -- +migrate StatementEnd 68 | 69 | -- +migrate StatementBegin 70 | ALTER TABLE claim 71 | DROP FOREIGN KEY claim_ibfk_1; 72 | -- +migrate StatementEnd 73 | 74 | -- +migrate StatementBegin 75 | ALTER TABLE claim 76 | CHANGE COLUMN transaction_by_hash_id transaction_hash_id VARCHAR(70) CHARACTER SET 'latin1' COLLATE 'latin1_general_ci' NULL DEFAULT NULL , 77 | CHANGE COLUMN is_n_s_f_w is_nsfw TINYINT(1) NOT NULL DEFAULT '0' , 78 | CHANGE COLUMN created created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 79 | CHANGE COLUMN modified modified_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; 80 | -- +migrate StatementEnd 81 | 82 | -- +migrate StatementBegin 83 | ALTER TABLE claim 84 | ADD CONSTRAINT claim_ibfk_1 85 | FOREIGN KEY (transaction_hash_id) 86 | REFERENCES transaction (hash) 87 | ON DELETE CASCADE 88 | ON UPDATE NO ACTION; 89 | -- +migrate StatementEnd 90 | 91 | -- +migrate StatementBegin 92 | ALTER TABLE transaction 93 | DROP FOREIGN KEY transaction_ibfk_1; 94 | -- +migrate StatementEnd 95 | 96 | -- +migrate StatementBegin 97 | ALTER TABLE transaction 98 | CHANGE COLUMN block_by_hash_id block_hash_id VARCHAR(70) CHARACTER SET 'latin1' COLLATE 'latin1_general_ci' NULL DEFAULT NULL ; 99 | -- +migrate StatementEnd 100 | 101 | -- +migrate StatementBegin 102 | ALTER TABLE transaction 103 | ADD CONSTRAINT transaction_ibfk_1 104 | FOREIGN KEY (block_hash_id) 105 | REFERENCES block (hash) 106 | ON DELETE CASCADE 107 | ON UPDATE NO ACTION; 108 | -- +migrate StatementEnd 109 | 110 | -- +migrate StatementBegin 111 | ALTER TABLE support 112 | CHANGE COLUMN created created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 113 | CHANGE COLUMN modified modified_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; 114 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/009_certificate_validation.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim 5 | ADD COLUMN is_cert_valid TINYINT(1) NOT NULL, 6 | ADD COLUMN is_cert_processed TINYINT(1) NOT NULL; 7 | -- +migrate StatementEnd 8 | 9 | -- +migrate StatementBegin 10 | ALTER TABLE claim 11 | ADD INDEX idx_cert_valid (is_cert_valid), 12 | ADD INDEX idx_cert_processed (is_cert_processed); 13 | -- +migrate StatementEnd 14 | 15 | -- +migrate StatementBegin 16 | UPDATE claim 17 | LEFT JOIN claim channel ON channel.claim_id = claim.publisher_id 18 | SET claim.is_cert_processed = TRUE 19 | WHERE channel.id IS NULL 20 | AND claim.is_cert_processed = FALSE 21 | -- +migrate StatementEnd 22 | -------------------------------------------------------------------------------- /migration/010_triggers.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | ALTER TABLE address ADD COLUMN balance DOUBLE(58,8) NOT NULL DEFAULT '0.00000000' ; 4 | -- +migrate StatementEnd 5 | 6 | -- +migrate StatementBegin 7 | ALTER TABLE transaction ADD COLUMN value DOUBLE(58,8) NOT NULL DEFAULT '0.00000000' ; 8 | -- +migrate StatementEnd 9 | 10 | -- +migrate StatementBegin 11 | CREATE TRIGGER tg_insert_value AFTER INSERT ON transaction_address 12 | FOR EACH ROW 13 | UPDATE transaction 14 | SET transaction.value = transaction.value + NEW.credit_amount 15 | WHERE transaction.id = NEW.transaction_id; 16 | -- +migrate StatementEnd 17 | 18 | -- +migrate StatementBegin 19 | CREATE TRIGGER tg_update_value AFTER UPDATE ON transaction_address 20 | FOR EACH ROW 21 | UPDATE transaction 22 | SET transaction.value = transaction.value - OLD.credit_amount + NEW.credit_amount 23 | WHERE transaction.id = NEW.transaction_id; 24 | -- +migrate StatementEnd 25 | 26 | -- +migrate StatementBegin 27 | CREATE TRIGGER tg_insert_balance AFTER INSERT ON transaction_address 28 | FOR EACH ROW 29 | UPDATE address 30 | SET address.balance = address.balance + (NEW.credit_amount - NEW.debit_amount) 31 | WHERE address.id = NEW.address_id; 32 | -- +migrate StatementEnd 33 | 34 | -- +migrate StatementBegin 35 | CREATE TRIGGER tg_update_balance AFTER UPDATE ON transaction_address 36 | FOR EACH ROW 37 | UPDATE address 38 | SET address.balance = address.balance - (OLD.credit_amount - OLD.debit_amount) + (NEW.credit_amount - NEW.debit_amount) 39 | WHERE address.id = NEW.address_id; 40 | -- +migrate StatementEnd 41 | 42 | -- +migrate StatementBegin 43 | CREATE TRIGGER tg_delete_balance AFTER DELETE ON transaction_address 44 | FOR EACH ROW 45 | UPDATE address 46 | SET address.balance = address.balance - (OLD.credit_amount - OLD.debit_amount) 47 | WHERE address.id = OLD.address_id; 48 | -- +migrate StatementEnd 49 | 50 | -- +migrate StatementBegin 51 | ALTER TABLE address ADD INDEX (balance); 52 | -- +migrate StatementEnd 53 | 54 | -- +migrate StatementBegin 55 | ALTER TABLE transaction ADD INDEX (value); 56 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/011_add_license.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim 5 | ADD COLUMN license NVARCHAR(255), 6 | ADD COLUMN license_url NVARCHAR(255), 7 | ADD COLUMN preview NVARCHAR(255); 8 | -- +migrate StatementEnd 9 | 10 | -- +migrate StatementBegin 11 | ALTER TABLE claim 12 | ADD INDEX Idx_License (license), 13 | ADD INDEX Idx_LicenseURL (license_url), 14 | ADD INDEX Idx_Preview (preview); 15 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/012_store_last_height.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE job_status ADD COLUMN state JSON; 5 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/013_add_input_vin.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE input ADD COLUMN vin INTEGER UNSIGNED; 5 | -- +migrate StatementEnd 6 | 7 | -- +migrate StatementBegin 8 | ALTER TABLE input CHANGE COLUMN coinbase coinbase VARCHAR(255) CHARACTER SET 'latin1' COLLATE 'latin1_general_ci' NULL DEFAULT NULL; 9 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/015_adjust_column_sizes.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE `tag` 5 | CHANGE COLUMN `tag` `tag` VARCHAR(500) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' NOT NULL; 6 | -- +migrate StatementEnd 7 | 8 | -- +migrate StatementBegin 9 | ALTER TABLE address CHANGE COLUMN address address VARCHAR(50) CHARACTER SET latin1 COLLATE latin1_general_ci UNIQUE NOT NULL; 10 | -- +migrate StatementEnd 11 | 12 | -- +migrate StatementBegin 13 | ALTER TABLE `input` ADD COLUMN `witness` TEXT; 14 | -- +migrate StatementEnd 15 | 16 | -------------------------------------------------------------------------------- /migration/016_transaction_hashes_adjustment.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE `block` 5 | CHANGE COLUMN `transaction_hashes` `transaction_hashes` MEDIUMTEXT; 6 | -- +migrate StatementEnd 7 | 8 | -- +migrate StatementBegin 9 | ALTER TABLE claim 10 | DROP INDEX Idx_License; 11 | -- +migrate StatementEnd 12 | 13 | -- +migrate StatementBegin 14 | ALTER TABLE `claim` 15 | CHANGE COLUMN `license` `license` TEXT; 16 | -- +migrate StatementEnd 17 | -------------------------------------------------------------------------------- /migration/017_claim_owner.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim 5 | ADD COLUMN transaction_hash_update VARCHAR(70), 6 | ADD COLUMN vout_update INT(10) UNSIGNED; 7 | -- +migrate StatementEnd 8 | 9 | -- +migrate StatementBegin 10 | ALTER TABLE claim 11 | ADD INDEX (transaction_hash_update,vout_update); 12 | -- +migrate StatementEnd 13 | 14 | -- +migrate StatementBegin 15 | UPDATE claim SET transaction_hash_update = transaction_hash_id, vout_update = vout; 16 | -- +migrate StatementEnd 17 | 18 | -------------------------------------------------------------------------------- /migration/018_cert_sync_index.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE input 5 | ADD INDEX Idx_TxHashVin (transaction_hash ASC, vin ASC); 6 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/019_raw_tx.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE transaction 5 | CHANGE COLUMN raw raw MEDIUMTEXT NULL DEFAULT NULL; 6 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/020_content_type.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim CHANGE content_type content_type VARCHAR(162) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL; 5 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/021_claim_reference.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim CHANGE COLUMN claim_reference claim_reference CHAR(40) CHARACTER SET 'latin1' COLLATE 'latin1_general_ci' NULL DEFAULT NULL ; 5 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/022_align_claim_id.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim_in_list 5 | DROP FOREIGN KEY claim_in_list_ibfk_1; 6 | -- +migrate StatementEnd 7 | 8 | -- +migrate StatementBegin 9 | ALTER TABLE claim_tag 10 | DROP FOREIGN KEY claim_tag_ibfk_1; 11 | -- +migrate StatementEnd 12 | 13 | -- +migrate StatementBegin 14 | ALTER TABLE claim 15 | CHANGE COLUMN claim_id claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' NOT NULL, 16 | CHANGE COLUMN claim_reference claim_reference VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' DEFAULT NULL; 17 | -- +migrate StatementEnd 18 | 19 | -- +migrate StatementBegin 20 | ALTER TABLE claim_in_list 21 | CHANGE COLUMN claim_id claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' DEFAULT NULL, 22 | CHANGE COLUMN list_claim_id list_claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' NOT NULL; 23 | -- +migrate StatementEnd 24 | 25 | -- +migrate StatementBegin 26 | ALTER TABLE claim_tag 27 | CHANGE COLUMN claim_id claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' NOT NULL; 28 | -- +migrate StatementEnd 29 | 30 | -- +migrate StatementBegin 31 | ALTER TABLE claim_tag 32 | ADD CONSTRAINT claim_tag_ibfk_1 33 | FOREIGN KEY (claim_id) 34 | REFERENCES claim (claim_id) 35 | ON DELETE CASCADE 36 | ON UPDATE NO ACTION; 37 | -- +migrate StatementEnd 38 | 39 | -- +migrate StatementBegin 40 | ALTER TABLE claim_in_list 41 | ADD CONSTRAINT claim_in_list_ibfk_1 42 | FOREIGN KEY (list_claim_id) 43 | REFERENCES claim (claim_id) 44 | ON DELETE CASCADE 45 | ON UPDATE NO ACTION; 46 | -- +migrate StatementEnd 47 | 48 | -- +migrate StatementBegin 49 | ALTER TABLE output 50 | CHANGE COLUMN claim_id claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' DEFAULT NULL; 51 | -- +migrate StatementEnd 52 | 53 | -- +migrate StatementBegin 54 | ALTER TABLE support 55 | CHANGE COLUMN supported_claim_id supported_claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' NOT NULL; 56 | -- +migrate StatementEnd 57 | 58 | -- +migrate StatementBegin 59 | ALTER TABLE abnormal_claim 60 | CHANGE COLUMN claim_id claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' NOT NULL; 61 | -- +migrate StatementEnd 62 | -------------------------------------------------------------------------------- /migration/023_sdhash_index.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim ADD INDEX (sd_hash ASC); 5 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/024_claims_in_channel.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | ALTER TABLE claim ADD COLUMN claim_count BIGINT NOT NULL DEFAULT 0; 4 | -- +migrate StatementEnd 5 | 6 | -- +migrate StatementBegin 7 | ALTER TABLE claim ADD INDEX (claim_count); 8 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/025_outputindices.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE output 5 | ADD INDEX Idx_ModifedSpentTxHash (modified_at ASC, is_spent ASC, transaction_hash ASC); 6 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/026_purchases.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | CREATE TABLE purchase 5 | ( 6 | id SERIAL, 7 | transaction_by_hash_id VARCHAR(70) CHARACTER SET latin1 COLLATE latin1_general_ci, 8 | vout INTEGER UNSIGNED NOT NULL, 9 | claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci', 10 | publisher_id CHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci', 11 | height INTEGER UNSIGNED NOT NULL, 12 | amount_satoshi BIGINT DEFAULT 0 NOT NULL, 13 | 14 | created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 15 | modified DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 16 | 17 | PRIMARY KEY PK_Purchase (id), 18 | FOREIGN KEY FK_PurchaseTransaction (transaction_by_hash_id) REFERENCES transaction (hash) ON DELETE CASCADE ON UPDATE NO ACTION, 19 | UNIQUE KEY Idx_PurchaseUnique (transaction_by_hash_id, vout, claim_id), 20 | INDEX Idx_PurchaseClaim (claim_id), 21 | INDEX Idx_PurchaseAmount (amount_satoshi), 22 | INDEX Idx_PurchaseCreated (created), 23 | INDEX Idx_PurchaseModified (modified) 24 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; 25 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/027_signed_supports.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE support ADD COLUMN supported_by_claim_id VARCHAR(40) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' DEFAULT NULL; 5 | -- +migrate StatementEnd 6 | 7 | -- +migrate StatementBegin 8 | ALTER TABLE support ADD INDEX idx_supported_by (supported_by_claim_id); 9 | -- +migrate StatementEnd 10 | -------------------------------------------------------------------------------- /migration/028_liscense_url.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | ALTER TABLE claim CHANGE COLUMN license_url license_url VARCHAR(255) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL; 5 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/029_support_index.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | CREATE INDEX idx_support_modified_at ON support (modified_at); 5 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/030_json_field.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | -- +migrate StatementBegin 4 | alter table claim modify value_as_json JSON null; 5 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/031_drop_unused_columns.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | alter table claim drop column website_url; 4 | -- +migrate StatementEnd 5 | -- +migrate StatementBegin 6 | alter table claim drop column country; 7 | -- +migrate StatementEnd 8 | -- +migrate StatementBegin 9 | alter table claim drop column state; 10 | -- +migrate StatementEnd 11 | -- +migrate StatementBegin 12 | alter table claim drop column city; 13 | -- +migrate StatementEnd 14 | -- +migrate StatementBegin 15 | alter table claim drop column `code`; 16 | -- +migrate StatementEnd 17 | -- +migrate StatementBegin 18 | alter table claim drop column latitude; 19 | -- +migrate StatementEnd 20 | -- +migrate StatementBegin 21 | alter table claim drop column longitude; 22 | -- +migrate StatementEnd 23 | -- +migrate StatementBegin 24 | alter table claim drop column license_url; 25 | -- +migrate StatementEnd 26 | -- +migrate StatementBegin 27 | alter table claim drop column preview; 28 | -- +migrate StatementEnd 29 | -- +migrate StatementBegin 30 | alter table claim drop column os; 31 | -- +migrate StatementEnd 32 | -- +migrate StatementBegin 33 | alter table claim modify fee_address varchar(40) collate latin1_general_ci null; 34 | -- +migrate StatementEnd 35 | -- +migrate StatementBegin 36 | update claim set fee_address = null where fee_address = ''; 37 | -- +migrate StatementEnd 38 | -- +migrate StatementBegin 39 | alter table claim modify version varchar(10) collate latin1_general_ci null; 40 | -- +migrate StatementEnd 41 | -- +migrate StatementBegin 42 | update claim set version = null where version = ''; 43 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/032_drop_block_txhashes.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | alter table block drop column transaction_hashes; 4 | -- +migrate StatementEnd 5 | -- +migrate StatementBegin 6 | alter table block drop column transactions_processed; 7 | -- +migrate StatementEnd 8 | -------------------------------------------------------------------------------- /migration/032_drop_transaction_cols.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | alter table transaction drop column fee; 4 | -- +migrate StatementEnd 5 | -- +migrate StatementBegin 6 | alter table transaction drop column raw; 7 | -- +migrate StatementEnd 8 | -- +migrate StatementBegin 9 | drop trigger tg_insert_value; 10 | -- +migrate StatementEnd 11 | -- +migrate StatementBegin 12 | drop trigger tg_update_value; 13 | -- +migrate StatementEnd 14 | -- +migrate StatementBegin 15 | drop trigger tg_insert_balance; 16 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /migration/033_vin_vout_changes.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | alter table input drop column prevout_spend_updated; 4 | -- +migrate StatementEnd 5 | -------------------------------------------------------------------------------- /migration/034_support_uniq_index.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | drop index Idx_outpoint on support; 4 | -- +migrate StatementEnd 5 | 6 | -- +migrate StatementBegin 7 | create unique index Idx_uniq_outpoint on support (transaction_hash_id, vout); 8 | -- +migrate StatementEnd 9 | -------------------------------------------------------------------------------- /migration/035_add_tx_count.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | -- +migrate StatementBegin 3 | alter table block add tx_count int not null after version_hex; 4 | -- +migrate StatementEnd -------------------------------------------------------------------------------- /model/boil_queries.go: -------------------------------------------------------------------------------- 1 | // Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. 2 | // This file is meant to be re-generated in place and/or deleted at any time. 3 | 4 | package model 5 | 6 | import ( 7 | "regexp" 8 | 9 | "github.com/volatiletech/sqlboiler/v4/drivers" 10 | "github.com/volatiletech/sqlboiler/v4/queries" 11 | "github.com/volatiletech/sqlboiler/v4/queries/qm" 12 | ) 13 | 14 | var dialect = drivers.Dialect{ 15 | LQ: 0x60, 16 | RQ: 0x60, 17 | 18 | UseIndexPlaceholders: false, 19 | UseLastInsertID: true, 20 | UseSchema: false, 21 | UseDefaultKeyword: false, 22 | UseAutoColumns: false, 23 | UseTopClause: false, 24 | UseOutputClause: false, 25 | UseCaseWhenExistsClause: false, 26 | } 27 | 28 | // This is a dummy variable to prevent unused regexp import error 29 | var _ = ®exp.Regexp{} 30 | 31 | // NewQuery initializes a new Query using the passed in QueryMods 32 | func NewQuery(mods ...qm.QueryMod) *queries.Query { 33 | q := &queries.Query{} 34 | queries.SetDialect(q, &dialect) 35 | qm.Apply(q, mods...) 36 | 37 | return q 38 | } 39 | -------------------------------------------------------------------------------- /model/boil_table_names.go: -------------------------------------------------------------------------------- 1 | // Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. 2 | // This file is meant to be re-generated in place and/or deleted at any time. 3 | 4 | package model 5 | 6 | var TableNames = struct { 7 | AbnormalClaim string 8 | Address string 9 | ApplicationStatus string 10 | Block string 11 | Claim string 12 | ClaimInList string 13 | ClaimTag string 14 | Input string 15 | JobStatus string 16 | Output string 17 | Purchase string 18 | Support string 19 | Tag string 20 | Transaction string 21 | TransactionAddress string 22 | }{ 23 | AbnormalClaim: "abnormal_claim", 24 | Address: "address", 25 | ApplicationStatus: "application_status", 26 | Block: "block", 27 | Claim: "claim", 28 | ClaimInList: "claim_in_list", 29 | ClaimTag: "claim_tag", 30 | Input: "input", 31 | JobStatus: "job_status", 32 | Output: "output", 33 | Purchase: "purchase", 34 | Support: "support", 35 | Tag: "tag", 36 | Transaction: "transaction", 37 | TransactionAddress: "transaction_address", 38 | } 39 | -------------------------------------------------------------------------------- /model/boil_types.go: -------------------------------------------------------------------------------- 1 | // Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. 2 | // This file is meant to be re-generated in place and/or deleted at any time. 3 | 4 | package model 5 | 6 | import ( 7 | "strconv" 8 | 9 | "github.com/friendsofgo/errors" 10 | "github.com/volatiletech/sqlboiler/v4/boil" 11 | "github.com/volatiletech/strmangle" 12 | ) 13 | 14 | // M type is for providing columns and column values to UpdateAll. 15 | type M map[string]interface{} 16 | 17 | // ErrSyncFail occurs during insert when the record could not be retrieved in 18 | // order to populate default value information. This usually happens when LastInsertId 19 | // fails or there was a primary key configuration that was not resolvable. 20 | var ErrSyncFail = errors.New("model: failed to synchronize data after insert") 21 | 22 | type insertCache struct { 23 | query string 24 | retQuery string 25 | valueMapping []uint64 26 | retMapping []uint64 27 | } 28 | 29 | type updateCache struct { 30 | query string 31 | valueMapping []uint64 32 | } 33 | 34 | func makeCacheKey(cols boil.Columns, nzDefaults []string) string { 35 | buf := strmangle.GetBuffer() 36 | 37 | buf.WriteString(strconv.Itoa(cols.Kind)) 38 | for _, w := range cols.Cols { 39 | buf.WriteString(w) 40 | } 41 | 42 | if len(nzDefaults) != 0 { 43 | buf.WriteByte('.') 44 | } 45 | for _, nz := range nzDefaults { 46 | buf.WriteString(nz) 47 | } 48 | 49 | str := buf.String() 50 | strmangle.PutBuffer(buf) 51 | return str 52 | } 53 | -------------------------------------------------------------------------------- /model/boil_view_names.go: -------------------------------------------------------------------------------- 1 | // Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. 2 | // This file is meant to be re-generated in place and/or deleted at any time. 3 | 4 | package model 5 | 6 | var ViewNames = struct { 7 | }{} 8 | -------------------------------------------------------------------------------- /model/mysql_upsert.go: -------------------------------------------------------------------------------- 1 | // Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. 2 | // This file is meant to be re-generated in place and/or deleted at any time. 3 | 4 | package model 5 | 6 | import ( 7 | "fmt" 8 | "strings" 9 | 10 | "github.com/volatiletech/sqlboiler/v4/drivers" 11 | "github.com/volatiletech/strmangle" 12 | ) 13 | 14 | // buildUpsertQueryMySQL builds a SQL statement string using the upsertData provided. 15 | func buildUpsertQueryMySQL(dia drivers.Dialect, tableName string, update, whitelist []string) string { 16 | whitelist = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, whitelist) 17 | tableName = strmangle.IdentQuote(dia.LQ, dia.RQ, tableName) 18 | 19 | buf := strmangle.GetBuffer() 20 | defer strmangle.PutBuffer(buf) 21 | 22 | var columns string 23 | if len(whitelist) != 0 { 24 | columns = strings.Join(whitelist, ",") 25 | } 26 | 27 | if len(update) == 0 { 28 | fmt.Fprintf( 29 | buf, 30 | "INSERT IGNORE INTO %s (%s) VALUES (%s)", 31 | tableName, 32 | columns, 33 | strmangle.Placeholders(dia.UseIndexPlaceholders, len(whitelist), 1, 1), 34 | ) 35 | return buf.String() 36 | } 37 | 38 | fmt.Fprintf( 39 | buf, 40 | "INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE ", 41 | tableName, 42 | columns, 43 | strmangle.Placeholders(dia.UseIndexPlaceholders, len(whitelist), 1, 1), 44 | ) 45 | 46 | for i, v := range update { 47 | if i != 0 { 48 | buf.WriteByte(',') 49 | } 50 | quoted := strmangle.IdentQuote(dia.LQ, dia.RQ, v) 51 | buf.WriteString(quoted) 52 | buf.WriteString(" = VALUES(") 53 | buf.WriteString(quoted) 54 | buf.WriteByte(')') 55 | } 56 | 57 | return buf.String() 58 | } 59 | -------------------------------------------------------------------------------- /notifications/events.go: -------------------------------------------------------------------------------- 1 | package notifications 2 | 3 | import ( 4 | "net/url" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/lbryio/chainquery/model" 9 | "github.com/lbryio/chainquery/sockety" 10 | 11 | "github.com/lbryio/lbry.go/v2/extras/jsonrpc" 12 | c "github.com/lbryio/lbry.go/v2/schema/stake" 13 | 14 | "github.com/OdyseeTeam/sockety/socketyapi" 15 | log "github.com/sirupsen/logrus" 16 | "github.com/spf13/cast" 17 | "github.com/volatiletech/sqlboiler/v4/queries/qm" 18 | ) 19 | 20 | const payment = "payment" 21 | const newClaim = "new_claim" 22 | 23 | // PaymentEvent event to notify subscribers of a payment transaction 24 | func PaymentEvent(lbc float64, address, txid string, vout uint) { 25 | values := url.Values{} 26 | values.Add("lbc", cast.ToString(lbc)) 27 | values.Add("tx_id", txid) 28 | values.Add("vout", cast.ToString(vout)) 29 | values.Add("address", address) 30 | go Notify(payment, values) 31 | go sockety.SendNotification(socketyapi.SendNotificationArgs{ 32 | Service: socketyapi.BlockChain, 33 | Type: "payments", 34 | IDs: []string{"payments", address, strconv.Itoa(int(lbc * 0.001))}, 35 | Data: map[string]interface{}{"lbc": lbc, "address": address, "txid": txid, "vout": vout}, 36 | }) 37 | } 38 | 39 | // ClaimEvent event to notify subscribers of a new claim that's been published 40 | func ClaimEvent(claim *model.Claim, tx model.Transaction, claimData *c.StakeHelper) { 41 | values := url.Values{} 42 | values.Add("claim_id", claim.ClaimID) 43 | values.Add("name", claim.Name) 44 | if !claim.Type.IsZero() { 45 | values.Add("type", claim.Type.String) 46 | } 47 | if claim.Title.IsZero() || claim.Title.String == "" { 48 | return //we can't use claims without a title 49 | } 50 | values.Add("title", claim.Title.String) 51 | if !claim.Description.IsZero() { 52 | values.Add("description", claim.Description.String) 53 | } 54 | if !claim.ThumbnailURL.IsZero() { 55 | values.Add("thumbnail_url", claim.ThumbnailURL.String) 56 | } 57 | if !claim.ReleaseTime.IsZero() { 58 | values.Add("release_time", strconv.Itoa(int(claim.ReleaseTime.Uint64))) 59 | } 60 | if !claim.SDHash.IsZero() { 61 | values.Add("sd_hash", claim.SDHash.String) 62 | } 63 | values.Add("tx_id", tx.Hash) 64 | if !claim.SourceHash.IsZero() { 65 | values.Add("source", claim.SourceHash.String) 66 | } 67 | if !claim.PublisherID.IsZero() { 68 | values.Add("channel_claim_id", claim.PublisherID.String) 69 | } 70 | 71 | isProtected := false 72 | isUnlisted := false 73 | for _, t := range claimData.Claim.GetTags() { 74 | if strings.Contains(t, string(jsonrpc.ProtectedContentTag)) { 75 | isProtected = true 76 | } 77 | if strings.Contains(t, string(jsonrpc.UnlistedContentTag)) { 78 | isUnlisted = true 79 | } 80 | } 81 | values.Add("is_protected", strconv.FormatBool(isProtected)) 82 | 83 | if claim.ClaimType != 2 && !claim.PublisherID.IsZero() { 84 | signingChannel, err := model.Claims(qm.Where("claim_id=?", claim.PublisherID.String)).OneG() 85 | if err != nil { 86 | log.Errorf("failed to get signing channel for claim %s: %v", claim.ClaimID, err) 87 | } 88 | if signingChannel != nil { 89 | values.Add("channel_name", signingChannel.Name) 90 | if !signingChannel.ThumbnailURL.IsZero() { 91 | values.Add("channel_thumbnail_url", signingChannel.ThumbnailURL.String) 92 | } 93 | } 94 | } 95 | //skip unlisted claims from being broadcast 96 | if isUnlisted { 97 | return 98 | } 99 | go Notify(newClaim, values) 100 | } 101 | -------------------------------------------------------------------------------- /notifications/notifications.go: -------------------------------------------------------------------------------- 1 | package notifications 2 | 3 | import ( 4 | "net/http" 5 | "net/url" 6 | 7 | "github.com/lbryio/chainquery/metrics" 8 | 9 | "github.com/lbryio/lbry.go/v2/extras/errors" 10 | 11 | "github.com/sirupsen/logrus" 12 | "golang.org/x/net/context" 13 | "golang.org/x/sync/semaphore" 14 | ) 15 | 16 | type subscriber struct { 17 | URL string 18 | Type string 19 | Params url.Values 20 | } 21 | 22 | var subscriptions map[string][]subscriber 23 | 24 | // AddSubscriber adds a subscriber to the subscribers list for a type 25 | func AddSubscriber(address, subType string, params map[string]interface{}) { 26 | if subscriptions == nil { 27 | subscriptions = make(map[string][]subscriber) 28 | } 29 | urlParams := url.Values{} 30 | for param, v := range params { 31 | value, ok := v.(string) 32 | if ok { 33 | urlParams.Set(param, value) 34 | } 35 | } 36 | subscriptions[subType] = append(subscriptions[subType], subscriber{URL: address, Type: subType, Params: urlParams}) 37 | } 38 | 39 | // ClearSubscribers clears the list of subscribers 40 | func ClearSubscribers() { 41 | subscriptions = make(map[string][]subscriber) 42 | } 43 | 44 | var notificationSem = semaphore.NewWeighted(20) 45 | 46 | // Notify notifies the list of subscribers for a type 47 | func Notify(t string, values url.Values) { 48 | err := notificationSem.Acquire(context.Background(), 1) 49 | if err != nil { 50 | logrus.Error(errors.Prefix("Notify", errors.Err(err))) 51 | return 52 | } 53 | defer notificationSem.Release(1) 54 | subs, ok := subscriptions[t] 55 | if ok { 56 | for _, s := range subs { 57 | for param, value := range s.Params { 58 | values.Set(param, value[0]) 59 | } 60 | s.notify(values) 61 | metrics.Notifications.WithLabelValues(t).Inc() 62 | } 63 | } 64 | } 65 | 66 | func (s subscriber) notify(values url.Values) { 67 | res, err := http.PostForm(s.URL, values) 68 | if err != nil { 69 | logrus.Error(errors.Prefix("Notify", errors.Err(err))) 70 | return 71 | } 72 | defer func() { 73 | err = res.Body.Close() 74 | if err != nil { 75 | logrus.Error(errors.Prefix("Notify", errors.Err(err))) 76 | } 77 | }() 78 | //b, err := io.ReadAll(res.Body) 79 | //if err != nil { 80 | // logrus.Error(errors.Prefix("Notify", errors.Err(err))) 81 | //} 82 | //if res.StatusCode != http.StatusOK { 83 | // logrus.Errorln(string(b)) 84 | //} 85 | } 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swagger-docs", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "engines": { 6 | "node": ">= 0.8.x" 7 | }, 8 | "dependencies": { 9 | "express": "3.x" 10 | }, 11 | "license": "Unlicense" 12 | } 13 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | cd "$DIR" 7 | cd ".." 8 | DIR="$PWD" 9 | 10 | 11 | echo "== Installing dependencies ==" 12 | go install golang.org/x/tools/cmd/goimports@latest 13 | go install github.com/kevinburke/go-bindata/v4/...@latest 14 | go mod download 15 | 16 | 17 | echo "== Checking dependencies ==" 18 | go mod verify 19 | set -e 20 | 21 | echo "== Compiling ==" 22 | export IMPORTPATH="github.com/lbryio/chainquery" 23 | mkdir -p "$DIR/bin" 24 | go generate -v 25 | export VERSIONSHORT="${TRAVIS_COMMIT:-"$(git describe --tags --always --dirty)"}" 26 | export VERSIONLONG="${TRAVIS_COMMIT:-"$(git describe --tags --always --dirty --long)"}" 27 | export COMMITMSG="$(echo ${TRAVIS_COMMIT_MESSAGE:-"$(git show -s --format=%s)"} | tr -d '"' | head -n 1)" 28 | CGO_ENABLED=0 go build -v -o "./bin/chainquery" -asmflags -trimpath="$DIR" -ldflags "-X ${IMPORTPATH}/meta.version=${VERSIONSHORT} -X ${IMPORTPATH}/meta.versionLong=${VERSIONLONG} -X \"${IMPORTPATH}/meta.commitMsg=${COMMITMSG}\"" 29 | 30 | echo "== Done building linux version $("$DIR/bin/chainquery" version) ==" 31 | echo "$(git describe --tags --always --dirty)" > ./bin/chainquery.txt 32 | chmod +x ./bin/chainquery 33 | exit 0 -------------------------------------------------------------------------------- /scripts/coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Generate test coverage statistics for Go packages. 3 | # 4 | # Works around the fact that `go test -coverprofile` currently does not work 5 | # with multiple packages, see https://code.google.com/p/go/issues/detail?id=6909 6 | # 7 | # Usage: script/coverage [--html|--coveralls] 8 | # 9 | # --html Additionally create HTML report and open it in browser 10 | # --coveralls Push coverage statistics to coveralls.io 11 | # 12 | 13 | set -e 14 | 15 | workdir=.cover 16 | profile="$workdir/cover.out" 17 | mode=count 18 | 19 | generate_cover_data() { 20 | rm -rf "$workdir" 21 | mkdir "$workdir" 22 | 23 | for pkg in "$@"; do 24 | f="$workdir/$(echo $pkg | tr / -).cover" 25 | go test -covermode="$mode" -coverprofile="$f" "$pkg" 26 | done 27 | 28 | echo "mode: $mode" >"$profile" 29 | grep -h -v "^mode:" "$workdir"/*.cover >>"$profile" 30 | } 31 | 32 | show_cover_report() { 33 | go tool cover -${1}="$profile" 34 | } 35 | 36 | push_to_coveralls() { 37 | echo "Pushing coverage statistics to coveralls.io" 38 | goveralls -repotoken tqwwNhoVNm2NbYb48Gro69rMc6wPRbKpi -coverprofile="$profile" 39 | } 40 | 41 | generate_cover_data $(go list ./... | grep -v /vendor/ | grep -v /model | grep -v /swagger/ | grep -v /migration ) 42 | push_to_coveralls -------------------------------------------------------------------------------- /scripts/cron_update_master.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This can be used to auto update your (linux) chainquery instance, keeping it up to date with the master branch. 4 | # Minor changes might be required for the script. The assumption is that the script is run in a tmux session and checks 5 | # a text file for changes. Whenever we push a new commit to master the text file is updated with the commit hash in 6 | # the AWS bucket. This script checks if the last copy downloaded with the binary is different. If so it will download 7 | # the latest master branch binary and restart the chainquery service. 8 | 9 | while true 10 | do 11 | 12 | wget --quiet -O chainquery.txt "http://s3.amazonaws.com/build.lbry.io/chainquery/branch-master/chainquery.txt" 13 | if ! cmp "./chainquery.txt" "./current.txt" 14 | then 15 | echo "bucket changed...downloading and deploying" 16 | wget -O chainquery.tmp "http://s3.amazonaws.com/build.lbry.io/chainquery/branch-master/chainquery" 17 | mv chainquery.tmp chainquery 18 | sudo chmod 755 chainquery 19 | sudo service chainquery restart 20 | cp "./chainquery.txt" "./current.txt" 21 | fi 22 | 23 | sleep 10 24 | done 25 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export IMPORTPATH="github.com/lbryio/chainquery" 4 | export VERSIONSHORT="${TRAVIS_COMMIT:-"$(git describe --tags --always --dirty)"}" 5 | export VERSIONLONG="${TRAVIS_COMMIT:-"$(git describe --tags --always --dirty --long)"}" 6 | export COMMITMSG="$(echo ${TRAVIS_COMMIT_MESSAGE:-"$(git show -s --format=%s)"} | tr -d '"' | head -n 1)" 7 | curl -sL https://git.io/goreleaser | bash -------------------------------------------------------------------------------- /scripts/gen_apis.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ( 3 | #download swagger-codegen-cli if not already there. 4 | cd "$PWD" 5 | mkdir -p $PWD/swagger 6 | if [ ! -f $PWD/swagger/swagger-codegen-cli.jar ]; then 7 | echo "swagger cli not found, downloading..." 8 | wget https://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/2.4.27/swagger-codegen-cli-2.4.27.jar -O ./swagger/swagger-codegen-cli.jar 9 | fi 10 | #Generate API docs 11 | 12 | executable="$PWD/swagger/swagger-codegen-cli.jar" 13 | 14 | export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" 15 | agsDocs="$@ generate -i $PWD/swagger/chainquery.yaml -l dynamic-html -o $PWD" 16 | agsServer="$@ generate -i $PWD/swagger/chainquery.yaml -l go-server -t $PWD/swagger/modules/go-server -Dmodel={} -o $PWD/swagger/apiserver" 17 | agsClient_go="$@ generate -i $PWD/swagger/chainquery.yaml -l go -o $PWD/swagger/clients/goclient" 18 | agsClient_python="$@ generate -i $PWD/swagger/chainquery.yaml -l python -o $PWD/swagger/clients/pythonclient" 19 | 20 | 21 | java $JAVA_OPTS -jar $executable $agsDocs 22 | 23 | java $JAVA_OPTS -jar $executable $agsServer 24 | 25 | java $JAVA_OPTS -jar $executable $agsClient_go 26 | java $JAVA_OPTS -jar $executable $agsClient_python 27 | 28 | ) -------------------------------------------------------------------------------- /scripts/gen_models.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | cd "$DIR" 5 | cd ".." 6 | DIR="$PWD" 7 | ( 8 | cd "$DIR" 9 | go install github.com/volatiletech/sqlboiler/v4@v4.16.2 10 | go install github.com/volatiletech/sqlboiler/v4/drivers/sqlboiler-mysql@v4.16.2 11 | sqlboiler --no-rows-affected --no-auto-timestamps --no-hooks --no-tests --no-context --add-global-variants --add-panic-variants --wipe mysql 12 | ) -------------------------------------------------------------------------------- /scripts/lint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | err=0 4 | trap 'err=1' ERR 5 | # All the .go files, excluding vendor/ and model (auto generated) 6 | GO_FILES=$(find . -iname '*.go' -type f | grep -v /vendor/ | grep -v /model/ | grep -v /swagger/ | grep -v /migration/) 7 | ( 8 | GO111MODULE=off 9 | go get -u golang.org/x/tools/cmd/goimports # Used in build script for generated files 10 | go get -u golang.org/x/lint/golint # Linter 11 | go get -u github.com/jgautheron/gocyclo # Check against high complexity 12 | go get -u github.com/mdempsky/unconvert # Identifies unnecessary type conversions 13 | go get -u github.com/kisielk/errcheck # Checks for unhandled errors 14 | go get -u github.com/opennota/check/cmd/varcheck # Checks for unused vars 15 | go get -u github.com/opennota/check/cmd/structcheck # Checks for unused fields in structs 16 | ) 17 | echo "Running varcheck..." && varcheck $(go list ./... | grep -v /vendor/ | grep -v /model | grep -v /swagger/ | grep -v /migration ) 18 | echo "Running structcheck..." && structcheck $(go list ./... | grep -v /vendor/ | grep -v /model | grep -v /migration ) 19 | # go vet is the official Go static analyzer 20 | echo "Running go vet..." && go vet $(go list ./... | grep -v /vendor/ | grep -v /model | grep -v /swagger/ | grep -v /migration ) 21 | # checks for unhandled errors 22 | echo "Running errcheck..." && errcheck $(go list ./... | grep -v /vendor/ | grep -v /model | grep -v /swagger/ | grep -v /migration ) 23 | # check for unnecessary conversions - ignore autogen code 24 | echo "Running unconvert..." && unconvert -v $(go list ./... | grep -v /vendor/ | grep -v /model | grep -v /swagger/ | grep -v /migration ) 25 | # checks for function complexity, too big or too many returns 26 | echo "Running gocyclo..." && gocyclo -ignore "_test" -avg -over 19 $GO_FILES 27 | 28 | ######## COMMENTED BELOW UNTIL THEY ARE ALL FIXED ######## 29 | # forbid code with huge functions 30 | # "go vet on steroids" + linter - ignore autogen code 31 | # one last linter - ignore autogen code 32 | echo "Running golint..." && golint -set_exit_status $(go list ./... | grep -v /vendor/ | grep -v /model/ | grep -v /swagger/ | grep -v /migration ) 33 | test $err = 0 # Return non-zero if any command failed -------------------------------------------------------------------------------- /scripts/regtest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo 'lbrycrdurl="rpc://lbry:lbry@localhost:11337"' > ~/chainqueryconfig.toml 4 | docker pull tiger5226/regtest 5 | curl https://raw.githubusercontent.com/lbryio/lbry-docker/regtest/lbrycrd/regtest/docker-compose.yml > ~/docker-compose.yml 6 | docker-compose up -d 7 | docker ps 8 | #alias lbrycrd-cli="docker-compose exec lbrycrd lbrycrd-cli -conf=/data/.lbrycrd/lbrycrd.conf" 9 | docker-compose exec lbrycrd lbrycrd-cli -conf=/data/.lbrycrd/lbrycrd.conf generate 101 10 | 11 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | go install github.com/caarlos0/svu@latest 4 | git tag `svu "$1"` 5 | git push --tags -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | go test -race ./daemon/... # Run all daemon package tests ... 4 | go test -race ./lbrycrd/... # Run all lbrycrd package tests ... 5 | go test -race ./db/... # Run all db package tests ... 6 | go test -race ./datastore/... # Run all datastore package tests ... 7 | go test -race ./daemon/jobs/... # Run all jobs package tests ... 8 | go test -race ./daemon/processing/... # Run all processing package tests ... -------------------------------------------------------------------------------- /sockety/sockety.go: -------------------------------------------------------------------------------- 1 | package sockety 2 | 3 | import ( 4 | "github.com/lbryio/chainquery/metrics" 5 | 6 | "github.com/lbryio/lbry.go/v2/extras/errors" 7 | 8 | "github.com/OdyseeTeam/sockety/socketyapi" 9 | "github.com/sirupsen/logrus" 10 | "github.com/volatiletech/null/v8" 11 | ) 12 | 13 | // Token token used to sent notifications to sockety 14 | var Token string 15 | 16 | // URL is the url to connect to an instance of sockety. 17 | var URL string 18 | 19 | var socketyClient *socketyapi.Client 20 | 21 | // SendNotification sends the notification to socket using client 22 | func SendNotification(args socketyapi.SendNotificationArgs) { 23 | if Token == "" || URL == "" { 24 | return 25 | } 26 | defer catchPanic() 27 | if socketyClient == nil { 28 | logrus.Debug("initializating sockety client") 29 | socketyClient = socketyapi.NewClient(URL, Token) 30 | } 31 | _, err := socketyClient.SendNotification(args) 32 | if err != nil { 33 | logrus.Error(errors.Prefix("Socket Send Notification", err)) 34 | } 35 | metrics.SocketyNotifications.WithLabelValues(args.Type, null.StringFromPtr(args.Category).String, null.StringFromPtr(args.SubCategory).String).Inc() 36 | } 37 | 38 | func catchPanic() { 39 | if r := recover(); r != nil { 40 | logrus.Error("sockety send recovered from: ", r) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sqlboiler.toml: -------------------------------------------------------------------------------- 1 | # this file is used for generating the models, not for connecting to the db 2 | # so username/password are the local dev login, not the production login 3 | 4 | pkgname="model" 5 | output="model" 6 | [mysql] 7 | blacklist=["gorp_migrations"] 8 | dbname="chainquery" 9 | host="localhost" 10 | port=3306 11 | user="chainquery" 12 | pass="chainquery" 13 | sslmode="false" -------------------------------------------------------------------------------- /swagger/apiserver/.swagger-codegen-ignore: -------------------------------------------------------------------------------- 1 | # Swagger Codegen Ignore 2 | # Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /swagger/apiserver/.swagger-codegen/VERSION: -------------------------------------------------------------------------------- 1 | unset -------------------------------------------------------------------------------- /swagger/apiserver/go/README.md: -------------------------------------------------------------------------------- 1 | # Go API Server for swagger 2 | 3 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 4 | 5 | ## Overview 6 | This server was generated by the [swagger-codegen] 7 | (https://github.com/swagger-api/swagger-codegen) project. 8 | By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. 9 | - 10 | 11 | To see how to make this your own, look here: 12 | 13 | [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) 14 | 15 | - API version: 0.1.0 16 | - Build date: 2018-05-06T02:15:07.364-04:00 17 | 18 | 19 | ### Running the server 20 | To run the server, follow these simple steps: 21 | 22 | ``` 23 | go run main.go 24 | ``` -------------------------------------------------------------------------------- /swagger/apiserver/go/address_summary.go: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Chain Query 4 | * 5 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 6 | * 7 | * API version: 0.1.0 8 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 9 | */ 10 | package swagger 11 | 12 | type AddressSummary struct { 13 | 14 | Address string `json:"Address,omitempty"` 15 | 16 | // Total amount received by address from all transactions it was a part of. 17 | TotalReceived float64 `json:"TotalReceived,omitempty"` 18 | 19 | // Total amount sent from address for all transactions it was a part of. 20 | TotalSent float64 `json:"TotalSent,omitempty"` 21 | 22 | // The current balance of an address 23 | Balance float64 `json:"Balance,omitempty"` 24 | } -------------------------------------------------------------------------------- /swagger/apiserver/go/logger.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | package swagger 10 | 11 | import ( 12 | "log" 13 | "net/http" 14 | "time" 15 | ) 16 | 17 | func Logger(inner http.Handler, name string) http.Handler { 18 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 19 | start := time.Now() 20 | 21 | inner.ServeHTTP(w, r) 22 | 23 | log.Printf( 24 | "%s %s %s %s", 25 | r.Method, 26 | r.RequestURI, 27 | name, 28 | time.Since(start), 29 | ) 30 | }) 31 | } -------------------------------------------------------------------------------- /swagger/apiserver/go/query_api.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | package swagger 10 | 11 | //Not using swagger for controller-api. These files have been added to the project git ignore. 12 | -------------------------------------------------------------------------------- /swagger/apiserver/go/routers.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | package swagger 10 | 11 | import ( 12 | "net/http" 13 | "strings" 14 | 15 | . "github.com/lbryio/chainquery/apiactions" 16 | . "github.com/lbryio/lbry.go/v2/extras/api" 17 | 18 | "github.com/gorilla/mux" 19 | "github.com/prometheus/client_golang/prometheus/promhttp" 20 | ) 21 | 22 | type Route struct { 23 | Name string 24 | Method string 25 | Pattern string 26 | HandlerFunc Handler 27 | } 28 | 29 | type Routes []Route 30 | 31 | func NewRouter() *mux.Router { 32 | router := mux.NewRouter().StrictSlash(true) 33 | for _, route := range routes { 34 | var handler http.Handler 35 | handler = route.HandlerFunc 36 | handler = Logger(handler, route.Name) 37 | 38 | router. 39 | Methods(route.Method). 40 | Path(route.Pattern). 41 | Name(route.Name). 42 | Handler(handler) 43 | } 44 | 45 | router.Handle("/metrics", promBasicAuthWrapper(promhttp.Handler())) 46 | 47 | return router 48 | } 49 | 50 | var routes = Routes{ 51 | Route{ 52 | "Index", 53 | "GET", 54 | "/api/", 55 | IndexAction, 56 | }, 57 | 58 | Route{ 59 | "AutoUpdate", 60 | strings.ToUpper("Post"), 61 | "/api/autoupdate", 62 | AutoUpdateAction, 63 | }, 64 | 65 | Route{ 66 | "SQLQuery", 67 | strings.ToUpper("Get"), 68 | "/api/sql", 69 | SQLQueryAction, 70 | }, 71 | 72 | Route{ 73 | "AddressSummary", 74 | strings.ToUpper("Get"), 75 | "/api/addresssummary", 76 | AddressSummaryAction, 77 | }, 78 | 79 | Route{ 80 | "ChainQueryStatus", 81 | strings.ToUpper("Get"), 82 | "/api/status", 83 | ChainQueryStatusAction, 84 | }, 85 | 86 | Route{ 87 | "ValidateChain", 88 | strings.ToUpper("Get"), 89 | "/api/validate", 90 | ValidateChainData, 91 | }, 92 | 93 | Route{ 94 | "ProcessBlocks", 95 | strings.ToUpper("Get"), 96 | "/api/process", 97 | ProcessBlocks, 98 | }, 99 | 100 | Route{ 101 | "SyncAddressBalance", 102 | strings.ToUpper("Get"), 103 | "/api/sync/addresses", 104 | SyncAddressBalance, 105 | }, 106 | 107 | Route{ 108 | "SyncClaimName", 109 | strings.ToUpper("Get"), 110 | "/api/sync/name", 111 | SyncName, 112 | }, 113 | 114 | Route{ 115 | "SyncTransactionValue", 116 | strings.ToUpper("Get"), 117 | "/api/sync/txvalues", 118 | SyncTransactionValue, 119 | }, 120 | } 121 | 122 | var PromPassword string 123 | var PromUser string 124 | 125 | func promBasicAuthWrapper(h http.Handler) http.Handler { 126 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 127 | user, pass, ok := r.BasicAuth() 128 | if !ok { 129 | http.Error(w, "authentication required", http.StatusBadRequest) 130 | return 131 | } 132 | if PromUser == "" { 133 | http.Error(w, "not configured", http.StatusPreconditionFailed) 134 | } else { 135 | if user == PromUser && pass == PromPassword { 136 | h.ServeHTTP(w, r) 137 | } else { 138 | http.Error(w, "invalid username or password", http.StatusForbidden) 139 | } 140 | } 141 | }) 142 | } 143 | -------------------------------------------------------------------------------- /swagger/apiserver/go/stat_api.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | package swagger 10 | 11 | //Not using swagger for controller-api. These files have been added to the project git ignore. 12 | -------------------------------------------------------------------------------- /swagger/apiserver/go/table_size.go: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Chain Query 4 | * 5 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 6 | * 7 | * API version: 0.1.0 8 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 9 | */ 10 | package swagger 11 | 12 | // Contains the name and number of rows for a table. 13 | type TableSize struct { 14 | 15 | // Name of the table being referenced. 16 | TableName string `json:"TableName,omitempty"` 17 | 18 | // The number of rows in the referenced table 19 | NrRows int64 `json:"NrRows,omitempty"` 20 | } -------------------------------------------------------------------------------- /swagger/apiserver/go/table_status.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | package swagger 10 | 11 | // Contains an array of tables and their row count. 12 | type TableStatus struct { 13 | Status []TableSize `json:"TableStatus,omitempty"` 14 | } 15 | -------------------------------------------------------------------------------- /swagger/apiserver/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | package swagger 10 | 11 | import ( 12 | "net/http" 13 | "strconv" 14 | 15 | "github.com/lbryio/chainquery/config" 16 | "github.com/lbryio/chainquery/db" 17 | sw "github.com/lbryio/chainquery/swagger/apiserver/go" 18 | "github.com/lbryio/lbry.go/v2/extras/api" 19 | 20 | "github.com/fatih/color" 21 | "github.com/sirupsen/logrus" 22 | ) 23 | 24 | func InitApiServer(hostAndPort string) { 25 | logrus.Info("API Server started") 26 | hs := make(map[string]string) 27 | hs["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS" 28 | hs["Content-Type"] = "application/json; charset=utf-8; application/x-www-form-urlencoded" 29 | hs["X-Content-Type-Options"] = "nosniff" 30 | hs["Content-Security-Policy"] = "default-src 'none'" 31 | hs["Server"] = "chainquery-server" 32 | hs["Access-Control-Allow-Origin"] = "*" 33 | api.ResponseHeaders = hs 34 | api.Log = func(request *http.Request, response *api.Response, err error) { 35 | if response.Status >= http.StatusInternalServerError { 36 | logrus.Error(err) 37 | } 38 | if err != nil { 39 | logrus.Debug("Error: ", err) 40 | } 41 | consoleText := request.RemoteAddr + " [" + strconv.Itoa(response.Status) + "]: " + request.Method + " " + request.URL.Path 42 | logrus.Debug(color.GreenString(consoleText)) 43 | 44 | } 45 | //API Chainquery DB connection 46 | chainqueryInstance, err := db.InitAPIQuery(config.GetAPIMySQLDSN(), false) 47 | if err != nil { 48 | logrus.Panic("unable to connect to chainquery database instance for API Server: ", err) 49 | } 50 | defer db.CloseDB(chainqueryInstance) 51 | router := sw.NewRouter() 52 | 53 | logrus.Fatal(http.ListenAndServe(hostAndPort, router)) 54 | } 55 | -------------------------------------------------------------------------------- /swagger/clients/goclient/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /swagger/clients/goclient/.swagger-codegen-ignore: -------------------------------------------------------------------------------- 1 | # Swagger Codegen Ignore 2 | # Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /swagger/clients/goclient/.swagger-codegen/VERSION: -------------------------------------------------------------------------------- 1 | unset -------------------------------------------------------------------------------- /swagger/clients/goclient/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | install: 4 | - go get -d -v . 5 | 6 | script: 7 | - go build -v ./ 8 | 9 | -------------------------------------------------------------------------------- /swagger/clients/goclient/README.md: -------------------------------------------------------------------------------- 1 | # Go API client for swagger 2 | 3 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 4 | 5 | ## Overview 6 | This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. 7 | 8 | - API version: 0.1.0 9 | - Package version: 1.0.0 10 | - Build package: io.swagger.codegen.languages.GoClientCodegen 11 | 12 | ## Installation 13 | Put the package under your project folder and add the following in import: 14 | ``` 15 | "./swagger" 16 | ``` 17 | 18 | ## Documentation for API Endpoints 19 | 20 | All URIs are relative to *http://0.0.0.0:6300/api* 21 | 22 | Class | Method | HTTP request | Description 23 | ------------ | ------------- | ------------- | ------------- 24 | *DefaultApi* | [**AutoUpdate**](docs/DefaultApi.md#autoupdate) | **Post** /autoupdate | auto updates the application with the latest release based on TravisCI webhook 25 | *QueryApi* | [**SQLQuery**](docs/QueryApi.md#sqlquery) | **Get** /sql | Use SQL in a RESTful way 26 | *StatApi* | [**AddressSummary**](docs/StatApi.md#addresssummary) | **Get** /addresssummary | Returns a summary of Address activity 27 | *StatApi* | [**ChainQueryStatus**](docs/StatApi.md#chainquerystatus) | **Get** /status | Returns important status information about Chain Query 28 | 29 | 30 | ## Documentation For Models 31 | 32 | - [AddressSummary](docs/AddressSummary.md) 33 | - [TableSize](docs/TableSize.md) 34 | - [TableStatus](docs/TableStatus.md) 35 | 36 | 37 | ## Documentation For Authorization 38 | Endpoints do not require authorization. 39 | 40 | 41 | ## Author 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /swagger/clients/goclient/address_summary.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | 10 | package swagger 11 | 12 | type AddressSummary struct { 13 | 14 | Address string `json:"Address,omitempty"` 15 | 16 | // Total amount received by address from all transactions it was a part of. 17 | TotalReceived float64 `json:"TotalReceived,omitempty"` 18 | 19 | // Total amount sent from address for all transactions it was a part of. 20 | TotalSent float64 `json:"TotalSent,omitempty"` 21 | 22 | // The current balance of an address 23 | Balance float64 `json:"Balance,omitempty"` 24 | } 25 | -------------------------------------------------------------------------------- /swagger/clients/goclient/api_response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | 10 | package swagger 11 | 12 | import ( 13 | "net/http" 14 | ) 15 | 16 | type APIResponse struct { 17 | *http.Response `json:"-"` 18 | Message string `json:"message,omitempty"` 19 | // Operation is the name of the swagger operation. 20 | Operation string `json:"operation,omitempty"` 21 | // RequestURL is the request URL. This value is always available, even if the 22 | // embedded *http.Response is nil. 23 | RequestURL string `json:"url,omitempty"` 24 | // Method is the HTTP method used for the request. This value is always 25 | // available, even if the embedded *http.Response is nil. 26 | Method string `json:"method,omitempty"` 27 | // Payload holds the contents of the response body (which may be nil or empty). 28 | // This is provided here as the raw response.Body() reader will have already 29 | // been drained. 30 | Payload []byte `json:"-"` 31 | } 32 | 33 | func NewAPIResponse(r *http.Response) *APIResponse { 34 | 35 | response := &APIResponse{Response: r} 36 | return response 37 | } 38 | 39 | func NewAPIResponseWithError(errorMessage string) *APIResponse { 40 | 41 | response := &APIResponse{Message: errorMessage} 42 | return response 43 | } 44 | -------------------------------------------------------------------------------- /swagger/clients/goclient/configuration.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | 10 | package swagger 11 | 12 | import ( 13 | "net/http" 14 | ) 15 | 16 | // contextKeys are used to identify the type of value in the context. 17 | // Since these are string, it is possible to get a short description of the 18 | // context key for logging and debugging using key.String(). 19 | 20 | type contextKey string 21 | 22 | func (c contextKey) String() string { 23 | return "auth " + string(c) 24 | } 25 | 26 | var ( 27 | // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. 28 | ContextOAuth2 = contextKey("token") 29 | 30 | // ContextBasicAuth takes BasicAuth as authentication for the request. 31 | ContextBasicAuth = contextKey("basic") 32 | 33 | // ContextAccessToken takes a string oauth2 access token as authentication for the request. 34 | ContextAccessToken = contextKey("accesstoken") 35 | 36 | // ContextAPIKey takes an APIKey as authentication for the request 37 | ContextAPIKey = contextKey("apikey") 38 | ) 39 | 40 | // BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth 41 | type BasicAuth struct { 42 | UserName string `json:"userName,omitempty"` 43 | Password string `json:"password,omitempty"` 44 | } 45 | 46 | // APIKey provides API key based authentication to a request passed via context using ContextAPIKey 47 | type APIKey struct { 48 | Key string 49 | Prefix string 50 | } 51 | 52 | type Configuration struct { 53 | BasePath string `json:"basePath,omitempty"` 54 | Host string `json:"host,omitempty"` 55 | Scheme string `json:"scheme,omitempty"` 56 | DefaultHeader map[string]string `json:"defaultHeader,omitempty"` 57 | UserAgent string `json:"userAgent,omitempty"` 58 | HTTPClient *http.Client 59 | } 60 | 61 | func NewConfiguration() *Configuration { 62 | cfg := &Configuration{ 63 | BasePath: "http://0.0.0.0:6300/api", 64 | DefaultHeader: make(map[string]string), 65 | UserAgent: "Swagger-Codegen/1.0.0/go", 66 | } 67 | return cfg 68 | } 69 | 70 | func (c *Configuration) AddDefaultHeader(key string, value string) { 71 | c.DefaultHeader[key] = value 72 | } 73 | -------------------------------------------------------------------------------- /swagger/clients/goclient/default_api.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | 10 | package swagger 11 | 12 | import ( 13 | "golang.org/x/net/context" 14 | "io/ioutil" 15 | "net/http" 16 | "net/url" 17 | "strings" 18 | ) 19 | 20 | // Linger please 21 | var ( 22 | _ context.Context 23 | ) 24 | 25 | type DefaultApiService service 26 | 27 | /* DefaultApiService auto updates the application with the latest release based on TravisCI webhook 28 | takes a webhook as defined by https://docs.travis-ci.com/user/notifications/#Webhooks-Delivery-Format, validates the public key, chooses whether or not update the application. If so it shuts down the api, downloads the latest release from https://github.com/lbryio/chainquery/releases, replaces the binary and starts the api again. 29 | * @param ctx context.Context for authentication, logging, tracing, etc. 30 | @param payload 31 | @return */ 32 | func (a *DefaultApiService) AutoUpdate(ctx context.Context, payload interface{}) (*http.Response, error) { 33 | var ( 34 | localVarHttpMethod = strings.ToUpper("Post") 35 | localVarPostBody interface{} 36 | localVarFileName string 37 | localVarFileBytes []byte 38 | ) 39 | 40 | // create path and map variables 41 | localVarPath := a.client.cfg.BasePath + "/autoupdate" 42 | 43 | localVarHeaderParams := make(map[string]string) 44 | localVarQueryParams := url.Values{} 45 | localVarFormParams := url.Values{} 46 | 47 | // to determine the Content-Type header 48 | localVarHttpContentTypes := []string{"application/x-www-form-urlencoded"} 49 | 50 | // set Content-Type header 51 | localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) 52 | if localVarHttpContentType != "" { 53 | localVarHeaderParams["Content-Type"] = localVarHttpContentType 54 | } 55 | 56 | // to determine the Accept header 57 | localVarHttpHeaderAccepts := []string{ 58 | "application/json", 59 | } 60 | 61 | // set Accept header 62 | localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) 63 | if localVarHttpHeaderAccept != "" { 64 | localVarHeaderParams["Accept"] = localVarHttpHeaderAccept 65 | } 66 | // body params 67 | localVarPostBody = &payload 68 | r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | localVarHttpResponse, err := a.client.callAPI(r) 74 | if err != nil || localVarHttpResponse == nil { 75 | return localVarHttpResponse, err 76 | } 77 | defer localVarHttpResponse.Body.Close() 78 | if localVarHttpResponse.StatusCode >= 300 { 79 | bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) 80 | return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) 81 | } 82 | 83 | return localVarHttpResponse, err 84 | } 85 | -------------------------------------------------------------------------------- /swagger/clients/goclient/docs/AddressSummary.md: -------------------------------------------------------------------------------- 1 | # AddressSummary 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **Address** | **string** | | [optional] [default to null] 7 | **TotalReceived** | **float64** | Total amount received by address from all transactions it was a part of. | [optional] [default to 0.0] 8 | **TotalSent** | **float64** | Total amount sent from address for all transactions it was a part of. | [optional] [default to 0.0] 9 | **Balance** | **float64** | The current balance of an address | [optional] [default to 0.0] 10 | 11 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 12 | 13 | 14 | -------------------------------------------------------------------------------- /swagger/clients/goclient/docs/DefaultApi.md: -------------------------------------------------------------------------------- 1 | # \DefaultApi 2 | 3 | All URIs are relative to *http://0.0.0.0:6300/api* 4 | 5 | Method | HTTP request | Description 6 | ------------- | ------------- | ------------- 7 | [**AutoUpdate**](DefaultApi.md#AutoUpdate) | **Post** /autoupdate | auto updates the application with the latest release based on TravisCI webhook 8 | 9 | 10 | # **AutoUpdate** 11 | > AutoUpdate(ctx, payload) 12 | auto updates the application with the latest release based on TravisCI webhook 13 | 14 | takes a webhook as defined by https://docs.travis-ci.com/user/notifications/#Webhooks-Delivery-Format, validates the public key, chooses whether or not update the application. If so it shuts down the api, downloads the latest release from https://github.com/lbryio/chainquery/releases, replaces the binary and starts the api again. 15 | 16 | ### Required Parameters 17 | 18 | Name | Type | Description | Notes 19 | ------------- | ------------- | ------------- | ------------- 20 | **ctx** | **context.Context** | context for logging, tracing, authentication, etc. 21 | **payload** | [**interface{}**](interface{}.md)| | 22 | 23 | ### Return type 24 | 25 | (empty response body) 26 | 27 | ### Authorization 28 | 29 | No authorization required 30 | 31 | ### HTTP request headers 32 | 33 | - **Content-Type**: application/x-www-form-urlencoded 34 | - **Accept**: application/json 35 | 36 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 37 | 38 | -------------------------------------------------------------------------------- /swagger/clients/goclient/docs/QueryApi.md: -------------------------------------------------------------------------------- 1 | # \QueryApi 2 | 3 | All URIs are relative to *http://0.0.0.0:6300/api* 4 | 5 | Method | HTTP request | Description 6 | ------------- | ------------- | ------------- 7 | [**SQLQuery**](QueryApi.md#SQLQuery) | **Get** /sql | Use SQL in a RESTful way 8 | 9 | 10 | # **SQLQuery** 11 | > []interface{} SQLQuery(ctx, query, values) 12 | Use SQL in a RESTful way 13 | 14 | API exposed for sending SQL queries directly against the chainquery database. Since this is an exposed API there are limits to its use. These limits include queries per hour, read-only, limited to 60 second timeout. 15 | 16 | ### Required Parameters 17 | 18 | Name | Type | Description | Notes 19 | ------------- | ------------- | ------------- | ------------- 20 | **ctx** | **context.Context** | context for logging, tracing, authentication, etc. 21 | **query** | **string**| The SQL query to be put against the chainquery database. | 22 | **values** | [**[]string**](string.md)| when passing in a query use '?' for values which will be replaced in order of appearance with this array. | 23 | 24 | ### Return type 25 | 26 | [**[]interface{}**](interface{}.md) 27 | 28 | ### Authorization 29 | 30 | No authorization required 31 | 32 | ### HTTP request headers 33 | 34 | - **Content-Type**: application/json 35 | - **Accept**: application/json 36 | 37 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 38 | 39 | -------------------------------------------------------------------------------- /swagger/clients/goclient/docs/StatApi.md: -------------------------------------------------------------------------------- 1 | # \StatApi 2 | 3 | All URIs are relative to *http://0.0.0.0:6300/api* 4 | 5 | Method | HTTP request | Description 6 | ------------- | ------------- | ------------- 7 | [**AddressSummary**](StatApi.md#AddressSummary) | **Get** /addresssummary | Returns a summary of Address activity 8 | [**ChainQueryStatus**](StatApi.md#ChainQueryStatus) | **Get** /status | Returns important status information about Chain Query 9 | 10 | 11 | # **AddressSummary** 12 | > AddressSummary AddressSummary(ctx, lbryAddress) 13 | Returns a summary of Address activity 14 | 15 | It returns sent, recieved, balance, and number of transactions it has been used in. 16 | 17 | ### Required Parameters 18 | 19 | Name | Type | Description | Notes 20 | ------------- | ------------- | ------------- | ------------- 21 | **ctx** | **context.Context** | context for logging, tracing, authentication, etc. 22 | **lbryAddress** | **string**| A LbryAddress | 23 | 24 | ### Return type 25 | 26 | [**AddressSummary**](AddressSummary.md) 27 | 28 | ### Authorization 29 | 30 | No authorization required 31 | 32 | ### HTTP request headers 33 | 34 | - **Content-Type**: application/json 35 | - **Accept**: application/json 36 | 37 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 38 | 39 | # **ChainQueryStatus** 40 | > TableStatus ChainQueryStatus(ctx, ) 41 | Returns important status information about Chain Query 42 | 43 | ### Required Parameters 44 | This endpoint does not need any parameter. 45 | 46 | ### Return type 47 | 48 | [**TableStatus**](TableStatus.md) 49 | 50 | ### Authorization 51 | 52 | No authorization required 53 | 54 | ### HTTP request headers 55 | 56 | - **Content-Type**: application/json 57 | - **Accept**: application/json 58 | 59 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 60 | 61 | -------------------------------------------------------------------------------- /swagger/clients/goclient/docs/TableSize.md: -------------------------------------------------------------------------------- 1 | # TableSize 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **TableName** | **string** | Name of the table being referenced. | [optional] [default to null] 7 | **NrRows** | **int64** | The number of rows in the referenced table | [optional] [default to null] 8 | 9 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 10 | 11 | 12 | -------------------------------------------------------------------------------- /swagger/clients/goclient/docs/TableStatus.md: -------------------------------------------------------------------------------- 1 | # TableStatus 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **Status** | [**[]TableSize**](TableSize.md) | | [optional] [default to null] 7 | 8 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 9 | 10 | 11 | -------------------------------------------------------------------------------- /swagger/clients/goclient/git_push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ 3 | # 4 | # Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" 5 | 6 | git_user_id=$1 7 | git_repo_id=$2 8 | release_note=$3 9 | 10 | if [ "$git_user_id" = "" ]; then 11 | git_user_id="GIT_USER_ID" 12 | echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" 13 | fi 14 | 15 | if [ "$git_repo_id" = "" ]; then 16 | git_repo_id="GIT_REPO_ID" 17 | echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" 18 | fi 19 | 20 | if [ "$release_note" = "" ]; then 21 | release_note="Minor update" 22 | echo "[INFO] No command line input provided. Set \$release_note to $release_note" 23 | fi 24 | 25 | # Initialize the local directory as a Git repository 26 | git init 27 | 28 | # Adds the files in the local repository and stages them for commit. 29 | git add . 30 | 31 | # Commits the tracked changes and prepares them to be pushed to a remote repository. 32 | git commit -m "$release_note" 33 | 34 | # Sets the new remote 35 | git_remote=`git remote` 36 | if [ "$git_remote" = "" ]; then # git remote not defined 37 | 38 | if [ "$GIT_TOKEN" = "" ]; then 39 | echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." 40 | git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git 41 | else 42 | git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git 43 | fi 44 | 45 | fi 46 | 47 | git pull origin master 48 | 49 | # Pushes (Forces) the changes in the local repository up to the remote repository 50 | echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" 51 | git push origin master 2>&1 | grep -v 'To https' 52 | 53 | -------------------------------------------------------------------------------- /swagger/clients/goclient/query_api.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | 10 | package swagger 11 | 12 | import ( 13 | "encoding/json" 14 | "fmt" 15 | "golang.org/x/net/context" 16 | "io/ioutil" 17 | "net/http" 18 | "net/url" 19 | "strings" 20 | ) 21 | 22 | // Linger please 23 | var ( 24 | _ context.Context 25 | ) 26 | 27 | type QueryApiService service 28 | 29 | /* QueryApiService Use SQL in a RESTful way 30 | API exposed for sending SQL queries directly against the chainquery database. Since this is an exposed API there are limits to its use. These limits include queries per hour, read-only, limited to 60 second timeout. 31 | * @param ctx context.Context for authentication, logging, tracing, etc. 32 | @param query The SQL query to be put against the chainquery database. 33 | @param values when passing in a query use '?' for values which will be replaced in order of appearance with this array. 34 | @return []interface{}*/ 35 | func (a *QueryApiService) SQLQuery(ctx context.Context, query string, values []string) ([]interface{}, *http.Response, error) { 36 | var ( 37 | localVarHttpMethod = strings.ToUpper("Get") 38 | localVarPostBody interface{} 39 | localVarFileName string 40 | localVarFileBytes []byte 41 | successPayload []interface{} 42 | ) 43 | 44 | // create path and map variables 45 | localVarPath := a.client.cfg.BasePath + "/sql" 46 | localVarPath = strings.Replace(localVarPath, "{"+"query"+"}", fmt.Sprintf("%v", query), -1) 47 | localVarPath = strings.Replace(localVarPath, "{"+"values"+"}", fmt.Sprintf("%v", values), -1) 48 | 49 | localVarHeaderParams := make(map[string]string) 50 | localVarQueryParams := url.Values{} 51 | localVarFormParams := url.Values{} 52 | 53 | // to determine the Content-Type header 54 | localVarHttpContentTypes := []string{"application/json"} 55 | 56 | // set Content-Type header 57 | localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) 58 | if localVarHttpContentType != "" { 59 | localVarHeaderParams["Content-Type"] = localVarHttpContentType 60 | } 61 | 62 | // to determine the Accept header 63 | localVarHttpHeaderAccepts := []string{ 64 | "application/json", 65 | } 66 | 67 | // set Accept header 68 | localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) 69 | if localVarHttpHeaderAccept != "" { 70 | localVarHeaderParams["Accept"] = localVarHttpHeaderAccept 71 | } 72 | r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) 73 | if err != nil { 74 | return successPayload, nil, err 75 | } 76 | 77 | localVarHttpResponse, err := a.client.callAPI(r) 78 | if err != nil || localVarHttpResponse == nil { 79 | return successPayload, localVarHttpResponse, err 80 | } 81 | defer localVarHttpResponse.Body.Close() 82 | if localVarHttpResponse.StatusCode >= 300 { 83 | bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) 84 | return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) 85 | } 86 | 87 | if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { 88 | return successPayload, localVarHttpResponse, err 89 | } 90 | 91 | return successPayload, localVarHttpResponse, err 92 | } 93 | -------------------------------------------------------------------------------- /swagger/clients/goclient/table_size.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | 10 | package swagger 11 | 12 | // Contains the name and number of rows for a table. 13 | type TableSize struct { 14 | 15 | // Name of the table being referenced. 16 | TableName string `json:"TableName,omitempty"` 17 | 18 | // The number of rows in the referenced table 19 | NrRows int64 `json:"NrRows,omitempty"` 20 | } 21 | -------------------------------------------------------------------------------- /swagger/clients/goclient/table_status.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Chain Query 3 | * 4 | * The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 5 | * 6 | * API version: 0.1.0 7 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 8 | */ 9 | 10 | package swagger 11 | 12 | // Contains an array of tables and their row count. 13 | type ChainqueryStatus struct { 14 | TableStatus []TableSize `json:"TableStatus,omitempty"` 15 | SemVersion string 16 | VersionShort string 17 | VersionLong string 18 | CommitMessage string 19 | } 20 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | venv/ 48 | .python-version 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | 57 | # Sphinx documentation 58 | docs/_build/ 59 | 60 | # PyBuilder 61 | target/ 62 | 63 | #Ipython Notebook 64 | .ipynb_checkpoints 65 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/.swagger-codegen-ignore: -------------------------------------------------------------------------------- 1 | # Swagger Codegen Ignore 2 | # Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/.swagger-codegen/VERSION: -------------------------------------------------------------------------------- 1 | unset -------------------------------------------------------------------------------- /swagger/clients/pythonclient/.travis.yml: -------------------------------------------------------------------------------- 1 | # ref: https://docs.travis-ci.com/user/languages/python 2 | language: python 3 | python: 4 | - "2.7" 5 | - "3.2" 6 | - "3.3" 7 | - "3.4" 8 | - "3.5" 9 | #- "3.5-dev" # 3.5 development branch 10 | #- "nightly" # points to the latest development branch e.g. 3.6-dev 11 | # command to install dependencies 12 | install: "pip install -r requirements.txt" 13 | # command to run tests 14 | script: nosetests 15 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/README.md: -------------------------------------------------------------------------------- 1 | # swagger-client 2 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. 3 | 4 | This Python package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: 5 | 6 | - API version: 0.1.0 7 | - Package version: 1.0.0 8 | - Build package: io.swagger.codegen.languages.PythonClientCodegen 9 | 10 | ## Requirements. 11 | 12 | Python 2.7 and 3.4+ 13 | 14 | ## Installation & Usage 15 | ### pip install 16 | 17 | If the python package is hosted on Github, you can install directly from Github 18 | 19 | ```sh 20 | pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git 21 | ``` 22 | (you may need to run `pip` with root permission: `sudo pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git`) 23 | 24 | Then import the package: 25 | ```python 26 | import swagger_client 27 | ``` 28 | 29 | ### Setuptools 30 | 31 | Install via [Setuptools](http://pypi.python.org/pypi/setuptools). 32 | 33 | ```sh 34 | python setup.py install --user 35 | ``` 36 | (or `sudo python setup.py install` to install the package for all users) 37 | 38 | Then import the package: 39 | ```python 40 | import swagger_client 41 | ``` 42 | 43 | ## Getting Started 44 | 45 | Please follow the [installation procedure](#installation--usage) and then run the following: 46 | 47 | ```python 48 | from __future__ import print_function 49 | import time 50 | import swagger_client 51 | from swagger_client.rest import ApiException 52 | from pprint import pprint 53 | # create an instance of the API class 54 | api_instance = swagger_client.DefaultApi() 55 | payload = NULL # object | 56 | 57 | try: 58 | # auto updates the application with the latest release based on TravisCI webhook 59 | api_instance.auto_update(payload) 60 | except ApiException as e: 61 | print("Exception when calling DefaultApi->auto_update: %s\n" % e) 62 | 63 | ``` 64 | 65 | ## Documentation for API Endpoints 66 | 67 | All URIs are relative to *http://0.0.0.0:6300/api* 68 | 69 | Class | Method | HTTP request | Description 70 | ------------ | ------------- | ------------- | ------------- 71 | *DefaultApi* | [**auto_update**](docs/DefaultApi.md#auto_update) | **POST** /autoupdate | auto updates the application with the latest release based on TravisCI webhook 72 | *QueryApi* | [**s_ql_query**](docs/QueryApi.md#s_ql_query) | **GET** /sql | Use SQL in a RESTful way 73 | *StatApi* | [**address_summary**](docs/StatApi.md#address_summary) | **GET** /addresssummary | Returns a summary of Address activity 74 | *StatApi* | [**chain_query_status**](docs/StatApi.md#chain_query_status) | **GET** /status | Returns important status information about Chain Query 75 | 76 | 77 | ## Documentation For Models 78 | 79 | - [AddressSummary](docs/AddressSummary.md) 80 | - [TableSize](docs/TableSize.md) 81 | - [TableStatus](docs/TableStatus.md) 82 | 83 | 84 | ## Documentation For Authorization 85 | 86 | All endpoints do not require authorization. 87 | 88 | 89 | ## Author 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/docs/AddressSummary.md: -------------------------------------------------------------------------------- 1 | # AddressSummary 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **address** | **str** | | [optional] 7 | **total_received** | **float** | Total amount received by address from all transactions it was a part of. | [optional] [default to 0.0] 8 | **total_sent** | **float** | Total amount sent from address for all transactions it was a part of. | [optional] [default to 0.0] 9 | **balance** | **float** | The current balance of an address | [optional] [default to 0.0] 10 | 11 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 12 | 13 | 14 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/docs/DefaultApi.md: -------------------------------------------------------------------------------- 1 | # swagger_client.DefaultApi 2 | 3 | All URIs are relative to *http://0.0.0.0:6300/api* 4 | 5 | Method | HTTP request | Description 6 | ------------- | ------------- | ------------- 7 | [**auto_update**](DefaultApi.md#auto_update) | **POST** /autoupdate | auto updates the application with the latest release based on TravisCI webhook 8 | 9 | 10 | # **auto_update** 11 | > auto_update(payload) 12 | 13 | auto updates the application with the latest release based on TravisCI webhook 14 | 15 | takes a webhook as defined by https://docs.travis-ci.com/user/notifications/#Webhooks-Delivery-Format, validates the public key, chooses whether or not update the application. If so it shuts down the api, downloads the latest release from https://github.com/lbryio/chainquery/releases, replaces the binary and starts the api again. 16 | 17 | ### Example 18 | ```python 19 | from __future__ import print_function 20 | import time 21 | import swagger_client 22 | from swagger_client.rest import ApiException 23 | from pprint import pprint 24 | 25 | # create an instance of the API class 26 | api_instance = swagger_client.DefaultApi() 27 | payload = NULL # object | 28 | 29 | try: 30 | # auto updates the application with the latest release based on TravisCI webhook 31 | api_instance.auto_update(payload) 32 | except ApiException as e: 33 | print("Exception when calling DefaultApi->auto_update: %s\n" % e) 34 | ``` 35 | 36 | ### Parameters 37 | 38 | Name | Type | Description | Notes 39 | ------------- | ------------- | ------------- | ------------- 40 | **payload** | **object**| | 41 | 42 | ### Return type 43 | 44 | void (empty response body) 45 | 46 | ### Authorization 47 | 48 | No authorization required 49 | 50 | ### HTTP request headers 51 | 52 | - **Content-Type**: application/x-www-form-urlencoded 53 | - **Accept**: application/json 54 | 55 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 56 | 57 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/docs/QueryApi.md: -------------------------------------------------------------------------------- 1 | # swagger_client.QueryApi 2 | 3 | All URIs are relative to *http://0.0.0.0:6300/api* 4 | 5 | Method | HTTP request | Description 6 | ------------- | ------------- | ------------- 7 | [**s_ql_query**](QueryApi.md#s_ql_query) | **GET** /sql | Use SQL in a RESTful way 8 | 9 | 10 | # **s_ql_query** 11 | > list[object] s_ql_query(query, values) 12 | 13 | Use SQL in a RESTful way 14 | 15 | API exposed for sending SQL queries directly against the chainquery database. Since this is an exposed API there are limits to its use. These limits include queries per hour, read-only, limited to 60 second timeout. 16 | 17 | ### Example 18 | ```python 19 | from __future__ import print_function 20 | import time 21 | import swagger_client 22 | from swagger_client.rest import ApiException 23 | from pprint import pprint 24 | 25 | # create an instance of the API class 26 | api_instance = swagger_client.QueryApi() 27 | query = 'query_example' # str | The SQL query to be put against the chainquery database. 28 | values = ['values_example'] # list[str] | when passing in a query use '?' for values which will be replaced in order of appearance with this array. 29 | 30 | try: 31 | # Use SQL in a RESTful way 32 | api_response = api_instance.s_ql_query(query, values) 33 | pprint(api_response) 34 | except ApiException as e: 35 | print("Exception when calling QueryApi->s_ql_query: %s\n" % e) 36 | ``` 37 | 38 | ### Parameters 39 | 40 | Name | Type | Description | Notes 41 | ------------- | ------------- | ------------- | ------------- 42 | **query** | **str**| The SQL query to be put against the chainquery database. | 43 | **values** | [**list[str]**](str.md)| when passing in a query use '?' for values which will be replaced in order of appearance with this array. | 44 | 45 | ### Return type 46 | 47 | **list[object]** 48 | 49 | ### Authorization 50 | 51 | No authorization required 52 | 53 | ### HTTP request headers 54 | 55 | - **Content-Type**: application/json 56 | - **Accept**: application/json 57 | 58 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 59 | 60 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/docs/StatApi.md: -------------------------------------------------------------------------------- 1 | # swagger_client.StatApi 2 | 3 | All URIs are relative to *http://0.0.0.0:6300/api* 4 | 5 | Method | HTTP request | Description 6 | ------------- | ------------- | ------------- 7 | [**address_summary**](StatApi.md#address_summary) | **GET** /addresssummary | Returns a summary of Address activity 8 | [**chain_query_status**](StatApi.md#chain_query_status) | **GET** /status | Returns important status information about Chain Query 9 | 10 | 11 | # **address_summary** 12 | > AddressSummary address_summary(lbry_address) 13 | 14 | Returns a summary of Address activity 15 | 16 | It returns sent, recieved, balance, and number of transactions it has been used in. 17 | 18 | ### Example 19 | ```python 20 | from __future__ import print_function 21 | import time 22 | import swagger_client 23 | from swagger_client.rest import ApiException 24 | from pprint import pprint 25 | 26 | # create an instance of the API class 27 | api_instance = swagger_client.StatApi() 28 | lbry_address = 'lbry_address_example' # str | A LbryAddress 29 | 30 | try: 31 | # Returns a summary of Address activity 32 | api_response = api_instance.address_summary(lbry_address) 33 | pprint(api_response) 34 | except ApiException as e: 35 | print("Exception when calling StatApi->address_summary: %s\n" % e) 36 | ``` 37 | 38 | ### Parameters 39 | 40 | Name | Type | Description | Notes 41 | ------------- | ------------- | ------------- | ------------- 42 | **lbry_address** | **str**| A LbryAddress | 43 | 44 | ### Return type 45 | 46 | [**AddressSummary**](AddressSummary.md) 47 | 48 | ### Authorization 49 | 50 | No authorization required 51 | 52 | ### HTTP request headers 53 | 54 | - **Content-Type**: application/json 55 | - **Accept**: application/json 56 | 57 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 58 | 59 | # **chain_query_status** 60 | > TableStatus chain_query_status() 61 | 62 | Returns important status information about Chain Query 63 | 64 | ### Example 65 | ```python 66 | from __future__ import print_function 67 | import time 68 | import swagger_client 69 | from swagger_client.rest import ApiException 70 | from pprint import pprint 71 | 72 | # create an instance of the API class 73 | api_instance = swagger_client.StatApi() 74 | 75 | try: 76 | # Returns important status information about Chain Query 77 | api_response = api_instance.chain_query_status() 78 | pprint(api_response) 79 | except ApiException as e: 80 | print("Exception when calling StatApi->chain_query_status: %s\n" % e) 81 | ``` 82 | 83 | ### Parameters 84 | This endpoint does not need any parameter. 85 | 86 | ### Return type 87 | 88 | [**TableStatus**](TableStatus.md) 89 | 90 | ### Authorization 91 | 92 | No authorization required 93 | 94 | ### HTTP request headers 95 | 96 | - **Content-Type**: application/json 97 | - **Accept**: application/json 98 | 99 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 100 | 101 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/docs/TableSize.md: -------------------------------------------------------------------------------- 1 | # TableSize 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **table_name** | **str** | Name of the table being referenced. | [optional] 7 | **nr_rows** | **int** | The number of rows in the referenced table | [optional] 8 | 9 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 10 | 11 | 12 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/docs/TableStatus.md: -------------------------------------------------------------------------------- 1 | # TableStatus 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **status** | [**list[TableSize]**](TableSize.md) | | [optional] 7 | 8 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 9 | 10 | 11 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/git_push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ 3 | # 4 | # Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" 5 | 6 | git_user_id=$1 7 | git_repo_id=$2 8 | release_note=$3 9 | 10 | if [ "$git_user_id" = "" ]; then 11 | git_user_id="GIT_USER_ID" 12 | echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" 13 | fi 14 | 15 | if [ "$git_repo_id" = "" ]; then 16 | git_repo_id="GIT_REPO_ID" 17 | echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" 18 | fi 19 | 20 | if [ "$release_note" = "" ]; then 21 | release_note="Minor update" 22 | echo "[INFO] No command line input provided. Set \$release_note to $release_note" 23 | fi 24 | 25 | # Initialize the local directory as a Git repository 26 | git init 27 | 28 | # Adds the files in the local repository and stages them for commit. 29 | git add . 30 | 31 | # Commits the tracked changes and prepares them to be pushed to a remote repository. 32 | git commit -m "$release_note" 33 | 34 | # Sets the new remote 35 | git_remote=`git remote` 36 | if [ "$git_remote" = "" ]; then # git remote not defined 37 | 38 | if [ "$GIT_TOKEN" = "" ]; then 39 | echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." 40 | git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git 41 | else 42 | git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git 43 | fi 44 | 45 | fi 46 | 47 | git pull origin master 48 | 49 | # Pushes (Forces) the changes in the local repository up to the remote repository 50 | echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" 51 | git push origin master 2>&1 | grep -v 'To https' 52 | 53 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi >= 14.05.14 2 | six >= 1.10 3 | python_dateutil >= 2.5.3 4 | setuptools >= 21.0.0 5 | urllib3 >= 1.15.1 6 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/setup.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Chain Query 5 | 6 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 7 | 8 | OpenAPI spec version: 0.1.0 9 | 10 | Generated by: https://github.com/swagger-api/swagger-codegen.git 11 | """ 12 | 13 | 14 | from setuptools import setup, find_packages # noqa: H301 15 | 16 | NAME = "swagger-client" 17 | VERSION = "1.0.0" 18 | # To install the library, run the following 19 | # 20 | # python setup.py install 21 | # 22 | # prerequisite: setuptools 23 | # http://pypi.python.org/pypi/setuptools 24 | 25 | REQUIRES = ["urllib3 >= 1.15", "six >= 1.10", "certifi", "python-dateutil"] 26 | 27 | setup( 28 | name=NAME, 29 | version=VERSION, 30 | description="Chain Query", 31 | author_email="", 32 | url="", 33 | keywords=["Swagger", "Chain Query"], 34 | install_requires=REQUIRES, 35 | packages=find_packages(), 36 | include_package_data=True, 37 | long_description="""\ 38 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 39 | """ 40 | ) 41 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/swagger_client/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | # flake8: noqa 4 | 5 | """ 6 | Chain Query 7 | 8 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 9 | 10 | OpenAPI spec version: 0.1.0 11 | 12 | Generated by: https://github.com/swagger-api/swagger-codegen.git 13 | """ 14 | 15 | 16 | from __future__ import absolute_import 17 | 18 | # import apis into sdk package 19 | from swagger_client.api.default_api import DefaultApi 20 | from swagger_client.api.query_api import QueryApi 21 | from swagger_client.api.stat_api import StatApi 22 | 23 | # import ApiClient 24 | from swagger_client.api_client import ApiClient 25 | from swagger_client.configuration import Configuration 26 | # import models into sdk package 27 | from swagger_client.models.address_summary import AddressSummary 28 | from swagger_client.models.table_size import TableSize 29 | from swagger_client.models.table_status import TableStatus 30 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/swagger_client/api/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # flake8: noqa 4 | 5 | # import apis into api package 6 | from swagger_client.api.default_api import DefaultApi 7 | from swagger_client.api.query_api import QueryApi 8 | from swagger_client.api.stat_api import StatApi 9 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/swagger_client/models/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | # flake8: noqa 4 | """ 5 | Chain Query 6 | 7 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 8 | 9 | OpenAPI spec version: 0.1.0 10 | 11 | Generated by: https://github.com/swagger-api/swagger-codegen.git 12 | """ 13 | 14 | 15 | from __future__ import absolute_import 16 | 17 | # import models into model package 18 | from swagger_client.models.address_summary import AddressSummary 19 | from swagger_client.models.table_size import TableSize 20 | from swagger_client.models.table_status import TableStatus 21 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/swagger_client/models/table_status.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Chain Query 5 | 6 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 7 | 8 | OpenAPI spec version: 0.1.0 9 | 10 | Generated by: https://github.com/swagger-api/swagger-codegen.git 11 | """ 12 | 13 | 14 | import pprint 15 | import re # noqa: F401 16 | 17 | import six 18 | 19 | from swagger_client.models.table_size import TableSize # noqa: F401,E501 20 | 21 | 22 | class TableStatus(object): 23 | """NOTE: This class is auto generated by the swagger code generator program. 24 | 25 | Do not edit the class manually. 26 | """ 27 | 28 | """ 29 | Attributes: 30 | swagger_types (dict): The key is attribute name 31 | and the value is attribute type. 32 | attribute_map (dict): The key is attribute name 33 | and the value is json key in definition. 34 | """ 35 | swagger_types = { 36 | 'status': 'list[TableSize]' 37 | } 38 | 39 | attribute_map = { 40 | 'status': 'Status' 41 | } 42 | 43 | def __init__(self, status=None): # noqa: E501 44 | """TableStatus - a model defined in Swagger""" # noqa: E501 45 | 46 | self._status = None 47 | self.discriminator = None 48 | 49 | if status is not None: 50 | self.status = status 51 | 52 | @property 53 | def status(self): 54 | """Gets the status of this TableStatus. # noqa: E501 55 | 56 | 57 | :return: The status of this TableStatus. # noqa: E501 58 | :rtype: list[TableSize] 59 | """ 60 | return self._status 61 | 62 | @status.setter 63 | def status(self, status): 64 | """Sets the status of this TableStatus. 65 | 66 | 67 | :param status: The status of this TableStatus. # noqa: E501 68 | :type: list[TableSize] 69 | """ 70 | 71 | self._status = status 72 | 73 | def to_dict(self): 74 | """Returns the model properties as a dict""" 75 | result = {} 76 | 77 | for attr, _ in six.iteritems(self.swagger_types): 78 | value = getattr(self, attr) 79 | if isinstance(value, list): 80 | result[attr] = list(map( 81 | lambda x: x.to_dict() if hasattr(x, "to_dict") else x, 82 | value 83 | )) 84 | elif hasattr(value, "to_dict"): 85 | result[attr] = value.to_dict() 86 | elif isinstance(value, dict): 87 | result[attr] = dict(map( 88 | lambda item: (item[0], item[1].to_dict()) 89 | if hasattr(item[1], "to_dict") else item, 90 | value.items() 91 | )) 92 | else: 93 | result[attr] = value 94 | 95 | return result 96 | 97 | def to_str(self): 98 | """Returns the string representation of the model""" 99 | return pprint.pformat(self.to_dict()) 100 | 101 | def __repr__(self): 102 | """For `print` and `pprint`""" 103 | return self.to_str() 104 | 105 | def __eq__(self, other): 106 | """Returns true if both objects are equal""" 107 | if not isinstance(other, TableStatus): 108 | return False 109 | 110 | return self.__dict__ == other.__dict__ 111 | 112 | def __ne__(self, other): 113 | """Returns true if both objects are not equal""" 114 | return not self == other 115 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/test-requirements.txt: -------------------------------------------------------------------------------- 1 | coverage>=4.0.3 2 | nose>=1.3.7 3 | pluggy>=0.3.1 4 | py>=1.4.31 5 | randomize>=0.13 6 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdyseeTeam/chainquery/48c092515dea5cd1856e7c84ce8611ee9b66e210/swagger/clients/pythonclient/test/__init__.py -------------------------------------------------------------------------------- /swagger/clients/pythonclient/test/test_address_summary.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Chain Query 5 | 6 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 7 | 8 | OpenAPI spec version: 0.1.0 9 | 10 | Generated by: https://github.com/swagger-api/swagger-codegen.git 11 | """ 12 | 13 | 14 | from __future__ import absolute_import 15 | 16 | import unittest 17 | 18 | import swagger_client 19 | from swagger_client.models.address_summary import AddressSummary # noqa: E501 20 | from swagger_client.rest import ApiException 21 | 22 | 23 | class TestAddressSummary(unittest.TestCase): 24 | """AddressSummary unit test stubs""" 25 | 26 | def setUp(self): 27 | pass 28 | 29 | def tearDown(self): 30 | pass 31 | 32 | def testAddressSummary(self): 33 | """Test AddressSummary""" 34 | # FIXME: construct object with mandatory attributes with example values 35 | # model = swagger_client.models.address_summary.AddressSummary() # noqa: E501 36 | pass 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/test/test_default_api.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Chain Query 5 | 6 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 7 | 8 | OpenAPI spec version: 0.1.0 9 | 10 | Generated by: https://github.com/swagger-api/swagger-codegen.git 11 | """ 12 | 13 | 14 | from __future__ import absolute_import 15 | 16 | import unittest 17 | 18 | import swagger_client 19 | from swagger_client.api.default_api import DefaultApi # noqa: E501 20 | from swagger_client.rest import ApiException 21 | 22 | 23 | class TestDefaultApi(unittest.TestCase): 24 | """DefaultApi unit test stubs""" 25 | 26 | def setUp(self): 27 | self.api = swagger_client.api.default_api.DefaultApi() # noqa: E501 28 | 29 | def tearDown(self): 30 | pass 31 | 32 | def test_self_update(self): 33 | """Test case for self_update 34 | 35 | auto updates the application with the latest release based on TravisCI webhook # noqa: E501 36 | """ 37 | pass 38 | 39 | 40 | if __name__ == '__main__': 41 | unittest.main() 42 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/test/test_query_api.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Chain Query 5 | 6 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 7 | 8 | OpenAPI spec version: 0.1.0 9 | 10 | Generated by: https://github.com/swagger-api/swagger-codegen.git 11 | """ 12 | 13 | 14 | from __future__ import absolute_import 15 | 16 | import unittest 17 | 18 | import swagger_client 19 | from swagger_client.api.query_api import QueryApi # noqa: E501 20 | from swagger_client.rest import ApiException 21 | 22 | 23 | class TestQueryApi(unittest.TestCase): 24 | """QueryApi unit test stubs""" 25 | 26 | def setUp(self): 27 | self.api = swagger_client.api.query_api.QueryApi() # noqa: E501 28 | 29 | def tearDown(self): 30 | pass 31 | 32 | def test_s_ql_query(self): 33 | """Test case for s_ql_query 34 | 35 | Use SQL in a RESTful way # noqa: E501 36 | """ 37 | pass 38 | 39 | 40 | if __name__ == '__main__': 41 | unittest.main() 42 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/test/test_stat_api.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Chain Query 5 | 6 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 7 | 8 | OpenAPI spec version: 0.1.0 9 | 10 | Generated by: https://github.com/swagger-api/swagger-codegen.git 11 | """ 12 | 13 | 14 | from __future__ import absolute_import 15 | 16 | import unittest 17 | 18 | import swagger_client 19 | from swagger_client.api.stat_api import StatApi # noqa: E501 20 | from swagger_client.rest import ApiException 21 | 22 | 23 | class TestStatApi(unittest.TestCase): 24 | """StatApi unit test stubs""" 25 | 26 | def setUp(self): 27 | self.api = swagger_client.api.stat_api.StatApi() # noqa: E501 28 | 29 | def tearDown(self): 30 | pass 31 | 32 | def test_address_summary(self): 33 | """Test case for address_summary 34 | 35 | Returns a summary of Address activity # noqa: E501 36 | """ 37 | pass 38 | 39 | def test_status(self): 40 | """Test case for status 41 | 42 | Returns important status information about Chain Query # noqa: E501 43 | """ 44 | pass 45 | 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/test/test_table_size.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Chain Query 5 | 6 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 7 | 8 | OpenAPI spec version: 0.1.0 9 | 10 | Generated by: https://github.com/swagger-api/swagger-codegen.git 11 | """ 12 | 13 | 14 | from __future__ import absolute_import 15 | 16 | import unittest 17 | 18 | import swagger_client 19 | from swagger_client.models.table_size import TableSize # noqa: E501 20 | from swagger_client.rest import ApiException 21 | 22 | 23 | class TestTableSize(unittest.TestCase): 24 | """TableSize unit test stubs""" 25 | 26 | def setUp(self): 27 | pass 28 | 29 | def tearDown(self): 30 | pass 31 | 32 | def testTableSize(self): 33 | """Test TableSize""" 34 | # FIXME: construct object with mandatory attributes with example values 35 | # model = swagger_client.models.table_size.TableSize() # noqa: E501 36 | pass 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/test/test_table_status.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Chain Query 5 | 6 | The LBRY blockchain is read into SQL where important structured information can be extracted through the Chain Query API. # noqa: E501 7 | 8 | OpenAPI spec version: 0.1.0 9 | 10 | Generated by: https://github.com/swagger-api/swagger-codegen.git 11 | """ 12 | 13 | 14 | from __future__ import absolute_import 15 | 16 | import unittest 17 | 18 | import swagger_client 19 | from swagger_client.models.table_status import TableStatus # noqa: E501 20 | from swagger_client.rest import ApiException 21 | 22 | 23 | class TestTableStatus(unittest.TestCase): 24 | """TableStatus unit test stubs""" 25 | 26 | def setUp(self): 27 | pass 28 | 29 | def tearDown(self): 30 | pass 31 | 32 | def testTableStatus(self): 33 | """Test TableStatus""" 34 | # FIXME: construct object with mandatory attributes with example values 35 | # model = swagger_client.models.table_status.TableStatus() # noqa: E501 36 | pass 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /swagger/clients/pythonclient/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27, py3 3 | 4 | [testenv] 5 | deps=-r{toxinidir}/requirements.txt 6 | -r{toxinidir}/test-requirements.txt 7 | 8 | commands= 9 | nosetests \ 10 | [] -------------------------------------------------------------------------------- /swagger/modules/go-server/README.mustache: -------------------------------------------------------------------------------- 1 | # Go API Server for {{packageName}} 2 | 3 | {{#appDescription}} 4 | {{{appDescription}}} 5 | {{/appDescription}} 6 | 7 | ## Overview 8 | This server was generated by the [swagger-codegen] 9 | (https://github.com/swagger-api/swagger-codegen) project. 10 | By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. 11 | - 12 | 13 | To see how to make this your own, look here: 14 | 15 | [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) 16 | 17 | - API version: {{appVersion}}{{^hideGenerationTimestamp}} 18 | - Build date: {{generatedDate}}{{/hideGenerationTimestamp}} 19 | {{#infoUrl}} 20 | For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) 21 | {{/infoUrl}} 22 | 23 | 24 | ### Running the server 25 | To run the server, follow these simple steps: 26 | 27 | ``` 28 | go run main.go 29 | ``` -------------------------------------------------------------------------------- /swagger/modules/go-server/controller-api.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | package {{packageName}} 3 | 4 | //Not using swagger for controller-api. These files have been added to the project git ignore. 5 | -------------------------------------------------------------------------------- /swagger/modules/go-server/logger.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | package {{packageName}} 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | func Logger(inner http.Handler, name string) http.Handler { 11 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 12 | start := time.Now() 13 | 14 | inner.ServeHTTP(w, r) 15 | 16 | log.Printf( 17 | "%s %s %s %s", 18 | r.Method, 19 | r.RequestURI, 20 | name, 21 | time.Since(start), 22 | ) 23 | }) 24 | } -------------------------------------------------------------------------------- /swagger/modules/go-server/main.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | package swagger 3 | 4 | import ( 5 | "net/http" 6 | "strconv" 7 | 8 | "github.com/lbryio/chainquery/config" 9 | "github.com/lbryio/chainquery/db" 10 | sw "github.com/lbryio/chainquery/swagger/apiserver/go" 11 | "github.com/lbryio/lbry.go/v2/extras/api" 12 | 13 | "github.com/fatih/color" 14 | "github.com/sirupsen/logrus" 15 | ) 16 | 17 | func InitApiServer(hostAndPort string) { 18 | logrus.Info("API Server started") 19 | hs := make(map[string]string) 20 | hs["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS" 21 | hs["Content-Type"] = "application/json; charset=utf-8; application/x-www-form-urlencoded" 22 | hs["X-Content-Type-Options"] = "nosniff" 23 | hs["Content-Security-Policy"] = "default-src 'none'" 24 | hs["Server"] = "chainquery-server" 25 | hs["Access-Control-Allow-Origin"] = "*" 26 | api.ResponseHeaders = hs 27 | api.Log = func(request *http.Request, response *api.Response, err error) { 28 | if err != nil { 29 | logrus.Error(err) 30 | } 31 | consoleText := request.RemoteAddr + " [" + strconv.Itoa(response.Status) + "]: " + request.Method + " " + request.URL.Path 32 | logrus.Debug(color.GreenString(consoleText)) 33 | 34 | } 35 | //API Chainquery DB connection 36 | chainqueryInstance, err := db.InitAPIQuery(config.GetAPIMySQLDSN(), false) 37 | if err != nil { 38 | logrus.Panic("unable to connect to chainquery database instance for API Server: ", err) 39 | } 40 | defer db.CloseDB(chainqueryInstance) 41 | router := sw.NewRouter() 42 | 43 | logrus.Fatal(http.ListenAndServe(hostAndPort, router)) 44 | } 45 | -------------------------------------------------------------------------------- /swagger/modules/go-server/model.mustache: -------------------------------------------------------------------------------- 1 | 2 | {{>partial_header}} 3 | package {{packageName}} 4 | {{#models}}{{#imports}} 5 | import ({{/imports}}{{#imports}} 6 | "{{import}}"{{/imports}}{{#imports}} 7 | ) 8 | {{/imports}}{{#model}}{{#isEnum}}{{#description}}// {{{classname}}} : {{{description}}}{{/description}} 9 | type {{{name}}} {{^format}}{{dataType}}{{/format}}{{#format}}{{{format}}}{{/format}} 10 | 11 | // List of {{{name}}} 12 | const ( 13 | {{#allowableValues}} 14 | {{#enumVars}} 15 | {{name}} {{{classname}}} = "{{{value}}}" 16 | {{/enumVars}} 17 | {{/allowableValues}} 18 | ){{/isEnum}}{{^isEnum}}{{#description}} 19 | // {{{description}}}{{/description}} 20 | type {{classname}} struct { 21 | {{#vars}}{{#description}} 22 | // {{{description}}}{{/description}} 23 | {{name}} {{^isEnum}}{{^isPrimitiveType}}{{^isContainer}}{{^isDateTime}}*{{/isDateTime}}{{/isContainer}}{{/isPrimitiveType}}{{/isEnum}}{{{datatype}}} `json:"{{baseName}}{{^required}},omitempty{{/required}}"` 24 | {{/vars}} 25 | }{{/isEnum}}{{/model}}{{/models}} -------------------------------------------------------------------------------- /swagger/modules/go-server/partial_header.mustache: -------------------------------------------------------------------------------- 1 | /* 2 | {{#appName}} 3 | * {{{appName}}} 4 | * 5 | {{/appName}} 6 | {{#appDescription}} 7 | * {{{appDescription}}} 8 | * 9 | {{/appDescription}} 10 | {{#version}} 11 | * API version: {{{version}}} 12 | {{/version}} 13 | {{#infoEmail}} 14 | * Contact: {{{infoEmail}}} 15 | {{/infoEmail}} 16 | * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) 17 | */ -------------------------------------------------------------------------------- /swagger/modules/go-server/routers.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | package {{packageName}} 3 | 4 | import ( 5 | "net/http" 6 | "strings" 7 | 8 | . "github.com/lbryio/chainquery/apiactions" 9 | . "github.com/lbryio/lbry.go/v2/extras/api" 10 | 11 | "github.com/gorilla/mux" 12 | ) 13 | 14 | type Route struct { 15 | Name string 16 | Method string 17 | Pattern string 18 | HandlerFunc Handler 19 | } 20 | 21 | type Routes []Route 22 | 23 | func NewRouter() *mux.Router { 24 | router := mux.NewRouter().StrictSlash(true) 25 | for _, route := range routes { 26 | var handler http.Handler 27 | handler = route.HandlerFunc 28 | handler = Logger(handler, route.Name) 29 | 30 | router. 31 | Methods(route.Method). 32 | Path(route.Pattern). 33 | Name(route.Name). 34 | Handler(handler) 35 | } 36 | 37 | return router 38 | } 39 | 40 | var routes = Routes{ 41 | Route{ 42 | "Index", 43 | "GET", 44 | "{{{basePathWithoutHost}}}/", 45 | IndexAction, 46 | },{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} 47 | 48 | Route{ 49 | "{{operationId}}", 50 | strings.ToUpper("{{httpMethod}}"), 51 | "{{{basePathWithoutHost}}}{{{path}}}", 52 | {{operationId}}Action, 53 | },{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} 54 | } -------------------------------------------------------------------------------- /swagger/modules/go-server/swagger.mustache: -------------------------------------------------------------------------------- 1 | {{{swagger-yaml}}} -------------------------------------------------------------------------------- /twilio/twilio.go: -------------------------------------------------------------------------------- 1 | package twilio 2 | 3 | import ( 4 | "github.com/sfreiberg/gotwilio" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | var twilioClient *gotwilio.Twilio 9 | 10 | //RecipientList is the list of phone numbers that twilio sends messages to. 11 | var RecipientList = []string{} 12 | 13 | //FromNumber is the phone number that text messages come from. 14 | var FromNumber = "" 15 | 16 | //TwilioAuthToken is the auth token for twilio account integration. 17 | var TwilioAuthToken = "" 18 | 19 | //TwilioSID is the twilio account SID. 20 | var TwilioSID = "" 21 | 22 | //InitTwilio initializes the twilio client to send SMS messages from chainquery to a list of numbers. 23 | func InitTwilio() { 24 | if TwilioAuthToken != "" && TwilioSID != "" { 25 | twilioClient = gotwilio.NewTwilioClient(TwilioSID, TwilioAuthToken) 26 | } 27 | } 28 | 29 | //SendSMS sends a text message to the recipient list if twilio integration is setup, based on configuration. 30 | func SendSMS(message string) { 31 | if twilioClient != nil { 32 | for _, recipient := range RecipientList { 33 | _, exception, err := twilioClient.SendSMS(FromNumber, recipient, "Chainquery: "+message, "", TwilioSID) 34 | if err != nil { 35 | logrus.Error(err) 36 | } 37 | if exception != nil { 38 | logrus.Warning("Status: ", exception.Status, "Code: ", exception.Code, "Message: ", exception.Message, "From Twilio: ", exception.MoreInfo) 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /util/utility.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "database/sql" 5 | "time" 6 | 7 | "github.com/lbryio/lbry.go/v2/extras/errors" 8 | 9 | "github.com/sirupsen/logrus" 10 | "github.com/spf13/viper" 11 | ) 12 | 13 | // TimeTrack is a function that tracks the time spent and outputs specific timing information. This is important for 14 | // chainquery profiling and is used throughout. It can be reused by just passing `always` as the profile. The basic 15 | // usage is `defer util.TimeTrack(time.Now(),"","")`. This should be placed at the top of 16 | // the function where time is to be tracked, or at any point where you want to start tracking time. 17 | func TimeTrack(start time.Time, name string, profile string) { 18 | if profile == "daemonprofile" && viper.GetBool("daemonprofile") { 19 | elapsed := time.Since(start) 20 | logrus.Infof("%s %s took %s", name, profile, elapsed) 21 | } 22 | if profile == "lbrycrdprofile" && viper.GetBool("lbrycrdprofile") { 23 | elapsed := time.Since(start) 24 | logrus.Infof("%s %s took %s", name, profile, elapsed) 25 | } 26 | if profile == "mysqlprofile" && viper.GetBool("mysqlprofile") { 27 | elapsed := time.Since(start) 28 | logrus.Infof("%s %s took %s", name, profile, elapsed) 29 | } 30 | if profile == "always" { 31 | elapsed := time.Since(start) 32 | logrus.Infof("%s took %s", name, elapsed) 33 | } 34 | 35 | } 36 | 37 | // Min is a helpful function to take the min between two integers. 38 | func Min(x, y int) int { 39 | if x < y { 40 | return x 41 | } 42 | return y 43 | } 44 | 45 | //CloseRows Closes SQL Rows for custom SQL queries. 46 | func CloseRows(rows *sql.Rows) { 47 | if err := rows.Close(); err != nil { 48 | logrus.Error("Closing rows error: ", errors.Err(err)) 49 | } 50 | } 51 | 52 | // ReverseBytes reverses a byte slice. useful for switching endian-ness 53 | func ReverseBytes(b []byte) []byte { 54 | r := make([]byte, len(b)) 55 | for left, right := 0, len(b)-1; left < right; left, right = left+1, right-1 { 56 | r[left], r[right] = b[right], b[left] 57 | } 58 | return r 59 | } 60 | -------------------------------------------------------------------------------- /util/utility_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding/hex" 5 | "testing" 6 | ) 7 | 8 | func TestReverseBytes(t *testing.T) { 9 | originalHex := "ad779413d8710f52a5c1d79af7e10a329147576f" 10 | bytes, err := hex.DecodeString(originalHex) 11 | if err != nil { 12 | t.Error(err) 13 | } 14 | reversed := ReverseBytes(bytes) 15 | reversedHex := hex.EncodeToString(reversed) 16 | if reversedHex != "6f574791320ae1f79ad7c1a5520f71d8139477ad" { 17 | t.Error("it doesnt match") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /util/worker.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "sync" 4 | 5 | // PieceOfWork is an interface type for representing a atomic piece of work that can be done independently. 6 | type PieceOfWork interface { 7 | // BeforeExecute will always be executed before the piece of work's execution. 8 | BeforeExecute() 9 | // Execute is the execution of the actual work. 10 | Execute() error 11 | // AfterExecute will always be executed after the piece of work's execution if successful. 12 | AfterExecute() 13 | // OnError will execute in the event an error is returned from the Execute function. 14 | OnError(err error) 15 | } 16 | 17 | // InitWorkers creates a worker pool that execute pieces of work. It is a way of controlling the number go routines to 18 | // optimize parallelism. It is recommended that this stay around the number of cores unless there is significant blocking 19 | // time associated with the work involved. 20 | func InitWorkers(numworkers int, jobs chan PieceOfWork) *sync.WaitGroup { 21 | wg := sync.WaitGroup{} 22 | for i := 0; i < numworkers; i++ { 23 | wg.Add(1) 24 | go func() { 25 | defer wg.Done() 26 | for job := range jobs { 27 | err := job.Execute() 28 | job.OnError(err) 29 | } 30 | }() 31 | } 32 | 33 | return &wg 34 | } 35 | 36 | // NewQueue creates a bi-directional channel that can take in pieces of work. This is leveraged with the worker pool 37 | // and is what they pull from while active. The worker pool will end once this channel is closed. The intention is that 38 | // this channel will be passed into the initialization of the worker pool. 39 | func NewQueue() chan PieceOfWork { 40 | return make(chan PieceOfWork) 41 | } 42 | --------------------------------------------------------------------------------