From 36099d8221e4df090f5ce8d898484af9001d857f Mon Sep 17 00:00:00 2001 From: Philip Su Date: Thu, 26 Jan 2023 09:08:48 -0800 Subject: [PATCH 01/69] Initial commit for sei-iavl --- sei-iavl/.github/CODEOWNERS | 2 + sei-iavl/.github/dependabot.yml | 16 + sei-iavl/.github/stale.yml | 47 + sei-iavl/.github/workflows/ci.yml | 42 + sei-iavl/.github/workflows/lint.yml | 31 + sei-iavl/.gitignore | 17 + sei-iavl/.golangci.yml | 74 + sei-iavl/.mergify.yml | 10 + sei-iavl/CHANGELOG.md | 460 ++++ sei-iavl/CONTRIBUTING.md | 12 + sei-iavl/FORKED_CHANGELOG.md | 22 + sei-iavl/LICENSE | 191 ++ sei-iavl/Makefile | 131 ++ sei-iavl/PERFORMANCE.md | 111 + sei-iavl/POEM | 29 + sei-iavl/README.md | 22 + sei-iavl/basic_test.go | 577 +++++ sei-iavl/benchmarks/README.md | 55 + sei-iavl/benchmarks/bench_test.go | 429 ++++ sei-iavl/benchmarks/cosmos-exim/README.md | 38 + sei-iavl/benchmarks/cosmos-exim/main.go | 202 ++ sei-iavl/benchmarks/hash_test.go | 53 + .../Adityas-MBP-0.12.3-4-ge3e5a91-results.txt | 62 + ...pu-8gb-160gb-0.12.3-7-gf5dfff0-results.txt | 62 + .../Rickys-MBP-0.12.4-4-g494d60b-result.txt | 69 + .../Rickys-MBP-0.12.4-3-ge247ad9-results.txt | 72 + .../results/legacy/Ethans-MBP-2717167.txt | 116 + .../results/legacy/aws-c4-large-f6f41ca.txt | 118 + .../legacy/digital-ocean-2gb-2717167.txt | 118 + ...al-ocean-64gb-fullbench-memory-8f19f23.txt | 149 ++ ...al-ocean-64gb-fullbench-memory-c1f6d4e.txt | 149 ++ sei-iavl/benchmarks/sdk_results/README.md | 21 + sei-iavl/benchmarks/sdk_results/results.csv | 98 + sei-iavl/benchmarks/setup/INSTALL_ROOT.sh | 32 + sei-iavl/benchmarks/setup/RUN_BENCHMARKS.sh | 28 + sei-iavl/buf.gen.yaml | 17 + sei-iavl/buf.yaml | 14 + sei-iavl/cache/cache.go | 110 + sei-iavl/cache/cache_bench_test.go | 69 + sei-iavl/cache/cache_test.go | 311 +++ sei-iavl/cmd/iaviewer/README.md | 118 + sei-iavl/cmd/iaviewer/main.go | 188 ++ sei-iavl/codecov.yml | 28 + sei-iavl/doc.go | 54 + sei-iavl/docs/architecture/README.md | 24 + sei-iavl/docs/architecture/adr-template.md | 47 + sei-iavl/docs/node/key_format.md | 36 + sei-iavl/docs/node/node.md | 133 ++ sei-iavl/docs/node/nodedb.md | 56 + sei-iavl/docs/overview.md | 42 + sei-iavl/docs/proof/proof.md | 347 +++ sei-iavl/docs/tree/export_import.md | 64 + sei-iavl/docs/tree/immutable_tree.md | 69 + sei-iavl/docs/tree/mutable_tree.md | 384 ++++ sei-iavl/export.go | 89 + sei-iavl/export_test.go | 305 +++ sei-iavl/fast_iterator.go | 133 ++ sei-iavl/fast_node.go | 76 + sei-iavl/fast_node_test.go | 58 + sei-iavl/go.mod | 36 + sei-iavl/go.sum | 1685 ++++++++++++++ sei-iavl/immutable_tree.go | 333 +++ sei-iavl/import.go | 199 ++ sei-iavl/import_test.go | 248 ++ sei-iavl/internal/bytes/bytes.go | 64 + sei-iavl/internal/bytes/bytes_test.go | 66 + sei-iavl/internal/bytes/string.go | 26 + sei-iavl/internal/bytes/string_test.go | 54 + sei-iavl/internal/encoding/encoding.go | 164 ++ sei-iavl/internal/encoding/encoding_test.go | 88 + sei-iavl/internal/logger/logger.go | 15 + sei-iavl/internal/rand/random.go | 245 ++ sei-iavl/internal/rand/random_test.go | 84 + sei-iavl/iterator.go | 261 +++ sei-iavl/iterator_test.go | 331 +++ sei-iavl/key_format.go | 182 ++ sei-iavl/key_format_test.go | 149 ++ sei-iavl/mock/db_mock.go | 420 ++++ sei-iavl/mutable_tree.go | 1255 ++++++++++ sei-iavl/mutable_tree_test.go | 1443 ++++++++++++ sei-iavl/node.go | 556 +++++ sei-iavl/node_test.go | 177 ++ sei-iavl/nodedb.go | 1111 +++++++++ sei-iavl/nodedb_test.go | 295 +++ sei-iavl/options.go | 89 + sei-iavl/proof.go | 288 +++ sei-iavl/proof_forgery_test.go | 106 + sei-iavl/proof_iavl_absence.go | 121 + sei-iavl/proof_iavl_test.go | 100 + sei-iavl/proof_iavl_value.go | 112 + sei-iavl/proof_ics23.go | 168 ++ sei-iavl/proof_ics23_test.go | 325 +++ sei-iavl/proof_path.go | 119 + sei-iavl/proof_range.go | 584 +++++ sei-iavl/proof_test.go | 324 +++ sei-iavl/proto/iavl/proof.proto | 42 + sei-iavl/proto/proof.pb.go | 1618 +++++++++++++ sei-iavl/repair.go | 69 + sei-iavl/repair_test.go | 197 ++ sei-iavl/scripts/protocgen.sh | 7 + .../testdata/0.13-orphans-v6.db/000001.log | Bin 0 -> 3590 bytes sei-iavl/testdata/0.13-orphans-v6.db/CURRENT | 1 + sei-iavl/testdata/0.13-orphans-v6.db/LOCK | 0 sei-iavl/testdata/0.13-orphans-v6.db/LOG | 6 + .../0.13-orphans-v6.db/MANIFEST-000000 | Bin 0 -> 54 bytes sei-iavl/testdata/0.13-orphans.db/000001.log | Bin 0 -> 4300 bytes sei-iavl/testdata/0.13-orphans.db/CURRENT | 1 + sei-iavl/testdata/0.13-orphans.db/LOCK | 0 sei-iavl/testdata/0.13-orphans.db/LOG | 6 + .../testdata/0.13-orphans.db/MANIFEST-000000 | Bin 0 -> 54 bytes sei-iavl/testutils_test.go | 366 +++ .../third_party/google/api/annotations.proto | 31 + sei-iavl/third_party/google/api/http.proto | 376 +++ sei-iavl/tree_dotgraph.go | 106 + sei-iavl/tree_dotgraph_test.go | 20 + sei-iavl/tree_fuzz_test.go | 128 ++ sei-iavl/tree_random_test.go | 503 ++++ sei-iavl/tree_test.go | 2044 +++++++++++++++++ sei-iavl/unsafe.go | 8 + sei-iavl/unsaved_fast_iterator.go | 218 ++ sei-iavl/util.go | 151 ++ sei-iavl/version.go | 37 + sei-iavl/with_gcc_test.go | 19 + 123 files changed, 24214 insertions(+) create mode 100644 sei-iavl/.github/CODEOWNERS create mode 100644 sei-iavl/.github/dependabot.yml create mode 100644 sei-iavl/.github/stale.yml create mode 100644 sei-iavl/.github/workflows/ci.yml create mode 100644 sei-iavl/.github/workflows/lint.yml create mode 100644 sei-iavl/.gitignore create mode 100644 sei-iavl/.golangci.yml create mode 100644 sei-iavl/.mergify.yml create mode 100644 sei-iavl/CHANGELOG.md create mode 100644 sei-iavl/CONTRIBUTING.md create mode 100644 sei-iavl/FORKED_CHANGELOG.md create mode 100644 sei-iavl/LICENSE create mode 100644 sei-iavl/Makefile create mode 100644 sei-iavl/PERFORMANCE.md create mode 100644 sei-iavl/POEM create mode 100644 sei-iavl/README.md create mode 100644 sei-iavl/basic_test.go create mode 100644 sei-iavl/benchmarks/README.md create mode 100644 sei-iavl/benchmarks/bench_test.go create mode 100644 sei-iavl/benchmarks/cosmos-exim/README.md create mode 100644 sei-iavl/benchmarks/cosmos-exim/main.go create mode 100644 sei-iavl/benchmarks/hash_test.go create mode 100644 sei-iavl/benchmarks/results/165-adityaversion/Adityas-MBP-0.12.3-4-ge3e5a91-results.txt create mode 100644 sei-iavl/benchmarks/results/165-adityaversion/DigitalOcean-4vcpu-8gb-160gb-0.12.3-7-gf5dfff0-results.txt create mode 100644 sei-iavl/benchmarks/results/168/Rickys-MBP-0.12.4-4-g494d60b-result.txt create mode 100644 sei-iavl/benchmarks/results/169/Rickys-MBP-0.12.4-3-ge247ad9-results.txt create mode 100644 sei-iavl/benchmarks/results/legacy/Ethans-MBP-2717167.txt create mode 100644 sei-iavl/benchmarks/results/legacy/aws-c4-large-f6f41ca.txt create mode 100644 sei-iavl/benchmarks/results/legacy/digital-ocean-2gb-2717167.txt create mode 100644 sei-iavl/benchmarks/results/legacy/digital-ocean-64gb-fullbench-memory-8f19f23.txt create mode 100644 sei-iavl/benchmarks/results/legacy/digital-ocean-64gb-fullbench-memory-c1f6d4e.txt create mode 100644 sei-iavl/benchmarks/sdk_results/README.md create mode 100644 sei-iavl/benchmarks/sdk_results/results.csv create mode 100755 sei-iavl/benchmarks/setup/INSTALL_ROOT.sh create mode 100755 sei-iavl/benchmarks/setup/RUN_BENCHMARKS.sh create mode 100644 sei-iavl/buf.gen.yaml create mode 100644 sei-iavl/buf.yaml create mode 100644 sei-iavl/cache/cache.go create mode 100644 sei-iavl/cache/cache_bench_test.go create mode 100644 sei-iavl/cache/cache_test.go create mode 100644 sei-iavl/cmd/iaviewer/README.md create mode 100644 sei-iavl/cmd/iaviewer/main.go create mode 100644 sei-iavl/codecov.yml create mode 100644 sei-iavl/doc.go create mode 100644 sei-iavl/docs/architecture/README.md create mode 100644 sei-iavl/docs/architecture/adr-template.md create mode 100644 sei-iavl/docs/node/key_format.md create mode 100644 sei-iavl/docs/node/node.md create mode 100644 sei-iavl/docs/node/nodedb.md create mode 100644 sei-iavl/docs/overview.md create mode 100644 sei-iavl/docs/proof/proof.md create mode 100644 sei-iavl/docs/tree/export_import.md create mode 100644 sei-iavl/docs/tree/immutable_tree.md create mode 100644 sei-iavl/docs/tree/mutable_tree.md create mode 100644 sei-iavl/export.go create mode 100644 sei-iavl/export_test.go create mode 100644 sei-iavl/fast_iterator.go create mode 100644 sei-iavl/fast_node.go create mode 100644 sei-iavl/fast_node_test.go create mode 100644 sei-iavl/go.mod create mode 100644 sei-iavl/go.sum create mode 100644 sei-iavl/immutable_tree.go create mode 100644 sei-iavl/import.go create mode 100644 sei-iavl/import_test.go create mode 100644 sei-iavl/internal/bytes/bytes.go create mode 100644 sei-iavl/internal/bytes/bytes_test.go create mode 100644 sei-iavl/internal/bytes/string.go create mode 100644 sei-iavl/internal/bytes/string_test.go create mode 100644 sei-iavl/internal/encoding/encoding.go create mode 100644 sei-iavl/internal/encoding/encoding_test.go create mode 100644 sei-iavl/internal/logger/logger.go create mode 100644 sei-iavl/internal/rand/random.go create mode 100644 sei-iavl/internal/rand/random_test.go create mode 100644 sei-iavl/iterator.go create mode 100644 sei-iavl/iterator_test.go create mode 100644 sei-iavl/key_format.go create mode 100644 sei-iavl/key_format_test.go create mode 100644 sei-iavl/mock/db_mock.go create mode 100644 sei-iavl/mutable_tree.go create mode 100644 sei-iavl/mutable_tree_test.go create mode 100644 sei-iavl/node.go create mode 100644 sei-iavl/node_test.go create mode 100644 sei-iavl/nodedb.go create mode 100644 sei-iavl/nodedb_test.go create mode 100644 sei-iavl/options.go create mode 100644 sei-iavl/proof.go create mode 100644 sei-iavl/proof_forgery_test.go create mode 100644 sei-iavl/proof_iavl_absence.go create mode 100644 sei-iavl/proof_iavl_test.go create mode 100644 sei-iavl/proof_iavl_value.go create mode 100644 sei-iavl/proof_ics23.go create mode 100644 sei-iavl/proof_ics23_test.go create mode 100644 sei-iavl/proof_path.go create mode 100644 sei-iavl/proof_range.go create mode 100644 sei-iavl/proof_test.go create mode 100644 sei-iavl/proto/iavl/proof.proto create mode 100644 sei-iavl/proto/proof.pb.go create mode 100644 sei-iavl/repair.go create mode 100644 sei-iavl/repair_test.go create mode 100644 sei-iavl/scripts/protocgen.sh create mode 100644 sei-iavl/testdata/0.13-orphans-v6.db/000001.log create mode 100644 sei-iavl/testdata/0.13-orphans-v6.db/CURRENT create mode 100644 sei-iavl/testdata/0.13-orphans-v6.db/LOCK create mode 100644 sei-iavl/testdata/0.13-orphans-v6.db/LOG create mode 100644 sei-iavl/testdata/0.13-orphans-v6.db/MANIFEST-000000 create mode 100644 sei-iavl/testdata/0.13-orphans.db/000001.log create mode 100644 sei-iavl/testdata/0.13-orphans.db/CURRENT create mode 100644 sei-iavl/testdata/0.13-orphans.db/LOCK create mode 100644 sei-iavl/testdata/0.13-orphans.db/LOG create mode 100644 sei-iavl/testdata/0.13-orphans.db/MANIFEST-000000 create mode 100644 sei-iavl/testutils_test.go create mode 100644 sei-iavl/third_party/google/api/annotations.proto create mode 100644 sei-iavl/third_party/google/api/http.proto create mode 100644 sei-iavl/tree_dotgraph.go create mode 100644 sei-iavl/tree_dotgraph_test.go create mode 100644 sei-iavl/tree_fuzz_test.go create mode 100644 sei-iavl/tree_random_test.go create mode 100644 sei-iavl/tree_test.go create mode 100644 sei-iavl/unsafe.go create mode 100644 sei-iavl/unsaved_fast_iterator.go create mode 100644 sei-iavl/util.go create mode 100644 sei-iavl/version.go create mode 100644 sei-iavl/with_gcc_test.go diff --git a/sei-iavl/.github/CODEOWNERS b/sei-iavl/.github/CODEOWNERS new file mode 100644 index 0000000000..b6f380a6d6 --- /dev/null +++ b/sei-iavl/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Primary repo maintainers +* @cosmos/sdk-core-dev diff --git a/sei-iavl/.github/dependabot.yml b/sei-iavl/.github/dependabot.yml new file mode 100644 index 0000000000..49052502f9 --- /dev/null +++ b/sei-iavl/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + time: "11:00" + open-pull-requests-limit: 10 + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + time: "11:00" + open-pull-requests-limit: 10 + labels: + - T:dependencies diff --git a/sei-iavl/.github/stale.yml b/sei-iavl/.github/stale.yml new file mode 100644 index 0000000000..a72edc8e7a --- /dev/null +++ b/sei-iavl/.github/stale.yml @@ -0,0 +1,47 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 60 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 9 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - S:wip + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: true + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: true + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +Limit to only `issues` or `pulls` +only: pulls + +Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +pulls: + daysUntilStale: 30 + markComment: > + This pull request has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. \ No newline at end of file diff --git a/sei-iavl/.github/workflows/ci.yml b/sei-iavl/.github/workflows/ci.yml new file mode 100644 index 0000000000..c35030ff1d --- /dev/null +++ b/sei-iavl/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: Test +on: + push: + branches: + - master + pull_request: + +jobs: + cleanup-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" + + Test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: '1.18' # The Go version to download (if necessary) and use. + + # Some tests, notably TestRandomOperations, are extremely slow in CI + # with the race detector enabled, so we use -short when -race is + # enabled to reduce the number of slow tests, and then run without + # -short with -race disabled for a larger test set. The same tests + # are run, just with smaller data sets. + # + # We also do a 32-bit run. Even though this is executed on a 64-bit + # system, it will use 32-bit instructions and semantics (e.g. 32-bit + # integer overflow). + - name: test & coverage report creation + run: | + go test ./... -mod=readonly -timeout 5m -short -race -coverprofile=coverage.txt -covermode=atomic + go test ./... -mod=readonly -timeout 5m + GOARCH=386 go test ./... -mod=readonly -timeout 5m + - uses: codecov/codecov-action@v3.1.0 + with: + file: ./coverage.txt + fail_ci_if_error: true diff --git a/sei-iavl/.github/workflows/lint.yml b/sei-iavl/.github/workflows/lint.yml new file mode 100644 index 0000000000..20086ed078 --- /dev/null +++ b/sei-iavl/.github/workflows/lint.yml @@ -0,0 +1,31 @@ +name: Lint +# Lint runs golangci-lint over the entire cosmos-sdk repository +# This workflow is run on every pull request and push to master +# The `golangci` will pass without running if no *.{go, mod, sum} files have been changed. +on: + pull_request: + push: + branches: + - master +jobs: + golangci: + name: golangci-lint + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: 1.18 + - uses: technote-space/get-diff-action@v6.1.0 + id: git_diff + with: + PATTERNS: | + **/**.go + go.mod + go.sum + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: latest + args: --out-format=tab + skip-go-installation: true + if: env.GIT_DIFF diff --git a/sei-iavl/.gitignore b/sei-iavl/.gitignore new file mode 100644 index 0000000000..8743c144c1 --- /dev/null +++ b/sei-iavl/.gitignore @@ -0,0 +1,17 @@ +vendor +.glide +*.swp +*.swo + +# created in test code +test.db + +# profiling data +*\.test +cpu*.out +mem*.out +cpu*.pdf +mem*.pdf + +# IDE files +.idea/* \ No newline at end of file diff --git a/sei-iavl/.golangci.yml b/sei-iavl/.golangci.yml new file mode 100644 index 0000000000..3ed11ffc0a --- /dev/null +++ b/sei-iavl/.golangci.yml @@ -0,0 +1,74 @@ +run: + tests: false + # timeout for analysis, e.g. 30s, 5m, default is 1m + timeout: 5m + +linters: + disable-all: true + enable: + - bodyclose + - deadcode + - depguard + - dogsled + # - errcheck + - exportloopref + - goconst + - gocritic + - gofmt + - goimports + - gosec + - gosimple + - govet + - ineffassign + - misspell + - nakedret + - nolintlint + - prealloc + - revive + - staticcheck + - structcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + # - wsl + +issues: + exclude-rules: + - text: "Use of weak random number generator" + linters: + - gosec + - text: "comment on exported var" + linters: + - golint + - text: "don't use an underscore in package name" + linters: + - golint + - text: "ST1003:" + linters: + - stylecheck + # FIXME: Disabled until golangci-lint updates stylecheck with this fix: + # https://github.com/dominikh/go-tools/issues/389 + - text: "ST1016:" + linters: + - stylecheck + - path: "migrations" + text: "SA1019:" + linters: + - staticcheck + + max-issues-per-linter: 10000 + max-same-issues: 10000 + +linters-settings: + dogsled: + max-blank-identifiers: 3 + maligned: + # print struct with more effective memory layout or not, false by default + suggest-new: true + nolintlint: + allow-unused: false + allow-leading-space: true + require-explanation: false + require-specific: false diff --git a/sei-iavl/.mergify.yml b/sei-iavl/.mergify.yml new file mode 100644 index 0000000000..b1bef433d4 --- /dev/null +++ b/sei-iavl/.mergify.yml @@ -0,0 +1,10 @@ +pull_request_rules: + - name: Automerge to master + conditions: + - base=master + - label=S:automerge + actions: + merge: + method: squash + strict: true + commit_message: title+body diff --git a/sei-iavl/CHANGELOG.md b/sei-iavl/CHANGELOG.md new file mode 100644 index 0000000000..1d032a6edc --- /dev/null +++ b/sei-iavl/CHANGELOG.md @@ -0,0 +1,460 @@ +# Changelog + +## Unreleased + +## 0.19.4 (October 28, 2022) + +- [#599](https://github.com/cosmos/iavl/pull/599) Populate ImmutableTree creation in copy function with missing field +- [#589](https://github.com/cosmos/iavl/pull/589) Wrap `tree.addUnsavedRemoval()` with missing `if !tree.skipFastStorageUpgrade` statement + +## 0.19.3 (October 8, 2022) + +- `ProofInner.Hash()` prevents both right and left from both being set. Only one is allowed to be set. + +> Note: It is recommended to not use the native proof structure of IAVL in its current form. Please refer to [ics23](https://github.com/confio/ics23/tree/master/go) for IAVL proofs + +## 0.19.2 (October 6, 2022) + + - [#547](https://github.com/cosmos/iavl/pull/547) Implement `skipFastStorageUpgrade` in order to skip fast storage upgrade and usage. + - [#531](https://github.com/cosmos/iavl/pull/531) Upgrade to fast storage in batches. + +## 0.19.1 (August 3, 2022) + +### Improvements + +- [#525](https://github.com/cosmos/iavl/pull/525) Optimization: use fast unsafe bytes->string conversion. +- [#506](https://github.com/cosmos/iavl/pull/506) Implement cache abstraction. + +### Bug Fixes + +- [#524](https://github.com/cosmos/iavl/pull/524) Fix: `MutableTree.Get`. + +## 0.19.0 (July 6, 2022) + +### Breaking Changes + +- [#514](https://github.com/cosmos/iavl/pull/514) Downgrade Tendermint to 0.34.x +- [#500](https://github.com/cosmos/iavl/pull/500) Return errors instead of panicking. + +### Improvements + +- [#514](https://github.com/cosmos/iavl/pull/514) Use Go v1.18 + +## 0.18.0 (March 10, 2022) + +### Breaking Changes + +- Bumped Tendermint to 0.35.1 + +### Improvements + +- [\#468](https://github.com/cosmos/iavl/pull/468) Fast storage optimization for queries and iterations +- [\#452](https://github.com/cosmos/iavl/pull/452) Optimization: remove unnecessary (\*bytes.Buffer).Reset right after creating buffer. +- [\#445](https://github.com/cosmos/iavl/pull/445) Bump github.com/tendermint/tendermint to v0.35.0 +- [\#453](https://github.com/cosmos/iavl/pull/453),[\#456](https://github.com/cosmos/iavl/pull/456) Optimization: buffer reuse +- [\#474](https://github.com/cosmos/iavl/pull/474) bump github.com/confio/ics23 to v0.7 +- [\#475](https://github.com/cosmos/iavl/pull/475) Use go v1.17 + +## 0.17.3 (December 1, 2021) + +### Bug Fixes + +- [\#448](https://github.com/cosmos/iavl/pull/448) Change RMutex to Mutex in `VersionExists()`. + +## 0.17.2 (November 13, 2021) + +### Improvements + +- [\#440](https://github.com/cosmos/iavl/pull/440) Introduce Cosmos SDK iterator type directly into IAVL. Improves the iterator performance by 40%. + +## 0.17.1 (September 15, 2021) + +### Bug Fixes + +- [\#432](https://github.com/cosmos/iavl/pull/432) Fix race condition related to Cosmos SDK and nodeDB usage. + +## 0.17.0 (August 31, 2021) + +### Improvements + +- Various performance improvements. Credits: Orijtech. +- Updating dependencies + +### CLI Breaking Changes + +- [\#396](https://github.com/cosmos/iavl/pull/396) Add "prefix" arg to iaviewer. + +## 0.16.0 (May 04, 2021) + +### Breaking Changes + +- [\#355](https://github.com/cosmos/iavl/pull/355) `Get` in `iavlServer` no longer returns an error if the requested key does not exist. `GetResponse` now contains a `NotFound` boolean to indicate that a key does not exist, and the returned index will be that of the next occupied key. + +### Improvements + +- [\#355](https://github.com/cosmos/iavl/pull/355) Add support for `GetByIndex` to `iavlServer` and RPC interface. + +### Bug Fixes + +- [\#385](https://github.com/cosmos/iavl/pull/385) Fix `GetVersioned` - now it works with `LazyLoadVersion`. +- [\#374](https://github.com/cosmos/iavl/pull/374) Fix large genesis file commit. + +## 0.15.3 (December 21, 2020) + +Special thanks to external contributors on this release: @odeke-em + +### Improvements + +- [\#352](https://github.com/cosmos/iavl/pull/352) Reuse buffer to improve performance of `GetMembershipProof()` and `GetNonMembershipProof()`. + +## 0.15.2 (December 14, 2020) + +Special thanks to external contributors on this release: @odeke-em + +### Bug Fixes + +- [\#347](https://github.com/cosmos/iavl/pull/347) Fix another integer overflow in `decodeBytes()` that can cause panics for certain inputs. The `ValueOp` and `AbsenceOp` proof decoders are vulnerable to this via malicious inputs since 0.15.0. + +- [\#349](https://github.com/cosmos/iavl/pull/349) Fix spurious blank lines in `PathToLeaf.String()`. + +## 0.15.1 (December 13, 2020) + +Special thanks to external contributors on this release: @odeke-em + +### Bug Fixes + +- [\#340](https://github.com/cosmos/iavl/pull/340) Fix integer overflow in `decodeBytes()` that can cause panics on 64-bit systems and out-of-memory issues on 32-bit systems. The `ValueOp` and `AbsenceOp` proof decoders are vulnerable to this via malicious inputs. The bug was introduced in 0.15.0. + +## 0.15.0 (November 23, 2020) + +The IAVL project has moved from https://github.com/tendermint/iavl to +https://github.com/cosmos/iavl. This changes the module import path, which is now +`github.com/cosmos/iavl`. + +Users upgrading from 0.13 should read important upgrade information in the 0.14.0 release below. + +### Breaking Changes + +- [\#285](https://github.com/cosmos/iavl/pull/285) The module path has changed from + `github.com/tendermint/iavl` to `github.com/cosmos/iavl`. + +- [\#304](https://github.com/cosmos/iavl/pull/304) Empty trees now return hashes rather than `nil` + from e.g. `Hash()`, `WorkingHash()`, and `SaveVersion()`, for conformance with RFC-6962. + +- [\#317](https://github.com/cosmos/iavl/pull/317) `LoadVersion()` and `LazyLoadVersion()` now + error if called with a positive version number on an empty tree. + +### Improvements + +- [\#296](https://github.com/cosmos/iavl/pull/296) Add `iavlserver`, a gRPC/REST API server. + +- [\#276](https://github.com/cosmos/iavl/pull/276/files) Introduced + `ImmutableTree.GetMembershipProof()` and `GetNonMembershipProof()` to return ics23 ExistenceProof + and NonExistenceProof respectively. + +- [\#265](https://github.com/cosmos/iavl/pull/265) Encoding of tree nodes and proofs is now done + using the Go stdlib and Protobuf instead of Amino. The binary encoding is identical. + +### Bug Fixes + +- [\#309](https://github.com/cosmos/iavl/pull/309) Allow `SaveVersion()` for old, empty versions as + long as the new version is identical. + +## 0.14.3 (November 23, 2020) + +Special thanks to external contributors on this release: @klim0v + +### Bug Fixes + +- [\#324](https://github.com/cosmos/iavl/pull/324) Fix `DeleteVersions` not properly removing + orphans, and add `DeleteVersionsRange` to delete a range. + +## 0.14.2 (October 12, 2020) + +### Bug Fixes + +- [\#318](https://github.com/cosmos/iavl/pull/318) Fix constant overflow when compiling for 32bit machines. + +## 0.14.1 (October 9, 2020) + +### Improvements + +- [\#299](https://github.com/cosmos/iavl/pull/299) Added `Options.InitialVersion` to specify the + initial version for new IAVL trees. + +- [\#312](https://github.com/cosmos/iavl/pull/312) Added `MutableTree.SetInitialVersion()` to + set the initial version after tree initialization. + +### Bug Fixes + +- [\#288](https://github.com/cosmos/iavl/pull/288) Fix panics when generating proofs for keys that are all `0xFF`. + +## 0.14.0 (July 2, 2020) + +**Important information:** the pruning functionality introduced with IAVL 0.13.0 via the options +`KeepEvery` and `KeepRecent` has problems with data corruption, performance, and memory usage. For +these reasons, this functionality has now been removed. All 0.13 users are urged to upgrade, and to +not change their pruning settings while on 0.13. + +Make sure to follow these instructions when upgrading, to avoid data corruption: + +- If using `KeepEvery: 1` (the default) then upgrading to 0.14 is safe. + +- Otherwise, upgrade after saving a multiple of `KeepEvery` - for example, with `KeepEvery: 1000` + stop 0.13 after saving e.g. version `7000` to disk. A later version must never have been saved + to the tree. Upgrading to 0.14 is then safe. + +- Otherwise, consider using the `Repair013Orphans()` function to repair faulty data in databases + last written to by 0.13. This must be done before opening the database with IAVL 0.14, and a + database backup should be taken first. Upgrading to 0.14 is then safe. + +- Otherwise, after upgrading to 0.14, do not delete the last version saved to disk by 0.13 - this + contains incorrect data that may cause data corruption when deleted, making the database + unusable. For example, with `KeepEvery: 1000` then stopping 0.13 at version `7364` (saving + `7000` to disk) and upgrading to 0.14 means version `7000` must never be deleted. + + It may be possible to delete it if the exact same sequence of changes have been written to the + newer versions as before the upgrade, and all versions between `7000` and `7364` are deleted + first, but thorough testing and backups are recommended if attempting this. + +Users wishing to prune historical versions can do so via `MutableTree.DeleteVersion()`. + +### Breaking Changes + +- [\#274](https://github.com/cosmos/iavl/pull/274) Remove pruning options `KeepEvery` and + `KeepRecent` (see warning above) and the `recentDB` parameter to `NewMutableTreeWithOpts()`. + +### Improvements + +- [\#282](https://github.com/cosmos/iavl/pull/282) Add `Repair013Orphans()` to repair faulty + orphans in a database last written to by IAVL 0.13.x + +- [\#271](https://github.com/cosmos/iavl/pull/271) Add `MutableTree.DeleteVersions()` for deleting + multiple versions. + +- [\#235](https://github.com/cosmos/iavl/pull/235) Reduce `ImmutableTree.Export()` buffer size from + 64 to 32 nodes. + +### Bug Fixes + +- [\#281](https://github.com/cosmos/iavl/pull/281) Remove unnecessary Protobuf dependencies. + +- [\#275](https://github.com/cosmos/iavl/pull/275) Fix data corruption with + `LoadVersionForOverwriting`. + +## 0.13.3 (April 5, 2020) + +### Bug Fixes + +- [import][\#230](https://github.com/tendermint/iavl/pull/230) Set correct version when committing an empty import. + +## 0.13.2 (March 18, 2020) + +### Improvements + +- [\#213] Added `ImmutableTree.Export()` and `MutableTree.Import()` to export tree contents at a specific version and import it to recreate an identical tree. + +## 0.13.1 (March 13, 2020) + +### Improvements + +- [dep][\#220](https://github.com/tendermint/iavl/pull/220) Update tm-db to 0.5.0, which includes a new B-tree based MemDB used by IAVL for non-persisted versions. + +### Bug Fixes + +- [nodedb][\#219](https://github.com/tendermint/iavl/pull/219) Fix a concurrent database access issue when deleting orphans. + +## 0.13.0 (January 16, 2020) + +Special thanks to external contributors on this release: +@rickyyangz, @mattkanwisher + +### BREAKING CHANGES + +- [pruning][\#158](https://github.com/tendermint/iavl/pull/158) NodeDB constructor must provide `keepRecent` and `keepEvery` fields to define PruningStrategy. All Save functionality must specify whether they should flushToDisk as well using `flushToDisk` boolean argument. All Delete functionality must specify whether object should be deleted from memory only using the `memOnly` boolean argument. +- [dep][\#194](https://github.com/tendermint/iavl/pull/194) Update tm-db to 0.4.0 this includes interface breaking to return errors. + +### IMPROVEMENTS + +### Bug Fix + +- [orphans][#177](https://github.com/tendermint/iavl/pull/177) Collect all orphans after remove (@rickyyangz) + +## 0.12.4 (July 31, 2019) + +### IMPROVEMENTS + +- [\#46](https://github.com/tendermint/iavl/issues/46) Removed all instances of cmn (tendermint/tendermint/libs/common) + +## 0.12.3 (July 12, 2019) + +Special thanks to external contributors on this release: +@ethanfrey + +IMPROVEMENTS + +- Implement LazyLoadVersion (@alexanderbez) + LazyLoadVersion attempts to lazy load only the specified target version + without loading previous roots/versions. - see [goDoc](https://godoc.org/github.com/tendermint/iavl#MutableTree.LazyLoadVersion) +- Move to go.mod (@Liamsi) +- `iaviewer` command to visualize IAVL database from leveldb (@ethanfrey) + +## 0.12.2 (March 13, 2019) + +IMPROVEMENTS + +- Use Tendermint v0.30.2 and close batch after write (related pull request in Tendermint: https://github.com/tendermint/tendermint/pull/3397) + +## 0.12.1 (February 12, 2019) + +IMPROVEMENTS + +- Use Tendermint v0.30 + +## 0.12.0 (November 26, 2018) + +BREAKING CHANGES + +- Uses new Tendermint ReverseIterator API. See https://github.com/tendermint/tendermint/pull/2913 + +## 0.11.1 (October 29, 2018) + +IMPROVEMENTS + +- Uses GoAmino v0.14 + +## 0.11.0 (September 7, 2018) + +BREAKING CHANGES + +- Changed internal database key format to store int64 key components in a full 8-byte fixed width ([#107]) +- Removed some architecture dependent methods (e.g., use `Get` instead of `Get64` etc) ([#96]) + +IMPROVEMENTS + +- Database key format avoids use of fmt.Sprintf fmt.Sscanf leading to ~10% speedup in benchmark BenchmarkTreeLoadAndDelete ([#107], thanks to [@silasdavis]) + +[#107]: https://github.com/tendermint/iavl/pull/107 +[@silasdavis]: https://github.com/silasdavis +[#96]: https://github.com/tendermint/iavl/pull/96 + +## 0.10.0 + +BREAKING CHANGES + +- refactored API for clean separation of [mutable][1] and [immutable][2] tree (#92, #88); + with possibility to: + - load read-only snapshots at previous versions on demand + - load mutable trees at the most recently saved tree + +[1]: https://github.com/tendermint/iavl/blob/9e62436856efa94c1223043be36ebda01ae0b6fc/mutable_tree.go#L14-L21 +[2]: https://github.com/tendermint/iavl/blob/9e62436856efa94c1223043be36ebda01ae0b6fc/immutable_tree.go#L10-L17 + +BUG FIXES + +- remove memory leaks (#92) + +IMPROVEMENTS + +- Change tendermint dep to ^v0.22.0 (#91) + +## 0.10.0 (July 11, 2018) + +BREAKING CHANGES + +- getRangeProof and Get\[Versioned\]\[Range\]WithProof return nil proof/error if tree is empty. + +## 0.9.2 (July 3, 2018) + +IMPROVEMENTS + +- some minor changes: mainly lints, updated parts of documentation, unexported some helpers (#80) + +## 0.9.1 (July 1, 2018) + +IMPROVEMENTS + +- RangeProof.ComputeRootHash() to compute root rather than provide as in Verify(hash) +- RangeProof.Verify\*() first require .Verify(root), which memoizes + +## 0.9.0 (July 1, 2018) + +BREAKING CHANGES + +- RangeProof.VerifyItem doesn't require an index. +- Only return values in range when getting proof. +- Return keys as well. + +BUG FIXES + +- traversal bugs in traverseRange. + +## 0.8.2 + +- Swap `tmlibs` for `tendermint/libs` +- Remove `sha256truncated` in favour of `tendermint/crypto/tmhash` - same hash + function but technically a breaking change to the API, though unlikely to effect anyone. + +NOTE this means IAVL is now dependent on Tendermint Core for the libs (since it +makes heavy use of the `db` package). Ideally, that dependency would be +abstracted away, and/or this repo will be merged into the Cosmos-SDK, which is +currently is primary consumer. Once it achieves greater stability, we could +consider breaking it out into it's own repo again. + +## 0.8.1 + +_July 1st, 2018_ + +BUG FIXES + +- fix bug in iterator going outside its range + +## 0.8.0 (June 24, 2018) + +BREAKING CHANGES + +- Nodes are encoded using proto3/amino style integers and byte slices (ie. varints and + varint prefixed byte slices) +- Unified RangeProof +- Proofs are encoded using Amino +- Hash function changed from RIPEMD160 to the first 20 bytes of SHA256 output + +## 0.7.0 (March 21, 2018) + +BREAKING CHANGES + +- LoadVersion and Load return the loaded version number + - NOTE: this behaviour was lost previously and we failed to document in changelog, + but now it's back :) + +## 0.6.1 (March 2, 2018) + +IMPROVEMENT + +- Remove spurious print statement from LoadVersion + +## 0.6.0 (March 2, 2018) + +BREAKING CHANGES + +- NewTree order of arguments swapped +- int -> int64, uint64 -> int64 +- NewNode takes a version +- Node serialization format changed so version is written right after size +- SaveVersion takes no args (auto increments) +- tree.Get -> tree.Get64 +- nodeDB.SaveBranch does not take a callback +- orphaningTree.SaveVersion -> SaveAs +- proofInnerNode includes Version +- ReadKeyXxxProof consolidated into ReadKeyProof +- KeyAbsentProof doesn't include Version +- KeyRangeProof.Version -> Versions + +FEATURES + +- Implement chunking algorithm to serialize entire tree + +## 0.5.0 (October 27, 2017) + +First versioned release! +(Originally accidentally released as v0.2.0) diff --git a/sei-iavl/CONTRIBUTING.md b/sei-iavl/CONTRIBUTING.md new file mode 100644 index 0000000000..f63efe6f6a --- /dev/null +++ b/sei-iavl/CONTRIBUTING.md @@ -0,0 +1,12 @@ +# Contributing + +Thank you for considering making contributions to IAVL+! +This repository follows the [contribution guidelines] of tendermint and the corresponding [coding repo]. +Please take a look if you are not already familiar with those. + +[contribution guidelines]: https://github.com/tendermint/tendermint/blob/master/CONTRIBUTING.md +[coding repo]: https://github.com/tendermint/coding + +## Protobuf + +Iavl utilizes [Protocol Buffers](https://developers.google.com/protocol-buffers) if used as a gRPC server. To generate the protobuf stubs have docker running locally and run `make proto-gen` diff --git a/sei-iavl/FORKED_CHANGELOG.md b/sei-iavl/FORKED_CHANGELOG.md new file mode 100644 index 0000000000..3d5cae4cd6 --- /dev/null +++ b/sei-iavl/FORKED_CHANGELOG.md @@ -0,0 +1,22 @@ +Forked from https://github.com/cosmos/iavl/tree/v0.19.4 +Last commit: +``` +commit f4499a9daed0a190a4df8d55950fb5d51c835bc9 (HEAD, tag: v0.19.4) +Author: Marko +Date: Fri Oct 28 00:37:21 2022 +0200 + + chore: changelog for 0.19.4 (#600) +``` + +# Changelog + + +## Current - 2023-01-26 + +### Bug Fixes + + +### Improvements + + +### Features diff --git a/sei-iavl/LICENSE b/sei-iavl/LICENSE new file mode 100644 index 0000000000..084d3f719f --- /dev/null +++ b/sei-iavl/LICENSE @@ -0,0 +1,191 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright Cosmos-IAVL Authors + Copyright 2015 Tendermint + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sei-iavl/Makefile b/sei-iavl/Makefile new file mode 100644 index 0000000000..0364b73506 --- /dev/null +++ b/sei-iavl/Makefile @@ -0,0 +1,131 @@ +GOTOOLS := github.com/golangci/golangci-lint/cmd/golangci-lint +VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//') +COMMIT := $(shell git log -1 --format='%H') +BRANCH=$(shell git rev-parse --abbrev-ref HEAD) +DOCKER_BUF := docker run -v $(shell pwd):/workspace --workdir /workspace bufbuild/buf +DOCKER := $(shell which docker) +HTTPS_GIT := https://github.com/cosmos/iavl.git + +PDFFLAGS := -pdf --nodefraction=0.1 +CMDFLAGS := -ldflags -X TENDERMINT_IAVL_COLORS_ON=on +LDFLAGS := -ldflags "-X github.com/cosmos/iavl.Version=$(VERSION) -X github.com/cosmos/iavl.Commit=$(COMMIT) -X github.com/cosmos/iavl.Branch=$(BRANCH)" + +all: lint test install + +install: +ifeq ($(COLORS_ON),) + go install ./cmd/iaviewer + go install ./cmd/iavlserver +else + go install $(CMDFLAGS) ./cmd/iaviewer + go install $(CMDFLAGS) ./cmd/iavlserver +endif +.PHONY: install + +test-short: + @echo "--> Running go test" + @go test ./... $(LDFLAGS) -v --race --short +.PHONY: test-short + +test: + @echo "--> Running go test" + @go test ./... $(LDFLAGS) -v +.PHONY: test + +tools: + go get -v $(GOTOOLS) +.PHONY: tools + +format: + find . -name '*.go' -type f -not -path "*.git*" -not -name '*.pb.go' -not -name '*pb_test.go' | xargs gofmt -w -s + find . -name '*.go' -type f -not -path "*.git*" -not -name '*.pb.go' -not -name '*pb_test.go' | xargs goimports -format +.PHONY: format + +# look into .golangci.yml for enabling / disabling linters +lint: + @echo "--> Running linter" + @golangci-lint run + @go mod verify +.PHONY: lint + +# bench is the basic tests that shouldn't crash an aws instance +bench: + cd benchmarks && \ + go test $(LDFLAGS) -tags cleveldb,rocksdb,boltdb,badgerdb -run=NOTEST -bench=Small . && \ + go test $(LDFLAGS) -tags cleveldb,rocksdb,boltdb,badgerdb -run=NOTEST -bench=Medium . && \ + go test $(LDFLAGS) -run=NOTEST -bench=RandomBytes . +.PHONY: bench + +# fullbench is extra tests needing lots of memory and to run locally +fullbench: + cd benchmarks && \ + go test $(LDFLAGS) -run=NOTEST -bench=RandomBytes . && \ + go test $(LDFLAGS) -tags cleveldb,rocksdb,boltdb,badgerdb -run=NOTEST -bench=Small . && \ + go test $(LDFLAGS) -tags cleveldb,rocksdb,boltdb,badgerdb -run=NOTEST -bench=Medium . && \ + go test $(LDFLAGS) -tags cleveldb,rocksdb,boltdb,badgerdb -run=NOTEST -timeout=30m -bench=Large . && \ + go test $(LDFLAGS) -run=NOTEST -bench=Mem . && \ + go test $(LDFLAGS) -run=NOTEST -timeout=60m -bench=LevelDB . +.PHONY: fullbench + +# note that this just profiles the in-memory version, not persistence +profile: + cd benchmarks && \ + go test $(LDFLAGS) -bench=Mem -cpuprofile=cpu.out -memprofile=mem.out . && \ + go tool pprof ${PDFFLAGS} benchmarks.test cpu.out > cpu.pdf && \ + go tool pprof --alloc_space ${PDFFLAGS} benchmarks.test mem.out > mem_space.pdf && \ + go tool pprof --alloc_objects ${PDFFLAGS} benchmarks.test mem.out > mem_obj.pdf +.PHONY: profile + +explorecpu: + cd benchmarks && \ + go tool pprof benchmarks.test cpu.out +.PHONY: explorecpu + +exploremem: + cd benchmarks && \ + go tool pprof --alloc_objects benchmarks.test mem.out +.PHONY: exploremem + +delve: + dlv test ./benchmarks -- -test.bench=. +.PHONY: delve + +all: tools +.PHONY: all + +tools: protobuf +.PHONY: tools + +check: check_tools +.PHONY: check + +check_tools: + @# https://stackoverflow.com/a/25668869 + @echo "Found tools: $(foreach tool,$(notdir $(GOTOOLS)),\ + $(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))" +.PHONY: check_tools + +tools-clean: + rm -f $(CERTSTRAP) $(PROTOBUF) $(GOX) $(GOODMAN) + rm -rf /usr/local/include/google/protobuf + rm -f /usr/local/bin/protoc +.PHONY: tooks-clean + +### +# Non Go tools +### + +.PHONY: lint test tools install delve exploremem explorecpu profile fullbench bench proto-gen proto-lint proto-check-breaking + +proto-lint: + @$(DOCKER_BUF) check lint --error-format=json +.PHONY: proto-lint + +proto-check-breaking: + @$(DOCKER_BUF) check breaking --against-input $(HTTPS_GIT)#branch=master +.PHONY: proto-check-breaking + +proto-gen: + @echo "Generating Protobuf files" + $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen:master sh scripts/protocgen.sh +.PHONY: proto-gen-d diff --git a/sei-iavl/PERFORMANCE.md b/sei-iavl/PERFORMANCE.md new file mode 100644 index 0000000000..b1acdd932b --- /dev/null +++ b/sei-iavl/PERFORMANCE.md @@ -0,0 +1,111 @@ +# Performance + +After some discussion with Jae on the usability, it seems performance is a big concern. If every write takes around 1ms, that puts a serious upper limit on the speed of the consensus engine (especially since with the check/tx dichotomy, we need at least two writes (to cache, only one to disk) and likely two or more queries to handle any transaction). + +As Jae notes: for CheckTx, a copy of IAVLTree doesn't need to be saved. During CheckTx it'll load inner nodes into the cache. The cache is shared w/ the AppendTx state IAVLTree, so during AppendTx we should save some time. There would only be 1 set of writes. Also, there's quite a bit of free time in between blocks as provided by Tendermint, during which CheckTx can run priming the cache, so hopefully this helps as well. + +Jae: That said, I'm not sure exactly what the tx throughput would be during normal running times. I'm hoping that we can have e.g. 3 second blocks w/ say over a hundred txs per sec per block w/ 1 million items. That will get us through for some time, but that time is limited. + +Ethan: I agree, and think this works now with goleveldb backing on most host machines. For public chains, maybe it is desired to push 1000 tx every 3 sec to a block, with a db size of 1 billion items. 10x the throughput with 1000x the data. That could be a long-term goal, and would scale to the cosmos and beyond. + +## Plan + +For any goal, we need some clear steps. + +1) Cleanup code, and write some more benchmark cases to capture "realistic" usage +2) Run tests on various hardware to see the best performing backing stores +3) Do profiling on the best performance to see if there are any easy performance gains +4) (Possibly) Write another implementation of merkle.Tree to improve all the memory overhead, consider CPU cache, etc.... +5) (Possibly) Write another backend datastore to persist the tree in a more efficient way + +The rest of this document is the planned or completed actions for the above-listed steps. + +## Cleanup + +Done in branch `cleanup_deps`: + * Fixed up dependeny management (tmlibs/db etc in glide/vendor) + * Updated Makefile (test, bench, get_deps) + * Fixed broken code - `looper.go` and one benchmark didn't run + +Benchmarks should be parameterized on: + 1) storage implementation + 2) initial data size + 3) length of keys + 4) length of data + 5) block size (frequency of copy/hash...) +Thus, we would see the same benchmark run against memdb with 100K items, goleveldb with 100K, leveldb with 100K, memdb with 10K, goleveldb with 10K... + +Scenarios to run after db is set up. + * Pure query time (known/hits, vs. random/misses) + * Write timing (known/updates, vs. random/inserts) + * Delete timing (existing keys only) + * TMSP Usage: + * For each block size: + * 2x copy "last commit" -> check and real + * repeat for each tx: + * (50% update + 50% insert?) + * query + insert/update in check + * query + insert/update in real + * get hash + * save real + * real -> "last commit" + + +## Benchmarks + +After writing the benchmarks, we can run them under various environments and store the results under benchmarks directory. Some useful environments to test: + + * Dev machines + * Digital ocean small/large machine + * Various AWS setups + +Please run the benchmark on more machines and add the result. Just type: `make record` in the directory and wait a (long) while (with little other load on the machine). + +This will require also a quick setup script to install go and run tests in these environments. Maybe some scripts even. Also, this will produce a lot of files and we may have to graph them to see something useful... + +But for starting, my laptop, and one digital ocean and one aws server should be sufficient. At least to find the winner, before profiling. + + +## Profiling + +Once we figure out which current implementation looks fastest, let's profile it to make it even faster. It is great to optimize the memdb code to really speed up the hashing and tree-building logic. And then focus on the backend implementation to optimize the disk storage, which will be the next major pain point. + +Some guides: + + * [Profiling benchmarks locally](https://medium.com/@hackintoshrao/daily-code-optimization-using-benchmarks-and-profiling-in-golang-gophercon-india-2016-talk-874c8b4dc3c5#.jmnd8w2qr) + * [On optimizing memory](https://signalfx.com/blog/a-pattern-for-optimizing-go-2/) + * [Profiling running programs](http://blog.ralch.com/tutorial/golang-performance-and-memory-analysis/) + * [Dave Chenny's profiler pkg](https://github.com/pkg/profile) + +Some ideas for speedups: + + * [Speedup SHA256 100x on ARM](https://blog.minio.io/accelerating-sha256-by-100x-in-golang-on-arm-1517225f5ff4#.pybt7bb3w) + * [Faster SHA256 golang implementation](https://github.com/minio/sha256-simd) + * [Data structure alignment](http://stackoverflow.com/questions/39063530/optimising-datastructure-word-alignment-padding-in-golang) + * [Slice alignment](http://blog.chewxy.com/2016/07/25/on-the-memory-alignment-of-go-slice-values/) + * [Tool to analyze your structs](https://github.com/dominikh/go-structlayout) + +## Tree Re-implementation + +If we want to copy lots of objects, it becomes better to think of using memcpy on large (eg. 4-16KB) buffers than copying individual structs. We also could allocate arrays of structs and align them to remove a lot of memory management and gc overhead. That means going down to some C-level coding... + +Some links for thought: + + * [Array representation of a binary tree](http://www.cse.hut.fi/en/research/SVG/TRAKLA2/tutorials/heap_tutorial/taulukkona.html) + * [Memcpy buffer size timing](http://stackoverflow.com/questions/21038965/why-does-the-speed-of-memcpy-drop-dramatically-every-4kb) + * [Calling memcpy from go](https://github.com/jsgilmore/shm/blob/master/memcpy.go) + * [Unsafe docs](https://godoc.org/unsafe) + * [...and how to use it](https://copyninja.info/blog/workaround-gotypesystems.html) + * [Or maybe just plain copy...](https://godoc.org/builtin#copy) + +## Backend implementation + +Storing each link in the tree in leveldb treats each node as an isolated item. Since we know some usage patterns (when a parent is hit, very likely one child will be hit), we could try to organize the memory and disk location of the nodes ourselves to make it more efficient. Or course, this could be a long, slippery slope. + +Inspired by the [Array representation](http://www.cse.hut.fi/en/research/SVG/TRAKLA2/tutorials/heap_tutorial/taulukkona.html) link above, we could consider other layouts for the nodes. For example, rather than store them alone, or the entire tree in one big array, the nodes could be placed in groups of 15 based on the parent (parent and 3 generations of children). Then we have 4 levels before jumping to another location. Maybe we just store this larger chunk as one leveldb location, or really try to do the mmap ourselves... + +In any case, assuming around 100 bytes for one non-leaf node (3 sha hashes, plus prefix, plus other data), 15 nodes would be a little less than 2K, maybe even go one more level to 31 nodes and 3-4KB, where we could take best advantage of the memory/disk page size. + +Some links for thought: + + * [Memory mapped files](https://github.com/edsrzf/mmap-go) diff --git a/sei-iavl/POEM b/sei-iavl/POEM new file mode 100644 index 0000000000..f361067a4d --- /dev/null +++ b/sei-iavl/POEM @@ -0,0 +1,29 @@ +writing down, my checksum +waiting for the, data to come +no need to pray for integrity +thats cuz I use, a merkle tree + +grab the root, with a quick hash run +if the hash works out, +it must have been done + +theres no need, for trust to arise +thanks to the crypto +now that I can merkleyes + +take that data, merklize +ye, I merklize ... + +then the truth, begins to shine +the inverse of a hash, you will never find +and as I watch, the dataset grow +producing a proof, is never slow + +Where do I find, the will to hash +How do I teach it? +It doesn't pay in cash +Bitcoin, here, I've realized +Thats what I need now, +cuz real currencies merklize + +-EB diff --git a/sei-iavl/README.md b/sei-iavl/README.md new file mode 100644 index 0000000000..557f8c65cc --- /dev/null +++ b/sei-iavl/README.md @@ -0,0 +1,22 @@ +# IAVL+ Tree + + +[![version](https://img.shields.io/github/tag/cosmos/iavl.svg)](https://github.com/cosmos/iavl/releases/latest) +[![license](https://img.shields.io/github/license/cosmos/iavl.svg)](https://github.com/cosmos/iavl/blob/master/LICENSE) +[![API Reference](https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667)](https://pkg.go.dev/github.com/cosmos/iavl) +[![codecov](https://codecov.io/gh/cosmos/iavl/branch/master/graph/badge.svg)](https://codecov.io/gh/cosmos/iavl) +![Lint](https://github.com/cosmos/iavl/workflows/Lint/badge.svg?branch=master) +![Test](https://github.com/cosmos/iavl/workflows/Test/badge.svg?branch=master) +[![Discord chat](https://img.shields.io/discord/669268347736686612.svg)](https://discord.gg/AzefAFd) + +**Note: Requires Go 1.17+** + +A versioned, snapshottable (immutable) AVL+ tree for persistent data. + +The purpose of this data structure is to provide persistent storage for key-value pairs (say to store account balances) such that a deterministic merkle root hash can be computed. The tree is balanced using a variant of the [AVL algorithm](http://en.wikipedia.org/wiki/AVL_tree) so all operations are O(log(n)). + +Nodes of this tree are immutable and indexed by their hash. Thus any node serves as an immutable snapshot which lets us stage uncommitted transactions from the mempool cheaply, and we can instantly roll back to the last committed state to process transactions of a newly committed block (which may not be the same set of transactions as those from the mempool). + +In an AVL tree, the heights of the two child subtrees of any node differ by at most one. Whenever this condition is violated upon an update, the tree is rebalanced by creating O(log(n)) new nodes that point to unmodified nodes of the old tree. In the original AVL algorithm, inner nodes can also hold key-value pairs. The AVL+ algorithm (note the plus) modifies the AVL algorithm to keep all values on leaf nodes, while only using branch-nodes to store keys. This simplifies the algorithm while keeping the merkle hash trail short. + +In Ethereum, the analog is [Patricia tries](http://en.wikipedia.org/wiki/Radix_tree). There are tradeoffs. Keys do not need to be hashed prior to insertion in IAVL+ trees, so this provides faster iteration in the key space which may benefit some applications. The logic is simpler to implement, requiring only two types of nodes -- inner nodes and leaf nodes. On the other hand, while IAVL+ trees provide a deterministic merkle root hash, it depends on the order of transactions. In practice this shouldn't be a problem, since you can efficiently encode the tree structure when serializing the tree contents. diff --git a/sei-iavl/basic_test.go b/sei-iavl/basic_test.go new file mode 100644 index 0000000000..13996c7dd4 --- /dev/null +++ b/sei-iavl/basic_test.go @@ -0,0 +1,577 @@ +// nolint: errcheck +package iavl + +import ( + "bytes" + "encoding/hex" + mrand "math/rand" + "sort" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + db "github.com/tendermint/tm-db" +) + +func TestBasic(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + up, err := tree.Set([]byte("1"), []byte("one")) + require.NoError(t, err) + if up { + t.Error("Did not expect an update (should have been create)") + } + up, err = tree.Set([]byte("2"), []byte("two")) + require.NoError(t, err) + if up { + t.Error("Did not expect an update (should have been create)") + } + up, err = tree.Set([]byte("2"), []byte("TWO")) + require.NoError(t, err) + if !up { + t.Error("Expected an update") + } + up, err = tree.Set([]byte("5"), []byte("five")) + require.NoError(t, err) + if up { + t.Error("Did not expect an update (should have been create)") + } + + // Test 0x00 + { + key := []byte{0x00} + expected := "" + + idx, val, err := tree.GetWithIndex(key) + require.NoError(t, err) + if val != nil { + t.Error("Expected no value to exist") + } + if idx != 0 { + t.Errorf("Unexpected idx %x", idx) + } + if string(val) != expected { + t.Errorf("Unexpected value %s", val) + } + + val, err = tree.Get(key) + if val != nil { + t.Error("Fast method - expected no value to exist") + } + if string(val) != expected { + t.Errorf("Fast method - Unexpected value %s", val) + } + } + + // Test "1" + { + key := []byte("1") + expected := "one" + + idx, val, err := tree.GetWithIndex(key) + require.NoError(t, err) + if val == nil { + t.Error("Expected value to exist") + } + if idx != 0 { + t.Errorf("Unexpected idx %x", idx) + } + if string(val) != expected { + t.Errorf("Unexpected value %s", val) + } + + val, err = tree.Get(key) + require.NoError(t, err) + if val == nil { + t.Error("Fast method - expected value to exist") + } + if string(val) != expected { + t.Errorf("Fast method - Unexpected value %s", val) + } + } + + // Test "2" + { + key := []byte("2") + expected := "TWO" + + idx, val, err := tree.GetWithIndex(key) + require.NoError(t, err) + if val == nil { + t.Error("Expected value to exist") + } + if idx != 1 { + t.Errorf("Unexpected idx %x", idx) + } + if string(val) != expected { + t.Errorf("Unexpected value %s", val) + } + + val, err = tree.Get(key) + if val == nil { + t.Error("Fast method - expected value to exist") + } + if string(val) != expected { + t.Errorf("Fast method - Unexpected value %s", val) + } + } + + // Test "4" + { + key := []byte("4") + expected := "" + + idx, val, err := tree.GetWithIndex(key) + require.NoError(t, err) + if val != nil { + t.Error("Expected no value to exist") + } + if idx != 2 { + t.Errorf("Unexpected idx %x", idx) + } + if string(val) != expected { + t.Errorf("Unexpected value %s", val) + } + + val, err = tree.Get(key) + if val != nil { + t.Error("Fast method - expected no value to exist") + } + if string(val) != expected { + t.Errorf("Fast method - Unexpected value %s", val) + } + } + + // Test "6" + { + key := []byte("6") + expected := "" + + idx, val, err := tree.GetWithIndex(key) + require.NoError(t, err) + if val != nil { + t.Error("Expected no value to exist") + } + if idx != 3 { + t.Errorf("Unexpected idx %x", idx) + } + if string(val) != expected { + t.Errorf("Unexpected value %s", val) + } + + val, err = tree.Get(key) + if val != nil { + t.Error("Fast method - expected no value to exist") + } + if string(val) != expected { + t.Errorf("Fast method - Unexpected value %s", val) + } + } +} + +func TestUnit(t *testing.T) { + + expectHash := func(tree *ImmutableTree, hashCount int64) { + // ensure number of new hash calculations is as expected. + hash, count, err := tree.root.hashWithCount() + require.NoError(t, err) + if count != hashCount { + t.Fatalf("Expected %v new hashes, got %v", hashCount, count) + } + // nuke hashes and reconstruct hash, ensure it's the same. + tree.root.traverse(tree, true, func(node *Node) bool { + node.hash = nil + return false + }) + // ensure that the new hash after nuking is the same as the old. + newHash, _, err := tree.root.hashWithCount() + require.NoError(t, err) + if !bytes.Equal(hash, newHash) { + t.Fatalf("Expected hash %v but got %v after nuking", hash, newHash) + } + } + + expectSet := func(tree *MutableTree, i int, repr string, hashCount int64) { + origNode := tree.root + updated, err := tree.Set(i2b(i), []byte{}) + require.NoError(t, err) + // ensure node was added & structure is as expected. + if updated || P(tree.root) != repr { + t.Fatalf("Adding %v to %v:\nExpected %v\nUnexpectedly got %v updated:%v", + i, P(origNode), repr, P(tree.root), updated) + } + // ensure hash calculation requirements + expectHash(tree.ImmutableTree, hashCount) + tree.root = origNode + } + + expectRemove := func(tree *MutableTree, i int, repr string, hashCount int64) { + origNode := tree.root + value, removed, err := tree.Remove(i2b(i)) + require.NoError(t, err) + // ensure node was added & structure is as expected. + if len(value) != 0 || !removed || P(tree.root) != repr { + t.Fatalf("Removing %v from %v:\nExpected %v\nUnexpectedly got %v value:%v removed:%v", + i, P(origNode), repr, P(tree.root), value, removed) + } + // ensure hash calculation requirements + expectHash(tree.ImmutableTree, hashCount) + tree.root = origNode + } + + // Test Set cases: + + // Case 1: + t1, err := T(N(4, 20)) + + require.NoError(t, err) + expectSet(t1, 8, "((4 8) 20)", 3) + expectSet(t1, 25, "(4 (20 25))", 3) + + t2, err := T(N(4, N(20, 25))) + + require.NoError(t, err) + expectSet(t2, 8, "((4 8) (20 25))", 3) + expectSet(t2, 30, "((4 20) (25 30))", 4) + + t3, err := T(N(N(1, 2), 6)) + + require.NoError(t, err) + expectSet(t3, 4, "((1 2) (4 6))", 4) + expectSet(t3, 8, "((1 2) (6 8))", 3) + + t4, err := T(N(N(1, 2), N(N(5, 6), N(7, 9)))) + + require.NoError(t, err) + expectSet(t4, 8, "(((1 2) (5 6)) ((7 8) 9))", 5) + expectSet(t4, 10, "(((1 2) (5 6)) (7 (9 10)))", 5) + + // Test Remove cases: + + t10, err := T(N(N(1, 2), 3)) + + require.NoError(t, err) + expectRemove(t10, 2, "(1 3)", 1) + expectRemove(t10, 3, "(1 2)", 0) + + t11, err := T(N(N(N(1, 2), 3), N(4, 5))) + + require.NoError(t, err) + expectRemove(t11, 4, "((1 2) (3 5))", 2) + expectRemove(t11, 3, "((1 2) (4 5))", 1) + +} + +func TestRemove(t *testing.T) { + keyLen, dataLen := 16, 40 + + size := 10000 + t1, err := getTestTree(size) + require.NoError(t, err) + + // insert a bunch of random nodes + keys := make([][]byte, size) + l := int32(len(keys)) + for i := 0; i < size; i++ { + key := randBytes(keyLen) + t1.Set(key, randBytes(dataLen)) + keys[i] = key + } + + for i := 0; i < 10; i++ { + step := 50 * i + // remove a bunch of existing keys (may have been deleted twice) + for j := 0; j < step; j++ { + key := keys[mrand.Int31n(l)] + t1.Remove(key) + } + t1.SaveVersion() + } +} + +func TestIntegration(t *testing.T) { + + type record struct { + key string + value string + } + + records := make([]*record, 400) + tree, err := getTestTree(0) + require.NoError(t, err) + + randomRecord := func() *record { + return &record{randstr(20), randstr(20)} + } + + for i := range records { + r := randomRecord() + records[i] = r + updated, err := tree.Set([]byte(r.key), []byte{}) + require.NoError(t, err) + if updated { + t.Error("should have not been updated") + } + updated, err = tree.Set([]byte(r.key), []byte(r.value)) + require.NoError(t, err) + if !updated { + t.Error("should have been updated") + } + if tree.Size() != int64(i+1) { + t.Error("size was wrong", tree.Size(), i+1) + } + } + + for _, r := range records { + has, err := tree.Has([]byte(r.key)) + require.NoError(t, err) + if !has { + t.Error("Missing key", r.key) + } + + has, err = tree.Has([]byte(randstr(12))) + require.NoError(t, err) + if has { + t.Error("Table has extra key") + } + + val, err := tree.Get([]byte(r.key)) + require.NoError(t, err) + if string(val) != r.value { + t.Error("wrong value") + } + } + + for i, x := range records { + if val, removed, err := tree.Remove([]byte(x.key)); err != nil { + require.NoError(t, err) + } else if !removed { + t.Error("Wasn't removed") + } else if string(val) != x.value { + t.Error("Wrong value") + } + require.NoError(t, err) + for _, r := range records[i+1:] { + has, err := tree.Has([]byte(r.key)) + require.NoError(t, err) + if !has { + t.Error("Missing key", r.key) + } + + has, err = tree.Has([]byte(randstr(12))) + require.NoError(t, err) + if has { + t.Error("Table has extra key") + } + + val, err := tree.Get([]byte(r.key)) + require.NoError(t, err) + if string(val) != r.value { + t.Error("wrong value") + } + } + if tree.Size() != int64(len(records)-(i+1)) { + t.Error("size was wrong", tree.Size(), (len(records) - (i + 1))) + } + } +} + +func TestIterateRange(t *testing.T) { + type record struct { + key string + value string + } + + records := []record{ + {"abc", "123"}, + {"low", "high"}, + {"fan", "456"}, + {"foo", "a"}, + {"foobaz", "c"}, + {"good", "bye"}, + {"foobang", "d"}, + {"foobar", "b"}, + {"food", "e"}, + {"foml", "f"}, + } + keys := make([]string, len(records)) + for i, r := range records { + keys[i] = r.key + } + sort.Strings(keys) + + tree, err := getTestTree(0) + require.NoError(t, err) + + // insert all the data + for _, r := range records { + updated, err := tree.Set([]byte(r.key), []byte(r.value)) + require.NoError(t, err) + if updated { + t.Error("should have not been updated") + } + } + // test traversing the whole node works... in order + viewed := []string{} + tree.Iterate(func(key []byte, value []byte) bool { + viewed = append(viewed, string(key)) + return false + }) + if len(viewed) != len(keys) { + t.Error("not the same number of keys as expected") + } + for i, v := range viewed { + if v != keys[i] { + t.Error("Keys out of order", v, keys[i]) + } + } + + trav := traverser{} + tree.IterateRange([]byte("foo"), []byte("goo"), true, trav.view) + expectTraverse(t, trav, "foo", "food", 5) + + trav = traverser{} + tree.IterateRange([]byte("aaa"), []byte("abb"), true, trav.view) + expectTraverse(t, trav, "", "", 0) + + trav = traverser{} + tree.IterateRange(nil, []byte("flap"), true, trav.view) + expectTraverse(t, trav, "abc", "fan", 2) + + trav = traverser{} + tree.IterateRange([]byte("foob"), nil, true, trav.view) + expectTraverse(t, trav, "foobang", "low", 6) + + trav = traverser{} + tree.IterateRange([]byte("very"), nil, true, trav.view) + expectTraverse(t, trav, "", "", 0) + + // make sure it doesn't include end + trav = traverser{} + tree.IterateRange([]byte("fooba"), []byte("food"), true, trav.view) + expectTraverse(t, trav, "foobang", "foobaz", 3) + + // make sure backwards also works... (doesn't include end) + trav = traverser{} + tree.IterateRange([]byte("fooba"), []byte("food"), false, trav.view) + expectTraverse(t, trav, "foobaz", "foobang", 3) + + // make sure backwards also works... + trav = traverser{} + tree.IterateRange([]byte("g"), nil, false, trav.view) + expectTraverse(t, trav, "low", "good", 2) +} + +func TestPersistence(t *testing.T) { + db := db.NewMemDB() + + // Create some random key value pairs + records := make(map[string]string) + for i := 0; i < 10000; i++ { + records[randstr(20)] = randstr(20) + } + + // Construct some tree and save it + t1, err := NewMutableTree(db, 0, false) + require.NoError(t, err) + for key, value := range records { + t1.Set([]byte(key), []byte(value)) + } + t1.SaveVersion() + + // Load a tree + t2, err := NewMutableTree(db, 0, false) + require.NoError(t, err) + t2.Load() + for key, value := range records { + t2value, err := t2.Get([]byte(key)) + require.NoError(t, err) + if string(t2value) != value { + t.Fatalf("Invalid value. Expected %v, got %v", value, t2value) + } + } +} + +func TestProof(t *testing.T) { + + // Construct some random tree + tree, err := getTestTree(100) + require.NoError(t, err) + for i := 0; i < 10; i++ { + key, value := randstr(20), randstr(20) + tree.Set([]byte(key), []byte(value)) + } + + // Persist the items so far + tree.SaveVersion() + + // Add more items so it's not all persisted + for i := 0; i < 10; i++ { + key, value := randstr(20), randstr(20) + tree.Set([]byte(key), []byte(value)) + } + + // Now for each item, construct a proof and verify + tree.Iterate(func(key []byte, value []byte) bool { + value2, proof, err := tree.GetWithProof(key) + assert.NoError(t, err) + assert.Equal(t, value, value2) + if assert.NotNil(t, proof) { + hash, err := tree.WorkingHash() + require.NoError(t, err) + verifyProof(t, proof, hash) + } + return false + }) +} + +func TestTreeProof(t *testing.T) { + db := db.NewMemDB() + tree, err := NewMutableTree(db, 100, false) + require.NoError(t, err) + hash, err := tree.Hash() + require.NoError(t, err) + assert.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) + + // should get false for proof with nil root + value, proof, err := tree.GetWithProof([]byte("foo")) + assert.Nil(t, value) + assert.Nil(t, proof) + assert.Error(t, proof.Verify([]byte(nil))) + assert.NoError(t, err) + + // insert lots of info and store the bytes + keys := make([][]byte, 200) + for i := 0; i < 200; i++ { + key := randstr(20) + tree.Set([]byte(key), []byte(key)) + keys[i] = []byte(key) + } + + tree.SaveVersion() + + // query random key fails + value, proof, err = tree.GetWithProof([]byte("foo")) + assert.Nil(t, value) + assert.NotNil(t, proof) + assert.NoError(t, err) + hash, err = tree.Hash() + assert.NoError(t, err) + assert.NoError(t, proof.Verify(hash)) + assert.NoError(t, proof.VerifyAbsence([]byte("foo"))) + + // valid proof for real keys + root, err := tree.WorkingHash() + assert.NoError(t, err) + for _, key := range keys { + value, proof, err := tree.GetWithProof(key) + if assert.NoError(t, err) { + require.Nil(t, err, "Failed to read proof from bytes: %v", err) + assert.Equal(t, key, value) + err := proof.Verify(root) + assert.NoError(t, err, "#### %v", proof.String()) + err = proof.VerifyItem(key, key) + assert.NoError(t, err, "#### %v", proof.String()) + } + } +} diff --git a/sei-iavl/benchmarks/README.md b/sei-iavl/benchmarks/README.md new file mode 100644 index 0000000000..cfac7b9982 --- /dev/null +++ b/sei-iavl/benchmarks/README.md @@ -0,0 +1,55 @@ +# Running Benchmarks + +These instructions are mainly for running the benchmarks on an cloud instance that is intended to be thrown away, not on a dev machine. Be careful with the install scripts locally. + +This has only been tested on Ubuntu 16.04 and 18.04. It *should* work on Ubuntu 14.04 as well. It *may* work on Debian, but has never been tested. + + +## Setting up the machine + +Put the files on the machine and login (all code assumes you are in this directory locally) + +``` +scp -r setup user@host: +ssh user@host +``` + +Run the install script (once per machine) + +``` +cd setup +chmod +x * +sudo ./INSTALL_ROOT.sh +``` + +## Running the tests + +Run the benchmarks in a screen: + +``` +screen +./RUN_BENCHMARKS.sh +``` + +Copy them back from your local machine: + +``` +scp user@host:go/src/github.com/cosmos/iavl/results.txt results.txt +git add results +``` + +## Running benchmarks with docker + +Run the command below to install leveldb and rocksdb from source then run the benchmarks all the dbs (memdb, goleveldb, rocksdb, badgerdb) except boltdb. + +replace: +- `baabeetaa` with your repo username and +- `fix-bencharks` with your branch. + +``` +docker run --rm -it ubuntu:16.04 /bin/bash -c \ +"apt-get update && apt-get install -y curl && \ +sh <(curl -s https://raw.githubusercontent.com/baabeetaa/iavl/fix-bencharks/benchmarks/setup/INSTALL_ROOT.sh) && \ +sh <(curl -s https://raw.githubusercontent.com/baabeetaa/iavl/fix-bencharks/benchmarks/setup/RUN_BENCHMARKS.sh) fix-bencharks baabeetaa && \ +cat ~/iavl/results.txt" +``` diff --git a/sei-iavl/benchmarks/bench_test.go b/sei-iavl/benchmarks/bench_test.go new file mode 100644 index 0000000000..f845c02d4f --- /dev/null +++ b/sei-iavl/benchmarks/bench_test.go @@ -0,0 +1,429 @@ +package benchmarks + +import ( + "fmt" + "math/rand" + "os" + "runtime" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/iavl" + db "github.com/tendermint/tm-db" +) + +const historySize = 20 + +func randBytes(length int) []byte { + key := make([]byte, length) + // math.rand.Read always returns err=nil + // we do not need cryptographic randomness for this test: + rand.Read(key) + return key +} + +func prepareTree(b *testing.B, db db.DB, size, keyLen, dataLen int) (*iavl.MutableTree, [][]byte) { + t, err := iavl.NewMutableTreeWithOpts(db, size, nil, false) + require.NoError(b, err) + keys := make([][]byte, size) + + for i := 0; i < size; i++ { + key := randBytes(keyLen) + t.Set(key, randBytes(dataLen)) + keys[i] = key + } + commitTree(b, t) + runtime.GC() + return t, keys +} + +// commit tree saves a new version and deletes old ones according to historySize +func commitTree(b *testing.B, t *iavl.MutableTree) { + t.Hash() + + _, version, err := t.SaveVersion() + + if err != nil { + b.Errorf("Can't save: %v", err) + } + + if version > historySize { + err = t.DeleteVersion(version - historySize) + if err != nil { + b.Errorf("Can't delete: %v", err) + } + } +} + +// queries random keys against live state. Keys are almost certainly not in the tree. +func runQueriesFast(b *testing.B, t *iavl.MutableTree, keyLen int) { + isFastCacheEnabled, err := t.IsFastCacheEnabled() + require.NoError(b, err) + require.True(b, isFastCacheEnabled) + for i := 0; i < b.N; i++ { + q := randBytes(keyLen) + t.Get(q) + } +} + +// queries keys that are known to be in state +func runKnownQueriesFast(b *testing.B, t *iavl.MutableTree, keys [][]byte) { + isFastCacheEnabled, err := t.IsFastCacheEnabled() // to ensure fast storage is enabled + require.NoError(b, err) + require.True(b, isFastCacheEnabled) + l := int32(len(keys)) + for i := 0; i < b.N; i++ { + q := keys[rand.Int31n(l)] + t.Get(q) + } +} + +func runQueriesSlow(b *testing.B, t *iavl.MutableTree, keyLen int) { + b.StopTimer() + // Save version to get an old immutable tree to query against, + // Fast storage is not enabled on old tree versions, allowing us to bench the desired behavior. + _, version, err := t.SaveVersion() + require.NoError(b, err) + + itree, err := t.GetImmutable(version - 1) + require.NoError(b, err) + isFastCacheEnabled, err := itree.IsFastCacheEnabled() // to ensure fast storage is enabled + require.NoError(b, err) + require.False(b, isFastCacheEnabled) // to ensure fast storage is not enabled + + b.StartTimer() + for i := 0; i < b.N; i++ { + q := randBytes(keyLen) + itree.GetWithIndex(q) + } +} + +func runKnownQueriesSlow(b *testing.B, t *iavl.MutableTree, keys [][]byte) { + b.StopTimer() + // Save version to get an old immutable tree to query against, + // Fast storage is not enabled on old tree versions, allowing us to bench the desired behavior. + _, version, err := t.SaveVersion() + require.NoError(b, err) + + itree, err := t.GetImmutable(version - 1) + require.NoError(b, err) + isFastCacheEnabled, err := itree.IsFastCacheEnabled() // to ensure fast storage is not enabled + require.NoError(b, err) + require.False(b, isFastCacheEnabled) + b.StartTimer() + l := int32(len(keys)) + for i := 0; i < b.N; i++ { + q := keys[rand.Int31n(l)] + index, value, err := itree.GetWithIndex(q) + require.NoError(b, err) + require.True(b, index >= 0, "the index must not be negative") + require.NotNil(b, value, "the value should exist") + } +} + +func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) { + isFastCacheEnabled, err := t.IsFastCacheEnabled() + require.NoError(b, err) + require.True(b, isFastCacheEnabled) // to ensure fast storage is enabled + for i := 0; i < b.N; i++ { + itr, err := t.ImmutableTree.Iterator(nil, nil, false) + require.NoError(b, err) + iterate(b, itr, expectedSize) + require.Nil(b, itr.Close(), ".Close should not error out") + } +} + +func runIterationSlow(b *testing.B, t *iavl.MutableTree, expectedSize int) { + for i := 0; i < b.N; i++ { + itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree) // create slow iterator directly + iterate(b, itr, expectedSize) + require.Nil(b, itr.Close(), ".Close should not error out") + } +} + +func iterate(b *testing.B, itr db.Iterator, expectedSize int) { + b.StartTimer() + keyValuePairs := make([][][]byte, 0, expectedSize) + for i := 0; i < expectedSize && itr.Valid(); i++ { + itr.Next() + keyValuePairs = append(keyValuePairs, [][]byte{itr.Key(), itr.Value()}) + } + b.StopTimer() + if g, w := len(keyValuePairs), expectedSize; g != w { + b.Errorf("iteration count mismatch: got=%d, want=%d", g, w) + } else { + b.Logf("completed %d iterations", len(keyValuePairs)) + } +} + +// func runInsert(b *testing.B, t *iavl.MutableTree, keyLen, dataLen, blockSize int) *iavl.MutableTree { +// for i := 1; i <= b.N; i++ { +// t.Set(randBytes(keyLen), randBytes(dataLen)) +// if i%blockSize == 0 { +// t.Hash() +// t.SaveVersion() +// } +// } +// return t +// } + +func runUpdate(b *testing.B, t *iavl.MutableTree, dataLen, blockSize int, keys [][]byte) *iavl.MutableTree { + l := int32(len(keys)) + for i := 1; i <= b.N; i++ { + key := keys[rand.Int31n(l)] + t.Set(key, randBytes(dataLen)) + if i%blockSize == 0 { + commitTree(b, t) + } + } + return t +} + +// func runDelete(b *testing.B, t *iavl.MutableTree, blockSize int, keys [][]byte) *iavl.MutableTree { +// var key []byte +// l := int32(len(keys)) +// for i := 1; i <= b.N; i++ { +// key = keys[rand.Int31n(l)] +// // key = randBytes(16) +// // TODO: test if removed, use more keys (from insert) +// t.Remove(key) +// if i%blockSize == 0 { +// commitTree(b, t) +// } +// } +// return t +// } + +// runBlock measures time for an entire block, not just one tx +func runBlock(b *testing.B, t *iavl.MutableTree, keyLen, dataLen, blockSize int, keys [][]byte) *iavl.MutableTree { + l := int32(len(keys)) + + // XXX: This was adapted to work with VersionedTree but needs to be re-thought. + + lastCommit := t + real := t + // check := t + + for i := 0; i < b.N; i++ { + for j := 0; j < blockSize; j++ { + // 50% insert, 50% update + var key []byte + if i%2 == 0 { + key = keys[rand.Int31n(l)] + } else { + key = randBytes(keyLen) + } + data := randBytes(dataLen) + + // perform query and write on check and then real + // check.GetFast(key) + // check.Set(key, data) + real.Get(key) + real.Set(key, data) + } + + // at the end of a block, move it all along.... + commitTree(b, real) + lastCommit = real + } + + return lastCommit +} + +func BenchmarkRandomBytes(b *testing.B) { + fmt.Printf("%s\n", iavl.GetVersionInfo()) + benchmarks := []struct { + length int + }{ + {4}, {16}, {32}, {100}, {1000}, + } + for _, bench := range benchmarks { + bench := bench + name := fmt.Sprintf("random-%d", bench.length) + b.Run(name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + randBytes(bench.length) + } + runtime.GC() + }) + } +} + +type benchmark struct { + dbType db.BackendType + initSize, blockSize int + keyLen, dataLen int +} + +func BenchmarkMedium(b *testing.B) { + benchmarks := []benchmark{ + {"memdb", 100000, 100, 16, 40}, + {"goleveldb", 100000, 100, 16, 40}, + // {"cleveldb", 100000, 100, 16, 40}, + // FIXME: idk why boltdb is too slow !? + // {"boltdb", 100000, 100, 16, 40}, + // {"rocksdb", 100000, 100, 16, 40}, + // {"badgerdb", 100000, 100, 16, 40}, + } + runBenchmarks(b, benchmarks) +} + +func BenchmarkSmall(b *testing.B) { + benchmarks := []benchmark{ + {"memdb", 1000, 100, 4, 10}, + {"goleveldb", 1000, 100, 4, 10}, + // {"cleveldb", 1000, 100, 4, 10}, + // {"boltdb", 1000, 100, 4, 10}, + // {"rocksdb", 1000, 100, 4, 10}, + // {"badgerdb", 1000, 100, 4, 10}, + } + runBenchmarks(b, benchmarks) +} + +func BenchmarkLarge(b *testing.B) { + benchmarks := []benchmark{ + {"memdb", 1000000, 100, 16, 40}, + {"goleveldb", 1000000, 100, 16, 40}, + // FIXME: idk why boltdb is too slow !? + // {"boltdb", 1000000, 100, 16, 40}, + // {"rocksdb", 1000000, 100, 16, 40}, + // {"badgerdb", 1000000, 100, 16, 40}, + } + runBenchmarks(b, benchmarks) +} + +func BenchmarkLevelDBBatchSizes(b *testing.B) { + benchmarks := []benchmark{ + {"goleveldb", 100000, 5, 16, 40}, + {"goleveldb", 100000, 25, 16, 40}, + {"goleveldb", 100000, 100, 16, 40}, + {"goleveldb", 100000, 400, 16, 40}, + {"goleveldb", 100000, 2000, 16, 40}, + } + runBenchmarks(b, benchmarks) +} + +// BenchmarkLevelDBLargeData is intended to push disk limits +// in the goleveldb, to make sure not everything is cached +func BenchmarkLevelDBLargeData(b *testing.B) { + benchmarks := []benchmark{ + {"goleveldb", 50000, 100, 32, 100}, + {"goleveldb", 50000, 100, 32, 1000}, + {"goleveldb", 50000, 100, 32, 10000}, + {"goleveldb", 50000, 100, 32, 100000}, + } + runBenchmarks(b, benchmarks) +} + +func runBenchmarks(b *testing.B, benchmarks []benchmark) { + fmt.Printf("%s\n", iavl.GetVersionInfo()) + for _, bb := range benchmarks { + bb := bb + prefix := fmt.Sprintf("%s-%d-%d-%d-%d", bb.dbType, + bb.initSize, bb.blockSize, bb.keyLen, bb.dataLen) + + // prepare a dir for the db and cleanup afterwards + dirName := fmt.Sprintf("./%s-db", prefix) + if (bb.dbType == db.RocksDBBackend) || (bb.dbType == db.CLevelDBBackend) || (bb.dbType == db.BoltDBBackend) { + _ = os.Mkdir(dirName, 0755) + } + + defer func() { + err := os.RemoveAll(dirName) + if err != nil { + b.Errorf("%+v\n", err) + } + }() + + // note that "" leads to nil backing db! + var ( + d db.DB + err error + ) + if bb.dbType != "nodb" { + d, err = db.NewDB("test", bb.dbType, dirName) + require.NoError(b, err) + defer d.Close() + } + b.Run(prefix, func(sub *testing.B) { + runSuite(sub, d, bb.initSize, bb.blockSize, bb.keyLen, bb.dataLen) + }) + } +} + +// returns number of MB in use +func memUseMB() float64 { + var mem runtime.MemStats + runtime.ReadMemStats(&mem) + asize := mem.Alloc + mb := float64(asize) / 1000000 + return mb +} + +func runSuite(b *testing.B, d db.DB, initSize, blockSize, keyLen, dataLen int) { + // measure mem usage + runtime.GC() + init := memUseMB() + + t, keys := prepareTree(b, d, initSize, keyLen, dataLen) + used := memUseMB() - init + fmt.Printf("Init Tree took %0.2f MB\n", used) + + b.ResetTimer() + + b.Run("query-no-in-tree-guarantee-fast", func(sub *testing.B) { + sub.ReportAllocs() + runQueriesFast(sub, t, keyLen) + }) + b.Run("query-no-in-tree-guarantee-slow", func(sub *testing.B) { + sub.ReportAllocs() + runQueriesSlow(sub, t, keyLen) + }) + // + b.Run("query-hits-fast", func(sub *testing.B) { + sub.ReportAllocs() + runKnownQueriesFast(sub, t, keys) + }) + b.Run("query-hits-slow", func(sub *testing.B) { + sub.ReportAllocs() + runKnownQueriesSlow(sub, t, keys) + }) + // + // Iterations for BenchmarkLevelDBLargeData timeout bencher in CI so + // we must skip them. + if b.Name() != "BenchmarkLevelDBLargeData" { + b.Run("iteration-fast", func(sub *testing.B) { + sub.ReportAllocs() + runIterationFast(sub, t, initSize) + }) + b.Run("iteration-slow", func(sub *testing.B) { + sub.ReportAllocs() + runIterationSlow(sub, t, initSize) + }) + } + + // + b.Run("update", func(sub *testing.B) { + sub.ReportAllocs() + t = runUpdate(sub, t, dataLen, blockSize, keys) + }) + b.Run("block", func(sub *testing.B) { + sub.ReportAllocs() + t = runBlock(sub, t, keyLen, dataLen, blockSize, keys) + }) + + // both of these edit size of the tree too much + // need to run with their own tree + // t = nil // for gc + // b.Run("insert", func(sub *testing.B) { + // it, _ := prepareTree(d, initSize, keyLen, dataLen) + // sub.ResetTimer() + // runInsert(sub, it, keyLen, dataLen, blockSize) + // }) + // b.Run("delete", func(sub *testing.B) { + // dt, dkeys := prepareTree(d, initSize+sub.N, keyLen, dataLen) + // sub.ResetTimer() + // runDelete(sub, dt, blockSize, dkeys) + // }) +} diff --git a/sei-iavl/benchmarks/cosmos-exim/README.md b/sei-iavl/benchmarks/cosmos-exim/README.md new file mode 100644 index 0000000000..2de7b8d4b0 --- /dev/null +++ b/sei-iavl/benchmarks/cosmos-exim/README.md @@ -0,0 +1,38 @@ +# cosmos-exim + +A small utility to benchmark export/import of Cosmos Hub IAVL stores. These stores can be downloaded e.g. from [chainlayer.io](https://www.chainlayer.io). Example usage: + +```sh +$ go run benchmarks/cosmos-exim/main.go ../cosmoshub-3/data +Exporting cosmoshub database at version 870068 + +acc : 67131 nodes (33566 leaves) in 676ms with size 3 MB +distribution : 66509 nodes (33255 leaves) in 804ms with size 3 MB +evidence : 0 nodes (0 leaves) in 0s with size 0 MB +god : 0 nodes (0 leaves) in 0s with size 0 MB +main : 1 nodes (1 leaves) in 0s with size 0 MB +mint : 1 nodes (1 leaves) in 0s with size 0 MB +params : 59 nodes (30 leaves) in 0s with size 0 MB +slashing : 1128139 nodes (564070 leaves) in 17.423s with size 41 MB +staking : 44573 nodes (22287 leaves) in 433ms with size 3 MB +supply : 1 nodes (1 leaves) in 0s with size 0 MB +upgrade : 0 nodes (0 leaves) in 0s with size 0 MB + +Exported 11 stores with 1306414 nodes (653211 leaves) in 19.336s with size 52 MB + +Importing into new LevelDB stores + +acc : 67131 nodes (33566 leaves) in 259ms with size 3 MB +distribution: 66509 nodes (33255 leaves) in 238ms with size 3 MB +evidence : 0 nodes (0 leaves) in 19ms with size 0 MB +god : 0 nodes (0 leaves) in 40ms with size 0 MB +main : 1 nodes (1 leaves) in 22ms with size 0 MB +mint : 1 nodes (1 leaves) in 26ms with size 0 MB +params : 59 nodes (30 leaves) in 26ms with size 0 MB +slashing : 1128139 nodes (564070 leaves) in 5.213s with size 41 MB +staking : 44573 nodes (22287 leaves) in 173ms with size 3 MB +supply : 1 nodes (1 leaves) in 25ms with size 0 MB +upgrade : 0 nodes (0 leaves) in 26ms with size 0 MB + +Imported 11 stores with 1306414 nodes (653211 leaves) in 6.067s with size 52 MB +``` \ No newline at end of file diff --git a/sei-iavl/benchmarks/cosmos-exim/main.go b/sei-iavl/benchmarks/cosmos-exim/main.go new file mode 100644 index 0000000000..4b7ee35807 --- /dev/null +++ b/sei-iavl/benchmarks/cosmos-exim/main.go @@ -0,0 +1,202 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "time" + + "github.com/cosmos/iavl" + tmdb "github.com/tendermint/tm-db" +) + +// stores is the list of stores in the CosmosHub database +// FIXME would be nice to autodetect this +var stores = []string{ + "acc", + "distribution", + "evidence", + "god", + "main", + "mint", + "params", + "slashing", + "staking", + "supply", + "upgrade", +} + +// Stats track import/export statistics +type Stats struct { + nodes uint64 + leafNodes uint64 + size uint64 + duration time.Duration +} + +func (s *Stats) Add(o Stats) { + s.nodes += o.nodes + s.leafNodes += o.leafNodes + s.size += o.size + s.duration += o.duration +} + +func (s *Stats) AddDurationSince(started time.Time) { + s.duration += time.Since(started) +} + +func (s *Stats) AddNode(node *iavl.ExportNode) { + s.nodes++ + if node.Height == 0 { + s.leafNodes++ + } + s.size += uint64(len(node.Key) + len(node.Value) + 8 + 1) +} + +func (s *Stats) String() string { + return fmt.Sprintf("%v nodes (%v leaves) in %v with size %v MB", + s.nodes, s.leafNodes, s.duration.Round(time.Millisecond), s.size/1024/1024) +} + +// main runs the main program +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "Usage: %v \n", os.Args[0]) + os.Exit(1) + } + err := run(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err.Error()) + os.Exit(1) + } +} + +// run runs the command with normal error handling +func run(dbPath string) error { + version, exports, err := runExport(dbPath) + if err != nil { + return err + } + + err = runImport(version, exports) + if err != nil { + return err + } + return nil +} + +// runExport runs an export benchmark and returns a map of store names/export nodes +func runExport(dbPath string) (int64, map[string][]*iavl.ExportNode, error) { + ldb, err := tmdb.NewDB("application", tmdb.GoLevelDBBackend, dbPath) + if err != nil { + return 0, nil, err + } + tree, err := iavl.NewMutableTree(tmdb.NewPrefixDB(ldb, []byte("s/k:main/")), 0, false) + if err != nil { + return 0, nil, err + } + version, err := tree.LoadVersion(0) + if err != nil { + return 0, nil, err + } + fmt.Printf("Exporting cosmoshub database at version %v\n\n", version) + + exports := make(map[string][]*iavl.ExportNode, len(stores)) + + totalStats := Stats{} + for _, name := range stores { + db := tmdb.NewPrefixDB(ldb, []byte("s/k:"+name+"/")) + tree, err := iavl.NewMutableTree(db, 0, false) + if err != nil { + return 0, nil, err + } + + stats := Stats{} + export := make([]*iavl.ExportNode, 0, 100000) + + storeVersion, err := tree.LoadVersion(0) + if err != nil { + return 0, nil, err + } + if storeVersion == 0 { + fmt.Printf("%-13v: %v\n", name, stats.String()) + continue + } + + itree, err := tree.GetImmutable(version) + if err != nil { + return 0, nil, err + } + start := time.Now().UTC() + exporter := itree.Export() + defer exporter.Close() + for { + node, err := exporter.Next() + if err == iavl.ExportDone { + break + } else if err != nil { + return 0, nil, err + } + export = append(export, node) + stats.AddNode(node) + } + stats.AddDurationSince(start) + fmt.Printf("%-13v: %v\n", name, stats.String()) + totalStats.Add(stats) + exports[name] = export + } + + fmt.Printf("\nExported %v stores with %v\n\n", len(stores), totalStats.String()) + + return version, exports, nil +} + +// runImport runs an import benchmark with nodes exported from runExport() +func runImport(version int64, exports map[string][]*iavl.ExportNode) error { + fmt.Print("Importing into new LevelDB stores\n\n") + + totalStats := Stats{} + + for _, name := range stores { + tempdir, err := ioutil.TempDir("", name) + if err != nil { + return err + } + defer os.RemoveAll(tempdir) + + start := time.Now() + stats := Stats{} + + newDB, err := tmdb.NewDB(name, tmdb.GoLevelDBBackend, tempdir) + if err != nil { + return err + } + newTree, err := iavl.NewMutableTree(newDB, 0, false) + if err != nil { + return err + } + importer, err := newTree.Import(version) + if err != nil { + return err + } + defer importer.Close() + for _, node := range exports[name] { + err = importer.Add(node) + if err != nil { + return err + } + stats.AddNode(node) + } + err = importer.Commit() + if err != nil { + return err + } + stats.AddDurationSince(start) + fmt.Printf("%-12v: %v\n", name, stats.String()) + totalStats.Add(stats) + } + + fmt.Printf("\nImported %v stores with %v\n", len(stores), totalStats.String()) + + return nil +} diff --git a/sei-iavl/benchmarks/hash_test.go b/sei-iavl/benchmarks/hash_test.go new file mode 100644 index 0000000000..4ed6c527de --- /dev/null +++ b/sei-iavl/benchmarks/hash_test.go @@ -0,0 +1,53 @@ +package benchmarks + +import ( + "crypto" + "fmt" + "hash" + "testing" + + "github.com/cosmos/iavl" + "github.com/stretchr/testify/require" + + _ "crypto/sha256" + + _ "golang.org/x/crypto/ripemd160" // nolint: staticcheck // need to test ripemd160 + _ "golang.org/x/crypto/sha3" +) + +func BenchmarkHash(b *testing.B) { + fmt.Printf("%s\n", iavl.GetVersionInfo()) + hashers := []struct { + name string + size int + hash hash.Hash + }{ + {"ripemd160", 64, crypto.RIPEMD160.New()}, + {"ripemd160", 512, crypto.RIPEMD160.New()}, + {"sha2-256", 64, crypto.SHA256.New()}, + {"sha2-256", 512, crypto.SHA256.New()}, + {"sha3-256", 64, crypto.SHA3_256.New()}, + {"sha3-256", 512, crypto.SHA3_256.New()}, + } + + for _, h := range hashers { + prefix := fmt.Sprintf("%s-%d", h.name, h.size) + hasher := h + b.Run(prefix, func(sub *testing.B) { + benchHasher(sub, hasher.hash, hasher.size) + }) + } +} + +func benchHasher(b *testing.B, hash hash.Hash, size int) { + // create all random bytes before to avoid timing this + inputs := randBytes(b.N + size + 1) + + for i := 0; i < b.N; i++ { + hash.Reset() + // grab a slice of size bytes from random string + _, err := hash.Write(inputs[i : i+size]) + require.NoError(b, err) + hash.Sum(nil) + } +} diff --git a/sei-iavl/benchmarks/results/165-adityaversion/Adityas-MBP-0.12.3-4-ge3e5a91-results.txt b/sei-iavl/benchmarks/results/165-adityaversion/Adityas-MBP-0.12.3-4-ge3e5a91-results.txt new file mode 100644 index 0000000000..0878c9020f --- /dev/null +++ b/sei-iavl/benchmarks/results/165-adityaversion/Adityas-MBP-0.12.3-4-ge3e5a91-results.txt @@ -0,0 +1,62 @@ +cd benchmarks && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.3-4-ge3e5a91 -X github.com/tendermint/iavl.Commit=e3e5a91edda5a9d525c49749ad102d9cf3b602b4 -X github.com/tendermint/iavl.Branch=aditya/version" -bench=RandomBytes . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.3-4-ge3e5a91 -X github.com/tendermint/iavl.Commit=e3e5a91edda5a9d525c49749ad102d9cf3b602b4 -X github.com/tendermint/iavl.Branch=aditya/version" -bench=Small . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.3-4-ge3e5a91 -X github.com/tendermint/iavl.Commit=e3e5a91edda5a9d525c49749ad102d9cf3b602b4 -X github.com/tendermint/iavl.Branch=aditya/version" -bench=Medium . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.3-4-ge3e5a91 -X github.com/tendermint/iavl.Commit=e3e5a91edda5a9d525c49749ad102d9cf3b602b4 -X github.com/tendermint/iavl.Branch=aditya/version" -bench=BenchmarkMemKeySizes . +iavl: 0.12.3-4-ge3e5a91 +git commit: e3e5a91edda5a9d525c49749ad102d9cf3b602b4 +git branch: aditya/version +go version go1.12.1 darwin/amd64 + +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkRandomBytes/random-4-8 30000000 51.1 ns/op +BenchmarkRandomBytes/random-16-8 20000000 77.0 ns/op +BenchmarkRandomBytes/random-32-8 20000000 111 ns/op +BenchmarkRandomBytes/random-100-8 5000000 255 ns/op +BenchmarkRandomBytes/random-1000-8 1000000 2115 ns/op +PASS +ok github.com/tendermint/iavl/benchmarks 9.235s +iavl: 0.12.3-4-ge3e5a91 +git commit: e3e5a91edda5a9d525c49749ad102d9cf3b602b4 +git branch: aditya/version +go version go1.12.1 darwin/amd64 + +Init Tree took 0.90 MB +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkSmall/memdb-1000-100-4-10/query-miss-8 1000000 2432 ns/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-8 500000 2825 ns/op +BenchmarkSmall/memdb-1000-100-4-10/update-8 20000 116399 ns/op +BenchmarkSmall/memdb-1000-100-4-10/block-8 100 16906178 ns/op +Init Tree took 0.49 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-8 500000 3790 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-8 300000 4671 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-8 20000 100226 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/block-8 100 18355816 ns/op +PASS +ok github.com/tendermint/iavl/benchmarks 17.244s +iavl: 0.12.3-4-ge3e5a91 +git commit: e3e5a91edda5a9d525c49749ad102d9cf3b602b4 +git branch: aditya/version +go version go1.12.1 darwin/amd64 + +Init Tree took 85.05 MB +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkMedium/memdb-100000-100-16-40/query-miss-8 200000 7335 ns/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-8 200000 8195 ns/op +BenchmarkMedium/memdb-100000-100-16-40/update-8 5000 1359239 ns/op +BenchmarkMedium/memdb-100000-100-16-40/block-8 10 169015024 ns/op +Init Tree took 47.53 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-8 50000 28617 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-8 50000 37218 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-8 10000 471017 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/block-8 20 62199885 ns/op +PASS +ok github.com/tendermint/iavl/benchmarks 31.865s +PASS +ok github.com/tendermint/iavl/benchmarks 0.016s diff --git a/sei-iavl/benchmarks/results/165-adityaversion/DigitalOcean-4vcpu-8gb-160gb-0.12.3-7-gf5dfff0-results.txt b/sei-iavl/benchmarks/results/165-adityaversion/DigitalOcean-4vcpu-8gb-160gb-0.12.3-7-gf5dfff0-results.txt new file mode 100644 index 0000000000..d6123296fa --- /dev/null +++ b/sei-iavl/benchmarks/results/165-adityaversion/DigitalOcean-4vcpu-8gb-160gb-0.12.3-7-gf5dfff0-results.txt @@ -0,0 +1,62 @@ +cd benchmarks && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.3-7-gf5dfff0 -X github.com/tendermint/iavl.Commit=f5dfff0a2707c82dd8bededc8799fff16c663b20 -X github.com/tendermint/iavl.Branch=aditya/version" -bench=RandomBytes . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.3-7-gf5dfff0 -X github.com/tendermint/iavl.Commit=f5dfff0a2707c82dd8bededc8799fff16c663b20 -X github.com/tendermint/iavl.Branch=aditya/version" -bench=Small . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.3-7-gf5dfff0 -X github.com/tendermint/iavl.Commit=f5dfff0a2707c82dd8bededc8799fff16c663b20 -X github.com/tendermint/iavl.Branch=aditya/version" -bench=Medium . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.3-7-gf5dfff0 -X github.com/tendermint/iavl.Commit=f5dfff0a2707c82dd8bededc8799fff16c663b20 -X github.com/tendermint/iavl.Branch=aditya/version" -bench=BenchmarkMemKeySizes . +iavl: 0.12.3-7-gf5dfff0 +git commit: f5dfff0a2707c82dd8bededc8799fff16c663b20 +git branch: aditya/version +go version go1.12.7 linux/amd64 + +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkRandomBytes/random-4-4 20000000 74.3 ns/op +BenchmarkRandomBytes/random-16-4 20000000 115 ns/op +BenchmarkRandomBytes/random-32-4 10000000 170 ns/op +BenchmarkRandomBytes/random-100-4 3000000 415 ns/op +BenchmarkRandomBytes/random-1000-4 500000 3403 ns/op +PASS +ok github.com/tendermint/iavl/benchmarks 9.286s +iavl: 0.12.3-7-gf5dfff0 +git commit: f5dfff0a2707c82dd8bededc8799fff16c663b20 +git branch: aditya/version +go version go1.12.7 linux/amd64 + +Init Tree took 0.90 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkSmall/memdb-1000-100-4-10/query-miss-4 300000 4112 ns/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-4 300000 4950 ns/op +BenchmarkSmall/memdb-1000-100-4-10/update-4 10000 165429 ns/op +BenchmarkSmall/memdb-1000-100-4-10/block-4 100 25848533 ns/op +Init Tree took 0.49 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-4 200000 6100 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-4 200000 7678 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-4 20000 101781 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/block-4 100 16241078 ns/op +PASS +ok github.com/tendermint/iavl/benchmarks 14.681s +iavl: 0.12.3-7-gf5dfff0 +git commit: f5dfff0a2707c82dd8bededc8799fff16c663b20 +git branch: aditya/version +go version go1.12.7 linux/amd64 + +Init Tree took 85.07 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkMedium/memdb-100000-100-16-40/query-miss-4 100000 10310 ns/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-4 200000 12132 ns/op +BenchmarkMedium/memdb-100000-100-16-40/update-4 3000 1278477 ns/op +BenchmarkMedium/memdb-100000-100-16-40/block-4 10 197126616 ns/op +Init Tree took 47.61 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-4 50000 27411 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-4 30000 35691 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-4 10000 295694 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/block-4 50 34368088 ns/op +PASS +ok github.com/tendermint/iavl/benchmarks 27.176s +PASS +ok github.com/tendermint/iavl/benchmarks 0.007s diff --git a/sei-iavl/benchmarks/results/168/Rickys-MBP-0.12.4-4-g494d60b-result.txt b/sei-iavl/benchmarks/results/168/Rickys-MBP-0.12.4-4-g494d60b-result.txt new file mode 100644 index 0000000000..f1a78a7ee1 --- /dev/null +++ b/sei-iavl/benchmarks/results/168/Rickys-MBP-0.12.4-4-g494d60b-result.txt @@ -0,0 +1,69 @@ +go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-4-g494d60b -X github.com/tendermint/iavl.Commit=494d60be6833a7bde8e4b8ddf3ad8d2a9df662c6 -X github.com/tendermint/iavl.Branch=master" -bench=MutableTree_Set . +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl +BenchmarkMutableTree_Set-12 300000 5936 ns/op 4454 B/op 25 allocs/op +PASS +ok github.com/tendermint/iavl 33.943s +cd benchmarks && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-4-g494d60b -X github.com/tendermint/iavl.Commit=494d60be6833a7bde8e4b8ddf3ad8d2a9df662c6 -X github.com/tendermint/iavl.Branch=master" -bench=RandomBytes . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-4-g494d60b -X github.com/tendermint/iavl.Commit=494d60be6833a7bde8e4b8ddf3ad8d2a9df662c6 -X github.com/tendermint/iavl.Branch=master" -bench=Small . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-4-g494d60b -X github.com/tendermint/iavl.Commit=494d60be6833a7bde8e4b8ddf3ad8d2a9df662c6 -X github.com/tendermint/iavl.Branch=master" -bench=Medium . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-4-g494d60b -X github.com/tendermint/iavl.Commit=494d60be6833a7bde8e4b8ddf3ad8d2a9df662c6 -X github.com/tendermint/iavl.Branch=master" -bench=BenchmarkMemKeySizes . +iavl: 0.12.4-4-g494d60b +git commit: 494d60be6833a7bde8e4b8ddf3ad8d2a9df662c6 +git branch: master +go version go1.12.5 darwin/amd64 + +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkRandomBytes/random-4-12 30000000 37.5 ns/op +BenchmarkRandomBytes/random-16-12 30000000 55.1 ns/op +BenchmarkRandomBytes/random-32-12 20000000 76.4 ns/op +BenchmarkRandomBytes/random-100-12 10000000 171 ns/op +BenchmarkRandomBytes/random-1000-12 1000000 1338 ns/op +PASS +ok github.com/tendermint/iavl/benchmarks 7.739s +iavl: 0.12.4-4-g494d60b +git commit: 494d60be6833a7bde8e4b8ddf3ad8d2a9df662c6 +git branch: master +go version go1.12.5 darwin/amd64 + +Init Tree took 0.90 MB +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkSmall/memdb-1000-100-4-10/query-miss-12 1000000 1814 ns/op 353 B/op 7 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-12 1000000 2087 ns/op 515 B/op 9 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/update-12 20000 76006 ns/op 47671 B/op 843 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/block-12 100 11481861 ns/op 6581560 B/op 118259 allocs/op +Init Tree took 0.49 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-12 500000 2903 ns/op 575 B/op 12 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-12 500000 3533 ns/op 788 B/op 15 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-12 30000 59931 ns/op 23571 B/op 247 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/block-12 200 13931032 ns/op 4455199 B/op 52266 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 16.641s +iavl: 0.12.4-4-g494d60b +git commit: 494d60be6833a7bde8e4b8ddf3ad8d2a9df662c6 +git branch: master +go version go1.12.5 darwin/amd64 + +Init Tree took 85.03 MB +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkMedium/memdb-100000-100-16-40/query-miss-12 200000 6072 ns/op 426 B/op 8 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-12 200000 6660 ns/op 557 B/op 9 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/update-12 5000 891292 ns/op 308110 B/op 6016 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/block-12 10 119351442 ns/op 39926731 B/op 791429 allocs/op +Init Tree took 47.50 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-12 100000 16961 ns/op 1592 B/op 28 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-12 100000 21351 ns/op 2209 B/op 38 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-12 10000 193156 ns/op 48430 B/op 616 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/block-12 50 28373250 ns/op 5519076 B/op 73151 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 21.117s +PASS +ok github.com/tendermint/iavl/benchmarks 0.009s diff --git a/sei-iavl/benchmarks/results/169/Rickys-MBP-0.12.4-3-ge247ad9-results.txt b/sei-iavl/benchmarks/results/169/Rickys-MBP-0.12.4-3-ge247ad9-results.txt new file mode 100644 index 0000000000..79d9fafb23 --- /dev/null +++ b/sei-iavl/benchmarks/results/169/Rickys-MBP-0.12.4-3-ge247ad9-results.txt @@ -0,0 +1,72 @@ +go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-3-ge247ad9 -X github.com/tendermint/iavl.Commit=e247ad97f779f28abbe31b05d8cbc8b62aa6994b -X github.com/tendermint/iavl.Branch=node_value" -bench=Node* . +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl +BenchmarkNode_aminoSize-12 200000000 8.72 ns/op 0 B/op 0 allocs/op +BenchmarkNode_WriteBytes/NoPreAllocate-12 5000000 373 ns/op 368 B/op 9 allocs/op +BenchmarkNode_WriteBytes/PreAllocate-12 5000000 328 ns/op 224 B/op 8 allocs/op +BenchmarkNodeKey-12 30000000 47.1 ns/op +PASS +ok github.com/tendermint/iavl 21.170s +cd benchmarks && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-3-ge247ad9 -X github.com/tendermint/iavl.Commit=e247ad97f779f28abbe31b05d8cbc8b62aa6994b -X github.com/tendermint/iavl.Branch=node_value" -bench=RandomBytes . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-3-ge247ad9 -X github.com/tendermint/iavl.Commit=e247ad97f779f28abbe31b05d8cbc8b62aa6994b -X github.com/tendermint/iavl.Branch=node_value" -bench=Small . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-3-ge247ad9 -X github.com/tendermint/iavl.Commit=e247ad97f779f28abbe31b05d8cbc8b62aa6994b -X github.com/tendermint/iavl.Branch=node_value" -bench=Medium . && \ + go test -ldflags "-X github.com/tendermint/iavl.Version=0.12.4-3-ge247ad9 -X github.com/tendermint/iavl.Commit=e247ad97f779f28abbe31b05d8cbc8b62aa6994b -X github.com/tendermint/iavl.Branch=node_value" -bench=BenchmarkMemKeySizes . +iavl: 0.12.4-3-ge247ad9 +git commit: e247ad97f779f28abbe31b05d8cbc8b62aa6994b +git branch: node_value +go version go1.12.5 darwin/amd64 + +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkRandomBytes/random-4-12 30000000 36.5 ns/op +BenchmarkRandomBytes/random-16-12 30000000 53.5 ns/op +BenchmarkRandomBytes/random-32-12 20000000 76.7 ns/op +BenchmarkRandomBytes/random-100-12 10000000 167 ns/op +BenchmarkRandomBytes/random-1000-12 1000000 1345 ns/op +PASS +ok github.com/tendermint/iavl/benchmarks 7.627s +iavl: 0.12.4-3-ge247ad9 +git commit: e247ad97f779f28abbe31b05d8cbc8b62aa6994b +git branch: node_value +go version go1.12.5 darwin/amd64 + +Init Tree took 0.82 MB +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkSmall/memdb-1000-100-4-10/query-miss-12 1000000 1787 ns/op 353 B/op 7 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-12 1000000 2138 ns/op 514 B/op 9 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/update-12 20000 74001 ns/op 47666 B/op 860 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/block-12 100 11359815 ns/op 6558684 B/op 119840 allocs/op +Init Tree took 0.48 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-12 500000 2800 ns/op 556 B/op 11 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-12 500000 3477 ns/op 787 B/op 15 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-12 30000 61296 ns/op 23580 B/op 263 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/block-12 200 14048236 ns/op 4472449 B/op 54353 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 17.569s +iavl: 0.12.4-3-ge247ad9 +git commit: e247ad97f779f28abbe31b05d8cbc8b62aa6994b +git branch: node_value +go version go1.12.5 darwin/amd64 + +Init Tree took 78.64 MB +goos: darwin +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkMedium/memdb-100000-100-16-40/query-miss-12 200000 5764 ns/op 426 B/op 8 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-12 200000 6485 ns/op 557 B/op 9 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/update-12 5000 892383 ns/op 308163 B/op 6040 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/block-12 10 120660641 ns/op 39925867 B/op 793685 allocs/op +Init Tree took 46.84 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-12 100000 17000 ns/op 1592 B/op 28 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-12 100000 20677 ns/op 2209 B/op 38 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-12 10000 189551 ns/op 48464 B/op 639 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/block-12 50 25864961 ns/op 5432798 B/op 74492 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 21.234s +PASS +ok github.com/tendermint/iavl/benchmarks 0.008s diff --git a/sei-iavl/benchmarks/results/legacy/Ethans-MBP-2717167.txt b/sei-iavl/benchmarks/results/legacy/Ethans-MBP-2717167.txt new file mode 100644 index 0000000000..0342129b2e --- /dev/null +++ b/sei-iavl/benchmarks/results/legacy/Ethans-MBP-2717167.txt @@ -0,0 +1,116 @@ +cd benchmarks && \ + go test -bench=RandomBytes . && \ + go test -bench=Small . && \ + go test -bench=Medium . && \ + go test -bench=BenchmarkMemKeySizes . +BenchmarkRandomBytes/random-4-4 20000000 63.1 ns/op +BenchmarkRandomBytes/random-16-4 20000000 88.9 ns/op +BenchmarkRandomBytes/random-32-4 10000000 123 ns/op +BenchmarkRandomBytes/random-100-4 5000000 275 ns/op +BenchmarkRandomBytes/random-1000-4 1000000 2131 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 8.390s +Init Tree took 0.42 MB +BenchmarkSmall/nodb-1000-100-4-10/query-miss-4 5000000 345 ns/op +BenchmarkSmall/nodb-1000-100-4-10/query-hits-4 5000000 320 ns/op +BenchmarkSmall/nodb-1000-100-4-10/update-4 200000 7959 ns/op +BenchmarkSmall/nodb-1000-100-4-10/tmsp-4 100000 25878 ns/op +BenchmarkSmall/nodb-1000-100-4-10/insert-4 100000 28215 ns/op +BenchmarkSmall/nodb-1000-100-4-10/delete-4 100000 15757 ns/op +Init Tree took 0.84 MB +BenchmarkSmall/memdb-1000-100-4-10/query-miss-4 500000 3296 ns/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-4 300000 3664 ns/op +BenchmarkSmall/memdb-1000-100-4-10/update-4 50000 25869 ns/op +BenchmarkSmall/memdb-1000-100-4-10/tmsp-4 30000 87781 ns/op +BenchmarkSmall/memdb-1000-100-4-10/insert-4 20000 70119 ns/op +BenchmarkSmall/memdb-1000-100-4-10/delete-4 50000 49289 ns/op +Init Tree took 0.47 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-4 300000 5219 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-4 300000 6329 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-4 30000 65849 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/tmsp-4 10000 157153 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/insert-4 10000 223123 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/delete-4 20000 105517 ns/op +Init Tree took 0.48 MB +BenchmarkSmall/leveldb-1000-100-4-10/query-miss-4 200000 6629 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/query-hits-4 200000 7247 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/update-4 20000 60328 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/tmsp-4 10000 133760 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/insert-4 10000 128193 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/delete-4 20000 87809 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 57.747s +Init Tree took 47.20 MB +BenchmarkMedium/nodb-100000-100-16-40/query-miss-4 1000000 1372 ns/op +BenchmarkMedium/nodb-100000-100-16-40/query-hits-4 1000000 1630 ns/op +BenchmarkMedium/nodb-100000-100-16-40/update-4 50000 27774 ns/op +BenchmarkMedium/nodb-100000-100-16-40/tmsp-4 50000 35904 ns/op +BenchmarkMedium/nodb-100000-100-16-40/insert-4 50000 29889 ns/op +BenchmarkMedium/nodb-100000-100-16-40/delete-4 100000 21200 ns/op +Init Tree took 85.08 MB +BenchmarkMedium/memdb-100000-100-16-40/query-miss-4 200000 8863 ns/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-4 200000 9878 ns/op +BenchmarkMedium/memdb-100000-100-16-40/update-4 20000 75840 ns/op +BenchmarkMedium/memdb-100000-100-16-40/tmsp-4 10000 112251 ns/op +BenchmarkMedium/memdb-100000-100-16-40/insert-4 20000 103080 ns/op +BenchmarkMedium/memdb-100000-100-16-40/delete-4 20000 66677 ns/op +Init Tree took 45.17 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-4 50000 21601 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-4 50000 27372 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-4 10000 148820 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/tmsp-4 5000 319488 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/insert-4 2000 530568 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/delete-4 2000 569455 ns/op +Init Tree took 36.12 MB +BenchmarkMedium/leveldb-100000-100-16-40/query-miss-4 50000 23190 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/query-hits-4 50000 27447 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/update-4 10000 147662 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/tmsp-4 5000 310984 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/insert-4 2000 549814 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/delete-4 2000 716094 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 202.957s +Init Tree took 49.20 MB +BenchmarkMemKeySizes/nodb-100000-100-4-80/query-miss-4 1000000 1079 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/query-hits-4 1000000 1122 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/update-4 100000 25405 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/tmsp-4 50000 35486 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/insert-4 50000 29162 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/delete-4 100000 19531 ns/op +Init Tree took 50.40 MB +BenchmarkMemKeySizes/nodb-100000-100-16-80/query-miss-4 1000000 1224 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/query-hits-4 1000000 1262 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/update-4 50000 25344 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/tmsp-4 50000 33859 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/insert-4 50000 28705 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/delete-4 100000 19679 ns/op +Init Tree took 52.00 MB +BenchmarkMemKeySizes/nodb-100000-100-32-80/query-miss-4 1000000 1333 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/query-hits-4 1000000 1348 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/update-4 50000 25319 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/tmsp-4 50000 33329 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/insert-4 50000 29624 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/delete-4 100000 20300 ns/op +Init Tree took 55.20 MB +BenchmarkMemKeySizes/nodb-100000-100-64-80/query-miss-4 1000000 1503 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/query-hits-4 1000000 1412 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/update-4 50000 26542 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/tmsp-4 50000 33529 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/insert-4 50000 32928 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/delete-4 100000 22184 ns/op +Init Tree took 61.60 MB +BenchmarkMemKeySizes/nodb-100000-100-128-80/query-miss-4 500000 2234 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/query-hits-4 1000000 2012 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/update-4 50000 28088 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/tmsp-4 50000 49556 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/insert-4 50000 31738 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/delete-4 100000 20232 ns/op +Init Tree took 74.40 MB +BenchmarkMemKeySizes/nodb-100000-100-256-80/query-miss-4 500000 2222 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/query-hits-4 1000000 1592 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/update-4 50000 29363 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/tmsp-4 50000 37905 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/insert-4 50000 33531 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/delete-4 100000 19828 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 147.856s diff --git a/sei-iavl/benchmarks/results/legacy/aws-c4-large-f6f41ca.txt b/sei-iavl/benchmarks/results/legacy/aws-c4-large-f6f41ca.txt new file mode 100644 index 0000000000..e5db99f2ef --- /dev/null +++ b/sei-iavl/benchmarks/results/legacy/aws-c4-large-f6f41ca.txt @@ -0,0 +1,118 @@ +make[1]: Entering directory '/home/ubuntu/go/src/github.com/tendermint/merkleeyes/iavl' +cd benchmarks && \ + go test -bench=RandomBytes . && \ + go test -bench=Small . && \ + go test -bench=Medium . && \ + go test -bench=BenchmarkMemKeySizes . +BenchmarkRandomBytes/random-4-2 20000000 58.1 ns/op +BenchmarkRandomBytes/random-16-2 20000000 85.5 ns/op +BenchmarkRandomBytes/random-32-2 20000000 118 ns/op +BenchmarkRandomBytes/random-100-2 5000000 267 ns/op +BenchmarkRandomBytes/random-1000-2 1000000 2129 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 9.276s +Init Tree took 0.42 MB +BenchmarkSmall/nodb-1000-100-4-10/query-miss-2 5000000 316 ns/op +BenchmarkSmall/nodb-1000-100-4-10/query-hits-2 5000000 297 ns/op +BenchmarkSmall/nodb-1000-100-4-10/update-2 200000 8469 ns/op +BenchmarkSmall/nodb-1000-100-4-10/tmsp-2 100000 31893 ns/op +BenchmarkSmall/nodb-1000-100-4-10/insert-2 100000 30303 ns/op +BenchmarkSmall/nodb-1000-100-4-10/delete-2 200000 20423 ns/op +Init Tree took 0.84 MB +BenchmarkSmall/memdb-1000-100-4-10/query-miss-2 500000 3156 ns/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-2 500000 3527 ns/op +BenchmarkSmall/memdb-1000-100-4-10/update-2 100000 22616 ns/op +BenchmarkSmall/memdb-1000-100-4-10/tmsp-2 30000 76474 ns/op +BenchmarkSmall/memdb-1000-100-4-10/insert-2 30000 69403 ns/op +BenchmarkSmall/memdb-1000-100-4-10/delete-2 50000 45710 ns/op +Init Tree took 0.47 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-2 300000 5451 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-2 200000 6857 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-2 20000 83362 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/tmsp-2 10000 165200 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/insert-2 10000 158884 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/delete-2 20000 116426 ns/op +Init Tree took -7.19 MB +BenchmarkSmall/leveldb-1000-100-4-10/query-miss-2 300000 5168 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/query-hits-2 200000 6381 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/update-2 20000 83882 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/tmsp-2 10000 154254 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/insert-2 10000 152926 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/delete-2 20000 115319 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 63.175s +Init Tree took 47.20 MB +BenchmarkMedium/nodb-100000-100-16-40/query-miss-2 2000000 971 ns/op +BenchmarkMedium/nodb-100000-100-16-40/query-hits-2 2000000 981 ns/op +BenchmarkMedium/nodb-100000-100-16-40/update-2 50000 30686 ns/op +BenchmarkMedium/nodb-100000-100-16-40/tmsp-2 30000 44455 ns/op +BenchmarkMedium/nodb-100000-100-16-40/insert-2 50000 35721 ns/op +BenchmarkMedium/nodb-100000-100-16-40/delete-2 50000 25793 ns/op +Init Tree took 85.13 MB +BenchmarkMedium/memdb-100000-100-16-40/query-miss-2 200000 7887 ns/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-2 200000 8736 ns/op +BenchmarkMedium/memdb-100000-100-16-40/update-2 20000 86067 ns/op +BenchmarkMedium/memdb-100000-100-16-40/tmsp-2 10000 122596 ns/op +BenchmarkMedium/memdb-100000-100-16-40/insert-2 20000 92261 ns/op +BenchmarkMedium/memdb-100000-100-16-40/delete-2 20000 66919 ns/op +Init Tree took 45.41 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-2 100000 17993 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-2 100000 22781 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-2 10000 210399 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/tmsp-2 3000 371019 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/insert-2 2000 597672 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/delete-2 2000 660506 ns/op +Init Tree took 36.39 MB +BenchmarkMedium/leveldb-100000-100-16-40/query-miss-2 100000 17543 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/query-hits-2 100000 22734 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/update-2 10000 208948 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/tmsp-2 3000 392419 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/insert-2 2000 622588 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/delete-2 2000 580446 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 185.401s +Init Tree took 49.20 MB +BenchmarkMemKeySizes/nodb-100000-100-4-80/query-miss-2 2000000 875 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/query-hits-2 2000000 928 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/update-2 50000 30808 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/tmsp-2 30000 41638 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/insert-2 50000 35774 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/delete-2 50000 23646 ns/op +Init Tree took 50.40 MB +BenchmarkMemKeySizes/nodb-100000-100-16-80/query-miss-2 1000000 1005 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/query-hits-2 1000000 1002 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/update-2 50000 31509 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/tmsp-2 30000 41108 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/insert-2 50000 36185 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/delete-2 50000 23535 ns/op +Init Tree took 52.00 MB +BenchmarkMemKeySizes/nodb-100000-100-32-80/query-miss-2 1000000 1023 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/query-hits-2 1000000 1010 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/update-2 50000 31243 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/tmsp-2 50000 43901 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/insert-2 50000 35957 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/delete-2 50000 23259 ns/op +Init Tree took 55.20 MB +BenchmarkMemKeySizes/nodb-100000-100-64-80/query-miss-2 1000000 1104 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/query-hits-2 2000000 937 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/update-2 50000 31014 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/tmsp-2 50000 40717 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/insert-2 50000 35122 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/delete-2 50000 22827 ns/op +Init Tree took 61.60 MB +BenchmarkMemKeySizes/nodb-100000-100-128-80/query-miss-2 1000000 1343 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/query-hits-2 2000000 978 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/update-2 50000 31088 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/tmsp-2 50000 42017 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/insert-2 50000 35814 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/delete-2 100000 21684 ns/op +Init Tree took 74.40 MB +BenchmarkMemKeySizes/nodb-100000-100-256-80/query-miss-2 1000000 1686 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/query-hits-2 2000000 937 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/update-2 50000 31305 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/tmsp-2 50000 41948 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/insert-2 50000 35809 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/delete-2 100000 20561 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 160.512s +make[1]: Leaving directory '/home/ubuntu/go/src/github.com/tendermint/merkleeyes/iavl' diff --git a/sei-iavl/benchmarks/results/legacy/digital-ocean-2gb-2717167.txt b/sei-iavl/benchmarks/results/legacy/digital-ocean-2gb-2717167.txt new file mode 100644 index 0000000000..c926dc3006 --- /dev/null +++ b/sei-iavl/benchmarks/results/legacy/digital-ocean-2gb-2717167.txt @@ -0,0 +1,118 @@ +make[1]: Entering directory '/root/go/src/github.com/tendermint/merkleeyes/iavl' +cd benchmarks && \ + go test -bench=RandomBytes . && \ + go test -bench=Small . && \ + go test -bench=Medium . && \ + go test -bench=BenchmarkMemKeySizes . +BenchmarkRandomBytes/random-4-2 10000000 109 ns/op +BenchmarkRandomBytes/random-16-2 10000000 138 ns/op +BenchmarkRandomBytes/random-32-2 10000000 293 ns/op +BenchmarkRandomBytes/random-100-2 2000000 929 ns/op +BenchmarkRandomBytes/random-1000-2 300000 7309 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 11.873s +Init Tree took 0.42 MB +BenchmarkSmall/nodb-1000-100-4-10/query-miss-2 2000000 699 ns/op +BenchmarkSmall/nodb-1000-100-4-10/query-hits-2 2000000 709 ns/op +BenchmarkSmall/nodb-1000-100-4-10/update-2 100000 25067 ns/op +BenchmarkSmall/nodb-1000-100-4-10/tmsp-2 30000 79326 ns/op +BenchmarkSmall/nodb-1000-100-4-10/insert-2 30000 71205 ns/op +BenchmarkSmall/nodb-1000-100-4-10/delete-2 50000 37782 ns/op +Init Tree took 0.84 MB +BenchmarkSmall/memdb-1000-100-4-10/query-miss-2 100000 11325 ns/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-2 300000 9585 ns/op +BenchmarkSmall/memdb-1000-100-4-10/update-2 20000 88439 ns/op +BenchmarkSmall/memdb-1000-100-4-10/tmsp-2 10000 235413 ns/op +BenchmarkSmall/memdb-1000-100-4-10/insert-2 10000 231453 ns/op +BenchmarkSmall/memdb-1000-100-4-10/delete-2 10000 121835 ns/op +Init Tree took 0.47 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-2 100000 10942 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-2 100000 13878 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-2 10000 125941 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/tmsp-2 5000 228558 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/insert-2 10000 439718 ns/op +BenchmarkSmall/goleveldb-1000-100-4-10/delete-2 10000 254810 ns/op +Init Tree took 0.47 MB +BenchmarkSmall/leveldb-1000-100-4-10/query-miss-2 200000 8161 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/query-hits-2 200000 10279 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/update-2 10000 140223 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/tmsp-2 5000 266231 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/insert-2 10000 440206 ns/op +BenchmarkSmall/leveldb-1000-100-4-10/delete-2 10000 262984 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 61.918s +Init Tree took 47.20 MB +BenchmarkMedium/nodb-100000-100-16-40/query-miss-2 500000 3026 ns/op +BenchmarkMedium/nodb-100000-100-16-40/query-hits-2 500000 2226 ns/op +BenchmarkMedium/nodb-100000-100-16-40/update-2 30000 47671 ns/op +BenchmarkMedium/nodb-100000-100-16-40/tmsp-2 20000 91781 ns/op +BenchmarkMedium/nodb-100000-100-16-40/insert-2 20000 70797 ns/op +BenchmarkMedium/nodb-100000-100-16-40/delete-2 30000 47361 ns/op +Init Tree took 85.08 MB +BenchmarkMedium/memdb-100000-100-16-40/query-miss-2 50000 22383 ns/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-2 100000 15686 ns/op +BenchmarkMedium/memdb-100000-100-16-40/update-2 10000 146801 ns/op +BenchmarkMedium/memdb-100000-100-16-40/tmsp-2 5000 301393 ns/op +BenchmarkMedium/memdb-100000-100-16-40/insert-2 10000 123555 ns/op +BenchmarkMedium/memdb-100000-100-16-40/delete-2 10000 130045 ns/op +Init Tree took 45.29 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-2 10000 331146 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-2 20000 72753 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-2 5000 655807 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/tmsp-2 1000 1174947 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/insert-2 1000 1570246 ns/op +BenchmarkMedium/goleveldb-100000-100-16-40/delete-2 1000 1500384 ns/op +Init Tree took 36.45 MB +BenchmarkMedium/leveldb-100000-100-16-40/query-miss-2 3000 382304 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/query-hits-2 30000 68459 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/update-2 5000 407120 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/tmsp-2 3000 962354 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/insert-2 1000 1806111 ns/op +BenchmarkMedium/leveldb-100000-100-16-40/delete-2 1000 1043286 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 321.607s +Init Tree took 49.20 MB +BenchmarkMemKeySizes/nodb-100000-100-4-80/query-miss-2 500000 3863 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/query-hits-2 500000 2577 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/update-2 30000 54838 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/tmsp-2 10000 110951 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/insert-2 30000 82763 ns/op +BenchmarkMemKeySizes/nodb-100000-100-4-80/delete-2 50000 36173 ns/op +Init Tree took 50.40 MB +BenchmarkMemKeySizes/nodb-100000-100-16-80/query-miss-2 500000 2017 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/query-hits-2 1000000 1852 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/update-2 50000 63354 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/tmsp-2 20000 104027 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/insert-2 30000 48495 ns/op +BenchmarkMemKeySizes/nodb-100000-100-16-80/delete-2 50000 37681 ns/op +Init Tree took 52.00 MB +BenchmarkMemKeySizes/nodb-100000-100-32-80/query-miss-2 1000000 2594 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/query-hits-2 500000 3050 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/update-2 30000 45242 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/tmsp-2 20000 80852 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/insert-2 30000 48661 ns/op +BenchmarkMemKeySizes/nodb-100000-100-32-80/delete-2 50000 42489 ns/op +Init Tree took 55.20 MB +BenchmarkMemKeySizes/nodb-100000-100-64-80/query-miss-2 1000000 2733 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/query-hits-2 1000000 2477 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/update-2 30000 71995 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/tmsp-2 30000 60682 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/insert-2 30000 65346 ns/op +BenchmarkMemKeySizes/nodb-100000-100-64-80/delete-2 50000 32863 ns/op +Init Tree took 61.60 MB +BenchmarkMemKeySizes/nodb-100000-100-128-80/query-miss-2 500000 3102 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/query-hits-2 500000 3365 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/update-2 30000 68945 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/tmsp-2 20000 62037 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/insert-2 20000 79507 ns/op +BenchmarkMemKeySizes/nodb-100000-100-128-80/delete-2 50000 48408 ns/op +Init Tree took 74.40 MB +BenchmarkMemKeySizes/nodb-100000-100-256-80/query-miss-2 300000 4619 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/query-hits-2 1000000 1975 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/update-2 30000 53841 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/tmsp-2 20000 87730 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/insert-2 30000 49158 ns/op +BenchmarkMemKeySizes/nodb-100000-100-256-80/delete-2 50000 31043 ns/op +PASS +ok github.com/tendermint/merkleeyes/iavl/benchmarks 247.827s +make[1]: Leaving directory '/root/go/src/github.com/tendermint/merkleeyes/iavl' diff --git a/sei-iavl/benchmarks/results/legacy/digital-ocean-64gb-fullbench-memory-8f19f23.txt b/sei-iavl/benchmarks/results/legacy/digital-ocean-64gb-fullbench-memory-8f19f23.txt new file mode 100644 index 0000000000..ca6a7c618f --- /dev/null +++ b/sei-iavl/benchmarks/results/legacy/digital-ocean-64gb-fullbench-memory-8f19f23.txt @@ -0,0 +1,149 @@ +cd benchmarks && \ + go test -bench=RandomBytes . -benchmem && \ + go test -bench=Small . -benchmem && \ + go test -bench=Medium . -benchmem && \ + go test -timeout=30m -bench=Large . -benchmem && \ + go test -bench=Mem . -benchmem && \ + go test -timeout=60m -bench=LevelDB . -benchmem +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkRandomBytes/random-4-24 20000000 72.0 ns/op 4 B/op 1 allocs/op +BenchmarkRandomBytes/random-16-24 20000000 118 ns/op 16 B/op 1 allocs/op +BenchmarkRandomBytes/random-32-24 10000000 156 ns/op 32 B/op 1 allocs/op +BenchmarkRandomBytes/random-100-24 5000000 370 ns/op 112 B/op 1 allocs/op +BenchmarkRandomBytes/random-1000-24 500000 2958 ns/op 1024 B/op 1 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 9.506s +Init Tree took 0.91 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkSmall/memdb-1000-100-4-10/query-miss-24 500000 4420 ns/op 435 B/op 9 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-24 200000 5272 ns/op 634 B/op 12 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/update-24 10000 159192 ns/op 42771 B/op 764 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/block-24 100 24824001 ns/op 6620344 B/op 120912 allocs/op +Init Tree took 0.49 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-24 300000 6368 ns/op 649 B/op 13 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-24 200000 8741 ns/op 918 B/op 18 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-24 10000 109113 ns/op 22326 B/op 254 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/block-24 100 17755475 ns/op 3487423 B/op 39158 allocs/op +Init Tree took 0.49 MB +BenchmarkSmall/leveldb-1000-100-4-10/query-miss-24 300000 6584 ns/op 651 B/op 14 allocs/op +BenchmarkSmall/leveldb-1000-100-4-10/query-hits-24 200000 7898 ns/op 918 B/op 18 allocs/op +BenchmarkSmall/leveldb-1000-100-4-10/update-24 10000 102305 ns/op 22352 B/op 254 allocs/op +BenchmarkSmall/leveldb-1000-100-4-10/block-24 100 16187510 ns/op 3461634 B/op 39097 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 20.641s +Init Tree took 85.10 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkMedium/memdb-100000-100-16-40/query-miss-24 200000 9595 ns/op 513 B/op 10 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-24 200000 10834 ns/op 676 B/op 12 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/update-24 3000 1261394 ns/op 246830 B/op 4746 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/block-24 10 198937291 ns/op 40016809 B/op 795945 allocs/op +Init Tree took 47.42 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-24 50000 22673 ns/op 1594 B/op 27 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-24 50000 28135 ns/op 2144 B/op 35 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-24 10000 294852 ns/op 53115 B/op 592 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/block-24 50 34807659 ns/op 5968256 B/op 67622 allocs/op +Init Tree took 47.80 MB +BenchmarkMedium/leveldb-100000-100-16-40/query-miss-24 50000 22686 ns/op 1532 B/op 25 allocs/op +BenchmarkMedium/leveldb-100000-100-16-40/query-hits-24 50000 27668 ns/op 2159 B/op 35 allocs/op +BenchmarkMedium/leveldb-100000-100-16-40/update-24 10000 287108 ns/op 53026 B/op 593 allocs/op +BenchmarkMedium/leveldb-100000-100-16-40/block-24 30 35596044 ns/op 6206475 B/op 67118 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 38.966s +Init Tree took 917.91 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkLarge/memdb-1000000-100-16-40/query-miss-24 100000 15911 ns/op 1061 B/op 20 allocs/op +BenchmarkLarge/memdb-1000000-100-16-40/query-hits-24 100000 15748 ns/op 829 B/op 15 allocs/op +BenchmarkLarge/memdb-1000000-100-16-40/update-24 300 5161409 ns/op 994056 B/op 20570 allocs/op +BenchmarkLarge/memdb-1000000-100-16-40/block-24 2 514923704 ns/op 100084344 B/op 2069282 allocs/op +Init Tree took 416.94 MB +BenchmarkLarge/goleveldb-1000000-100-16-40/query-miss-24 20000 60866 ns/op 4902 B/op 82 allocs/op +BenchmarkLarge/goleveldb-1000000-100-16-40/query-hits-24 30000 49123 ns/op 3745 B/op 62 allocs/op +BenchmarkLarge/goleveldb-1000000-100-16-40/update-24 10000 478900 ns/op 81376 B/op 836 allocs/op +BenchmarkLarge/goleveldb-1000000-100-16-40/block-24 20 53327657 ns/op 10397199 B/op 98883 allocs/op +Init Tree took 404.64 MB +BenchmarkLarge/leveldb-1000000-100-16-40/query-miss-24 20000 57290 ns/op 4590 B/op 76 allocs/op +BenchmarkLarge/leveldb-1000000-100-16-40/query-hits-24 30000 48691 ns/op 3640 B/op 60 allocs/op +BenchmarkLarge/leveldb-1000000-100-16-40/update-24 5000 381530 ns/op 69914 B/op 736 allocs/op +BenchmarkLarge/leveldb-1000000-100-16-40/block-24 30 56220875 ns/op 10656291 B/op 101281 allocs/op +Init Tree took 24.87 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/query-miss-24 50000 23263 ns/op 1745 B/op 27 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/query-hits-24 50000 25201 ns/op 2238 B/op 34 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/update-24 10000 283769 ns/op 52149 B/op 563 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/block-24 50 33455540 ns/op 5749534 B/op 64612 allocs/op +Init Tree took 39.73 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/query-miss-24 50000 23683 ns/op 2716 B/op 28 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/query-hits-24 50000 32174 ns/op 3716 B/op 37 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/update-24 10000 317281 ns/op 64047 B/op 616 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/block-24 50 44231625 ns/op 7399545 B/op 73233 allocs/op +Init Tree took 264.19 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/query-miss-24 30000 35564 ns/op 11875 B/op 30 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/query-hits-24 30000 45093 ns/op 16763 B/op 39 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/update-24 10000 574978 ns/op 207200 B/op 752 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/block-24 20 76693083 ns/op 28530852 B/op 92942 allocs/op +Init Tree took 2676.96 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/query-miss-24 10000 147724 ns/op 256119 B/op 64 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/query-hits-24 10000 169279 ns/op 307666 B/op 70 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/update-24 1000 3882880 ns/op 2601694 B/op 639 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/block-24 10 520453137 ns/op 431258147 B/op 102744 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 448.959s +PASS +ok github.com/tendermint/iavl/benchmarks 0.008s +Init Tree took 47.64 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkLevelDBBatchSizes/goleveldb-100000-5-16-40/query-miss-24 50000 22097 ns/op 1601 B/op 27 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-5-16-40/query-hits-24 50000 27734 ns/op 2157 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-5-16-40/update-24 10000 511317 ns/op 78187 B/op 842 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-5-16-40/block-24 500 2681891 ns/op 398000 B/op 4350 allocs/op +Init Tree took 47.60 MB +BenchmarkLevelDBBatchSizes/goleveldb-100000-25-16-40/query-miss-24 50000 23397 ns/op 1536 B/op 26 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-25-16-40/query-hits-24 50000 28137 ns/op 2163 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-25-16-40/update-24 10000 349234 ns/op 64083 B/op 704 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-25-16-40/block-24 200 9405218 ns/op 1702630 B/op 18575 allocs/op +Init Tree took 35.87 MB +BenchmarkLevelDBBatchSizes/goleveldb-100000-100-16-40/query-miss-24 50000 22684 ns/op 1609 B/op 27 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-100-16-40/query-hits-24 50000 28836 ns/op 2156 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-100-16-40/update-24 10000 279935 ns/op 52609 B/op 595 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-100-16-40/block-24 50 34924252 ns/op 5994318 B/op 67455 allocs/op +Init Tree took 40.94 MB +BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/query-miss-24 50000 21974 ns/op 1568 B/op 26 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/query-hits-24 50000 29079 ns/op 2212 B/op 36 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/update-24 10000 200319 ns/op 40108 B/op 454 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/block-24 10 143250792 ns/op 23631405 B/op 273493 allocs/op +Init Tree took 38.19 MB +BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/query-miss-24 50000 22070 ns/op 1543 B/op 26 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/query-hits-24 50000 28305 ns/op 2150 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/update-24 10000 150990 ns/op 31752 B/op 326 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/block-24 3 416917935 ns/op 78008320 B/op 824207 allocs/op +Init Tree took 23.60 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/query-miss-24 100000 19841 ns/op 1591 B/op 24 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/query-hits-24 50000 25320 ns/op 2237 B/op 34 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/update-24 10000 310418 ns/op 51051 B/op 564 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/block-24 50 33174907 ns/op 5796150 B/op 64856 allocs/op +Init Tree took 39.77 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/query-miss-24 100000 23820 ns/op 2638 B/op 27 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/query-hits-24 50000 28973 ns/op 3720 B/op 37 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/update-24 10000 315650 ns/op 64815 B/op 618 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/block-24 50 41392373 ns/op 7424452 B/op 74022 allocs/op +Init Tree took 266.07 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/query-miss-24 30000 33961 ns/op 11884 B/op 30 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/query-hits-24 30000 45861 ns/op 16535 B/op 39 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/update-24 10000 594813 ns/op 213379 B/op 760 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/block-24 20 77458855 ns/op 28589214 B/op 92146 allocs/op +Init Tree took 2677.35 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/query-miss-24 10000 148305 ns/op 252620 B/op 63 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/query-hits-24 10000 169529 ns/op 310811 B/op 71 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/update-24 1000 3540659 ns/op 2632158 B/op 640 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/block-24 10 515252342 ns/op 440797695 B/op 102385 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 243.566s diff --git a/sei-iavl/benchmarks/results/legacy/digital-ocean-64gb-fullbench-memory-c1f6d4e.txt b/sei-iavl/benchmarks/results/legacy/digital-ocean-64gb-fullbench-memory-c1f6d4e.txt new file mode 100644 index 0000000000..5c43e9624e --- /dev/null +++ b/sei-iavl/benchmarks/results/legacy/digital-ocean-64gb-fullbench-memory-c1f6d4e.txt @@ -0,0 +1,149 @@ +cd benchmarks && \ + go test -bench=RandomBytes . -benchmem && \ + go test -bench=Small . -benchmem && \ + go test -bench=Medium . -benchmem && \ + go test -timeout=30m -bench=Large . -benchmem && \ + go test -bench=Mem . -benchmem && \ + go test -timeout=60m -bench=LevelDB . -benchmem +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkRandomBytes/random-4-24 20000000 74.8 ns/op 4 B/op 1 allocs/op +BenchmarkRandomBytes/random-16-24 20000000 121 ns/op 16 B/op 1 allocs/op +BenchmarkRandomBytes/random-32-24 10000000 166 ns/op 32 B/op 1 allocs/op +BenchmarkRandomBytes/random-100-24 5000000 376 ns/op 112 B/op 1 allocs/op +BenchmarkRandomBytes/random-1000-24 500000 2943 ns/op 1024 B/op 1 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 9.769s +Init Tree took 0.91 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkSmall/memdb-1000-100-4-10/query-miss-24 300000 4081 ns/op 434 B/op 9 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/query-hits-24 300000 5112 ns/op 633 B/op 12 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/update-24 10000 157089 ns/op 42683 B/op 763 allocs/op +BenchmarkSmall/memdb-1000-100-4-10/block-24 100 25654741 ns/op 6619026 B/op 120940 allocs/op +Init Tree took 0.49 MB +BenchmarkSmall/goleveldb-1000-100-4-10/query-miss-24 200000 7127 ns/op 637 B/op 13 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/query-hits-24 200000 8713 ns/op 918 B/op 18 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/update-24 10000 103509 ns/op 22232 B/op 253 allocs/op +BenchmarkSmall/goleveldb-1000-100-4-10/block-24 100 17394312 ns/op 3483478 B/op 39338 allocs/op +Init Tree took 0.49 MB +BenchmarkSmall/leveldb-1000-100-4-10/query-miss-24 300000 6214 ns/op 646 B/op 13 allocs/op +BenchmarkSmall/leveldb-1000-100-4-10/query-hits-24 200000 8254 ns/op 919 B/op 18 allocs/op +BenchmarkSmall/leveldb-1000-100-4-10/update-24 10000 107058 ns/op 22312 B/op 254 allocs/op +BenchmarkSmall/leveldb-1000-100-4-10/block-24 100 17031744 ns/op 3482495 B/op 39144 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 19.874s +Init Tree took 85.10 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkMedium/memdb-100000-100-16-40/query-miss-24 200000 10064 ns/op 513 B/op 10 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/query-hits-24 200000 11143 ns/op 676 B/op 12 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/update-24 3000 1303374 ns/op 246834 B/op 4746 allocs/op +BenchmarkMedium/memdb-100000-100-16-40/block-24 10 190258294 ns/op 40016520 B/op 795943 allocs/op +Init Tree took 47.63 MB +BenchmarkMedium/goleveldb-100000-100-16-40/query-miss-24 50000 22452 ns/op 1539 B/op 26 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/query-hits-24 50000 28301 ns/op 2148 B/op 35 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/update-24 10000 296013 ns/op 52887 B/op 594 allocs/op +BenchmarkMedium/goleveldb-100000-100-16-40/block-24 30 35855483 ns/op 6213133 B/op 67658 allocs/op +Init Tree took 42.26 MB +BenchmarkMedium/leveldb-100000-100-16-40/query-miss-24 50000 22802 ns/op 1595 B/op 27 allocs/op +BenchmarkMedium/leveldb-100000-100-16-40/query-hits-24 50000 31757 ns/op 2147 B/op 35 allocs/op +BenchmarkMedium/leveldb-100000-100-16-40/update-24 10000 297615 ns/op 52713 B/op 594 allocs/op +BenchmarkMedium/leveldb-100000-100-16-40/block-24 30 36791150 ns/op 6289507 B/op 67963 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 38.736s +Init Tree took 917.92 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkLarge/memdb-1000000-100-16-40/query-miss-24 100000 15781 ns/op 1061 B/op 20 allocs/op +BenchmarkLarge/memdb-1000000-100-16-40/query-hits-24 100000 15750 ns/op 829 B/op 15 allocs/op +BenchmarkLarge/memdb-1000000-100-16-40/update-24 300 5256647 ns/op 994044 B/op 20570 allocs/op +BenchmarkLarge/memdb-1000000-100-16-40/block-24 2 534785952 ns/op 100083320 B/op 2069277 allocs/op +Init Tree took 416.96 MB +BenchmarkLarge/goleveldb-1000000-100-16-40/query-miss-24 20000 59997 ns/op 4900 B/op 82 allocs/op +BenchmarkLarge/goleveldb-1000000-100-16-40/query-hits-24 30000 51637 ns/op 3748 B/op 62 allocs/op +BenchmarkLarge/goleveldb-1000000-100-16-40/update-24 10000 476117 ns/op 81887 B/op 838 allocs/op +BenchmarkLarge/goleveldb-1000000-100-16-40/block-24 30 56340657 ns/op 10034120 B/op 95529 allocs/op +Init Tree took 404.27 MB +BenchmarkLarge/leveldb-1000000-100-16-40/query-miss-24 20000 62528 ns/op 5003 B/op 81 allocs/op +BenchmarkLarge/leveldb-1000000-100-16-40/query-hits-24 30000 50966 ns/op 3701 B/op 61 allocs/op +BenchmarkLarge/leveldb-1000000-100-16-40/update-24 10000 456299 ns/op 86644 B/op 841 allocs/op +BenchmarkLarge/leveldb-1000000-100-16-40/block-24 30 58929008 ns/op 12193146 B/op 100887 allocs/op +Init Tree took 25.20 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/query-miss-24 50000 20237 ns/op 1659 B/op 26 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/query-hits-24 50000 26440 ns/op 2248 B/op 34 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/update-24 10000 276849 ns/op 52649 B/op 565 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/block-24 50 33371134 ns/op 5881967 B/op 65264 allocs/op +Init Tree took 39.72 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/query-miss-24 50000 23127 ns/op 2732 B/op 28 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/query-hits-24 50000 30518 ns/op 3739 B/op 37 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/update-24 10000 317968 ns/op 63822 B/op 616 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/block-24 50 40372117 ns/op 7424951 B/op 73717 allocs/op +Init Tree took 264.06 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/query-miss-24 30000 34792 ns/op 11953 B/op 30 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/query-hits-24 30000 45317 ns/op 16693 B/op 39 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/update-24 5000 521571 ns/op 189390 B/op 695 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/block-24 20 78074233 ns/op 26628664 B/op 93850 allocs/op +Init Tree took 2676.68 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/query-miss-24 10000 160833 ns/op 257161 B/op 65 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/query-hits-24 10000 172494 ns/op 312459 B/op 71 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/update-24 1000 3285298 ns/op 2404346 B/op 621 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/block-24 5 482757364 ns/op 364325902 B/op 84213 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 441.311s +PASS +ok github.com/tendermint/iavl/benchmarks 0.008s +Init Tree took 47.04 MB +goos: linux +goarch: amd64 +pkg: github.com/tendermint/iavl/benchmarks +BenchmarkLevelDBBatchSizes/goleveldb-100000-5-16-40/query-miss-24 50000 22448 ns/op 1530 B/op 25 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-5-16-40/query-hits-24 50000 32738 ns/op 2172 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-5-16-40/update-24 10000 515236 ns/op 78273 B/op 843 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-5-16-40/block-24 500 2702588 ns/op 402931 B/op 4385 allocs/op +Init Tree took 47.13 MB +BenchmarkLevelDBBatchSizes/goleveldb-100000-25-16-40/query-miss-24 50000 23648 ns/op 1598 B/op 27 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-25-16-40/query-hits-24 50000 28103 ns/op 2160 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-25-16-40/update-24 10000 351358 ns/op 65065 B/op 703 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-25-16-40/block-24 200 9918965 ns/op 1711946 B/op 18689 allocs/op +Init Tree took 42.02 MB +BenchmarkLevelDBBatchSizes/goleveldb-100000-100-16-40/query-miss-24 50000 24165 ns/op 1620 B/op 27 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-100-16-40/query-hits-24 50000 29367 ns/op 2154 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-100-16-40/update-24 10000 291198 ns/op 53061 B/op 594 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-100-16-40/block-24 30 35941442 ns/op 6034383 B/op 67049 allocs/op +Init Tree took 45.32 MB +BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/query-miss-24 50000 22196 ns/op 1579 B/op 26 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/query-hits-24 50000 28725 ns/op 2154 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/update-24 10000 200024 ns/op 40108 B/op 448 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/block-24 10 152324790 ns/op 23616529 B/op 273242 allocs/op +Init Tree took 38.47 MB +BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/query-miss-24 50000 22555 ns/op 1538 B/op 26 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/query-hits-24 50000 28427 ns/op 2159 B/op 35 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/update-24 10000 143810 ns/op 30211 B/op 320 allocs/op +BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/block-24 3 408154340 ns/op 78403509 B/op 815927 allocs/op +Init Tree took 27.54 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/query-miss-24 50000 20109 ns/op 1668 B/op 26 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/query-hits-24 50000 25620 ns/op 2243 B/op 34 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/update-24 10000 276745 ns/op 52750 B/op 566 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100/block-24 50 33831408 ns/op 5826982 B/op 64847 allocs/op +Init Tree took 39.80 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/query-miss-24 50000 23057 ns/op 2722 B/op 28 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/query-hits-24 50000 28850 ns/op 3742 B/op 37 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/update-24 10000 310652 ns/op 63335 B/op 617 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-1000/block-24 30 40865126 ns/op 7547879 B/op 74541 allocs/op +Init Tree took 266.72 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/query-miss-24 30000 33848 ns/op 12084 B/op 30 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/query-hits-24 30000 43692 ns/op 16592 B/op 39 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/update-24 10000 588636 ns/op 211307 B/op 754 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-10000/block-24 20 82922740 ns/op 29007420 B/op 93883 allocs/op +Init Tree took 2675.64 MB +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/query-miss-24 10000 147862 ns/op 250440 B/op 63 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/query-hits-24 10000 178420 ns/op 313624 B/op 72 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/update-24 1000 3606703 ns/op 2569932 B/op 640 allocs/op +BenchmarkLevelDBLargeData/goleveldb-50000-100-32-100000/block-24 5 459105626 ns/op 401755606 B/op 89339 allocs/op +PASS +ok github.com/tendermint/iavl/benchmarks 241.593s diff --git a/sei-iavl/benchmarks/sdk_results/README.md b/sei-iavl/benchmarks/sdk_results/README.md new file mode 100644 index 0000000000..1fef4d4e08 --- /dev/null +++ b/sei-iavl/benchmarks/sdk_results/README.md @@ -0,0 +1,21 @@ +Results.csv holdsthe results of running SDK benchmark with IAVL pruning testing with different pruning parameters. + +## Schema +every - keepEvery configuration +recent - keepRecent configuration +sim_time - SDK benchmark simulation run time +max_cpu - maximum CPU during simulation +max_mem - maximum memory usage during simulation + +## Steps to reproduce the results + +1. SSH into the machine you want to run the simulation and clone the Cosmos SDK +`git clone http://github.com/cosmos/cosmos-sdk` + +2. Checkout the tim/pruning-test branch +`git checkout tim/pruning-test` + +3. Run the grid_search.py script +`python grid_search.py` + +If you want to try a different range of pruning params, you can modify the script to change the min and max ranges. diff --git a/sei-iavl/benchmarks/sdk_results/results.csv b/sei-iavl/benchmarks/sdk_results/results.csv new file mode 100644 index 0000000000..f1024d0eb3 --- /dev/null +++ b/sei-iavl/benchmarks/sdk_results/results.csv @@ -0,0 +1,98 @@ +every,recent,sim_time,max_cpu,max_mem +1,151,1514.017,156.4,1312.793 +1,201,1532.657,159.4,1381.539 +1,251,1540.935,153.5,1431.125 +1,301,1538.684,165.0,1473.312 +1,351,1535.435,163.4,1510.496 +1,401,1541.614,167.5,1555.281 +1,451,1508.293,162.8,1568.688 +451,1,1416.687,129.2,312.594 +451,51,1438.157,131.7,662.992 +451,101,1470.564,132.6,926.523 +451,151,1492.237,134.3,1149.09 +451,201,1513.664,133.7,1250.734 +451,251,1515.880,134.9,1258.551 +451,301,1520.870,134.7,1313.852 +451,351,1520.953,134.4,1349.668 +451,401,1498.549,135.5,1396.91 +451,451,1486.171,136.4,1413.352 +101,1,1473.871,136.3,1477.281 +101,51,1451.413,136.3,1473.172 +101,101,1439.962,135.8,1454.371 +101,151,1434.421,135.9,1473.379 +101,201,1434.665,135.3,1474.691 +101,251,1437.749,135.5,1468.234 +101,301,1437.466,135.9,1451.621 +101,351,1438.126,135.9,1453.57 +101,401,1448.480,136.7,1472.062 +101,451,1450.976,135.7,1472.637 +201,1,1423.411,135.9,1469.059 +201,51,1422.885,136.0,1471.879 +201,101,1445.515,135.1,1474.887 +201,151,1426.950,135.0,1447.227 +201,201,1423.495,136.1,1452.746 +201,251,1430.685,136.4,1474.234 +201,301,1427.875,135.0,1445.262 +201,351,1442.899,135.8,1449.84 +201,401,1439.263,135.2,1454.102 +201,451,1445.961,135.9,1474.453 +301,1,1436.947,136.0,1473.016 +301,51,1429.552,135.8,1474.066 +301,101,1436.137,134.6,1472.137 +301,151,1440.573,135.5,1454.711 +301,201,1436.428,135.9,1476.141 +301,251,1432.788,135.9,1475.758 +301,301,1429.419,135.9,1471.59 +301,351,1427.612,135.5,1455.324 +301,401,1467.895,135.6,1374.039 +301,451,1447.902,134.4,1430.773 +401,1,1410.233,129.3,260.105 +401,51,1436.970,131.5,669.082 +401,101,1449.739,132.9,893.953 +401,151,1487.265,133.9,1149.93 +401,201,1485.108,134.2,1244.66 +401,251,1486.935,134.7,1297.875 +401,301,1500.033,136.1,1307.594 +401,351,1500.460,135.5,1333.438 +401,401,1488.885,136.1,1395.02 +401,451,1467.255,135.3,1428.539 +51,1,1402.913,129.2,300.777 +51,51,1439.816,135.7,1457.918 +51,101,1435.350,135.7,1472.102 +51,151,1448.041,136.1,1470.078 +51,201,1456.272,135.2,1451.703 +51,251,1437.499,135.7,1469.277 +51,301,1464.756,136.6,1474.988 +51,351,1465.644,137.2,1478.207 +51,401,1473.698,136.1,1482.172 +51,451,1466.381,136.0,1455.27 +151,1,1441.365,135.3,1452.402 +151,51,1447.196,136.5,1473.066 +151,101,1458.460,136.0,1473.312 +151,151,1443.220,134.6,1453.773 +151,201,1417.892,136.1,1470.895 +151,251,1430.177,135.7,1478.102 +151,301,1425.994,134.8,1452.426 +151,351,1430.587,135.8,1470.641 +151,401,1414.692,135.4,1465.562 +151,451,1423.519,135.0,1452.387 +251,1,1426.660,135.9,1451.523 +251,51,1439.819,135.4,1459.688 +251,101,1440.728,135.4,1450.691 +251,151,1435.941,136.0,1473.227 +251,201,1447.975,136.4,1472.16 +251,251,1423.207,135.3,1466.766 +251,301,1429.464,135.4,1474.418 +251,351,1427.153,135.9,1452.832 +251,401,1433.500,135.7,1476.754 +251,451,1431.558,135.9,1470.02 +351,1,1401.018,128.9,274.988 +351,51,1417.596,131.1,663.898 +351,101,1434.701,132.9,917.777 +351,151,1470.807,133.8,1169.207 +351,201,1469.728,135.1,1246.5 +351,251,1499.359,134.1,1270.023 +351,301,1478.456,135.3,1313.504 +351,351,1486.347,135.9,1337.0 +351,401,1477.687,135.6,1388.016 +351,451,1460.510,135.5,1422.824 \ No newline at end of file diff --git a/sei-iavl/benchmarks/setup/INSTALL_ROOT.sh b/sei-iavl/benchmarks/setup/INSTALL_ROOT.sh new file mode 100755 index 0000000000..bcd719c01f --- /dev/null +++ b/sei-iavl/benchmarks/setup/INSTALL_ROOT.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +export DEBIAN_FRONTEND=noninteractive + +apt-get update +apt-get -y upgrade +apt-get -y install screen wget git build-essential libsnappy-dev libgflags-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev + +# Installing leveldb from source +cd ~/ +git clone https://github.com/google/leveldb +cd leveldb +git checkout v1.7 +make -j2 +cp --preserve=links libleveldb.* /usr/local/lib +cp -r include/leveldb /usr/local/include/ +ldconfig + +# installing rocksdb from source +cd ~/ +git clone https://github.com/facebook/rocksdb +cd rocksdb +git checkout v6.15.5 +make -j4 install-shared +ldconfig + +# install go +cd ~/ +mkdir go +wget https://go.dev/dl/go1.17.6.linux-amd64.tar.gz +tar -C /usr/local -xzf go1.17.6.linux-amd64.tar.gz + diff --git a/sei-iavl/benchmarks/setup/RUN_BENCHMARKS.sh b/sei-iavl/benchmarks/setup/RUN_BENCHMARKS.sh new file mode 100755 index 0000000000..3c9dd4c8d0 --- /dev/null +++ b/sei-iavl/benchmarks/setup/RUN_BENCHMARKS.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# This runs benchmarks, by default from master branch of +# github.com/cosmos/iavl +# You can customize this by optional command line args +# +# INSTALL_USER.sh [branch] [repouser] +# +# set repouser as your username to time your fork + +BRANCH=${1:-master} +REPOUSER=${2:-tendermint} + +export PATH=$PATH:/usr/local/go/bin +export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin +export GOROOT=/usr/local/go +export GOPATH=$HOME/go + +export CGO_CFLAGS="-I/usr/local/include" +export CGO_LDFLAGS="-L/usr/local/lib -lleveldb -lrocksdb -lstdc++ -lm -lz -lbz2 -lsnappy -llz4 -lzstd" + +cd ~/ +git clone https://github.com/${REPOUSER}/iavl +cd iavl +git checkout ${BRANCH} + +make bench > results.txt + diff --git a/sei-iavl/buf.gen.yaml b/sei-iavl/buf.gen.yaml new file mode 100644 index 0000000000..f47275752f --- /dev/null +++ b/sei-iavl/buf.gen.yaml @@ -0,0 +1,17 @@ +# The version of the generation template. +# Required. +# The only currently-valid value is v1beta1. +version: v1beta1 + +# The plugins to run. +plugins: + # The name of the plugin. + - name: gogofaster + # The the relative output directory. + out: proto + # Any options to provide to the plugin. + opt: plugins=grpc,paths=source_relative + + - name: grpc-gateway + out: proto + opt: logtostderr=true,paths=source_relative diff --git a/sei-iavl/buf.yaml b/sei-iavl/buf.yaml new file mode 100644 index 0000000000..11558c5e7a --- /dev/null +++ b/sei-iavl/buf.yaml @@ -0,0 +1,14 @@ +version: v1beta1 + +build: + roots: + - proto + - third_party +lint: + use: + - MINIMAL + - FILE_LOWER_SNAKE_CASE + - FILE_LAYOUT +breaking: + use: + - FILE diff --git a/sei-iavl/cache/cache.go b/sei-iavl/cache/cache.go new file mode 100644 index 0000000000..a4ca88d672 --- /dev/null +++ b/sei-iavl/cache/cache.go @@ -0,0 +1,110 @@ +package cache + +import ( + "container/list" + + ibytes "github.com/cosmos/iavl/internal/bytes" +) + +// Node represents a node eligible for caching. +type Node interface { + GetKey() []byte +} + +// Cache is an in-memory structure to persist nodes for quick access. +// Please see lruCache for more details about why we need a custom +// cache implementation. +type Cache interface { + // Adds node to cache. If full and had to remove the oldest element, + // returns the oldest, otherwise nil. + // CONTRACT: node can never be nil. Otherwise, cache panics. + Add(node Node) Node + + // Returns Node for the key, if exists. nil otherwise. + Get(key []byte) Node + + // Has returns true if node with key exists in cache, false otherwise. + Has(key []byte) bool + + // Remove removes node with key from cache. The removed node is returned. + // if not in cache, return nil. + Remove(key []byte) Node + + // Len returns the cache length. + Len() int +} + +// lruCache is an LRU cache implementation. +// The motivation for using a custom cache implementation is to +// allow for a custom max policy. +// +// Currently, the cache maximum is implemented in terms of the +// number of nodes which is not intuitive to configure. +// Instead, we are planning to add a byte maximum. +// The alternative implementations do not allow for +// customization and the ability to estimate the byte +// size of the cache. +type lruCache struct { + dict map[string]*list.Element // FastNode cache. + maxElementCount int // FastNode the maximum number of nodes in the cache. + ll *list.List // LRU queue of cache elements. Used for deletion. +} + +var _ Cache = (*lruCache)(nil) + +func New(maxElementCount int) Cache { + return &lruCache{ + dict: make(map[string]*list.Element), + maxElementCount: maxElementCount, + ll: list.New(), + } +} + +func (c *lruCache) Add(node Node) Node { + keyStr := ibytes.UnsafeBytesToStr(node.GetKey()) + if e, exists := c.dict[keyStr]; exists { + c.ll.MoveToFront(e) + old := e.Value + e.Value = node + return old.(Node) + } + + elem := c.ll.PushFront(node) + c.dict[keyStr] = elem + + if c.ll.Len() > c.maxElementCount { + oldest := c.ll.Back() + return c.remove(oldest) + } + return nil +} + +func (nc *lruCache) Get(key []byte) Node { + if ele, hit := nc.dict[ibytes.UnsafeBytesToStr(key)]; hit { + nc.ll.MoveToFront(ele) + return ele.Value.(Node) + } + return nil +} + +func (c *lruCache) Has(key []byte) bool { + _, exists := c.dict[ibytes.UnsafeBytesToStr(key)] + return exists +} + +func (nc *lruCache) Len() int { + return nc.ll.Len() +} + +func (c *lruCache) Remove(key []byte) Node { + if elem, exists := c.dict[ibytes.UnsafeBytesToStr(key)]; exists { + return c.remove(elem) + } + return nil +} + +func (c *lruCache) remove(e *list.Element) Node { + removed := c.ll.Remove(e).(Node) + delete(c.dict, ibytes.UnsafeBytesToStr(removed.GetKey())) + return removed +} diff --git a/sei-iavl/cache/cache_bench_test.go b/sei-iavl/cache/cache_bench_test.go new file mode 100644 index 0000000000..7332b68697 --- /dev/null +++ b/sei-iavl/cache/cache_bench_test.go @@ -0,0 +1,69 @@ +package cache_test + +import ( + "math/rand" + "testing" + + "github.com/cosmos/iavl/cache" +) + +func BenchmarkAdd(b *testing.B) { + b.ReportAllocs() + testcases := map[string]struct { + cacheMax int + keySize int + }{ + "small - max: 10K, key size - 10b": { + cacheMax: 10000, + keySize: 10, + }, + "med - max: 100K, key size 20b": { + cacheMax: 100000, + keySize: 20, + }, + "large - max: 1M, key size 30b": { + cacheMax: 1000000, + keySize: 30, + }, + } + + for name, tc := range testcases { + cache := cache.New(tc.cacheMax) + b.Run(name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + key := randBytes(tc.keySize) + b.StartTimer() + + _ = cache.Add(&testNode{ + key: key, + }) + } + }) + } +} + +func BenchmarkRemove(b *testing.B) { + b.ReportAllocs() + + cache := cache.New(1000) + existentKeyMirror := [][]byte{} + // Populate cache + for i := 0; i < 50; i++ { + key := randBytes(1000) + + existentKeyMirror = append(existentKeyMirror, key) + + cache.Add(&testNode{ + key: key, + }) + } + + randSeed := 498727689 // For deterministic tests + r := rand.New(rand.NewSource(int64(randSeed))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + key := existentKeyMirror[r.Intn(len(existentKeyMirror))] + _ = cache.Remove(key) + } +} diff --git a/sei-iavl/cache/cache_test.go b/sei-iavl/cache/cache_test.go new file mode 100644 index 0000000000..7b2413ef3a --- /dev/null +++ b/sei-iavl/cache/cache_test.go @@ -0,0 +1,311 @@ +package cache_test + +import ( + "crypto/rand" + "fmt" + "testing" + + "github.com/cosmos/iavl/cache" + "github.com/stretchr/testify/require" +) + +// expectedResult represents the expected result of each add/remove operation. +// It can be noneRemoved or the index of the removed node in testNodes +type expectedResult int + +const ( + noneRemoved expectedResult = -1 + // The rest represent the index of the removed node +) + +// testNode is the node used for testing cache implementation +type testNode struct { + key []byte +} + +type cacheOp struct { + testNodexIdx int + expectedResult expectedResult +} + +type testcase struct { + setup func(cache.Cache) + cacheMax int + cacheOps []cacheOp + expectedNodeIndexes []int // contents of the cache once test case completes represent by indexes in testNodes +} + +func (tn *testNode) GetKey() []byte { + return tn.key +} + +const ( + testKey = "key" +) + +var _ cache.Node = (*testNode)(nil) + +var ( + testNodes = []cache.Node{ + &testNode{ + key: []byte(fmt.Sprintf("%s%d", testKey, 1)), + }, + &testNode{ + key: []byte(fmt.Sprintf("%s%d", testKey, 2)), + }, + &testNode{ + key: []byte(fmt.Sprintf("%s%d", testKey, 3)), + }, + } +) + +func Test_Cache_Add(t *testing.T) { + testcases := map[string]testcase{ + "add 1 node with 1 max - added": { + cacheMax: 1, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: noneRemoved, + }, + }, + expectedNodeIndexes: []int{0}, + }, + "add 1 node twice, cache max 2 - only one added": { + cacheMax: 2, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: noneRemoved, + }, + { + testNodexIdx: 0, + expectedResult: 0, + }, + }, + expectedNodeIndexes: []int{0}, + }, + "add 1 node with 0 max - not added and return itself": { + cacheMax: 0, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: 0, + }, + }, + }, + "add 3 nodes with 1 max - first 2 removed": { + cacheMax: 1, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: noneRemoved, + }, + { + testNodexIdx: 1, + expectedResult: 0, + }, + { + testNodexIdx: 2, + expectedResult: 1, + }, + }, + expectedNodeIndexes: []int{2}, + }, + "add 3 nodes with 2 max - first removed": { + cacheMax: 2, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: noneRemoved, + }, + { + testNodexIdx: 1, + expectedResult: noneRemoved, + }, + { + testNodexIdx: 2, + expectedResult: 0, + }, + }, + expectedNodeIndexes: []int{1, 2}, + }, + "add 3 nodes with 10 max - non removed": { + cacheMax: 10, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: noneRemoved, + }, + { + testNodexIdx: 1, + expectedResult: noneRemoved, + }, + { + testNodexIdx: 2, + expectedResult: noneRemoved, + }, + }, + expectedNodeIndexes: []int{0, 1, 2}, + }, + } + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + cache := cache.New(tc.cacheMax) + + expectedCurSize := 0 + + for _, op := range tc.cacheOps { + + actualResult := cache.Add(testNodes[op.testNodexIdx]) + + expectedResult := op.expectedResult + + if expectedResult == noneRemoved { + require.Nil(t, actualResult) + expectedCurSize++ + } else { + require.NotNil(t, actualResult) + + // Here, op.expectedResult represents the index of the removed node in tc.cacheOps + require.Equal(t, testNodes[int(op.expectedResult)], actualResult) + } + require.Equal(t, expectedCurSize, cache.Len()) + } + + validateCacheContentsAfterTest(t, tc, cache) + }) + } +} + +func Test_Cache_Remove(t *testing.T) { + testcases := map[string]testcase{ + "remove non-existent key, cache max 0 - nil returned": { + cacheMax: 0, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: noneRemoved, + }, + }, + }, + "remove non-existent key, cache max 1 - nil returned": { + setup: func(c cache.Cache) { + require.Nil(t, c.Add(testNodes[1])) + require.Equal(t, 1, c.Len()) + }, + cacheMax: 1, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: noneRemoved, + }, + }, + expectedNodeIndexes: []int{1}, + }, + "remove existent key, cache max 1 - removed": { + setup: func(c cache.Cache) { + require.Nil(t, c.Add(testNodes[0])) + require.Equal(t, 1, c.Len()) + }, + cacheMax: 1, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: 0, + }, + }, + }, + "remove twice, cache max 1 - removed first time, then nil": { + setup: func(c cache.Cache) { + require.Nil(t, c.Add(testNodes[0])) + require.Equal(t, 1, c.Len()) + }, + cacheMax: 1, + cacheOps: []cacheOp{ + { + testNodexIdx: 0, + expectedResult: 0, + }, + { + testNodexIdx: 0, + expectedResult: noneRemoved, + }, + }, + }, + "remove all, cache max 3": { + setup: func(c cache.Cache) { + require.Nil(t, c.Add(testNodes[0])) + require.Nil(t, c.Add(testNodes[1])) + require.Nil(t, c.Add(testNodes[2])) + require.Equal(t, 3, c.Len()) + }, + cacheMax: 3, + cacheOps: []cacheOp{ + { + testNodexIdx: 2, + expectedResult: 2, + }, + { + testNodexIdx: 0, + expectedResult: 0, + }, + { + testNodexIdx: 1, + expectedResult: 1, + }, + }, + }, + } + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + cache := cache.New(tc.cacheMax) + + if tc.setup != nil { + tc.setup(cache) + } + + expectedCurSize := cache.Len() + + for _, op := range tc.cacheOps { + + actualResult := cache.Remove(testNodes[op.testNodexIdx].GetKey()) + + expectedResult := op.expectedResult + + if expectedResult == noneRemoved { + require.Nil(t, actualResult) + } else { + expectedCurSize-- + require.NotNil(t, actualResult) + + // Here, op.expectedResult represents the index of the removed node in tc.cacheOps + require.Equal(t, testNodes[int(op.expectedResult)], actualResult) + } + require.Equal(t, expectedCurSize, cache.Len()) + } + + validateCacheContentsAfterTest(t, tc, cache) + }) + } +} + +func validateCacheContentsAfterTest(t *testing.T, tc testcase, cache cache.Cache) { + require.Equal(t, len(tc.expectedNodeIndexes), cache.Len()) + for _, idx := range tc.expectedNodeIndexes { + expectedNode := testNodes[idx] + require.True(t, cache.Has(expectedNode.GetKey())) + require.Equal(t, expectedNode, cache.Get(expectedNode.GetKey())) + } +} + +func randBytes(length int) []byte { + key := make([]byte, length) + // math.rand.Read always returns err=nil + // we do not need cryptographic randomness for this test: + //nolint:gosec + rand.Read(key) + return key +} diff --git a/sei-iavl/cmd/iaviewer/README.md b/sei-iavl/cmd/iaviewer/README.md new file mode 100644 index 0000000000..ef21f1b983 --- /dev/null +++ b/sei-iavl/cmd/iaviewer/README.md @@ -0,0 +1,118 @@ +# IaViewer + +`iaviewer` is a utility to inspect the contents of a persisted iavl tree, given (a copy of) the leveldb store. +This can be quite useful for debugging, especially when you find odd errors, or non-deterministic behavior. +Below is a brief introduction to the tool. + +## Installation + +Once this is merged into the offical repo, master, you should be able to do: + +```shell +go get github.com/cosmos/iavl +cd ${GOPATH}/src/github.com/cosmos/iavl +make install +``` + +## Using the tool + +First make sure it is properly installed and you have `${GOPATH}/bin` in your `PATH`. +Typing `iaviewer` should run and print out a usage message. + +### Sample databases + +Once you understand the tool, you will most likely want to run it on captures from your +own abci app (built on cosmos-sdk or weave), but as a tutorial, you can try to use some +captures from an actual bug I found in my code... Same data, different hash. + +```shell +mkdir ./testdata +cd ./testdata +curl -L https://github.com/iov-one/iavl/files/2860877/bns-a.db.zip > bns-a.db.zip +unzip bns-a.db.zip +curl -L https://github.com/iov-one/iavl/files/2860878/bns-b.db.zip > bns-b.db.zip +unzip bns-b.db.zip +``` + +Now, if you run `ls -l`, you should see two directories... `bns-a.db` and `bns-b.db` + +### Inspecting available versions + +```shell +iaviewer versions ./bns-a.db "" +``` + +This should print out a list of 20 versions of the code. Note the the iavl tree will persist multiple +historical versions, which is a great aid in forensic queries (thanks Tendermint team!). For the rest +of the cases, we will consider only the last two versions, 190257 (last one where they match) and 190258 +(where they are different). + +### Checking keys and app hash + +First run these two and take a quick a look at the output: + +```shell +iaviewer data ./bns-a.db "" +iaviewer data ./bns-a.db "" 190257 +``` + +Notice you see the different heights and there is a change in size and app hash. +That's what happens when we process a transaction. Let's go further and use +the handy tool `diff` to compare two states. + +```shell +iaviewer data ./bns-a.db "" 190257 > a-last.data +iaviewer data ./bns-b.db "" 190257 > b-last.data + +diff a-last.data b-last.data +``` + +Same, same :) +But if we take the current version... + +```shell +iaviewer data ./bns-a.db "" 190258 > a-cur.data +iaviewer data ./bns-b.db "" 190258 > b-cur.data + +diff a-cur.data b-cur.data +``` + +Hmmm... everything is the same, except the hash. Odd... +So odd that I [wrote an article about it](https://medium.com/@ethan.frey/tracking-down-a-tendermint-consensus-failure-77f6ff414406) + +And finally, if we want to inspect which keys were modified in the last block: + +```shell +diff a-cur.data a-last.data +``` + +You should see 6 writes.. the `_i.usernft_*` are the secondary indexes on the username nft. +`sigs.*` is setting the nonce (if this were an update, you would see a previous value). +And `usrnft:*` is creating the actual username nft. + +### Checking the tree shape + +So, remember above, when we found that the current state of a and b have the same data +but different hashes. This must be due to the shape of the iavl tree. +To confirm that, and possibly get more insights, there is another command. + +```shell +iaviewer shape ./bns-a.db "" 190258 > a-cur.shape +iaviewer shape ./bns-b.db "" 190258 > b-cur.shape + +diff a-cur.shape b-cur.shape +``` + +Yup, that is quite some difference. You can also look at the tree as a whole. +So, stretch your terminal nice and wide, and... + +```shell +less a-cur.shape +``` + +It has `-5 ` for an inner node of depth 5, and `*6 ` for a leaf node (data) of depth 6. +Indentation also suggests the shape of the tree. + +Note, if anyone wants to improve the visualization, that would be awesome. +I have no idea how to do this well, but at least text output makes some +sense and is diff-able. \ No newline at end of file diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go new file mode 100644 index 0000000000..871e512aed --- /dev/null +++ b/sei-iavl/cmd/iaviewer/main.go @@ -0,0 +1,188 @@ +package main + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "fmt" + "os" + "strconv" + "strings" + + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/iavl" + ibytes "github.com/cosmos/iavl/internal/bytes" +) + +// TODO: make this configurable? +const ( + DefaultCacheSize int = 10000 +) + +func main() { + args := os.Args[1:] + if len(args) < 3 || (args[0] != "data" && args[0] != "shape" && args[0] != "versions") { + fmt.Fprintln(os.Stderr, "Usage: iaviewer [version number]") + fmt.Fprintln(os.Stderr, " is the prefix of db, and the iavl tree of different modules in cosmos-sdk uses ") + fmt.Fprintln(os.Stderr, "different to identify, just like \"s/k:gov/\" represents the prefix of gov module") + os.Exit(1) + } + + version := 0 + if len(args) == 4 { + var err error + version, err = strconv.Atoi(args[3]) + if err != nil { + fmt.Fprintf(os.Stderr, "Invalid version number: %s\n", err) + os.Exit(1) + } + } + + tree, err := ReadTree(args[1], version, []byte(args[2])) + if err != nil { + fmt.Fprintf(os.Stderr, "Error reading data: %s\n", err) + os.Exit(1) + } + + switch args[0] { + case "data": + PrintKeys(tree) + hash, err := tree.Hash() + if err != nil { + fmt.Fprintf(os.Stderr, "Error hashing tree: %s\n", err) + os.Exit(1) + } + fmt.Printf("Hash: %X\n", hash) + fmt.Printf("Size: %X\n", tree.Size()) + case "shape": + PrintShape(tree) + case "versions": + PrintVersions(tree) + } +} + +func OpenDB(dir string) (dbm.DB, error) { + switch { + case strings.HasSuffix(dir, ".db"): + dir = dir[:len(dir)-3] + case strings.HasSuffix(dir, ".db/"): + dir = dir[:len(dir)-4] + default: + return nil, fmt.Errorf("database directory must end with .db") + } + // TODO: doesn't work on windows! + cut := strings.LastIndex(dir, "/") + if cut == -1 { + return nil, fmt.Errorf("cannot cut paths on %s", dir) + } + name := dir[cut+1:] + db, err := dbm.NewGoLevelDB(name, dir[:cut]) + if err != nil { + return nil, err + } + return db, nil +} + +// nolint: deadcode +func PrintDBStats(db dbm.DB) { + count := 0 + prefix := map[string]int{} + itr, err := db.Iterator(nil, nil) + if err != nil { + panic(err) + } + + defer itr.Close() + for ; itr.Valid(); itr.Next() { + key := ibytes.UnsafeBytesToStr(itr.Key()[:1]) + prefix[key]++ + count++ + } + if err := itr.Error(); err != nil { + panic(err) + } + fmt.Printf("DB contains %d entries\n", count) + for k, v := range prefix { + fmt.Printf(" %s: %d\n", k, v) + } +} + +// ReadTree loads an iavl tree from the directory +// If version is 0, load latest, otherwise, load named version +// The prefix represents which iavl tree you want to read. The iaviwer will always set a prefix. +func ReadTree(dir string, version int, prefix []byte) (*iavl.MutableTree, error) { + db, err := OpenDB(dir) + if err != nil { + return nil, err + } + if len(prefix) != 0 { + db = dbm.NewPrefixDB(db, prefix) + } + + tree, err := iavl.NewMutableTree(db, DefaultCacheSize, false) + if err != nil { + return nil, err + } + ver, err := tree.LoadVersion(int64(version)) + fmt.Printf("Got version: %d\n", ver) + return tree, err +} + +func PrintKeys(tree *iavl.MutableTree) { + fmt.Println("Printing all keys with hashed values (to detect diff)") + tree.Iterate(func(key []byte, value []byte) bool { + printKey := parseWeaveKey(key) + digest := sha256.Sum256(value) + fmt.Printf(" %s\n %X\n", printKey, digest) + return false + }) +} + +// parseWeaveKey assumes a separating : where all in front should be ascii, +// and all afterwards may be ascii or binary +func parseWeaveKey(key []byte) string { + cut := bytes.IndexRune(key, ':') + if cut == -1 { + return encodeID(key) + } + prefix := key[:cut] + id := key[cut+1:] + return fmt.Sprintf("%s:%s", encodeID(prefix), encodeID(id)) +} + +// casts to a string if it is printable ascii, hex-encodes otherwise +func encodeID(id []byte) string { + for _, b := range id { + if b < 0x20 || b >= 0x80 { + return strings.ToUpper(hex.EncodeToString(id)) + } + } + return string(id) +} + +func PrintShape(tree *iavl.MutableTree) { + // shape := tree.RenderShape(" ", nil) + //TODO: handle this error + shape, _ := tree.RenderShape(" ", nodeEncoder) + fmt.Println(strings.Join(shape, "\n")) +} + +func nodeEncoder(id []byte, depth int, isLeaf bool) string { + prefix := fmt.Sprintf("-%d ", depth) + if isLeaf { + prefix = fmt.Sprintf("*%d ", depth) + } + if len(id) == 0 { + return fmt.Sprintf("%s", prefix) + } + return fmt.Sprintf("%s%s", prefix, parseWeaveKey(id)) +} + +func PrintVersions(tree *iavl.MutableTree) { + versions := tree.AvailableVersions() + fmt.Println("Available versions:") + for _, v := range versions { + fmt.Printf(" %d\n", v) + } +} diff --git a/sei-iavl/codecov.yml b/sei-iavl/codecov.yml new file mode 100644 index 0000000000..9bf12242fb --- /dev/null +++ b/sei-iavl/codecov.yml @@ -0,0 +1,28 @@ +# +# This codecov.yml is the default configuration for +# all repositories on Codecov. You may adjust the settings +# below in your own codecov.yml in your repository. +# +codecov: + require_ci_to_pass: yes + +coverage: + precision: 2 + round: down + range: 70...100 + + status: + # Learn more at https://docs.codecov.io/docs/commit-status + project: + default: + threshold: 1% # allow this much decrease on project + +comment: + layout: "reach, diff, files, tree" + behavior: default # update if exists else create new + require_changes: true + +ignore: + - "docs" + - "benchmarks/" + - "**.pb.go" diff --git a/sei-iavl/doc.go b/sei-iavl/doc.go new file mode 100644 index 0000000000..97ae918aff --- /dev/null +++ b/sei-iavl/doc.go @@ -0,0 +1,54 @@ +// Package iavl implements a versioned, snapshottable (immutable) AVL+ tree +// for persisting key-value pairs. +// +// The tree is not safe for concurrent use, and must be guarded by a Mutex +// or RWLock as appropriate - the exception is immutable trees returned by +// MutableTree.GetImmutable() which are safe for concurrent use as long as +// the version is not deleted via DeleteVersion(). +// +// +// Basic usage of MutableTree: +// +// import "github.com/cosmos/iavl" +// import "github.com/tendermint/tm-db" +// ... +// +// tree := iavl.NewMutableTree(db.NewMemDB(), 128) +// +// tree.IsEmpty() // true +// +// tree.Set([]byte("alice"), []byte("abc")) +// tree.SaveVersion(1) +// +// tree.Set([]byte("alice"), []byte("xyz")) +// tree.Set([]byte("bob"), []byte("xyz")) +// tree.SaveVersion(2) +// +// tree.LatestVersion() // 2 +// +// tree.GetVersioned([]byte("alice"), 1) // "abc" +// tree.GetVersioned([]byte("alice"), 2) // "xyz" +// +// Proof of existence: +// +// root := tree.Hash() +// val, proof, err := tree.GetVersionedWithProof([]byte("bob"), 2) // "xyz", RangeProof, nil +// proof.Verify([]byte("bob"), val, root) // nil +// +// Proof of absence: +// +// _, proof, err = tree.GetVersionedWithProof([]byte("tom"), 2) // nil, RangeProof, nil +// proof.Verify([]byte("tom"), nil, root) // nil +// +// Now we delete an old version: +// +// tree.DeleteVersion(1) +// tree.VersionExists(1) // false +// tree.Get([]byte("alice")) // "xyz" +// tree.GetVersioned([]byte("alice"), 1) // nil +// +// Can't create a proof of absence for a version we no longer have: +// +// _, proof, err = tree.GetVersionedWithProof([]byte("tom"), 1) // nil, nil, error +// +package iavl diff --git a/sei-iavl/docs/architecture/README.md b/sei-iavl/docs/architecture/README.md new file mode 100644 index 0000000000..ea59d1670f --- /dev/null +++ b/sei-iavl/docs/architecture/README.md @@ -0,0 +1,24 @@ +# Architecture Decision Records (ADR) + +This is a location to record all high-level architecture decisions for the Golang IAVL library. + +You can read more about the ADR concept in this [blog post](https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t). + +An ADR should provide: + +- Context on the relevant goals and the current state +- Proposed changes to achieve the goals +- Summary of pros and cons +- References +- Changelog + +Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something new. The spec is +much more compressed and streamlined summary of everything as it stands today. + +If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, +and then modify the code to match. + +## ADR Table of Contents + +- [ADR 001: Flush Version](./adr-001-flush-version.md) diff --git a/sei-iavl/docs/architecture/adr-template.md b/sei-iavl/docs/architecture/adr-template.md new file mode 100644 index 0000000000..657f85605a --- /dev/null +++ b/sei-iavl/docs/architecture/adr-template.md @@ -0,0 +1,47 @@ +# ADR {ADR-NUMBER}: {TITLE} + +## Changelog + +- {date}: {changelog} + +## Status + +> A decision may be "proposed" if the project stakeholders haven't agreed with it yet, or "accepted" +> once it is agreed. If a later ADR changes or reverses a decision, it may be marked as "deprecated" +> or "superseded" with a reference to its replacement. +> {Deprecated|Proposed|Accepted} + +## Context + +> This section describes the forces at play, including technological, political, social, and project +> local. These forces are probably in tension, and should be called out as such. The language in this +> section is value-neutral. It is simply describing facts. +> {context body} + +## Decision + +> This section describes our response to these forces. It is stated in full sentences, with active +> voice. "We will ...". +> {decision body} + +## Consequences + +> This section describes the resulting context, after applying the decision. All consequences should +> be listed here, not just the "positive" ones. A particular decision may have positive, negative, +> and neutral consequences, but all of them affect the team and project in the future. + +### Positive + +{positive consequences} + +### Negative + +{negative consequences} + +### Neutral + +{neutral consequences} + +## References + +- {reference link} diff --git a/sei-iavl/docs/node/key_format.md b/sei-iavl/docs/node/key_format.md new file mode 100644 index 0000000000..f180ce66eb --- /dev/null +++ b/sei-iavl/docs/node/key_format.md @@ -0,0 +1,36 @@ +# Key Format + +Nodes, orphans, and roots are stored under the database with different key formats to ensure there are no key collisions and a structured key from which we can extract useful information. + +### Nodes + +Node KeyFormat: `n|` + +Nodes are marshalled and stored under nodekey with prefix `n` to prevent collisions and then appended with the node's hash. + +### Orphans + +Orphan KeyFormat: `o|toVersion|fromVersion|hash` + +Orphans are marshalled nodes stored with prefix `o` to prevent collisions. You can extract the toVersion, fromVersion and hash from the orphan key by using: + +```golang +// orphanKey: o|50|30|0xABCD +var toVersion, fromVersion int64 +var hash []byte +orphanKeyFormat.Scan(orphanKey, &toVersion, &fromVersion, hash) + +/* +toVersion = 50 +fromVersion = 30 +hash = 0xABCD +*/ +``` + +The order of the orphan KeyFormat matters. Since deleting a version `v` will delete all orphans whose `toVersion = v`, we can easily retrieve all orphans from nodeDb by iterating over the key prefix: `o|v`. + +### Roots + +Root KeyFormat: `r|` + +Root hash of the IAVL tree at version `v` is stored under the key `r|v` (prefixed with `r` to avoid collision). diff --git a/sei-iavl/docs/node/node.md b/sei-iavl/docs/node/node.md new file mode 100644 index 0000000000..24647fe1bf --- /dev/null +++ b/sei-iavl/docs/node/node.md @@ -0,0 +1,133 @@ +# Node + +The Node struct stores a node in the IAVL tree. + +### Structure + +```golang +// Node represents a node in a Tree. +type Node struct { + key []byte // key for the node. + value []byte // value of leaf node. If inner node, value = nil + version int64 // The version of the IAVL that this node was first added in. + height int8 // The height of the node. Leaf nodes have height 0 + size int64 // The number of leaves that are under the current node. Leaf nodes have size = 1 + hash []byte // hash of above field and leftHash, rightHash + leftHash []byte // hash of left child + leftNode *Node // pointer to left child + rightHash []byte // hash of right child + rightNode *Node // pointer to right child + persisted bool // persisted to disk +} +``` + +Inner nodes have keys equal to the highest key on their left branch and have values set to nil. + +The version of a node is the first version of the IAVL tree that the node gets added in. Future versions of the IAVL may point to this node if they also contain the node, however the node's version itself does not change. + +Size is the number of leaves under a given node. With a full subtree, `node.size = 2^(node.height)`. + +### Marshaling + +Every node is persisted by encoding the key, version, height, size and hash. If the node is a leaf node, then the value is persisted as well. If the node is not a leaf node, then the leftHash and rightHash are persisted as well. + +```golang +// Writes the node as a serialized byte slice to the supplied io.Writer. +func (node *Node) writeBytes(w io.Writer) error { + cause := encodeVarint(w, node.height) + if cause != nil { + return errors.Wrap(cause, "writing height") + } + cause = encodeVarint(w, node.size) + if cause != nil { + return errors.Wrap(cause, "writing size") + } + cause = encodeVarint(w, node.version) + if cause != nil { + return errors.Wrap(cause, "writing version") + } + + // Unlike writeHashBytes, key is written for inner nodes. + cause = encodeBytes(w, node.key) + if cause != nil { + return errors.Wrap(cause, "writing key") + } + + if node.isLeaf() { + cause = encodeBytes(w, node.value) + if cause != nil { + return errors.Wrap(cause, "writing value") + } + } else { + if node.leftHash == nil { + panic("node.leftHash was nil in writeBytes") + } + cause = encodeBytes(w, node.leftHash) + if cause != nil { + return errors.Wrap(cause, "writing left hash") + } + + if node.rightHash == nil { + panic("node.rightHash was nil in writeBytes") + } + cause = encodeBytes(w, node.rightHash) + if cause != nil { + return errors.Wrap(cause, "writing right hash") + } + } + return nil +} +``` + +### Hashes + +A node's hash is calculated by hashing the height, size, and version of the node. If the node is a leaf node, then the key and value are also hashed. If the node is an inner node, the leftHash and rightHash are included in hash but the key is not. + +```golang +// Writes the node's hash to the given io.Writer. This function expects +// child hashes to be already set. +func (node *Node) writeHashBytes(w io.Writer) error { + err := encodeVarint(w, node.height) + if err != nil { + return errors.Wrap(err, "writing height") + } + err = encodeVarint(w, node.size) + if err != nil { + return errors.Wrap(err, "writing size") + } + err = encodeVarint(w, node.version) + if err != nil { + return errors.Wrap(err, "writing version") + } + + // Key is not written for inner nodes, unlike writeBytes. + + if node.isLeaf() { + err = encodeBytes(w, node.key) + if err != nil { + return errors.Wrap(err, "writing key") + } + // Indirection needed to provide proofs without values. + // (e.g. proofLeafNode.ValueHash) + valueHash := tmhash.Sum(node.value) + err = encodeBytes(w, valueHash) + if err != nil { + return errors.Wrap(err, "writing value") + } + } else { + if node.leftHash == nil || node.rightHash == nil { + panic("Found an empty child hash") + } + err = encodeBytes(w, node.leftHash) + if err != nil { + return errors.Wrap(err, "writing left hash") + } + err = encodeBytes(w, node.rightHash) + if err != nil { + return errors.Wrap(err, "writing right hash") + } + } + + return nil +} +``` diff --git a/sei-iavl/docs/node/nodedb.md b/sei-iavl/docs/node/nodedb.md new file mode 100644 index 0000000000..2224d35cb6 --- /dev/null +++ b/sei-iavl/docs/node/nodedb.md @@ -0,0 +1,56 @@ +# NodeDB + +### Structure + +The nodeDB is responsible for persisting nodes, orphans, and roots correctly in persistent storage. + +### Saving Versions + +The nodeDB saves the roothash of the IAVL tree under the key: `r|`. + +It marshals and saves any new node that has been created under: `n|`. For more details on how the node gets marshaled, see [node documentation](./node.md). Any old node that is still part of the latest IAVL tree will not get rewritten. Instead its parent will simply have a hash pointer with which the nodeDB can retrieve the old node if necessary. + +Any old nodes that were part of the previous version IAVL but are no longer part of this one have been saved in an orphan map `orphan.hash => orphan.version`. This map will get passed into the nodeDB's `SaveVersion` function. The map maps from the orphan's hash to the version that it was added to the IAVL tree. The nodeDB iterates through this map and stores each marshalled orphan node under the key: `o|toVersion|fromVersion`. Since the toVersion is always the previous version (if we are saving version `v`, toVersion of all new orphans is `v-1`), we can save the orphans by iterating over the map and saving: `o|(latestVersion-1)|orphan.fromVersion => orphan.hash`. + +(For more details on key formats see the [keyformat docs](./key_format.md)) + +### Deleting Versions + +When a version `v` is deleted, the roothash corresponding to version `v` is deleted from nodeDB. All orphans whose `toVersion = v`, will get the `toVersion` pushed back to the highest predecessor of `v` that still exists in nodeDB. If the `toVersion <= fromVersion` then this implies that there does not exist a version of the IAVL tree in the nodeDB that still contains this node. Thus, it can be safely deleted and uncached. + +##### Deleting Orphans + +The deleteOrphans algorithm is shown below: + +```golang +// deleteOrphans deletes orphaned nodes from disk, and the associated orphan +// entries. +func (ndb *nodeDB) deleteOrphans(version int64) { + // Will be zero if there is no previous version. + predecessor := ndb.getPreviousVersion(version) + + // Traverse orphans with a lifetime ending at the version specified. + ndb.traverseOrphansVersion(version, func(key, hash []byte) { + var fromVersion, toVersion int64 + + // See comment on `orphanKeyFmt`. Note that here, `version` and + // `toVersion` are always equal. + orphanKeyFormat.Scan(key, &toVersion, &fromVersion) + + // Delete orphan key and reverse-lookup key. + ndb.batch.Delete(key) + + // If there is no predecessor, or the predecessor is earlier than the + // beginning of the lifetime (ie: negative lifetime), or the lifetime + // spans a single version and that version is the one being deleted, we + // can delete the orphan. Otherwise, we shorten its lifetime, by + // moving its endpoint to the previous version. + if predecessor < fromVersion || fromVersion == toVersion { + ndb.batch.Delete(ndb.nodeKey(hash)) + ndb.uncacheNode(hash) + } else { + ndb.saveOrphan(hash, fromVersion, predecessor) + } + }) +} +``` diff --git a/sei-iavl/docs/overview.md b/sei-iavl/docs/overview.md new file mode 100644 index 0000000000..02f32fc406 --- /dev/null +++ b/sei-iavl/docs/overview.md @@ -0,0 +1,42 @@ +# IAVL Spec + +The IAVL tree is a versioned, snapshottable (immutable) AVL+ tree for persistent data. + +The purpose of this data structure is to provide persistent storage for key-value pairs (say to store account balances) such that a deterministic merkle root hash can be computed. The tree is balanced using a variant of the [AVL algorithm](http://en.wikipedia.org/wiki/AVL_tree) so all operations are O(log(n)). + +Nodes of this tree are immutable and indexed by their hash. Thus any node serves as an immutable snapshot which lets us stage uncommitted transactions from the mempool cheaply, and we can instantly roll back to the last committed state to process transactions of a newly committed block (which may not be the same set of transactions as those from the mempool). + +In an AVL tree, the heights of the two child subtrees of any node differ by at most one. Whenever this condition is violated upon an update, the tree is rebalanced by creating O(log(n)) new nodes that point to unmodified nodes of the old tree. In the original AVL algorithm, inner nodes can also hold key-value pairs. The AVL+ algorithm (note the plus) modifies the AVL algorithm to keep all values on leaf nodes, while only using branch-nodes to store keys. This simplifies the algorithm while keeping the merkle hash trail short. + +The IAVL tree will typically be wrapped by a `MutableTree` to enable updates to the tree. Any changes between versions get persisted to disk while nodes that exist in both the old version and new version are simply pointed to by the respective tree without duplicated the node data. + +When a node is no longer part of the latest IAVL tree, it is called an orphan. The orphaned node will exist in the nodeDB so long as there are versioned IAVL trees that are persisted in nodeDB that contain the orphaned node. Once all trees that referred to orphaned node have been deleted from database, the orphaned node will also get deleted. + +In Ethereum, the analog is [Patricia tries](http://en.wikipedia.org/wiki/Radix_tree). There are tradeoffs. Keys do not need to be hashed prior to insertion in IAVL+ trees, so this provides faster iteration in the key space which may benefit some applications. The logic is simpler to implement, requiring only two types of nodes -- inner nodes and leaf nodes. On the other hand, while IAVL+ trees provide a deterministic merkle root hash, it depends on the order of transactions. In practice this shouldn't be a problem, since you can efficiently encode the tree structure when serializing the tree contents. + +### Suggested Order for Understanding IAVL + +1. [Node docs](./node/node.md) + - Explains node structure + - Explains how node gets marshalled and hashed +2. [KeyFormat docs](./node/key_format.md) + - Explains keyformats for how nodes, orphans, and roots are stored under formatted keys in database +3. [NodeDB docs](./node/nodedb.md): + - Explains how nodes, orphans, roots get saved in database + - Explains saving and deleting tree logic. +4. [ImmutableTree docs](./tree/immutable_tree.md) + - Explains ImmutableTree structure + - Explains ImmutableTree Iteration functions +5. [MutableTree docs](./tree/mutable_tree.md) + - Explains MutableTree structure + - Explains how to make updates (set/delete) to current working tree of IAVL + - Explains how automatic rebalancing of IAVL works + - Explains how Saving and Deleting versions of IAVL works +6. [Proof docs](./proof/proof.md) + - Explains what Merkle proofs are + - Explains how IAVL supports presence, absence, and range proofs + - Explains the IAVL proof data structures +7. [Export/import docs](./tree/export_import.md) + - Explains the overall export/import functionality + - Explains the `ExportNode` format for exported nodes + - Explains the algorithms for exporting and importing nodes \ No newline at end of file diff --git a/sei-iavl/docs/proof/proof.md b/sei-iavl/docs/proof/proof.md new file mode 100644 index 0000000000..ad4617ddd2 --- /dev/null +++ b/sei-iavl/docs/proof/proof.md @@ -0,0 +1,347 @@ +# Proofs + +What sets IAVL apart from most other key/value stores is the ability to return +[Merkle proofs](https://en.wikipedia.org/wiki/Merkle_tree) along with values. These proofs can +be used to verify that a returned value is, in fact, the value contained within a given IAVL tree. +This verification is done by comparing the proof's root hash with the tree's root hash. + +Somewhat simplified, an IAVL tree is a variant of a +[binary search tree](https://en.wikipedia.org/wiki/Binary_search_tree) where inner nodes contain +keys used for binary search, and leaf nodes contain the actual key/value pairs ordered by key. +Consider the following example, containing five key/value pairs (such as key `a` with value `1`): + +``` + d + / \ + c e + / \ / \ + b c=3 d=4 e=5 + / \ +a=1 b=2 +``` + +In reality, IAVL nodes contain more data than shown here - for details please refer to the +[node documentation](../node/node.md). However, this simplified version is sufficient for an +overview. + +A cryptographically secure hash is generated for each node in the tree by hashing the node's key +and value (if leaf node), version, and height, as well as the hashes of each direct child (if +any). This implies that the hash of any given node also depends on the hashes of all descendants +of the node. In turn, this implies that the hash of the root node depends on the hashes of all +nodes (and therefore all data) in the tree. + +If we fetch the value `a=1` from the tree and want to verify that this is the correct value, we +need the following information: + +``` + d + / \ + c hash=d6f56d + / \ + b hash=ec6088 + / \ +a,hash(1) hash=92fd030 +``` + +Note that we take the hash of the value of `a=1` instead of simply using the value `1` itself; +both would work, but the value can be arbitrarily large while the hash has a constant size. + +With this data, we are able to compute the hashes for all nodes up to and including the root, +and can compare this root hash with the root hash of the IAVL tree - if they match, we can be +reasonably certain that the provided value is the same as the value in the tree. This data is +therefore considered a _proof_ for the value. Notice how we don't need to include any data from +e.g. the `e`-branch of the tree at all, only the hash - as the tree grows in size, these savings +become very significant, requiring only `logâ‚‚(n)` hashes for a tree of `n` keys. + +However, this still introduces quite a bit of overhead. Since we usually want to fetch several +values from the tree and verify them, it is often useful to generate a _range proof_, which can +prove any and all key/value pairs within a contiguous, ordered key range. For example, the +following proof can verify both `a=1`, `b=2`, and `c=3`: + +``` + d + / \ + c hash=d6f56d + / \ + b c,hash(3) + / \ +a,hash(1) b,hash(2) +``` + +Range proofs can also prove the _absence_ of any keys within the range. For example, the above +proof can prove that the key `ab` is not in the tree, because if it was it would have to be +ordered between `a` and `b` - it is clear from the proof that there is no such node, and if +there was it would cause the parent hashes to be different from what we see. + +Range proofs can be generated for non-existant endpoints by including the nearest neighboring +keys, which allows them to cover any arbitrary key range. This can also be used to generate an +absence proof for a _single_ non-existant key, by returning a range proof between the two nearest +neighbors. The range proof is therefore a complete proof for all existing and all absent key/value +pairs ordered between two arbitrary endpoints. + +Note that the IAVL terminology for range proofs may differ from that used in other systems, where +it refers to proofs that a value lies within some interval without revealing the exact value. IAVL +range proofs are used to prove which key/value pairs exist (or not) in some key range, and may be +known as range queries elsewhere. + +## API Overview + +The following is a general overview of the API - for details, see the +[API reference](https://pkg.go.dev/github.com/cosmos/iavl). + +As an example, we will be using the same IAVL tree as described in the introduction: + +``` + d + / \ + c e + / \ / \ + b c=3 d=4 e=5 + / \ +a=1 b=2 +``` + +This tree can be generated as follows: + +```go +package main + +import ( + "fmt" + "log" + + "github.com/cosmos/iavl" + db "github.com/tendermint/tm-db" +) + +func main() { + tree, err := iavl.NewMutableTree(db.NewMemDB(), 0) + if err != nil { + log.Fatal(err) + } + + tree.Set([]byte("e"), []byte{5}) + tree.Set([]byte("d"), []byte{4}) + tree.Set([]byte("c"), []byte{3}) + tree.Set([]byte("b"), []byte{2}) + tree.Set([]byte("a"), []byte{1}) + + rootHash, version, err := tree.SaveVersion() + if err != nil { + log.Fatal(err) + } + fmt.Printf("Saved version %v with root hash %x\n", version, rootHash) + + // Output tree structure, including all node hashes (prefixed with 'n') + fmt.Println(tree.String()) +} +``` + +### Tree Root Hash + +Proofs are verified against the root hash of an IAVL tree. This root hash is retrived via +`MutableTree.Hash()` or `ImmutableTree.Hash()`, returning a `[]byte` hash. It is also returned by +`MutableTree.SaveVersion()`, as shown above. + +```go +fmt.Printf("%x\n", tree.Hash()) +// Outputs: dd21329c026b0141e76096b5df395395ae3fc3293bd46706b97c034218fe2468 +``` + +### Generating Proofs + +The following methods are used to generate proofs, all of which are of type `RangeProof`: + +* `ImmutableTree.GetWithProof(key []byte)`: fetches the key's value (if it exists) along with a + proof of existence or proof of absence. + +* `ImmutableTree.GetRangeWithProof(start, end []byte, limit int)`: fetches the keys, values, and + proofs for the given key range, optionally with a limit (end key is excluded). + +* `MutableTree.GetVersionedWithProof(key []byte, version int64)`: like `GetWithProof()`, but for a + specific version of the tree. + +* `MutableTree.GetVersionedRangeWithProof(key []byte, version int64)`: like `GetRangeWithProof()`, + but for a specific version of the tree. + +### Verifying Proofs + +The following `RangeProof` methods are used to verify proofs: + +* `Verify(rootHash []byte)`: verify that the proof root hash matches the given tree root hash. + +* `VerifyItem(key, value []byte)`: verify that the given key exists with the given value, according + to the proof. + +* `VerifyAbsent(key []byte)`: verify that the given key is absent, according to the proof. + +To verify that a `RangeProof` is valid for a given IAVL tree (i.e. that the proof root hash matches +the tree root hash), run `RangeProof.Verify()` with the tree's root hash: + +```go +// Generate a proof for a=1 +value, proof, err := tree.GetWithProof([]byte("a")) +if err != nil { + log.Fatal(err) +} + +// Verify that the proof's root hash matches the tree's +err = proof.Verify(tree.Hash()) +if err != nil { + log.Fatalf("Invalid proof: %v", err) +} +``` + +The proof must always be verified against the root hash with `Verify()` before attempting other +operations. The proof can also be verified manually with `RangeProof.ComputeRootHash()`: + +```go +if !bytes.Equal(proof.ComputeRootHash(), tree.Hash()) { + log.Fatal("Proof hash mismatch") +} +``` + +To verify that a key has a given value according to the proof, use `VerifyItem()` on a proof +generated for this key (or key range): + +```go +// The proof was generated for the item a=1, so this is successful +err = proof.VerifyItem([]byte("a"), []byte{1}) +fmt.Printf("prove a=1: %v\n", err) +// outputs nil + +// If we instead claim that a=2, the proof will error +err = proof.VerifyItem([]byte("a"), []byte{2}) +fmt.Printf("prove a=2: %v\n", err) +// outputs "leaf value hash not same: invalid proof" + +// Also, verifying b=2 errors even though it is correct, since the proof is for a=1 +err = proof.VerifyItem([]byte("b"), []byte{2}) +fmt.Printf("prove b=2: %v\n", err) +// outputs "leaf key not found in proof: invalid proof" +``` + +If we generate a proof for a range of keys, we can use this both to prove the value of any of the +keys in the range as well as the absence of any keys that would have been within it: + +```go +// Note that the end key is not inclusive, so c is not in the proof. 0 means +// no key limit (all keys). +keys, values, proof, err := tree.GetRangeWithProof([]byte("a"), []byte("c"), 0) +if err != nil { + log.Fatal(err) +} + +err = proof.Verify(tree.Hash()) +if err != nil { + log.Fatal(err) +} + +// Prove that a=1 is in the range +err = proof.VerifyItem([]byte("a"), []byte{1}) +fmt.Printf("prove a=1: %v\n", err) +// outputs nil + +// Prove that b=2 is also in the range +err = proof.VerifyItem([]byte("b"), []byte{2}) +fmt.Printf("prove b=2: %v\n", err) +// outputs nil + +// Since "ab" is ordered after "a" but before "b", we can prove that it +// is not in the range and therefore not in the tree at all +err = proof.VerifyAbsence([]byte("ab")) +fmt.Printf("prove no ab: %v\n", err) +// outputs nil + +// If we try to prove ab, we get an error: +err = proof.VerifyItem([]byte("ab"), []byte{0}) +fmt.Printf("prove ab=0: %v\n", err) +// outputs "leaf key not found in proof: invalid proof" +``` + +### Proof Structure + +The overall proof structure was described in the introduction. Here, we will have a look at the +actual data structure. Knowledge of this is not necessary to use proofs. It may also be useful +to have a look at the [`Node` data structure](../node/node.md). + +Recall our example tree: + +``` + d + / \ + c e + / \ / \ + b c=3 d=4 e=5 + / \ +a=1 b=2 +``` + +A `RangeProof` contains the following data, as well as JSON tags for serialization: + +```go +type RangeProof struct { + LeftPath PathToLeaf `json:"left_path"` + InnerNodes []PathToLeaf `json:"inner_nodes"` + Leaves []ProofLeafNode `json:"leaves"` +} +``` + +* `LeftPath` contains the path to the leftmost node in the proof. For a proof of the range `a` to + `e` (excluding `e=5`), it contains information about the inner nodes `d`, `c`, and `b` in that + order. + +* `InnerNodes` contains paths with any additional inner nodes not already in `LeftPath`, with `nil` + paths for nodes already traversed. For a proof of the range `a` to `e` (excluding `e=5`), this + contains the paths `nil`, `nil`, `[e]` where the `nil` paths refer to the paths to `b=2` and + `c=3` already traversed in `LeftPath`, and `[e]` contains data about the `e` inner node needed + to prove `d=4`. + +* `Leaves` contains data about the leaf nodes in the range. For the range `a` to `e` (exluding + `e=5`) this contains info about `a=1`, `b=2`, `c=3`, and `d=4` in left-to-right order. + +Note that `Leaves` may contain additional leaf nodes outside the requested range, for example to +satisfy absence proofs if a given key does not exist. This may require additional inner nodes +to be included as well. + +`PathToLeaf` is simply a slice of `ProofInnerNode`: + +```go +type PathToLeaf []ProofInnerNode +``` + +Where `ProofInnerNode` contains the following data (a subset of the [node data](../node/node.md)): + +```go +type ProofInnerNode struct { + Height int8 `json:"height"` + Size int64 `json:"size"` + Version int64 `json:"version"` + Left []byte `json:"left"` + Right []byte `json:"right"` +} +``` + +Unlike in our diagrams, the key of the inner nodes are not actually part of the proof. This is +because they are only used to guide binary searches and do not necessarily correspond to actual keys +in the data set, and are thus not included in any hashes. + +Similarly, `ProofLeafNode` contains a subset of leaf node data: + +```go +type ProofLeafNode struct { + Key cmn.HexBytes `json:"key"` + ValueHash cmn.HexBytes `json:"value"` + Version int64 `json:"version"` +} +``` + +Notice how the proof contains a hash of the node's value rather than the value itself. This is +because values can be arbitrarily large while the hash has a constant size. The Merkle hashes of +the tree are computed in the same way, by hashing the value before including it in the node +hash. + +The information in these proofs is sufficient to reasonably prove that a given value exists (or +does not exist) in a given version of an IAVL dataset without fetching the entire dataset, requiring +only `logâ‚‚(n)` hashes for a dataset of `n` items. For more information, please see the +[API reference](https://pkg.go.dev/github.com/cosmos/iavl). \ No newline at end of file diff --git a/sei-iavl/docs/tree/export_import.md b/sei-iavl/docs/tree/export_import.md new file mode 100644 index 0000000000..0bbd22486a --- /dev/null +++ b/sei-iavl/docs/tree/export_import.md @@ -0,0 +1,64 @@ +# Export/Import + +A single `ImmutableTree` (i.e. a single version) can be exported via `ImmutableTree.Export()`, returning an iterator over `ExportNode` items. These nodes can be imported into an empty `MutableTree` with `MutableTree.Import()` to recreate an identical tree. The structure of `ExportNode` is: + +```go +type ExportNode struct { + Key []byte + Value []byte + Version int64 + Height int8 +} +``` + +This is the minimum amount of data about nodes that can be exported, see the [node documentation](../node/node.md) for comparison. The other node attributes, such as `hash` and `size`, can be derived from this data. Both leaf nodes and inner nodes are exported, since `Version` is part of the hash and inner nodes have different versions than the leaf nodes with the same key. + +The order of exported nodes is significant. Nodes are exported by depth-first post-order (LRN) tree traversal. Consider the following tree (with nodes in `key@version=value` format): + +``` + d@3 + / \ + c@3 e@3 + / \ / \ + b@3 c@3=3 d@2=4 e@3=5 + / \ +a@1=1 b@3=2 + +``` + +This would produce the following export: + +```go +[]*ExportNode{ + {Key: []byte("a"), Value: []byte{1}, Version: 1, Height: 0}, + {Key: []byte("b"), Value: []byte{2}, Version: 3, Height: 0}, + {Key: []byte("b"), Value: nil, Version: 3, Height: 1}, + {Key: []byte("c"), Value: []byte{3}, Version: 3, Height: 0}, + {Key: []byte("c"), Value: nil, Version: 3, Height: 2}, + {Key: []byte("d"), Value: []byte{4}, Version: 2, Height: 0}, + {Key: []byte("e"), Value: []byte{5}, Version: 3, Height: 0}, + {Key: []byte("e"), Value: nil, Version: 3, Height: 1}, + {Key: []byte("d"), Value: nil, Version: 3, Height: 3}, +} +``` + +When importing, the tree must be rebuilt in the same order, such that the missing attributes (e.g. `hash` and `size`) can be generated. This is possible because children are always given before their parents. We can therefore first generate the hash and size of the left and right leaf nodes, and then use these to recursively generate the hash and size of the parent. + +One way to do this is to keep a stack of orphaned children, and then pop those children once we build their parent, which then becomes a new child on the stack. We know that we encounter a parent because its height is higher than the child or children on top of the stack. We need a stack because we may need to recursively build a right branch while holding an orphaned left child. For the above export this would look like the following (in `key:height=value` format): + +``` +| Stack | Import node | +|-----------------|-------------------------------------------------------------| +| | {Key: []byte("a"), Value: []byte{1}, Version: 1, Height: 0} | +| a:0=1 | {Key: []byte("b"), Value: []byte{2}, Version: 3, Height: 0} | +| a:0=1,b:0=2 | {Key: []byte("b"), Value: nil, Version: 3, Height: 1} | +| b:1 | {Key: []byte("c"), Value: []byte{3}, Version: 3, Height: 0} | +| b:1,c:0=3 | {Key: []byte("c"), Value: nil, Version: 3, Height: 2} | +| c:2 | {Key: []byte("d"), Value: []byte{4}, Version: 2, Height: 0} | +| c:2,d:0=4 | {Key: []byte("e"), Value: []byte{5}, Version: 3, Height: 0} | +| c:2,d:0=4,e:0=5 | {Key: []byte("e"), Value: nil, Version: 3, Height: 1} | +| c:2,e:1 | {Key: []byte("d"), Value: nil, Version: 3, Height: 3} | +| d:3 | | +``` + +At the end, there will be a single node left on the stack, which is the root node of the tree. \ No newline at end of file diff --git a/sei-iavl/docs/tree/immutable_tree.md b/sei-iavl/docs/tree/immutable_tree.md new file mode 100644 index 0000000000..0f7154100b --- /dev/null +++ b/sei-iavl/docs/tree/immutable_tree.md @@ -0,0 +1,69 @@ +# Immutable Tree + +### Structure + +The Immutable tree struct contains an IAVL version. + +```golang +type ImmutableTree struct { + root *Node + ndb *nodeDB + version int64 +} +``` + +Using the root and the nodeDB, the ImmutableTree can retrieve any node that is a part of the IAVL tree at this version. + +Users can get information about the IAVL tree by calling getter functions such as `Size()` and `Height()` which will return the tree's size and height by querying the root node's size and height. + +### Get + +Users can get values by specifying the key or the index of the leaf node they want to get value for. + +Get by key will return both the index and the value. + +```golang +// Get returns the index and value of the specified key if it exists, or nil +// and the next index, if it doesn't. +func (t *ImmutableTree) Get(key []byte) (index int64, value []byte) { + if t.root == nil { + return 0, nil + } + return t.root.get(t, key) +} +``` + +Get by index will return both the key and the value. The index is the index in the list of leaf nodes sorted lexicographically by key. The leftmost leaf has index 0. It's neighbor has index 1 and so on. + +```golang +// GetByIndex gets the key and value at the specified index. +func (t *ImmutableTree) GetByIndex(index int64) (key []byte, value []byte) { + if t.root == nil { + return nil, nil + } + return t.root.getByIndex(t, index) +} +``` + +### Iterating + +Iteration works by traversing from the root node. All iteration functions are provided a callback function `func(key, value []byte) (stop bool`). This callback is called on every leaf node's key and value in order of the iteration. If the callback returns true, then the iteration stops. Otherwise it continues. + +Thus the callback is useful both as a way to run some logic on every key-value pair stored in the IAVL and as a way to dynamically stop the iteration. + +The `IterateRange` functions allow users to iterate over a specific range and specify if the iteration should be in ascending or descending order. + +The API's for Iteration functions are shown below. + +```golang +// Iterate iterates over all keys of the tree, in order. +func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool) + +// IterateRange makes a callback for all nodes with key between start and end non-inclusive. +// If either are nil, then it is open on that side (nil, nil is the same as Iterate) +func (t *ImmutableTree) IterateRange(start, end []byte, ascending bool, fn func(key []byte, value []byte) bool) (stopped bool) + +// IterateRangeInclusive makes a callback for all nodes with key between start and end inclusive. +// If either are nil, then it is open on that side (nil, nil is the same as Iterate) +func (t *ImmutableTree) IterateRangeInclusive(start, end []byte, ascending bool, fn func(key, value []byte, version int64) bool) (stopped bool) +``` diff --git a/sei-iavl/docs/tree/mutable_tree.md b/sei-iavl/docs/tree/mutable_tree.md new file mode 100644 index 0000000000..86080a1d09 --- /dev/null +++ b/sei-iavl/docs/tree/mutable_tree.md @@ -0,0 +1,384 @@ +# Mutable Tree + +### Structure + +The MutableTree struct is a wrapper around ImmutableTree to allow for updates that get stored in successive versions. + +The MutableTree stores the last saved ImmutableTree and the current working tree in its struct while all other saved, available versions are accessible from the nodeDB. + +```golang +// MutableTree is a persistent tree which keeps track of versions. +type MutableTree struct { + *ImmutableTree // The current, working tree. + lastSaved *ImmutableTree // The most recently saved tree. + orphans map[string]int64 // Nodes removed by changes to working tree. + versions map[int64]bool // The previous, saved versions of the tree. + ndb *nodeDB +} +``` + +The versions map stores which versions of the IAVL are stored in nodeDB. Anytime a version `v` gets persisted, `versions[v]` is set to `true`. Anytime a version gets deleted, `versions[v]` is set to false. + +### Set + +Set can be used to add a new key-value pair to the IAVL tree, or to update an existing key with a new value. + +Set starts at the root of the IAVL tree, if the key is less than or equal to the root key, it recursively calls set on root's left child. Else, it recursively calls set on root's right child. It continues to recurse down the IAVL tree based on comparing the set key and the node key until it reaches a leaf node. + +If the leaf node has the same key as the set key, then the set is just updating an existing key with a new value. The value is updated, and the old version of the node is orphaned. + +If the leaf node does not have the same key as the set key, then the set is trying to add a new key to the IAVL tree. The leaf node is replaced by an inner node that has the original leaf node and the new node from the set call as its children. + +If the `setKey` < `leafKey`: + +```golang +// new leaf node that gets created by Set +// since this is a new update since latest saved version, +// this node has version=latestVersion+1 +newVersion := latestVersion+1 +newNode := NewNode(key, value, newVersion) +// original leaf node: originalLeaf gets replaced by inner node below +Node{ + key: setKey, // inner node key is equal to left child's key + height: 1, // height=1 since node is parent of leaves + size: 2, // 2 leaf nodes under this node + leftNode: newNode, // left Node is the new added leaf node + rightNode: originalLeaf, // right Node is the original leaf node + version: newVersion, // inner node is new since lastVersion, so it has an incremented version +} +``` + +If `setKey` > `leafKey`: + +```golang +// new leaf node that gets created by Set +// since this is a new update since latest saved version, +// this node has version=latestVersion+1 +newVersion := latestVersion+1 +newNode := NewNode(key, value, latestVersion+1) +// original leaf node: originalLeaf gets replaced by inner node below +Node{ + key: leafKey, // inner node key is equal to left child's key + height: 1, // height=1 since node is parent of leaves + size: 2, // 2 leaf nodes under this node + leftNode: originalLeaf, // left Node is the original leaf node + rightNode: newNode, // right Node is the new added leaf node + version: newVersion, // inner node is new since lastVersion, so it has an incremented version +} +``` + +Any node that gets recursed upon during a Set call is necessarily orphaned since it will either have a new value (in the case of an update) or it will have a new descendant. The recursive calls accumulate a list of orphans as it descends down the IAVL tree. This list of orphans is ultimately added to the mutable tree's orphan list at the end of the Set call. + +After each set, the current working tree has its height and size recalculated. If the height of the left branch and right branch of the working tree differs by more than one, then the mutable tree has to be balanced before the Set call can return. + +### Remove + +Remove is another recursive function to remove a key-value pair from the IAVL pair. If the key that is trying to be removed does not exist, Remove is a no-op. + +Remove recurses down the IAVL tree in the same way that Set does until it reaches a leaf node. If the leaf node's key is equal to the remove key, the node is removed, and all of its parents are recursively updated. If not, the remove call does nothing. + +#### Recursive Remove + +Remove works by calling an inner function `recursiveRemove` that returns the following values after a recursive call `recursiveRemove(recurseNode, removeKey)`: + +##### NewHash + +If a node in recurseNode's subtree gets removed, then the hash of the recurseNode will change. Thus during the recursive calls down the subtree, all of recurseNode's children will return their new hashes after the remove (if they have changed). Using this information, recurseNode can calculate its own updated hash and return that value. + +If recurseNode is the node getting removed itself, NewHash is `nil`. + +##### ReplaceNode + +Just like with recursiveSet, any node that gets recursed upon (in a successful remove) will get orphaned since its hash must be updated and the nodes are immutable. Thus, ReplaceNode is the new node that replaces `recurseNode`. + +If recurseNode is the leaf that gets removed, then ReplaceNode is `nil`. + +If recurseNode is the direct parent of the leaf that got removed, then it can simply be replaced by the other child. Since the parent of recurseNode can directly refer to recurseNode's remaining child. For example if recurseNode's left child gets removed, the following happens: + + +Before LeftLeaf removed: +``` + |---RightLeaf +IAVLTREE---recurseNode--| + |---LeftLeaf +``` + +After LeftLeaf removed: +``` +IAVLTREE---RightLeaf + +ReplaceNode = RightLeaf +orphaned = [LeftLeaf, recurseNode] +``` + +If recurseNode is an inner node that got called in the recursiveRemove, but is not a direct parent of the removed leaf. Then an updated version of the node will exist in the tree. Notably, it will have an incremented version, a new hash (as explained in the `NewHash` section), and recalculated height and size. + +The ReplaceNode will be a cloned version of `recurseNode` with an incremented version. The hash will be updated given the NewHash of recurseNode's left child or right child (depending on which branch got recurse upon). + +The height and size of the ReplaceNode will have to be calculated since these values can change after the `remove`. + +It's possible that the subtree for `ReplaceNode` will have to be rebalanced (see `Balance` section). If this is the case, this will also update `ReplaceNode`'s hash since the structure of `ReplaceNode`'s subtree will change. + +##### LeftmostLeafKey + +The LeftmostLeafKey is the key of the leftmost leaf of `recurseNode`'s subtree. This is only used if `recurseNode` is the right child of its parent. Since inner nodes should have their key equal to the leftmost key of their right branch (if leftmostkey is not `nil`). If recurseNode is the right child of its parent `parentNode`, `parentNode` will set its key to `parentNode.key = leftMostKeyOfRecurseNodeSubTree`. + +If `recurseNode` is a leaf, it will return `nil`. + +If `recurseNode` is a parent of the leaf that got removed, it will return its own key if the left child was removed. If the right child is removed, it will return `nil`. + +If `recurseNode` is a generic inner node that isn't a direct parent of the removed node, it will return the leftmost key of its child's recursive call if `node.key < removeKey`. It will return `nil` otherwise. + +If `removeKey` does not exist in the IAVL tree, leftMostKey is `nil` for entire recursive stack. + +##### RemovedValue + +RemovedValue is the value that was at the node that was removed. It does not get changed as it travels up the recursive stack. + +If `removeKey` does not exist in the IAVL tree, RemovedValue is `nil`. + +##### Orphans + +Just like `recursiveSet`, any node that gets recursed upon by `recursiveRemove` in a successful `Remove` call will have to be orphaned. The Orphans list in `recursiveRemove` accumulates the list of orphans so that it can return them to `Remove`. `Remove` will then iterate through this list and add all the orphans to the mutable tree's `orphans` map. + +If the `removeKey` does not exist in the IAVL tree, then the orphans list is `nil`. + +### Balance + +Anytime a node is unbalanced such that the height of its left branch and the height of its right branch differs by more than 1, the IAVL tree will rebalance itself. + +This is acheived by rotating the subtrees until there is no more than one height difference between two branches of any subtree in the IAVL. + +Since Balance is mutating the structure of the tree, any displaced nodes will be orphaned. + +#### RotateRight + +To rotate right on a node `rotatedNode`, we first orphan its left child. We clone the left child to create a new node `newNode`. We set `newNode`'s right hash and child to the `rotatedNode`. We now set `rotatedNode`'s left child to be the old right child of `newNode`. + +Visualization (Nodes are numbered to show correct key order is still preserved): + +Before `RotateRight(node8)`: +``` + |---9 +8---| + | |---7 + | |---6 + | | |---5 + |---4 + | |---3 + |---2 + |---1 +``` + +After `RotateRight(node8)`: +``` + |---9 + |---8 + | | |---7 + | |---6 + | |---5 +4'---| + | |---1 + |---2 + |---3 + +Orphaned: 4 +``` + +Note that the key order for subtrees is still preserved. + +#### RotateLeft + +Similarly, to rotate left on a node `rotatedNode` we first orphan its right child. We clone the right child to create a new node `newNode`. We set the `newNode`'s left hash and child to the `rotatedNode`. We then set the `rotatedNode`'s right child to be the old left child of the node. + +Before `RotateLeft(node2)`: +``` + |---9 + |---8 + | |---7 + |---6 + | | |---5 + | |---4 + | |---3 +2---| + |---1 +``` + +After `RotateLeft(node2)`: +``` + |---9 + |---8 + | |---7 +6'---| + | |---5 + | |---4 + | | |---3 + |---2 + |---1 + +Orphaned: 6 +``` + +The IAVL detects whenever a subtree has become unbalanced by 2 (after any set/remove). If this does happen, then the tree is immediately rebalanced. Thus, any unbalanced subtree can only exist in 4 states: + +#### Left Left Case + +1. `RotateRight(node8)` + +**Before: Left Left Unbalanced** +``` + |---9 +8---| + | |---6 + |---4 + | |---3 + |---2 +``` + +**After 1: Balanced** +``` + |---9 + |---8 + | |---6 +4'---| + | |---3 + |---2 + +Orphaned: 4 +``` + +#### Left Right Case + +Make tree left left unbalanced, and then balance. + +1. `RotateLeft(node4)` +2. `RotateRight(node8)` + +**Before: Left Right Unbalanced** +``` + |---9 +8---| + | |---6 + | | |---5 + |---4 + |---2 +``` + +**After 1: Left Left Unbalanced** +``` + |---9 +8---| + |---6' + | |---5 + |---4 + |---2 + +Orphaned: 6 +``` + +**After 2: Balanced** +``` + |---9 + |---8 +6'---| + | |---5 + |---4 + |---2 + +Orphaned: 6 +``` + +Note: 6 got orphaned again, so omit list repitition + +#### Right Right Case + +1. `RotateLeft(node2)` + +**Before: Right Right Unbalanced** +``` + |---9 + |---8 + |---6 + | |---4 +2---| + |---1 +``` + +**After: Balanced** +``` + |---9 + |---8 +6'---| + | |---4 + |---2 + |---1 + +Orphaned: 6 +``` + +#### Right Left Case + +Make tree right right unbalanced, then balance. + +1. `RotateRight(6)` +2. `RotateLeft(2)` + +**Before: Right Left Unbalanced** +``` + |---8 + |---6 + | |---4 + | |---3 +2---| + |---1 +``` + +**After 1: Right Right Unbalanced** +``` + |---8 + |---6 + |---4' + | |---3 +2---| + |---1 + +Orphaned: 4 +``` + +**After 2: Balanced** +``` + |---8 + |---6 +4'---| + | |---3 + |---2 + |---1 + +Orphaned: 4 +``` + +### SaveVersion + +SaveVersion saves the current working tree as the latest version, `tree.version+1`. + +If the tree's root is empty, then there are no nodes to save. The `nodeDB` must still save any orphans since the root itself could be the node that has been removed since the last version. Then the `nodeDB` also saves the empty root for this version. + +If the root is not empty. Then SaveVersion will ensure that the `nodeDB` saves the orphans, roots and any new nodes that have been created since the last version was saved. + +SaveVersion also calls `nodeDB.Commit`, this ensures that any batched writes from the last save gets committed to the appropriate databases. + +`tree.version` gets incremented and the versions map has `versions[tree.version] = true`. + +It will set the lastSaved `ImmutableTree` to the current working tree, and clone the tree to allow for future updates on the next working tree. It also resets orphans to the empty map. + +Lastly, it returns the tree's hash, the latest version, and nil for error. + +SaveVersion will error if a tree at the version trying to be saved already exists. + +### DeleteVersion + +DeleteVersion will simply call nodeDB's `DeleteVersion` function which is documented in the [nodeDB docs](./nodedb.md) and then call `nodeDB.Commit` to flush all batched updates. + +It will also delete the version from the versions map. + +DeleteVersion will return an error if the version is invalid, or nonexistent. DeleteVersion will also return an error if the version trying to be deleted is the latest version of the IAVL tree since that is unallowed. diff --git a/sei-iavl/export.go b/sei-iavl/export.go new file mode 100644 index 0000000000..c65b81b210 --- /dev/null +++ b/sei-iavl/export.go @@ -0,0 +1,89 @@ +package iavl + +import ( + "context" + + "github.com/pkg/errors" +) + +// exportBufferSize is the number of nodes to buffer in the exporter. It improves throughput by +// processing multiple nodes per context switch, but take care to avoid excessive memory usage, +// especially since callers may export several IAVL stores in parallel (e.g. the Cosmos SDK). +const exportBufferSize = 32 + +// ExportDone is returned by Exporter.Next() when all items have been exported. +// nolint:revive +var ExportDone = errors.New("export is complete") // nolint:golint + +// ExportNode contains exported node data. +type ExportNode struct { + Key []byte + Value []byte + Version int64 + Height int8 +} + +// Exporter exports nodes from an ImmutableTree. It is created by ImmutableTree.Export(). +// +// Exported nodes can be imported into an empty tree with MutableTree.Import(). Nodes are exported +// depth-first post-order (LRN), this order must be preserved when importing in order to recreate +// the same tree structure. +type Exporter struct { + tree *ImmutableTree + ch chan *ExportNode + cancel context.CancelFunc +} + +// NewExporter creates a new Exporter. Callers must call Close() when done. +func newExporter(tree *ImmutableTree) *Exporter { + ctx, cancel := context.WithCancel(context.Background()) + exporter := &Exporter{ + tree: tree, + ch: make(chan *ExportNode, exportBufferSize), + cancel: cancel, + } + + tree.ndb.incrVersionReaders(tree.version) + go exporter.export(ctx) + + return exporter +} + +// export exports nodes +func (e *Exporter) export(ctx context.Context) { + e.tree.root.traversePost(e.tree, true, func(node *Node) bool { + exportNode := &ExportNode{ + Key: node.key, + Value: node.value, + Version: node.version, + Height: node.height, + } + + select { + case e.ch <- exportNode: + return false + case <-ctx.Done(): + return true + } + }) + close(e.ch) +} + +// Next fetches the next exported node, or returns ExportDone when done. +func (e *Exporter) Next() (*ExportNode, error) { + if exportNode, ok := <-e.ch; ok { + return exportNode, nil + } + return nil, ExportDone +} + +// Close closes the exporter. It is safe to call multiple times. +func (e *Exporter) Close() { + e.cancel() + for range e.ch { // drain channel + } + if e.tree != nil { + e.tree.ndb.decrVersionReaders(e.tree.version) + } + e.tree = nil +} diff --git a/sei-iavl/export_test.go b/sei-iavl/export_test.go new file mode 100644 index 0000000000..8b7051f2d2 --- /dev/null +++ b/sei-iavl/export_test.go @@ -0,0 +1,305 @@ +package iavl + +import ( + "math" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + db "github.com/tendermint/tm-db" +) + +// setupExportTreeBasic sets up a basic tree with a handful of +// create/update/delete operations over a few versions. +func setupExportTreeBasic(t require.TestingT) *ImmutableTree { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + + tree.Set([]byte("x"), []byte{255}) + tree.Set([]byte("z"), []byte{255}) + tree.Set([]byte("a"), []byte{1}) + tree.Set([]byte("b"), []byte{2}) + tree.Set([]byte("c"), []byte{3}) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + tree.Remove([]byte("x")) + tree.Remove([]byte("b")) + tree.Set([]byte("c"), []byte{255}) + tree.Set([]byte("d"), []byte{4}) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + tree.Set([]byte("b"), []byte{2}) + tree.Set([]byte("c"), []byte{3}) + tree.Set([]byte("e"), []byte{5}) + tree.Remove([]byte("z")) + _, version, err := tree.SaveVersion() + require.NoError(t, err) + + itree, err := tree.GetImmutable(version) + require.NoError(t, err) + return itree +} + +// setupExportTreeRandom sets up a randomly generated tree. +// nolint: dupl +func setupExportTreeRandom(t *testing.T) *ImmutableTree { + const ( + randSeed = 49872768940 // For deterministic tests + keySize = 16 + valueSize = 16 + + versions = 8 // number of versions to generate + versionOps = 1024 // number of operations (create/update/delete) per version + updateRatio = 0.4 // ratio of updates out of all operations + deleteRatio = 0.2 // ratio of deletes out of all operations + ) + + r := rand.New(rand.NewSource(randSeed)) + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + + var version int64 + keys := make([][]byte, 0, versionOps) + for i := 0; i < versions; i++ { + for j := 0; j < versionOps; j++ { + key := make([]byte, keySize) + value := make([]byte, valueSize) + + // The performance of this is likely to be terrible, but that's fine for small tests + switch { + case len(keys) > 0 && r.Float64() <= deleteRatio: + index := r.Intn(len(keys)) + key = keys[index] + keys = append(keys[:index], keys[index+1:]...) + _, removed, err := tree.Remove(key) + require.NoError(t, err) + require.True(t, removed) + + case len(keys) > 0 && r.Float64() <= updateRatio: + key = keys[r.Intn(len(keys))] + r.Read(value) + updated, err := tree.Set(key, value) + require.NoError(t, err) + require.True(t, updated) + + default: + r.Read(key) + r.Read(value) + // If we get an update, set again + for updated, err := tree.Set(key, value); updated && err == nil; { + key = make([]byte, keySize) + r.Read(key) + } + keys = append(keys, key) + } + } + _, version, err = tree.SaveVersion() + require.NoError(t, err) + } + + require.EqualValues(t, versions, tree.Version()) + require.GreaterOrEqual(t, tree.Size(), int64(math.Trunc(versions*versionOps*(1-updateRatio-deleteRatio))/2)) + + itree, err := tree.GetImmutable(version) + require.NoError(t, err) + return itree +} + +// setupExportTreeSized sets up a single-version tree with a given number +// of randomly generated key/value pairs, useful for benchmarking. +func setupExportTreeSized(t require.TestingT, treeSize int) *ImmutableTree { + const ( + randSeed = 49872768940 // For deterministic tests + keySize = 16 + valueSize = 16 + ) + + r := rand.New(rand.NewSource(randSeed)) + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + + for i := 0; i < treeSize; i++ { + key := make([]byte, keySize) + value := make([]byte, valueSize) + r.Read(key) + r.Read(value) + updated, err := tree.Set(key, value) + require.NoError(t, err) + + if updated { + i-- + } + } + + _, version, err := tree.SaveVersion() + require.NoError(t, err) + + itree, err := tree.GetImmutable(version) + require.NoError(t, err) + + return itree +} + +func TestExporter(t *testing.T) { + tree := setupExportTreeBasic(t) + + expect := []*ExportNode{ + {Key: []byte("a"), Value: []byte{1}, Version: 1, Height: 0}, + {Key: []byte("b"), Value: []byte{2}, Version: 3, Height: 0}, + {Key: []byte("b"), Value: nil, Version: 3, Height: 1}, + {Key: []byte("c"), Value: []byte{3}, Version: 3, Height: 0}, + {Key: []byte("c"), Value: nil, Version: 3, Height: 2}, + {Key: []byte("d"), Value: []byte{4}, Version: 2, Height: 0}, + {Key: []byte("e"), Value: []byte{5}, Version: 3, Height: 0}, + {Key: []byte("e"), Value: nil, Version: 3, Height: 1}, + {Key: []byte("d"), Value: nil, Version: 3, Height: 3}, + } + + actual := make([]*ExportNode, 0, len(expect)) + exporter := tree.Export() + defer exporter.Close() + for { + node, err := exporter.Next() + if err == ExportDone { + break + } + require.NoError(t, err) + actual = append(actual, node) + } + + assert.Equal(t, expect, actual) +} + +func TestExporter_Import(t *testing.T) { + testcases := map[string]*ImmutableTree{ + "empty tree": NewImmutableTree(db.NewMemDB(), 0, false), + "basic tree": setupExportTreeBasic(t), + } + if !testing.Short() { + testcases["sized tree"] = setupExportTreeSized(t, 4096) + testcases["random tree"] = setupExportTreeRandom(t) + } + + for desc, tree := range testcases { + tree := tree + t.Run(desc, func(t *testing.T) { + t.Parallel() + + exporter := tree.Export() + defer exporter.Close() + + newTree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + importer, err := newTree.Import(tree.Version()) + require.NoError(t, err) + defer importer.Close() + + for { + item, err := exporter.Next() + if err == ExportDone { + err = importer.Commit() + require.NoError(t, err) + break + } + require.NoError(t, err) + err = importer.Add(item) + require.NoError(t, err) + } + + treeHash, err := tree.Hash() + require.NoError(t, err) + newTreeHash, err := newTree.Hash() + require.NoError(t, err) + + require.Equal(t, treeHash, newTreeHash, "Tree hash mismatch") + require.Equal(t, tree.Size(), newTree.Size(), "Tree size mismatch") + require.Equal(t, tree.Version(), newTree.Version(), "Tree version mismatch") + + tree.Iterate(func(key, value []byte) bool { + index, _, err := tree.GetWithIndex(key) + require.NoError(t, err) + newIndex, newValue, err := newTree.GetWithIndex(key) + require.NoError(t, err) + require.Equal(t, index, newIndex, "Index mismatch for key %v", key) + require.Equal(t, value, newValue, "Value mismatch for key %v", key) + return false + }) + }) + } +} + +func TestExporter_Close(t *testing.T) { + tree := setupExportTreeSized(t, 4096) + exporter := tree.Export() + + node, err := exporter.Next() + require.NoError(t, err) + require.NotNil(t, node) + + exporter.Close() + node, err = exporter.Next() + require.Error(t, err) + require.Equal(t, ExportDone, err) + require.Nil(t, node) + + node, err = exporter.Next() + require.Error(t, err) + require.Equal(t, ExportDone, err) + require.Nil(t, node) + + exporter.Close() + exporter.Close() +} + +func TestExporter_DeleteVersionErrors(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + + tree.Set([]byte("a"), []byte{1}) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + tree.Set([]byte("b"), []byte{2}) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + tree.Set([]byte("c"), []byte{3}) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + itree, err := tree.GetImmutable(2) + require.NoError(t, err) + exporter := itree.Export() + defer exporter.Close() + + err = tree.DeleteVersion(2) + require.Error(t, err) + err = tree.DeleteVersion(1) + require.NoError(t, err) + + exporter.Close() + err = tree.DeleteVersion(2) + require.NoError(t, err) +} + +func BenchmarkExport(b *testing.B) { + b.StopTimer() + tree := setupExportTreeSized(b, 4096) + b.StartTimer() + for n := 0; n < b.N; n++ { + exporter := tree.Export() + for { + _, err := exporter.Next() + if err == ExportDone { + break + } else if err != nil { + b.Error(err) + } + } + exporter.Close() + } +} diff --git a/sei-iavl/fast_iterator.go b/sei-iavl/fast_iterator.go new file mode 100644 index 0000000000..aa423cae1d --- /dev/null +++ b/sei-iavl/fast_iterator.go @@ -0,0 +1,133 @@ +package iavl + +import ( + "errors" + + dbm "github.com/tendermint/tm-db" +) + +var errFastIteratorNilNdbGiven = errors.New("fast iterator must be created with a nodedb but it was nil") + +// FastIterator is a dbm.Iterator for ImmutableTree +// it iterates over the latest state via fast nodes, +// taking advantage of keys being located in sequence in the underlying database. +type FastIterator struct { + start, end []byte + + valid bool + + ascending bool + + err error + + ndb *nodeDB + + nextFastNode *FastNode + + fastIterator dbm.Iterator +} + +var _ dbm.Iterator = (*FastIterator)(nil) + +func NewFastIterator(start, end []byte, ascending bool, ndb *nodeDB) *FastIterator { + iter := &FastIterator{ + start: start, + end: end, + err: nil, + ascending: ascending, + ndb: ndb, + nextFastNode: nil, + fastIterator: nil, + } + // Move iterator before the first element + iter.Next() + return iter +} + +// Domain implements dbm.Iterator. +// Maps the underlying nodedb iterator domain, to the 'logical' keys involved. +func (iter *FastIterator) Domain() ([]byte, []byte) { + if iter.fastIterator == nil { + return iter.start, iter.end + } + + start, end := iter.fastIterator.Domain() + + if start != nil { + start = start[1:] + if len(start) == 0 { + start = nil + } + } + + if end != nil { + end = end[1:] + if len(end) == 0 { + end = nil + } + } + + return start, end +} + +// Valid implements dbm.Iterator. +func (iter *FastIterator) Valid() bool { + return iter.fastIterator != nil && iter.fastIterator.Valid() && iter.valid +} + +// Key implements dbm.Iterator +func (iter *FastIterator) Key() []byte { + if iter.valid { + return iter.nextFastNode.key + } + return nil +} + +// Value implements dbm.Iterator +func (iter *FastIterator) Value() []byte { + if iter.valid { + return iter.nextFastNode.value + } + return nil +} + +// Next implements dbm.Iterator +func (iter *FastIterator) Next() { + if iter.ndb == nil { + iter.err = errFastIteratorNilNdbGiven + iter.valid = false + return + } + + if iter.fastIterator == nil { + iter.fastIterator, iter.err = iter.ndb.getFastIterator(iter.start, iter.end, iter.ascending) + iter.valid = true + } else { + iter.fastIterator.Next() + } + + if iter.err == nil { + iter.err = iter.fastIterator.Error() + } + + iter.valid = iter.valid && iter.fastIterator.Valid() + if iter.valid { + iter.nextFastNode, iter.err = DeserializeFastNode(iter.fastIterator.Key()[1:], iter.fastIterator.Value()) + iter.valid = iter.err == nil + } +} + +// Close implements dbm.Iterator +func (iter *FastIterator) Close() error { + if iter.fastIterator != nil { + iter.err = iter.fastIterator.Close() + } + iter.valid = false + iter.fastIterator = nil + return iter.err +} + +// Error implements dbm.Iterator +func (iter *FastIterator) Error() error { + return iter.err +} diff --git a/sei-iavl/fast_node.go b/sei-iavl/fast_node.go new file mode 100644 index 0000000000..2d03287abe --- /dev/null +++ b/sei-iavl/fast_node.go @@ -0,0 +1,76 @@ +package iavl + +import ( + "io" + + "github.com/cosmos/iavl/cache" + "github.com/cosmos/iavl/internal/encoding" + "github.com/pkg/errors" +) + +// NOTE: This file favors int64 as opposed to int for size/counts. +// The Tree on the other hand favors int. This is intentional. + +type FastNode struct { + key []byte + versionLastUpdatedAt int64 + value []byte +} + +var _ cache.Node = (*FastNode)(nil) + +// NewFastNode returns a new fast node from a value and version. +func NewFastNode(key []byte, value []byte, version int64) *FastNode { + return &FastNode{ + key: key, + versionLastUpdatedAt: version, + value: value, + } +} + +// DeserializeFastNode constructs an *FastNode from an encoded byte slice. +func DeserializeFastNode(key []byte, buf []byte) (*FastNode, error) { + ver, n, cause := encoding.DecodeVarint(buf) + if cause != nil { + return nil, errors.Wrap(cause, "decoding fastnode.version") + } + buf = buf[n:] + + val, _, cause := encoding.DecodeBytes(buf) + if cause != nil { + return nil, errors.Wrap(cause, "decoding fastnode.value") + } + + fastNode := &FastNode{ + key: key, + versionLastUpdatedAt: ver, + value: val, + } + + return fastNode, nil +} + +func (fn *FastNode) GetKey() []byte { + return fn.key +} + +func (node *FastNode) encodedSize() int { + n := encoding.EncodeVarintSize(node.versionLastUpdatedAt) + encoding.EncodeBytesSize(node.value) + return n +} + +// writeBytes writes the FastNode as a serialized byte slice to the supplied io.Writer. +func (node *FastNode) writeBytes(w io.Writer) error { + if node == nil { + return errors.New("cannot write nil node") + } + cause := encoding.EncodeVarint(w, node.versionLastUpdatedAt) + if cause != nil { + return errors.Wrap(cause, "writing version last updated at") + } + cause = encoding.EncodeBytes(w, node.value) + if cause != nil { + return errors.Wrap(cause, "writing value") + } + return nil +} diff --git a/sei-iavl/fast_node_test.go b/sei-iavl/fast_node_test.go new file mode 100644 index 0000000000..b6e1ffd984 --- /dev/null +++ b/sei-iavl/fast_node_test.go @@ -0,0 +1,58 @@ +package iavl + +import ( + "bytes" + "encoding/hex" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFastNode_encodedSize(t *testing.T) { + fastNode := &FastNode{ + key: randBytes(10), + versionLastUpdatedAt: 1, + value: randBytes(20), + } + + expectedSize := 1 + len(fastNode.value) + 1 + + require.Equal(t, expectedSize, fastNode.encodedSize()) +} + +func TestFastNode_encode_decode(t *testing.T) { + testcases := map[string]struct { + node *FastNode + expectHex string + expectError bool + }{ + "nil": {nil, "", true}, + "empty": {&FastNode{}, "0000", false}, + "inner": {&FastNode{ + key: []byte{0x4}, + versionLastUpdatedAt: 1, + value: []byte{0x2}, + }, "020102", false}, + } + for name, tc := range testcases { + tc := tc + t.Run(name, func(t *testing.T) { + var buf bytes.Buffer + err := tc.node.writeBytes(&buf) + if tc.expectError { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tc.expectHex, hex.EncodeToString(buf.Bytes())) + + node, err := DeserializeFastNode(tc.node.key, buf.Bytes()) + require.NoError(t, err) + // since value and leafHash are always decoded to []byte{} we augment the expected struct here + if tc.node.value == nil { + tc.node.value = []byte{} + } + require.Equal(t, tc.node, node) + }) + } +} diff --git a/sei-iavl/go.mod b/sei-iavl/go.mod new file mode 100644 index 0000000000..0badc8552b --- /dev/null +++ b/sei-iavl/go.mod @@ -0,0 +1,36 @@ +module github.com/cosmos/iavl + +go 1.18 + +require ( + github.com/confio/ics23/go v0.7.0 + github.com/gogo/protobuf v1.3.2 + github.com/golang/mock v1.6.0 + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.8.0 + github.com/tendermint/tendermint v0.34.20 + github.com/tendermint/tm-db v0.6.6 + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e +) + +require ( + github.com/DataDog/zstd v1.4.1 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgraph-io/badger/v2 v2.2007.2 // indirect + github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect + github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/google/btree v1.0.0 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect + github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + go.etcd.io/bbolt v1.3.6 // indirect + golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 // indirect + golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect + google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/sei-iavl/go.sum b/sei-iavl/go.sum new file mode 100644 index 0000000000..d42aada086 --- /dev/null +++ b/sei-iavl/go.sum @@ -0,0 +1,1685 @@ +4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= +bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= +cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Antonboom/errname v0.1.6/go.mod h1:7lz79JAnuoMNDAWE9MeeIr1/c/VpSUWatBv2FH9NYpI= +github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/GaijinEntertainment/go-exhaustruct/v2 v2.1.0/go.mod h1:LGOGuvEgCfCQsy3JF2tRmpGDpzA53iZfyGEWSPwQ6/4= +github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= +github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI= +github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= +github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= +github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= +github.com/breml/bidichk v0.2.3/go.mod h1:8u2C6DnAy0g2cEq+k/A2+tr9O1s+vHGxWn0LTc70T2A= +github.com/breml/errchkjson v0.3.0/go.mod h1:9Cogkyv9gcT8HREpzi3TiqBxCqDzo8awa92zSDFcofU= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/bufbuild/buf v1.4.0/go.mod h1:mwHG7klTHnX+rM/ym8LXGl7vYpVmnwT96xWoRB4H5QI= +github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= +github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4/go.mod h1:W8EnPSQ8Nv4fUjc/v1/8tHFqhuOJXnRub0dTfuAQktU= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8= +github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/daixiang0/gci v0.3.3/go.mod h1:1Xr2bxnQbDxCqqulUOv8qpGqkgRw9RSCGGjEC2LjF8o= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= +github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/cli v20.10.14+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= +github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= +github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/firefart/nonamedreturns v1.0.1/go.mod h1:D3dpIBojGGNh5UfElmwPu73SwDCm+VKhHYqwlNOk2uQ= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= +github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw= +github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= +github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= +github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= +github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.46.2/go.mod h1:3DkdHnxn9eoTTrpT2gB0TEv8KSziuoqe9FitgQLHvAY= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= +github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= +github.com/gostaticanalysis/analysisutil v0.4.1/go.mod h1:18U/DLpRgIUd459wGxVHE0fRgmo1UgHDcbw7F5idXu0= +github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= +github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= +github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= +github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= +github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= +github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= +github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= +github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f/go.mod h1:qr2b5kx4HbFS7/g4uYO5qv9ei8303JMsC7ESbYiqr2Q= +github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= +github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= +github.com/jhump/protoreflect v1.12.1-0.20220417024638-438db461d753/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= +github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/txtarfs v0.0.0-20210218200122-0702f000015a/go.mod h1:izVPOvVRsHiKkeGCT6tYBNWyDVuzj9wAaBb5R9qamfw= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kulti/thelper v0.6.2/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= +github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= +github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= +github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= +github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= +github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= +github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= +github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= +github.com/mgechev/revive v1.2.1/go.mod h1:+Ro3wqY4vakcYNtkBWdZC7dBg1xSB6sp054wWwmeFm0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= +github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= +github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= +github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= +github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= +github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= +github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= +github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nishanths/exhaustive v0.7.11/go.mod h1:gX+MP7DWMKJmNa1HfMozK+u04hQd3na9i0hyqf3/dOI= +github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= +github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.0/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= +github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= +github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polyfloyd/go-errorlint v1.0.0/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= +github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= +github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= +github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a/go.mod h1:VMX+OnnSw4LicdiEGtRSD/1X8kW7GuEscjYNr4cOIT4= +github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/dsl v0.3.16/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/dsl v0.3.19/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= +github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= +github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/go-dbus v0.0.0-20121104212943-b7232d34b1d5/go.mod h1:+u151txRmLpwxBmpYn9z3d1sdJdjRPQpsXuYeY9jNls= +github.com/remyoudompheng/go-liblzma v0.0.0-20190506200333-81bf2d431b96/go.mod h1:90HvCY7+oHHUKkbeMCiHt1WuFR2/hPJ9QrljDG+v6ls= +github.com/remyoudompheng/go-misc v0.0.0-20190427085024-2d6ac652a50e/go.mod h1:80FQABjoFzZ2M5uEa6FUaJYEmqU2UOKojlFVak1UAwI= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= +github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= +github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= +github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= +github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= +github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/securego/gosec/v2 v2.11.0/go.mod h1:SX8bptShuG8reGC0XS09+a4H2BoWSJi+fscA+Pulbpo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/shirou/gopsutil/v3 v3.22.4/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H4ifUguaQzHM= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw= +github.com/sivchari/tenv v1.5.0/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= +github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= +github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= +github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/tendermint/tendermint v0.34.20 h1:/pmvJhO3IqOxhbi8iRXudTjA2YKpaMqrLwFNkyxDSzw= +github.com/tendermint/tendermint v0.34.20/go.mod h1:KtOwCLYJcsS1ymtAfnjjAtXfXClbqcqjdqzFt2Em1Ac= +github.com/tendermint/tm-db v0.6.6 h1:EzhaOfR0bdKyATqcd5PNeyeq8r+V4bRPHBfyFdD9kGM= +github.com/tendermint/tm-db v0.6.6/go.mod h1:wP8d49A85B7/erz/r4YbKssKw6ylsO/hKtFk7E1aWZI= +github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= +github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= +github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= +github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tomarrell/wrapcheck/v2 v2.6.1/go.mod h1:Eo+Opt6pyMW1b6cNllOcDSSoHO0aTJ+iF6BfCUbHltA= +github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= +github.com/tommy-muehle/go-mnd/v2 v2.5.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= +github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/vektra/mockery/v2 v2.14.0/go.mod h1:bnD1T8tExSgPD1ripLkDbr60JA9VtQeu12P3wgLZd7M= +github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= +github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +gitlab.com/bosi/decorder v0.2.1/go.mod h1:6C/nhLSbF6qZbYD8bRmISBwc6vcWdNsiIBkRvjJFrH0= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.etcd.io/etcd/client/v2 v2.305.2/go.mod h1:2D7ZejHVMIfog1221iLSYlQRzrtECw3kz4I4VAQm3qI= +go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= +go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220403020550-483a9cbc67c0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190228203856-589c23e65e65/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201028025901-8cd080b735b3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.6/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.3.1/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= +mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5/go.mod h1:b8RRCBm0eeiWR8cfN88xeq2G5SG3VKGO+5UPWi5FSOY= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go new file mode 100644 index 0000000000..5113873c86 --- /dev/null +++ b/sei-iavl/immutable_tree.go @@ -0,0 +1,333 @@ +package iavl + +import ( + "fmt" + "strings" + + dbm "github.com/tendermint/tm-db" +) + +// ImmutableTree contains the immutable tree at a given version. It is typically created by calling +// MutableTree.GetImmutable(), in which case the returned tree is safe for concurrent access as +// long as the version is not deleted via DeleteVersion() or the tree's pruning settings. +// +// Returned key/value byte slices must not be modified, since they may point to data located inside +// IAVL which would also be modified. +type ImmutableTree struct { + root *Node + ndb *nodeDB + version int64 + skipFastStorageUpgrade bool +} + +// NewImmutableTree creates both in-memory and persistent instances +func NewImmutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) *ImmutableTree { + if db == nil { + // In-memory Tree. + return &ImmutableTree{} + } + return &ImmutableTree{ + // NodeDB-backed Tree. + ndb: newNodeDB(db, cacheSize, nil), + skipFastStorageUpgrade: skipFastStorageUpgrade, + } +} + +// NewImmutableTreeWithOpts creates an ImmutableTree with the given options. +func NewImmutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) *ImmutableTree { + return &ImmutableTree{ + // NodeDB-backed Tree. + ndb: newNodeDB(db, cacheSize, opts), + skipFastStorageUpgrade: skipFastStorageUpgrade, + } +} + +// String returns a string representation of Tree. +func (t *ImmutableTree) String() string { + leaves := []string{} + t.Iterate(func(key []byte, val []byte) (stop bool) { + leaves = append(leaves, fmt.Sprintf("%x: %x", key, val)) + return false + }) + return "Tree{" + strings.Join(leaves, ", ") + "}" +} + +// RenderShape provides a nested tree shape, ident is prepended in each level +// Returns an array of strings, one per line, to join with "\n" or display otherwise +func (t *ImmutableTree) RenderShape(indent string, encoder NodeEncoder) ([]string, error) { + if encoder == nil { + encoder = defaultNodeEncoder + } + return t.renderNode(t.root, indent, 0, encoder) +} + +// NodeEncoder will take an id (hash, or key for leaf nodes), the depth of the node, +// and whether or not this is a leaf node. +// It returns the string we wish to print, for iaviwer +type NodeEncoder func(id []byte, depth int, isLeaf bool) string + +// defaultNodeEncoder can encode any node unless the client overrides it +func defaultNodeEncoder(id []byte, depth int, isLeaf bool) string { + prefix := "- " + if isLeaf { + prefix = "* " + } + if len(id) == 0 { + return fmt.Sprintf("%s", prefix) + } + return fmt.Sprintf("%s%X", prefix, id) +} + +func (t *ImmutableTree) renderNode(node *Node, indent string, depth int, encoder func([]byte, int, bool) string) ([]string, error) { + prefix := strings.Repeat(indent, depth) + // handle nil + if node == nil { + return []string{fmt.Sprintf("%s", prefix)}, nil + } + // handle leaf + if node.isLeaf() { + here := fmt.Sprintf("%s%s", prefix, encoder(node.key, depth, true)) + return []string{here}, nil + } + + // recurse on inner node + here := fmt.Sprintf("%s%s", prefix, encoder(node.hash, depth, false)) + + rightNode, err := node.getRightNode(t) + if err != nil { + return nil, err + } + + leftNode, err := node.getLeftNode(t) + if err != nil { + return nil, err + } + + right, err := t.renderNode(rightNode, indent, depth+1, encoder) + if err != nil { + return nil, err + } + + result, err := t.renderNode(leftNode, indent, depth+1, encoder) // left + if err != nil { + return nil, err + } + + result = append(result, here) + result = append(result, right...) + return result, nil +} + +// Size returns the number of leaf nodes in the tree. +func (t *ImmutableTree) Size() int64 { + if t.root == nil { + return 0 + } + return t.root.size +} + +// Version returns the version of the tree. +func (t *ImmutableTree) Version() int64 { + return t.version +} + +// Height returns the height of the tree. +func (t *ImmutableTree) Height() int8 { + if t.root == nil { + return 0 + } + return t.root.height +} + +// Has returns whether or not a key exists. +func (t *ImmutableTree) Has(key []byte) (bool, error) { + if t.root == nil { + return false, nil + } + return t.root.has(t, key) +} + +// Hash returns the root hash. +func (t *ImmutableTree) Hash() ([]byte, error) { + hash, _, err := t.root.hashWithCount() + return hash, err +} + +// Export returns an iterator that exports tree nodes as ExportNodes. These nodes can be +// imported with MutableTree.Import() to recreate an identical tree. +func (t *ImmutableTree) Export() *Exporter { + return newExporter(t) +} + +// GetWithIndex returns the index and value of the specified key if it exists, or nil and the next index +// otherwise. The returned value must not be modified, since it may point to data stored within +// IAVL. +// +// The index is the index in the list of leaf nodes sorted lexicographically by key. The leftmost leaf has index 0. +// It's neighbor has index 1 and so on. +func (t *ImmutableTree) GetWithIndex(key []byte) (int64, []byte, error) { + if t.root == nil { + return 0, nil, nil + } + return t.root.get(t, key) +} + +// Get returns the value of the specified key if it exists, or nil. +// The returned value must not be modified, since it may point to data stored within IAVL. +// Get potentially employs a more performant strategy than GetWithIndex for retrieving the value. +// If tree.skipFastStorageUpgrade is true, this will work almost the same as GetWithIndex. +func (t *ImmutableTree) Get(key []byte) ([]byte, error) { + if t.root == nil { + return nil, nil + } + + if !t.skipFastStorageUpgrade { + // attempt to get a FastNode directly from db/cache. + // if call fails, fall back to the original IAVL logic in place. + fastNode, err := t.ndb.GetFastNode(key) + if err != nil { + _, result, err := t.root.get(t, key) + return result, err + } + + if fastNode == nil { + // If the tree is of the latest version and fast node is not in the tree + // then the regular node is not in the tree either because fast node + // represents live state. + if t.version == t.ndb.latestVersion { + return nil, nil + } + + _, result, err := t.root.get(t, key) + return result, err + } + + if fastNode.versionLastUpdatedAt <= t.version { + return fastNode.value, nil + } + } + + // otherwise skipFastStorageUpgrade is true or + // the cached node was updated later than the current tree. In this case, + // we need to use the regular stategy for reading from the current tree to avoid staleness. + _, result, err := t.root.get(t, key) + return result, err +} + +// GetByIndex gets the key and value at the specified index. +func (t *ImmutableTree) GetByIndex(index int64) (key []byte, value []byte, err error) { + if t.root == nil { + return nil, nil, nil + } + + return t.root.getByIndex(t, index) +} + +// Iterate iterates over all keys of the tree. The keys and values must not be modified, +// since they may point to data stored within IAVL. Returns true if stopped by callback, false otherwise +func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (bool, error) { + if t.root == nil { + return false, nil + } + + itr, err := t.Iterator(nil, nil, true) + defer itr.Close() + if err != nil { + return false, err + } + for ; itr.Valid(); itr.Next() { + if fn(itr.Key(), itr.Value()) { + return true, nil + } + + } + return false, nil +} + +// Iterator returns an iterator over the immutable tree. +func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { + if !t.skipFastStorageUpgrade { + isFastCacheEnabled, err := t.IsFastCacheEnabled() + if err != nil { + return nil, err + } + + if isFastCacheEnabled { + return NewFastIterator(start, end, ascending, t.ndb), nil + } + } + return NewIterator(start, end, ascending, t), nil +} + +// IterateRange makes a callback for all nodes with key between start and end non-inclusive. +// If either are nil, then it is open on that side (nil, nil is the same as Iterate). The keys and +// values must not be modified, since they may point to data stored within IAVL. +func (t *ImmutableTree) IterateRange(start, end []byte, ascending bool, fn func(key []byte, value []byte) bool) (stopped bool) { + if t.root == nil { + return false + } + return t.root.traverseInRange(t, start, end, ascending, false, false, func(node *Node) bool { + if node.height == 0 { + return fn(node.key, node.value) + } + return false + }) +} + +// IterateRangeInclusive makes a callback for all nodes with key between start and end inclusive. +// If either are nil, then it is open on that side (nil, nil is the same as Iterate). The keys and +// values must not be modified, since they may point to data stored within IAVL. +func (t *ImmutableTree) IterateRangeInclusive(start, end []byte, ascending bool, fn func(key, value []byte, version int64) bool) (stopped bool) { + if t.root == nil { + return false + } + return t.root.traverseInRange(t, start, end, ascending, true, false, func(node *Node) bool { + if node.height == 0 { + return fn(node.key, node.value, node.version) + } + return false + }) +} + +// IsFastCacheEnabled returns true if fast cache is enabled, false otherwise. +// For fast cache to be enabled, the following 2 conditions must be met: +// 1. The tree is of the latest version. +// 2. The underlying storage has been upgraded to fast cache +func (t *ImmutableTree) IsFastCacheEnabled() (bool, error) { + isLatestTreeVersion, err := t.isLatestTreeVersion() + if err != nil { + return false, err + } + return isLatestTreeVersion && t.ndb.hasUpgradedToFastStorage(), nil +} + +func (t *ImmutableTree) isLatestTreeVersion() (bool, error) { + latestVersion, err := t.ndb.getLatestVersion() + if err != nil { + return false, err + } + return t.version == latestVersion, nil +} + +// Clone creates a clone of the tree. +// Used internally by MutableTree. +func (t *ImmutableTree) clone() *ImmutableTree { + return &ImmutableTree{ + root: t.root, + ndb: t.ndb, + version: t.version, + skipFastStorageUpgrade: t.skipFastStorageUpgrade, + } +} + +// nodeSize is like Size, but includes inner nodes too. +// +//nolint:unused +func (t *ImmutableTree) nodeSize() int { + size := 0 + t.root.traverse(t, true, func(n *Node) bool { + size++ + return false + }) + return size +} diff --git a/sei-iavl/import.go b/sei-iavl/import.go new file mode 100644 index 0000000000..aff719bda9 --- /dev/null +++ b/sei-iavl/import.go @@ -0,0 +1,199 @@ +package iavl + +import ( + "bytes" + + "github.com/pkg/errors" + + db "github.com/tendermint/tm-db" +) + +// maxBatchSize is the maximum size of the import batch before flushing it to the database +const maxBatchSize = 10000 + +// ErrNoImport is returned when calling methods on a closed importer +var ErrNoImport = errors.New("no import in progress") + +// Importer imports data into an empty MutableTree. It is created by MutableTree.Import(). Users +// must call Close() when done. +// +// ExportNodes must be imported in the order returned by Exporter, i.e. depth-first post-order (LRN). +// +// Importer is not concurrency-safe, it is the caller's responsibility to ensure the tree is not +// modified while performing an import. +type Importer struct { + tree *MutableTree + version int64 + batch db.Batch + batchSize uint32 + stack []*Node +} + +// newImporter creates a new Importer for an empty MutableTree. +// +// version should correspond to the version that was initially exported. It must be greater than +// or equal to the highest ExportNode version number given. +func newImporter(tree *MutableTree, version int64) (*Importer, error) { + if version < 0 { + return nil, errors.New("imported version cannot be negative") + } + if tree.ndb.latestVersion > 0 { + return nil, errors.Errorf("found database at version %d, must be 0", tree.ndb.latestVersion) + } + if !tree.IsEmpty() { + return nil, errors.New("tree must be empty") + } + + return &Importer{ + tree: tree, + version: version, + batch: tree.ndb.db.NewBatch(), + stack: make([]*Node, 0, 8), + }, nil +} + +// Close frees all resources. It is safe to call multiple times. Uncommitted nodes may already have +// been flushed to the database, but will not be visible. +func (i *Importer) Close() { + if i.batch != nil { + i.batch.Close() + } + i.batch = nil + i.tree = nil +} + +// Add adds an ExportNode to the import. ExportNodes must be added in the order returned by +// Exporter, i.e. depth-first post-order (LRN). Nodes are periodically flushed to the database, +// but the imported version is not visible until Commit() is called. +func (i *Importer) Add(exportNode *ExportNode) error { + if i.tree == nil { + return ErrNoImport + } + if exportNode == nil { + return errors.New("node cannot be nil") + } + if exportNode.Version > i.version { + return errors.Errorf("node version %v can't be greater than import version %v", + exportNode.Version, i.version) + } + + node := &Node{ + key: exportNode.Key, + value: exportNode.Value, + version: exportNode.Version, + height: exportNode.Height, + } + + // We build the tree from the bottom-left up. The stack is used to store unresolved left + // children while constructing right children. When all children are built, the parent can + // be constructed and the resolved children can be discarded from the stack. Using a stack + // ensures that we can handle additional unresolved left children while building a right branch. + // + // We don't modify the stack until we've verified the built node, to avoid leaving the + // importer in an inconsistent state when we return an error. + stackSize := len(i.stack) + switch { + case stackSize >= 2 && i.stack[stackSize-1].height < node.height && i.stack[stackSize-2].height < node.height: + node.leftNode = i.stack[stackSize-2] + node.leftHash = node.leftNode.hash + node.rightNode = i.stack[stackSize-1] + node.rightHash = node.rightNode.hash + case stackSize >= 1 && i.stack[stackSize-1].height < node.height: + node.leftNode = i.stack[stackSize-1] + node.leftHash = node.leftNode.hash + } + + if node.height == 0 { + node.size = 1 + } + if node.leftNode != nil { + node.size += node.leftNode.size + } + if node.rightNode != nil { + node.size += node.rightNode.size + } + + _, err := node._hash() + if err != nil { + return err + } + + err = node.validate() + if err != nil { + return err + } + + buf := bufPool.Get().(*bytes.Buffer) + buf.Reset() + defer bufPool.Put(buf) + + if err = node.writeBytes(buf); err != nil { + return err + } + + bytesCopy := make([]byte, buf.Len()) + copy(bytesCopy, buf.Bytes()) + + if err = i.batch.Set(i.tree.ndb.nodeKey(node.hash), bytesCopy); err != nil { + return err + } + + i.batchSize++ + if i.batchSize >= maxBatchSize { + err = i.batch.Write() + if err != nil { + return err + } + i.batch.Close() + i.batch = i.tree.ndb.db.NewBatch() + i.batchSize = 0 + } + + // Update the stack now that we know there were no errors + switch { + case node.leftHash != nil && node.rightHash != nil: + i.stack = i.stack[:stackSize-2] + case node.leftHash != nil || node.rightHash != nil: + i.stack = i.stack[:stackSize-1] + } + i.stack = append(i.stack, node) + + return nil +} + +// Commit finalizes the import by flushing any outstanding nodes to the database, making the +// version visible, and updating the tree metadata. It can only be called once, and calls Close() +// internally. +func (i *Importer) Commit() error { + if i.tree == nil { + return ErrNoImport + } + + switch len(i.stack) { + case 0: + if err := i.batch.Set(i.tree.ndb.rootKey(i.version), []byte{}); err != nil { + return err + } + case 1: + if err := i.batch.Set(i.tree.ndb.rootKey(i.version), i.stack[0].hash); err != nil { + return err + } + default: + return errors.Errorf("invalid node structure, found stack size %v when committing", + len(i.stack)) + } + + err := i.batch.WriteSync() + if err != nil { + return err + } + i.tree.ndb.resetLatestVersion(i.version) + + _, err = i.tree.LoadVersion(i.version) + if err != nil { + return err + } + + i.Close() + return nil +} diff --git a/sei-iavl/import_test.go b/sei-iavl/import_test.go new file mode 100644 index 0000000000..5fbf7d733e --- /dev/null +++ b/sei-iavl/import_test.go @@ -0,0 +1,248 @@ +package iavl + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + db "github.com/tendermint/tm-db" +) + +func ExampleImporter() { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + if err != nil { + // handle err + } + + tree.Set([]byte("a"), []byte{1}) + tree.Set([]byte("b"), []byte{2}) + tree.Set([]byte("c"), []byte{3}) + _, version, err := tree.SaveVersion() + if err != nil { + // handle err + } + + itree, err := tree.GetImmutable(version) + if err != nil { + // handle err + } + exporter := itree.Export() + defer exporter.Close() + exported := []*ExportNode{} + for { + var node *ExportNode + node, err = exporter.Next() + if err == ExportDone { + break + } else if err != nil { + // handle err + } + exported = append(exported, node) + } + + newTree, err := NewMutableTree(db.NewMemDB(), 0, false) + if err != nil { + // handle err + } + importer, err := newTree.Import(version) + if err != nil { + // handle err + } + defer importer.Close() + for _, node := range exported { + err = importer.Add(node) + if err != nil { + // handle err + } + } + err = importer.Commit() + if err != nil { + // handle err + } +} + +func TestImporter_NegativeVersion(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + _, err = tree.Import(-1) + require.Error(t, err) +} + +func TestImporter_NotEmpty(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + tree.Set([]byte("a"), []byte{1}) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + _, err = tree.Import(1) + require.Error(t, err) +} + +func TestImporter_NotEmptyDatabase(t *testing.T) { + db := db.NewMemDB() + + tree, err := NewMutableTree(db, 0, false) + require.NoError(t, err) + tree.Set([]byte("a"), []byte{1}) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + tree, err = NewMutableTree(db, 0, false) + require.NoError(t, err) + _, err = tree.Load() + require.NoError(t, err) + + _, err = tree.Import(1) + require.Error(t, err) +} + +func TestImporter_NotEmptyUnsaved(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + tree.Set([]byte("a"), []byte{1}) + + _, err = tree.Import(1) + require.Error(t, err) +} + +func TestImporter_Add(t *testing.T) { + k := []byte("key") + v := []byte("value") + + testcases := map[string]struct { + node *ExportNode + valid bool + }{ + "nil node": {nil, false}, + "valid": {&ExportNode{Key: k, Value: v, Version: 1, Height: 0}, true}, + "no key": {&ExportNode{Key: nil, Value: v, Version: 1, Height: 0}, false}, + "no value": {&ExportNode{Key: k, Value: nil, Version: 1, Height: 0}, false}, + "version too large": {&ExportNode{Key: k, Value: v, Version: 2, Height: 0}, false}, + "no version": {&ExportNode{Key: k, Value: v, Version: 0, Height: 0}, false}, + // further cases will be handled by Node.validate() + } + for desc, tc := range testcases { + tc := tc // appease scopelint + t.Run(desc, func(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + importer, err := tree.Import(1) + require.NoError(t, err) + defer importer.Close() + + err = importer.Add(tc.node) + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} + +func TestImporter_Add_Closed(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + importer, err := tree.Import(1) + require.NoError(t, err) + + importer.Close() + err = importer.Add(&ExportNode{Key: []byte("key"), Value: []byte("value"), Version: 1, Height: 0}) + require.Error(t, err) + require.Equal(t, ErrNoImport, err) +} + +func TestImporter_Close(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + importer, err := tree.Import(1) + require.NoError(t, err) + + err = importer.Add(&ExportNode{Key: []byte("key"), Value: []byte("value"), Version: 1, Height: 0}) + require.NoError(t, err) + + importer.Close() + has, err := tree.Has([]byte("key")) + require.NoError(t, err) + require.False(t, has) + + importer.Close() +} + +func TestImporter_Commit(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + importer, err := tree.Import(1) + require.NoError(t, err) + + err = importer.Add(&ExportNode{Key: []byte("key"), Value: []byte("value"), Version: 1, Height: 0}) + require.NoError(t, err) + + err = importer.Commit() + require.NoError(t, err) + has, err := tree.Has([]byte("key")) + require.NoError(t, err) + require.True(t, has) +} + +func TestImporter_Commit_Closed(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + importer, err := tree.Import(1) + require.NoError(t, err) + + err = importer.Add(&ExportNode{Key: []byte("key"), Value: []byte("value"), Version: 1, Height: 0}) + require.NoError(t, err) + + importer.Close() + err = importer.Commit() + require.Error(t, err) + require.Equal(t, ErrNoImport, err) +} + +func TestImporter_Commit_Empty(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + importer, err := tree.Import(3) + require.NoError(t, err) + defer importer.Close() + + err = importer.Commit() + require.NoError(t, err) + assert.EqualValues(t, 3, tree.Version()) +} + +func BenchmarkImport(b *testing.B) { + b.StopTimer() + tree := setupExportTreeSized(b, 4096) + exported := make([]*ExportNode, 0, 4096) + exporter := tree.Export() + for { + item, err := exporter.Next() + if err == ExportDone { + break + } else if err != nil { + b.Error(err) + } + exported = append(exported, item) + } + exporter.Close() + b.StartTimer() + + for n := 0; n < b.N; n++ { + newTree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(b, err) + importer, err := newTree.Import(tree.Version()) + require.NoError(b, err) + for _, item := range exported { + err = importer.Add(item) + if err != nil { + b.Error(err) + } + } + err = importer.Commit() + require.NoError(b, err) + } +} diff --git a/sei-iavl/internal/bytes/bytes.go b/sei-iavl/internal/bytes/bytes.go new file mode 100644 index 0000000000..ac3197d8af --- /dev/null +++ b/sei-iavl/internal/bytes/bytes.go @@ -0,0 +1,64 @@ +package common + +import ( + "encoding/hex" + "fmt" + "strings" +) + +// The main purpose of HexBytes is to enable HEX-encoding for json/encoding. +type HexBytes []byte + +// Marshal needed for protobuf compatibility +func (bz HexBytes) Marshal() ([]byte, error) { + return bz, nil +} + +// Unmarshal needed for protobuf compatibility +func (bz *HexBytes) Unmarshal(data []byte) error { + *bz = data + return nil +} + +// This is the point of Bytes. +func (bz HexBytes) MarshalJSON() ([]byte, error) { + s := strings.ToUpper(hex.EncodeToString(bz)) + jbz := make([]byte, len(s)+2) + jbz[0] = '"' + copy(jbz[1:], s) + jbz[len(jbz)-1] = '"' + return jbz, nil +} + +// This is the point of Bytes. +func (bz *HexBytes) UnmarshalJSON(data []byte) error { + if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { + return fmt.Errorf("invalid hex string: %s", data) + } + data = data[1 : len(data)-1] + dest := make([]byte, hex.DecodedLen(len(data))) + _, err := hex.Decode(dest, data) + if err != nil { + return err + } + *bz = dest + return nil +} + +// Allow it to fulfill various interfaces in light-client, etc... +func (bz HexBytes) Bytes() []byte { + return bz +} + +func (bz HexBytes) String() string { + return strings.ToUpper(hex.EncodeToString(bz)) +} + +func (bz HexBytes) Format(s fmt.State, verb rune) { + switch verb { + case 'p': + s.Write([]byte(fmt.Sprintf("%p", bz))) + default: + s.Write([]byte(fmt.Sprintf("%X", []byte(bz)))) + } +} diff --git a/sei-iavl/internal/bytes/bytes_test.go b/sei-iavl/internal/bytes/bytes_test.go new file mode 100644 index 0000000000..40ef393a4f --- /dev/null +++ b/sei-iavl/internal/bytes/bytes_test.go @@ -0,0 +1,66 @@ +// nolint: scopelint +package common + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +// This is a trivial test for protobuf compatibility. +func TestMarshal(t *testing.T) { + bz := []byte("hello world") + dataB := HexBytes(bz) + bz2, err := dataB.Marshal() + assert.Nil(t, err) + assert.Equal(t, bz, bz2) + + var dataB2 HexBytes + err = (&dataB2).Unmarshal(bz) + assert.Nil(t, err) + assert.Equal(t, dataB, dataB2) +} + +// Test that the hex encoding works. +func TestJSONMarshal(t *testing.T) { + + type TestStruct struct { + B1 []byte + B2 HexBytes + } + + cases := []struct { + input []byte + expected string + }{ + {[]byte(``), `{"B1":"","B2":""}`}, + {[]byte(`a`), `{"B1":"YQ==","B2":"61"}`}, + {[]byte(`abc`), `{"B1":"YWJj","B2":"616263"}`}, + } + + for i, tc := range cases { + t.Run(fmt.Sprintf("Case %d", i), func(t *testing.T) { + ts := TestStruct{B1: tc.input, B2: tc.input} + + // Test that it marshals correctly to JSON. + jsonBytes, err := json.Marshal(ts) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, string(jsonBytes), tc.expected) + + // TODO do fuzz testing to ensure that unmarshal fails + + // Test that unmarshaling works correctly. + ts2 := TestStruct{} + err = json.Unmarshal(jsonBytes, &ts2) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, ts2.B1, tc.input) + assert.Equal(t, ts2.B2, HexBytes(tc.input)) + }) + } +} diff --git a/sei-iavl/internal/bytes/string.go b/sei-iavl/internal/bytes/string.go new file mode 100644 index 0000000000..a09422218b --- /dev/null +++ b/sei-iavl/internal/bytes/string.go @@ -0,0 +1,26 @@ +package common + +import ( + "reflect" + "unsafe" +) + +// UnsafeStrToBytes uses unsafe to convert string into byte array. Returned bytes +// must not be altered after this function is called as it will cause a segmentation fault. +func UnsafeStrToBytes(s string) []byte { + var buf []byte + sHdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) + bufHdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + bufHdr.Data = sHdr.Data + bufHdr.Cap = sHdr.Len + bufHdr.Len = sHdr.Len + return buf +} + +// UnsafeBytesToStr is meant to make a zero allocation conversion +// from []byte -> string to speed up operations, it is not meant +// to be used generally, but for a specific pattern to delete keys +// from a map. +func UnsafeBytesToStr(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} diff --git a/sei-iavl/internal/bytes/string_test.go b/sei-iavl/internal/bytes/string_test.go new file mode 100644 index 0000000000..f704e2f852 --- /dev/null +++ b/sei-iavl/internal/bytes/string_test.go @@ -0,0 +1,54 @@ +package common + +import ( + "runtime" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/suite" +) + +func TestStringSuite(t *testing.T) { + suite.Run(t, new(StringSuite)) +} + +type StringSuite struct{ suite.Suite } + +func unsafeConvertStr() []byte { + return UnsafeStrToBytes("abc") +} + +func (s *StringSuite) TestUnsafeStrToBytes() { + // we convert in other function to trigger GC. We want to check that + // the underlying array in []bytes is accessible after GC will finish swapping. + for i := 0; i < 5; i++ { + b := unsafeConvertStr() + runtime.GC() + <-time.NewTimer(2 * time.Millisecond).C + b2 := append(b, 'd') + s.Equal("abc", string(b)) + s.Equal("abcd", string(b2)) + } +} + +func unsafeConvertBytes() string { + return UnsafeBytesToStr([]byte("abc")) +} + +func (s *StringSuite) TestUnsafeBytesToStr() { + // we convert in other function to trigger GC. We want to check that + // the underlying array in []bytes is accessible after GC will finish swapping. + for i := 0; i < 5; i++ { + str := unsafeConvertBytes() + runtime.GC() + <-time.NewTimer(2 * time.Millisecond).C + s.Equal("abc", str) + } +} + +func BenchmarkUnsafeStrToBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + UnsafeStrToBytes(strconv.Itoa(i)) + } +} diff --git a/sei-iavl/internal/encoding/encoding.go b/sei-iavl/internal/encoding/encoding.go new file mode 100644 index 0000000000..788a6fff77 --- /dev/null +++ b/sei-iavl/internal/encoding/encoding.go @@ -0,0 +1,164 @@ +package encoding + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math/bits" + "sync" +) + +var bufPool = &sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, +} + +var varintPool = &sync.Pool{ + New: func() interface{} { + return &[binary.MaxVarintLen64]byte{} + }, +} + +var uvarintPool = &sync.Pool{ + New: func() interface{} { + return &[binary.MaxVarintLen64]byte{} + }, +} + +// decodeBytes decodes a varint length-prefixed byte slice, returning it along with the number +// of input bytes read. +func DecodeBytes(bz []byte) ([]byte, int, error) { + s, n, err := DecodeUvarint(bz) + if err != nil { + return nil, n, err + } + // Make sure size doesn't overflow. ^uint(0) >> 1 will help determine the + // max int value variably on 32-bit and 64-bit machines. We also doublecheck + // that size is positive. + size := int(s) + if s >= uint64(^uint(0)>>1) || size < 0 { + return nil, n, fmt.Errorf("invalid out of range length %v decoding []byte", s) + } + // Make sure end index doesn't overflow. We know n>0 from decodeUvarint(). + end := n + size + if end < n { + return nil, n, fmt.Errorf("invalid out of range length %v decoding []byte", size) + } + // Make sure the end index is within bounds. + if len(bz) < end { + return nil, n, fmt.Errorf("insufficient bytes decoding []byte of length %v", size) + } + bz2 := make([]byte, size) + copy(bz2, bz[n:end]) + return bz2, end, nil +} + +// decodeUvarint decodes a varint-encoded unsigned integer from a byte slice, returning it and the +// number of bytes decoded. +func DecodeUvarint(bz []byte) (uint64, int, error) { + u, n := binary.Uvarint(bz) + if n == 0 { + // buf too small + return u, n, errors.New("buffer too small") + } else if n < 0 { + // value larger than 64 bits (overflow) + // and -n is the number of bytes read + n = -n + return u, n, errors.New("EOF decoding uvarint") + } + return u, n, nil +} + +// decodeVarint decodes a varint-encoded integer from a byte slice, returning it and the number of +// bytes decoded. +func DecodeVarint(bz []byte) (int64, int, error) { + i, n := binary.Varint(bz) + if n == 0 { + return i, n, errors.New("buffer too small") + } else if n < 0 { + // value larger than 64 bits (overflow) + // and -n is the number of bytes read + n = -n + return i, n, errors.New("EOF decoding varint") + } + return i, n, nil +} + +// EncodeBytes writes a varint length-prefixed byte slice to the writer. +func EncodeBytes(w io.Writer, bz []byte) error { + err := EncodeUvarint(w, uint64(len(bz))) + if err != nil { + return err + } + _, err = w.Write(bz) + return err +} + +// encodeBytesSlice length-prefixes the byte slice and returns it. +func EncodeBytesSlice(bz []byte) ([]byte, error) { + buf := bufPool.Get().(*bytes.Buffer) + buf.Reset() + defer bufPool.Put(buf) + + err := EncodeBytes(buf, bz) + + bytesCopy := make([]byte, buf.Len()) + copy(bytesCopy, buf.Bytes()) + + return bytesCopy, err +} + +// encodeBytesSize returns the byte size of the given slice including length-prefixing. +func EncodeBytesSize(bz []byte) int { + return EncodeUvarintSize(uint64(len(bz))) + len(bz) +} + +// EncodeUvarint writes a varint-encoded unsigned integer to an io.Writer. +func EncodeUvarint(w io.Writer, u uint64) error { + // See comment in encodeVarint + buf := uvarintPool.Get().(*[binary.MaxVarintLen64]byte) + + n := binary.PutUvarint(buf[:], u) + _, err := w.Write(buf[0:n]) + + uvarintPool.Put(buf) + + return err +} + +// EncodeUvarintSize returns the byte size of the given integer as a varint. +func EncodeUvarintSize(u uint64) int { + if u == 0 { + return 1 + } + return (bits.Len64(u) + 6) / 7 +} + +// EncodeVarint writes a varint-encoded integer to an io.Writer. +func EncodeVarint(w io.Writer, i int64) error { + // Use a pool here to reduce allocations. + // + // Though this allocates just 10 bytes on the stack, doing allocation for every calls + // cost us a huge memory. The profiling show that using pool save us ~30% memory. + // + // Since when we don't have concurrent access to the pool, the speed will nearly identical. + // If we need to support concurrent access, we can accept a *[binary.MaxVarintLen64]byte as + // input, so the caller can allocate just one and pass the same array pointer to each call. + buf := varintPool.Get().(*[binary.MaxVarintLen64]byte) + + n := binary.PutVarint(buf[:], i) + _, err := w.Write(buf[0:n]) + + varintPool.Put(buf) + + return err +} + +// EncodeVarintSize returns the byte size of the given integer as a varint. +func EncodeVarintSize(i int64) int { + var buf [binary.MaxVarintLen64]byte + return binary.PutVarint(buf[:], i) +} diff --git a/sei-iavl/internal/encoding/encoding_test.go b/sei-iavl/internal/encoding/encoding_test.go new file mode 100644 index 0000000000..36c402f3e2 --- /dev/null +++ b/sei-iavl/internal/encoding/encoding_test.go @@ -0,0 +1,88 @@ +package encoding + +import ( + "encoding/binary" + "math" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDecodeBytes(t *testing.T) { + bz := []byte{0, 1, 2, 3, 4, 5, 6, 7} + testcases := map[string]struct { + bz []byte + lengthPrefix uint64 + expect []byte + expectErr bool + }{ + "full": {bz, 8, bz, false}, + "empty": {bz, 0, []byte{}, false}, + "partial": {bz, 3, []byte{0, 1, 2}, false}, + "out of bounds": {bz, 9, nil, true}, + "empty input": {[]byte{}, 0, []byte{}, false}, + "empty input out of bounds": {[]byte{}, 1, nil, true}, + + // The following will always fail, since the byte slice is only 8 bytes, + // but we're making sure they don't panic due to overflow issues. See: + // https://github.com/cosmos/iavl/issues/339 + "max int32": {bz, uint64(math.MaxInt32), nil, true}, + "max int32 -1": {bz, uint64(math.MaxInt32) - 1, nil, true}, + "max int32 -10": {bz, uint64(math.MaxInt32) - 10, nil, true}, + "max int32 +1": {bz, uint64(math.MaxInt32) + 1, nil, true}, + "max int32 +10": {bz, uint64(math.MaxInt32) + 10, nil, true}, + + "max int32*2": {bz, uint64(math.MaxInt32) * 2, nil, true}, + "max int32*2 -1": {bz, uint64(math.MaxInt32)*2 - 1, nil, true}, + "max int32*2 -10": {bz, uint64(math.MaxInt32)*2 - 10, nil, true}, + "max int32*2 +1": {bz, uint64(math.MaxInt32)*2 + 1, nil, true}, + "max int32*2 +10": {bz, uint64(math.MaxInt32)*2 + 10, nil, true}, + + "max uint32": {bz, uint64(math.MaxUint32), nil, true}, + "max uint32 -1": {bz, uint64(math.MaxUint32) - 1, nil, true}, + "max uint32 -10": {bz, uint64(math.MaxUint32) - 10, nil, true}, + "max uint32 +1": {bz, uint64(math.MaxUint32) + 1, nil, true}, + "max uint32 +10": {bz, uint64(math.MaxUint32) + 10, nil, true}, + + "max uint32*2": {bz, uint64(math.MaxUint32) * 2, nil, true}, + "max uint32*2 -1": {bz, uint64(math.MaxUint32)*2 - 1, nil, true}, + "max uint32*2 -10": {bz, uint64(math.MaxUint32)*2 - 10, nil, true}, + "max uint32*2 +1": {bz, uint64(math.MaxUint32)*2 + 1, nil, true}, + "max uint32*2 +10": {bz, uint64(math.MaxUint32)*2 + 10, nil, true}, + + "max int64": {bz, uint64(math.MaxInt64), nil, true}, + "max int64 -1": {bz, uint64(math.MaxInt64) - 1, nil, true}, + "max int64 -10": {bz, uint64(math.MaxInt64) - 10, nil, true}, + "max int64 +1": {bz, uint64(math.MaxInt64) + 1, nil, true}, + "max int64 +10": {bz, uint64(math.MaxInt64) + 10, nil, true}, + + "max uint64": {bz, uint64(math.MaxUint64), nil, true}, + "max uint64 -1": {bz, uint64(math.MaxUint64) - 1, nil, true}, + "max uint64 -10": {bz, uint64(math.MaxUint64) - 10, nil, true}, + } + for name, tc := range testcases { + tc := tc + t.Run(name, func(t *testing.T) { + // Generate an input slice. + buf := make([]byte, binary.MaxVarintLen64) + varintBytes := binary.PutUvarint(buf, tc.lengthPrefix) + buf = append(buf[:varintBytes], tc.bz...) + + // Attempt to decode it. + b, n, err := DecodeBytes(buf) + if tc.expectErr { + require.Error(t, err) + require.Equal(t, varintBytes, n) + } else { + require.NoError(t, err) + require.Equal(t, uint64(n), uint64(varintBytes)+tc.lengthPrefix) + require.Equal(t, tc.bz[:tc.lengthPrefix], b) + } + }) + } +} + +func TestDecodeBytes_invalidVarint(t *testing.T) { + _, _, err := DecodeBytes([]byte{0xff}) + require.Error(t, err) +} diff --git a/sei-iavl/internal/logger/logger.go b/sei-iavl/internal/logger/logger.go new file mode 100644 index 0000000000..093576bd1a --- /dev/null +++ b/sei-iavl/internal/logger/logger.go @@ -0,0 +1,15 @@ +package logger + +import ( + "fmt" +) + +var ( + debugging = false +) + +func Debug(format string, args ...interface{}) { + if debugging { + fmt.Printf(format, args...) + } +} diff --git a/sei-iavl/internal/rand/random.go b/sei-iavl/internal/rand/random.go new file mode 100644 index 0000000000..2b52df9dee --- /dev/null +++ b/sei-iavl/internal/rand/random.go @@ -0,0 +1,245 @@ +package common + +import ( + crand "crypto/rand" + mrand "math/rand" + "sync" + "time" +) + +const ( + strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters +) + +// Rand is a prng, that is seeded with OS randomness. +// The OS randomness is obtained from crypto/rand, however none of the provided +// methods are suitable for cryptographic usage. +// They all utilize math/rand's prng internally. +// +// All of the methods here are suitable for concurrent use. +// This is achieved by using a mutex lock on all of the provided methods. +type Rand struct { + sync.Mutex + rand *mrand.Rand +} + +var grand *Rand + +func init() { + grand = NewRand() + grand.init() +} + +func NewRand() *Rand { + rand := &Rand{} + rand.init() + return rand +} + +func (r *Rand) init() { + bz := cRandBytes(8) + var seed uint64 + for i := 0; i < 8; i++ { + seed |= uint64(bz[i]) + seed <<= 8 + } + r.reset(int64(seed)) +} + +func (r *Rand) reset(seed int64) { + r.rand = mrand.New(mrand.NewSource(seed)) +} + +//---------------------------------------- +// Global functions + +func Seed(seed int64) { + grand.Seed(seed) +} + +func RandStr(length int) string { + return grand.Str(length) +} + +func RandInt() int { + return grand.Int() +} + +func RandInt31() int32 { + return grand.Int31() +} + +func RandBytes(n int) []byte { + return grand.Bytes(n) +} + +func RandPerm(n int) []int { + return grand.Perm(n) +} + +//---------------------------------------- +// Rand methods + +func (r *Rand) Seed(seed int64) { + r.Lock() + r.reset(seed) + r.Unlock() +} + +// Str constructs a random alphanumeric string of given length. +func (r *Rand) Str(length int) string { + chars := []byte{} +MAIN_LOOP: + for { + val := r.Int63() + for i := 0; i < 10; i++ { + v := int(val & 0x3f) // rightmost 6 bits + if v >= 62 { // only 62 characters in strChars + val >>= 6 + continue + } else { + chars = append(chars, strChars[v]) + if len(chars) == length { + break MAIN_LOOP + } + val >>= 6 + } + } + } + + return string(chars) +} + +func (r *Rand) Uint16() uint16 { + return uint16(r.Uint32() & (1<<16 - 1)) +} + +func (r *Rand) Uint32() uint32 { + r.Lock() + u32 := r.rand.Uint32() + r.Unlock() + return u32 +} + +func (r *Rand) Uint64() uint64 { + return uint64(r.Uint32())<<32 + uint64(r.Uint32()) +} + +func (r *Rand) Uint() uint { + r.Lock() + i := r.rand.Int() + r.Unlock() + return uint(i) +} + +func (r *Rand) Int16() int16 { + return int16(r.Uint32() & (1<<16 - 1)) +} + +func (r *Rand) Int32() int32 { + return int32(r.Uint32()) +} + +func (r *Rand) Int64() int64 { + return int64(r.Uint64()) +} + +func (r *Rand) Int() int { + r.Lock() + i := r.rand.Int() + r.Unlock() + return i +} + +func (r *Rand) Int31() int32 { + r.Lock() + i31 := r.rand.Int31() + r.Unlock() + return i31 +} + +func (r *Rand) Int31n(n int32) int32 { + r.Lock() + i31n := r.rand.Int31n(n) + r.Unlock() + return i31n +} + +func (r *Rand) Int63() int64 { + r.Lock() + i63 := r.rand.Int63() + r.Unlock() + return i63 +} + +func (r *Rand) Int63n(n int64) int64 { + r.Lock() + i63n := r.rand.Int63n(n) + r.Unlock() + return i63n +} + +func (r *Rand) Float32() float32 { + r.Lock() + f32 := r.rand.Float32() + r.Unlock() + return f32 +} + +func (r *Rand) Float64() float64 { + r.Lock() + f64 := r.rand.Float64() + r.Unlock() + return f64 +} + +func (r *Rand) Time() time.Time { + return time.Unix(int64(r.Uint64()), 0) +} + +// Bytes returns n random bytes generated from the internal +// prng. +func (r *Rand) Bytes(n int) []byte { + // cRandBytes isn't guaranteed to be fast so instead + // use random bytes generated from the internal PRNG + bs := make([]byte, n) + for i := 0; i < len(bs); i++ { + bs[i] = byte(r.Int() & 0xFF) + } + return bs +} + +// Intn returns, as an int, a uniform pseudo-random number in the range [0, n). +// It panics if n <= 0. +func (r *Rand) Intn(n int) int { + r.Lock() + i := r.rand.Intn(n) + r.Unlock() + return i +} + +// Bool returns a uniformly random boolean +func (r *Rand) Bool() bool { + // See https://github.com/golang/go/issues/23804#issuecomment-365370418 + // for reasoning behind computing like this + return r.Int63()%2 == 0 +} + +// Perm returns a pseudo-random permutation of n integers in [0, n). +func (r *Rand) Perm(n int) []int { + r.Lock() + perm := r.rand.Perm(n) + r.Unlock() + return perm +} + +// NOTE: This relies on the os's random number generator. +// For real security, we should salt that with some seed. +func cRandBytes(numBytes int) []byte { + b := make([]byte, numBytes) + _, err := crand.Read(b) + if err != nil { + panic(err) + } + return b +} diff --git a/sei-iavl/internal/rand/random_test.go b/sei-iavl/internal/rand/random_test.go new file mode 100644 index 0000000000..1827419442 --- /dev/null +++ b/sei-iavl/internal/rand/random_test.go @@ -0,0 +1,84 @@ +package common + +import ( + "bytes" + "encoding/json" + "fmt" + mrand "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRandStr(t *testing.T) { + l := 243 + s := RandStr(l) + assert.Equal(t, l, len(s)) +} + +func TestRandBytes(t *testing.T) { + l := 243 + b := RandBytes(l) + assert.Equal(t, l, len(b)) +} + +// Test to make sure that we never call math.rand(). +// We do this by ensuring that outputs are deterministic. +func TestDeterminism(t *testing.T) { + var firstOutput string + + // Set math/rand's seed for the sake of debugging this test. + // (It isn't strictly necessary). + mrand.Seed(1) + + for i := 0; i < 100; i++ { + output := testThemAll() + if i == 0 { + firstOutput = output + } else if firstOutput != output { + t.Errorf("Run #%d's output was different from first run.\nfirst: %v\nlast: %v", + i, firstOutput, output) + } + } +} + +func testThemAll() string { + + // Such determinism. + grand.reset(1) + + // Use it. + out := new(bytes.Buffer) + perm := RandPerm(10) + blob, _ := json.Marshal(perm) + fmt.Fprintf(out, "perm: %s\n", blob) + fmt.Fprintf(out, "randInt: %d\n", RandInt()) + fmt.Fprintf(out, "randInt31: %d\n", RandInt31()) + return out.String() +} + +func BenchmarkRandBytes10B(b *testing.B) { + benchmarkRandBytes(b, 10) +} +func BenchmarkRandBytes100B(b *testing.B) { + benchmarkRandBytes(b, 100) +} +func BenchmarkRandBytes1KiB(b *testing.B) { + benchmarkRandBytes(b, 1024) +} +func BenchmarkRandBytes10KiB(b *testing.B) { + benchmarkRandBytes(b, 10*1024) +} +func BenchmarkRandBytes100KiB(b *testing.B) { + benchmarkRandBytes(b, 100*1024) +} +func BenchmarkRandBytes1MiB(b *testing.B) { + benchmarkRandBytes(b, 1024*1024) +} + +func benchmarkRandBytes(b *testing.B, n int) { + for i := 0; i < b.N; i++ { + _ = RandBytes(n) + } + b.ReportAllocs() +} diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go new file mode 100644 index 0000000000..a509ed1ad4 --- /dev/null +++ b/sei-iavl/iterator.go @@ -0,0 +1,261 @@ +package iavl + +// NOTE: This file favors int64 as opposed to int for size/counts. +// The Tree on the other hand favors int. This is intentional. + +import ( + "bytes" + "errors" + + dbm "github.com/tendermint/tm-db" +) + +type traversal struct { + tree *ImmutableTree + start, end []byte // iteration domain + ascending bool // ascending traversal + inclusive bool // end key inclusiveness + post bool // postorder traversal + delayedNodes *delayedNodes // delayed nodes to be traversed +} + +var errIteratorNilTreeGiven = errors.New("iterator must be created with an immutable tree but the tree was nil") + +func (node *Node) newTraversal(tree *ImmutableTree, start, end []byte, ascending bool, inclusive bool, post bool) *traversal { + return &traversal{ + tree: tree, + start: start, + end: end, + ascending: ascending, + inclusive: inclusive, + post: post, + delayedNodes: &delayedNodes{{node, true}}, // set initial traverse to the node + } +} + +// delayedNode represents the delayed iteration on the nodes. +// When delayed is set to true, the delayedNode should be expanded, and their +// children should be traversed. When delayed is set to false, the delayedNode is +// already have expanded, and it could be immediately returned. +type delayedNode struct { + node *Node + delayed bool +} + +type delayedNodes []delayedNode + +func (nodes *delayedNodes) pop() (*Node, bool) { + node := (*nodes)[len(*nodes)-1] + *nodes = (*nodes)[:len(*nodes)-1] + return node.node, node.delayed +} + +func (nodes *delayedNodes) push(node *Node, delayed bool) { + *nodes = append(*nodes, delayedNode{node, delayed}) +} + +func (nodes *delayedNodes) length() int { + return len(*nodes) +} + +// `traversal` returns the delayed execution of recursive traversal on a tree. +// +// `traversal` will traverse the tree in a depth-first manner. To handle locating +// the next element, and to handle unwinding, the traversal maintains its future +// iteration under `delayedNodes`. At each call of `next()`, it will retrieve the +// next element from the `delayedNodes` and acts accordingly. The `next()` itself +// defines how to unwind the delayed nodes stack. The caller can either call the +// next traversal to proceed, or simply discard the `traversal` struct to stop iteration. +// +// At the each step of `next`, the `delayedNodes` can have one of the three states: +// 1. It has length of 0, meaning that their is no more traversable nodes. +// 2. It has length of 1, meaning that the traverse is being started from the initial node. +// 3. It has length of 2>=, meaning that there are delayed nodes to be traversed. +// +// When the `delayedNodes` are not empty, `next` retrieves the first `delayedNode` and initially check: +// 1. If it is not an delayed node (node.delayed == false) it immediately returns it. +// +// A. If the `node` is a branch node: +// 1. If the traversal is postorder, then append the current node to the t.delayedNodes, +// with `delayed` set to false. This makes the current node returned *after* all the children +// are traversed, without being expanded. +// 2. Append the traversable children nodes into the `delayedNodes`, with `delayed` set to true. This +// makes the children nodes to be traversed, and expanded with their respective children. +// 3. If the traversal is preorder, (with the children to be traversed already pushed to the +// `delayedNodes`), returns the current node. +// 4. Call `traversal.next()` to further traverse through the `delayedNodes`. +// +// B. If the `node` is a leaf node, it will be returned without expand, by the following process: +// 1. If the traversal is postorder, the current node will be append to the `delayedNodes` with `delayed` +// set to false, and immediately returned at the subsequent call of `traversal.next()` at the last line. +// 2. If the traversal is preorder, the current node will be returned. +func (t *traversal) next() (*Node, error) { + // End of traversal. + if t.delayedNodes.length() == 0 { + return nil, nil + } + + node, delayed := t.delayedNodes.pop() + + // Already expanded, immediately return. + if !delayed || node == nil { + return node, nil + } + + afterStart := t.start == nil || bytes.Compare(t.start, node.key) < 0 + startOrAfter := afterStart || bytes.Equal(t.start, node.key) + beforeEnd := t.end == nil || bytes.Compare(node.key, t.end) < 0 + if t.inclusive { + beforeEnd = beforeEnd || bytes.Equal(node.key, t.end) + } + + // case of postorder. A-1 and B-1 + // Recursively process left sub-tree, then right-subtree, then node itself. + if t.post && (!node.isLeaf() || (startOrAfter && beforeEnd)) { + t.delayedNodes.push(node, false) + } + + // case of branch node, traversing children. A-2. + if !node.isLeaf() { + // if node is a branch node and the order is ascending, + // We traverse through the left subtree, then the right subtree. + if t.ascending { + if beforeEnd { + // push the delayed traversal for the right nodes, + rightNode, err := node.getRightNode(t.tree) + if err != nil { + return nil, err + } + t.delayedNodes.push(rightNode, true) + } + if afterStart { + // push the delayed traversal for the left nodes, + leftNode, err := node.getLeftNode(t.tree) + if err != nil { + return nil, err + } + t.delayedNodes.push(leftNode, true) + } + } else { + // if node is a branch node and the order is not ascending + // We traverse through the right subtree, then the left subtree. + if afterStart { + // push the delayed traversal for the left nodes, + leftNode, err := node.getLeftNode(t.tree) + if err != nil { + return nil, err + } + t.delayedNodes.push(leftNode, true) + } + if beforeEnd { + // push the delayed traversal for the right nodes, + rightNode, err := node.getRightNode(t.tree) + if err != nil { + return nil, err + } + t.delayedNodes.push(rightNode, true) + } + } + } + + // case of preorder traversal. A-3 and B-2. + // Process root then (recursively) processing left child, then process right child + if !t.post && (!node.isLeaf() || (startOrAfter && beforeEnd)) { + return node, nil + } + + // Keep traversing and expanding the remaning delayed nodes. A-4. + return t.next() +} + +// Iterator is a dbm.Iterator for ImmutableTree +type Iterator struct { + start, end []byte + + key, value []byte + + valid bool + + err error + + t *traversal +} + +var _ dbm.Iterator = (*Iterator)(nil) + +// Returns a new iterator over the immutable tree. If the tree is nil, the iterator will be invalid. +func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree) dbm.Iterator { + iter := &Iterator{ + start: start, + end: end, + } + + if tree == nil { + iter.err = errIteratorNilTreeGiven + } else { + iter.valid = true + iter.t = tree.root.newTraversal(tree, start, end, ascending, false, false) + // Move iterator before the first element + iter.Next() + } + return iter +} + +// Domain implements dbm.Iterator. +func (iter *Iterator) Domain() ([]byte, []byte) { + return iter.start, iter.end +} + +// Valid implements dbm.Iterator. +func (iter *Iterator) Valid() bool { + return iter.valid +} + +// Key implements dbm.Iterator +func (iter *Iterator) Key() []byte { + return iter.key +} + +// Value implements dbm.Iterator +func (iter *Iterator) Value() []byte { + return iter.value +} + +// Next implements dbm.Iterator +func (iter *Iterator) Next() { + if iter.t == nil { + return + } + + node, err := iter.t.next() + // TODO: double-check if this error is correctly handled. + if node == nil || err != nil { + iter.t = nil + iter.valid = false + return + } + + if node.height == 0 { + iter.key, iter.value = node.key, node.value + return + } + + iter.Next() +} + +// Close implements dbm.Iterator +func (iter *Iterator) Close() error { + iter.t = nil + iter.valid = false + return iter.err +} + +// Error implements dbm.Iterator +func (iter *Iterator) Error() error { + return iter.err +} + +// IsFast returnts true if iterator uses fast strategy +func (iter *Iterator) IsFast() bool { + return false +} diff --git a/sei-iavl/iterator_test.go b/sei-iavl/iterator_test.go new file mode 100644 index 0000000000..4164e055a8 --- /dev/null +++ b/sei-iavl/iterator_test.go @@ -0,0 +1,331 @@ +package iavl + +import ( + "math/rand" + "sort" + "testing" + + "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" +) + +func TestIterator_NewIterator_NilTree_Failure(t *testing.T) { + var start, end = []byte{'a'}, []byte{'c'} + ascending := true + + performTest := func(t *testing.T, itr dbm.Iterator) { + require.NotNil(t, itr) + require.False(t, itr.Valid()) + actualsStart, actualEnd := itr.Domain() + require.Equal(t, start, actualsStart) + require.Equal(t, end, actualEnd) + require.Error(t, itr.Error()) + } + + t.Run("Iterator", func(t *testing.T) { + itr := NewIterator(start, end, ascending, nil) + performTest(t, itr) + require.ErrorIs(t, errIteratorNilTreeGiven, itr.Error()) + }) + + t.Run("Fast Iterator", func(t *testing.T) { + itr := NewFastIterator(start, end, ascending, nil) + performTest(t, itr) + require.ErrorIs(t, errFastIteratorNilNdbGiven, itr.Error()) + }) + + t.Run("Unsaved Fast Iterator", func(t *testing.T) { + itr := NewUnsavedFastIterator(start, end, ascending, nil, map[string]*FastNode{}, map[string]interface{}{}) + performTest(t, itr) + require.ErrorIs(t, errFastIteratorNilNdbGiven, itr.Error()) + }) +} + +func TestUnsavedFastIterator_NewIterator_NilAdditions_Failure(t *testing.T) { + var start, end = []byte{'a'}, []byte{'c'} + ascending := true + + performTest := func(t *testing.T, itr dbm.Iterator) { + require.NotNil(t, itr) + require.False(t, itr.Valid()) + actualsStart, actualEnd := itr.Domain() + require.Equal(t, start, actualsStart) + require.Equal(t, end, actualEnd) + require.Error(t, itr.Error()) + } + + t.Run("Nil additions given", func(t *testing.T) { + tree, err := NewMutableTree(dbm.NewMemDB(), 0, false) + require.NoError(t, err) + itr := NewUnsavedFastIterator(start, end, ascending, tree.ndb, nil, tree.unsavedFastNodeRemovals) + performTest(t, itr) + require.ErrorIs(t, errUnsavedFastIteratorNilAdditionsGiven, itr.Error()) + }) + + t.Run("Nil removals given", func(t *testing.T) { + tree, err := NewMutableTree(dbm.NewMemDB(), 0, false) + require.NoError(t, err) + itr := NewUnsavedFastIterator(start, end, ascending, tree.ndb, tree.unsavedFastNodeAdditions, nil) + performTest(t, itr) + require.ErrorIs(t, errUnsavedFastIteratorNilRemovalsGiven, itr.Error()) + }) + + t.Run("All nil", func(t *testing.T) { + itr := NewUnsavedFastIterator(start, end, ascending, nil, nil, nil) + performTest(t, itr) + require.ErrorIs(t, errFastIteratorNilNdbGiven, itr.Error()) + }) + + t.Run("Additions and removals are nil", func(t *testing.T) { + tree, err := NewMutableTree(dbm.NewMemDB(), 0, false) + require.NoError(t, err) + itr := NewUnsavedFastIterator(start, end, ascending, tree.ndb, nil, nil) + performTest(t, itr) + require.ErrorIs(t, errUnsavedFastIteratorNilAdditionsGiven, itr.Error()) + }) +} + +func TestIterator_Empty_Invalid(t *testing.T) { + config := &iteratorTestConfig{ + startByteToSet: 'a', + endByteToSet: 'z', + startIterate: []byte("a"), + endIterate: []byte("a"), + ascending: true, + } + + performTest := func(t *testing.T, itr dbm.Iterator, mirror [][]string) { + require.Equal(t, 0, len(mirror)) + require.False(t, itr.Valid()) + } + + t.Run("Iterator", func(t *testing.T) { + itr, mirror := setupIteratorAndMirror(t, config) + performTest(t, itr, mirror) + }) + + t.Run("Fast Iterator", func(t *testing.T) { + itr, mirror := setupFastIteratorAndMirror(t, config) + performTest(t, itr, mirror) + }) + + t.Run("Unsaved Fast Iterator", func(t *testing.T) { + itr, mirror := setupUnsavedFastIterator(t, config) + performTest(t, itr, mirror) + }) +} + +func TestIterator_Basic_Ranged_Ascending_Success(t *testing.T) { + config := &iteratorTestConfig{ + startByteToSet: 'a', + endByteToSet: 'z', + startIterate: []byte("e"), + endIterate: []byte("w"), + ascending: true, + } + iteratorSuccessTest(t, config) +} + +func TestIterator_Basic_Ranged_Descending_Success(t *testing.T) { + config := &iteratorTestConfig{ + startByteToSet: 'a', + endByteToSet: 'z', + startIterate: []byte("e"), + endIterate: []byte("w"), + ascending: false, + } + iteratorSuccessTest(t, config) +} + +func TestIterator_Basic_Full_Ascending_Success(t *testing.T) { + config := &iteratorTestConfig{ + startByteToSet: 'a', + endByteToSet: 'z', + startIterate: nil, + endIterate: nil, + ascending: true, + } + + iteratorSuccessTest(t, config) +} + +func TestIterator_Basic_Full_Descending_Success(t *testing.T) { + config := &iteratorTestConfig{ + startByteToSet: 'a', + endByteToSet: 'z', + startIterate: nil, + endIterate: nil, + ascending: false, + } + iteratorSuccessTest(t, config) +} + +func TestIterator_WithDelete_Full_Ascending_Success(t *testing.T) { + config := &iteratorTestConfig{ + startByteToSet: 'a', + endByteToSet: 'z', + startIterate: nil, + endIterate: nil, + ascending: false, + } + + tree, mirror := getRandomizedTreeAndMirror(t) + + _, _, err := tree.SaveVersion() + require.NoError(t, err) + + randomizeTreeAndMirror(t, tree, mirror) + + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + err = tree.DeleteVersion(1) + require.NoError(t, err) + + latestVersion, err := tree.ndb.getLatestVersion() + require.NoError(t, err) + immutableTree, err := tree.GetImmutable(latestVersion) + require.NoError(t, err) + + // sort mirror for assertion + sortedMirror := make([][]string, 0, len(mirror)) + for k, v := range mirror { + sortedMirror = append(sortedMirror, []string{k, v}) + } + + sort.Slice(sortedMirror, func(i, j int) bool { + return sortedMirror[i][0] > sortedMirror[j][0] + }) + + t.Run("Iterator", func(t *testing.T) { + itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree) + require.True(t, itr.Valid()) + assertIterator(t, itr, sortedMirror, config.ascending) + }) + + t.Run("Fast Iterator", func(t *testing.T) { + itr := NewFastIterator(config.startIterate, config.endIterate, config.ascending, immutableTree.ndb) + require.True(t, itr.Valid()) + assertIterator(t, itr, sortedMirror, config.ascending) + }) + + t.Run("Unsaved Fast Iterator", func(t *testing.T) { + itr := NewUnsavedFastIterator(config.startIterate, config.endIterate, config.ascending, immutableTree.ndb, tree.unsavedFastNodeAdditions, tree.unsavedFastNodeRemovals) + require.True(t, itr.Valid()) + assertIterator(t, itr, sortedMirror, config.ascending) + }) +} + +func iteratorSuccessTest(t *testing.T, config *iteratorTestConfig) { + performTest := func(t *testing.T, itr dbm.Iterator, mirror [][]string) { + actualStart, actualEnd := itr.Domain() + require.Equal(t, config.startIterate, actualStart) + require.Equal(t, config.endIterate, actualEnd) + + require.NoError(t, itr.Error()) + + assertIterator(t, itr, mirror, config.ascending) + } + + t.Run("Iterator", func(t *testing.T) { + itr, mirror := setupIteratorAndMirror(t, config) + require.True(t, itr.Valid()) + performTest(t, itr, mirror) + }) + + t.Run("Fast Iterator", func(t *testing.T) { + itr, mirror := setupFastIteratorAndMirror(t, config) + require.True(t, itr.Valid()) + performTest(t, itr, mirror) + }) + + t.Run("Unsaved Fast Iterator", func(t *testing.T) { + itr, mirror := setupUnsavedFastIterator(t, config) + require.True(t, itr.Valid()) + performTest(t, itr, mirror) + }) +} + +func setupIteratorAndMirror(t *testing.T, config *iteratorTestConfig) (dbm.Iterator, [][]string) { + tree, err := NewMutableTree(dbm.NewMemDB(), 0, false) + require.NoError(t, err) + + mirror := setupMirrorForIterator(t, config, tree) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + latestVersion, err := tree.ndb.getLatestVersion() + require.NoError(t, err) + immutableTree, err := tree.GetImmutable(latestVersion) + require.NoError(t, err) + + itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree) + return itr, mirror +} + +func setupFastIteratorAndMirror(t *testing.T, config *iteratorTestConfig) (dbm.Iterator, [][]string) { + tree, err := NewMutableTree(dbm.NewMemDB(), 0, false) + require.NoError(t, err) + + mirror := setupMirrorForIterator(t, config, tree) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + itr := NewFastIterator(config.startIterate, config.endIterate, config.ascending, tree.ndb) + return itr, mirror +} + +func setupUnsavedFastIterator(t *testing.T, config *iteratorTestConfig) (dbm.Iterator, [][]string) { + tree, err := NewMutableTree(dbm.NewMemDB(), 0, false) + require.NoError(t, err) + + // For unsaved fast iterator, we would like to test the state where + // there are saved fast nodes as well as some unsaved additions and removals. + // So, we split the byte range in half where the first half is saved and the second half is unsaved. + breakpointByte := (config.endByteToSet + config.startByteToSet) / 2 + + firstHalfConfig := *config + firstHalfConfig.endByteToSet = breakpointByte // exclusive + + secondHalfConfig := *config + secondHalfConfig.startByteToSet = breakpointByte + + // First half of the mirror + mirror := setupMirrorForIterator(t, &firstHalfConfig, tree) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + // No unsaved additions or removals should be present after saving + require.Equal(t, 0, len(tree.unsavedFastNodeAdditions)) + require.Equal(t, 0, len(tree.unsavedFastNodeRemovals)) + + // Ensure that there are unsaved additions and removals present + secondHalfMirror := setupMirrorForIterator(t, &secondHalfConfig, tree) + + require.True(t, len(tree.unsavedFastNodeAdditions) >= len(secondHalfMirror)) + require.Equal(t, 0, len(tree.unsavedFastNodeRemovals)) + + // Merge the two halves + if config.ascending { + mirror = append(mirror, secondHalfMirror...) + } else { + mirror = append(secondHalfMirror, mirror...) + } + + if len(mirror) > 0 { + // Remove random keys + for i := 0; i < len(mirror)/4; i++ { + randIndex := rand.Intn(len(mirror)) + keyToRemove := mirror[randIndex][0] + + _, removed, err := tree.Remove([]byte(keyToRemove)) + require.NoError(t, err) + require.True(t, removed) + + mirror = append(mirror[:randIndex], mirror[randIndex+1:]...) + } + } + + itr := NewUnsavedFastIterator(config.startIterate, config.endIterate, config.ascending, tree.ndb, tree.unsavedFastNodeAdditions, tree.unsavedFastNodeRemovals) + return itr, mirror +} diff --git a/sei-iavl/key_format.go b/sei-iavl/key_format.go new file mode 100644 index 0000000000..31ff82a26f --- /dev/null +++ b/sei-iavl/key_format.go @@ -0,0 +1,182 @@ +package iavl + +import ( + "encoding/binary" + "fmt" +) + +// Provides a fixed-width lexicographically sortable []byte key format +type KeyFormat struct { + layout []int + length int + prefix byte + unbounded bool +} + +// Create a []byte key format based on a single byte prefix and fixed width key segments each of whose length is +// specified by by the corresponding element of layout. +// +// For example, to store keys that could index some objects by a version number and their SHA256 hash using the form: +// 'c' then you would define the KeyFormat with: +// +// var keyFormat = NewKeyFormat('c', 8, 32) +// +// Then you can create a key with: +// +// func ObjectKey(version uint64, objectBytes []byte) []byte { +// hasher := sha256.New() +// hasher.Sum(nil) +// return keyFormat.Key(version, hasher.Sum(nil)) +// } +// if the last term of the layout ends in 0 +func NewKeyFormat(prefix byte, layout ...int) *KeyFormat { + // For prefix byte + length := 1 + for i, l := range layout { + length += l + if l == 0 && i != len(layout)-1 { + panic("Only the last item in a key format can be 0") + } + } + return &KeyFormat{ + prefix: prefix, + layout: layout, + length: length, + unbounded: len(layout) > 0 && layout[len(layout)-1] == 0, + } +} + +// Format the byte segments into the key format - will panic if the segment lengths do not match the layout. +func (kf *KeyFormat) KeyBytes(segments ...[]byte) []byte { + keyLen := kf.length + // In case segments length is less than layouts length, + // we don't have to allocate the whole kf.length, just + // enough space to store the segments. + if len(segments) < len(kf.layout) { + keyLen = 1 + for i := range segments { + keyLen += kf.layout[i] + } + } + + if kf.unbounded { + if len(segments) > 0 { + keyLen += len(segments[len(segments)-1]) + } + } + key := make([]byte, keyLen) + key[0] = kf.prefix + n := 1 + for i, s := range segments { + l := kf.layout[i] + + switch l { + case 0: + // If the expected segment length is unbounded, increase it by `string length` + n += len(s) + default: + if len(s) > l { + panic(fmt.Errorf("length of segment %X provided to KeyFormat.KeyBytes() is longer than the %d bytes "+ + "required by layout for segment %d", s, l, i)) + } + // Otherwise increase n by the segment length + n += l + + } + // Big endian so pad on left if not given the full width for this segment + copy(key[n-len(s):n], s) + } + return key[:n] +} + +// Format the args passed into the key format - will panic if the arguments passed do not match the length +// of the segment to which they correspond. When called with no arguments returns the raw prefix (useful as a start +// element of the entire keys space when sorted lexicographically). +func (kf *KeyFormat) Key(args ...interface{}) []byte { + if len(args) > len(kf.layout) { + panic(fmt.Errorf("keyFormat.Key() is provided with %d args but format only has %d segments", + len(args), len(kf.layout))) + } + segments := make([][]byte, len(args)) + for i, a := range args { + segments[i] = format(a) + } + return kf.KeyBytes(segments...) +} + +// Reads out the bytes associated with each segment of the key format from key. +func (kf *KeyFormat) ScanBytes(key []byte) [][]byte { + segments := make([][]byte, len(kf.layout)) + n := 1 + for i, l := range kf.layout { + n += l + // if current section is longer than key, then there are no more subsequent segments. + if n > len(key) { + return segments[:i] + } + // if unbounded, segment is rest of key + if l == 0 { + segments[i] = key[n:] + break + } else { + segments[i] = key[n-l : n] + } + } + return segments +} + +// Extracts the segments into the values pointed to by each of args. Each arg must be a pointer to int64, uint64, or +// []byte, and the width of the args must match layout. +func (kf *KeyFormat) Scan(key []byte, args ...interface{}) { + segments := kf.ScanBytes(key) + if len(args) > len(segments) { + panic(fmt.Errorf("keyFormat.Scan() is provided with %d args but format only has %d segments in key %X", + len(args), len(segments), key)) + } + for i, a := range args { + scan(a, segments[i]) + } +} + +// Return the prefix as a string. +func (kf *KeyFormat) Prefix() string { + return string([]byte{kf.prefix}) +} + +func scan(a interface{}, value []byte) { + switch v := a.(type) { + case *int64: + // Negative values will be mapped correctly when read in as uint64 and then type converted + *v = int64(binary.BigEndian.Uint64(value)) + case *uint64: + *v = binary.BigEndian.Uint64(value) + case *[]byte: + *v = value + default: + panic(fmt.Errorf("keyFormat scan() does not support scanning value of type %T: %v", a, a)) + } +} + +func format(a interface{}) []byte { + switch v := a.(type) { + case uint64: + return formatUint64(v) + case int64: + return formatUint64(uint64(v)) + // Provide formatting from int,uint as a convenience to avoid casting arguments + case uint: + return formatUint64(uint64(v)) + case int: + return formatUint64(uint64(v)) + case []byte: + return v + default: + panic(fmt.Errorf("keyFormat format() does not support formatting value of type %T: %v", a, a)) + } +} + +func formatUint64(v uint64) []byte { + bs := make([]byte, 8) + binary.BigEndian.PutUint64(bs, v) + return bs +} diff --git a/sei-iavl/key_format_test.go b/sei-iavl/key_format_test.go new file mode 100644 index 0000000000..cc3a2d4f71 --- /dev/null +++ b/sei-iavl/key_format_test.go @@ -0,0 +1,149 @@ +package iavl + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestKeyFormatBytes(t *testing.T) { + type keyPairs struct { + key [][]byte + expected []byte + } + emptyTestVector := keyPairs{key: [][]byte{}, expected: []byte{'e'}} + threeByteTestVector := keyPairs{ + key: [][]byte{{1, 2, 3}}, + expected: []byte{'e', 0, 0, 0, 0, 0, 1, 2, 3}, + } + eightByteTestVector := keyPairs{ + key: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8}}, + expected: []byte{'e', 1, 2, 3, 4, 5, 6, 7, 8}, + } + + tests := []struct { + name string + kf *KeyFormat + testVectors []keyPairs + }{{ + name: "simple 3 int key format", + kf: NewKeyFormat(byte('e'), 8, 8, 8), + testVectors: []keyPairs{ + emptyTestVector, + threeByteTestVector, + eightByteTestVector, + { + key: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8}, {1, 2, 3, 4, 5, 6, 7, 8}, {1, 1, 2, 2, 3, 3}}, + expected: []byte{'e', 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 1, 1, 2, 2, 3, 3}, + }, + }, + }, { + name: "zero suffix key format", + kf: NewKeyFormat(byte('e'), 8, 0), + testVectors: []keyPairs{ + emptyTestVector, + threeByteTestVector, + eightByteTestVector, + { + key: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8}, {1, 2, 3, 4, 5, 6, 7, 8, 9}}, + expected: []byte{'e', 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + key: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8}, []byte("hellohello")}, + expected: []byte{'e', 1, 2, 3, 4, 5, 6, 7, 8, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x68, 0x65, 0x6c, 0x6c, 0x6f}, + }, + }, + }} + for _, tc := range tests { + kf := tc.kf + for i, v := range tc.testVectors { + assert.Equal(t, v.expected, kf.KeyBytes(v.key...), "key format %s, test case %d", tc.name, i) + } + } +} + +func TestKeyFormat(t *testing.T) { + kf := NewKeyFormat(byte('e'), 8, 8, 8) + key := []byte{'e', 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 1, 144} + var a, b, c int64 = 100, 200, 400 + assert.Equal(t, key, kf.Key(a, b, c)) + + var ao, bo, co = new(int64), new(int64), new(int64) + kf.Scan(key, ao, bo, co) + assert.Equal(t, a, *ao) + assert.Equal(t, b, *bo) + assert.Equal(t, c, *co) + + bs := new([]byte) + kf.Scan(key, ao, bo, bs) + assert.Equal(t, a, *ao) + assert.Equal(t, b, *bo) + assert.Equal(t, []byte{0, 0, 0, 0, 0, 0, 1, 144}, *bs) + + assert.Equal(t, []byte{'e', 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 200}, kf.Key(a, b)) +} + +func TestNegativeKeys(t *testing.T) { + kf := NewKeyFormat(byte('e'), 8, 8) + + var a, b int64 = -100, -200 + // One's complement plus one + key := []byte{'e', + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, byte(0xff + a + 1), + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, byte(0xff + b + 1)} + assert.Equal(t, key, kf.Key(a, b)) + + var ao, bo = new(int64), new(int64) + kf.Scan(key, ao, bo) + assert.Equal(t, a, *ao) + assert.Equal(t, b, *bo) +} + +func TestOverflow(t *testing.T) { + kf := NewKeyFormat(byte('o'), 8, 8) + + var a int64 = 1 << 62 + var b uint64 = 1 << 63 + key := []byte{'o', + 0x40, 0, 0, 0, 0, 0, 0, 0, + 0x80, 0, 0, 0, 0, 0, 0, 0, + } + assert.Equal(t, key, kf.Key(a, b)) + + var ao, bo = new(int64), new(int64) + kf.Scan(key, ao, bo) + assert.Equal(t, a, *ao) + assert.Equal(t, int64(b), *bo) +} + +func benchmarkKeyFormatBytes(b *testing.B, kf *KeyFormat, segments ...[]byte) { + for i := 0; i < b.N; i++ { + kf.KeyBytes(segments...) + } +} + +func BenchmarkKeyFormat_KeyBytesOneSegment(b *testing.B) { + benchmarkKeyFormatBytes(b, NewKeyFormat('e', 8, 8, 8), nil) +} + +func BenchmarkKeyFormat_KeyBytesThreeSegment(b *testing.B) { + segments := [][]byte{ + {1, 2, 3, 4, 5, 6, 7, 8}, + {1, 2, 3, 4, 5, 6, 7, 8}, + {1, 1, 2, 2, 3, 3}, + } + benchmarkKeyFormatBytes(b, NewKeyFormat('e', 8, 8, 8), segments...) +} + +func BenchmarkKeyFormat_KeyBytesOneSegmentWithVariousLayouts(b *testing.B) { + benchmarkKeyFormatBytes(b, NewKeyFormat('e', 8, 16, 32), nil) +} + +func BenchmarkKeyFormat_KeyBytesThreeSegmentWithVariousLayouts(b *testing.B) { + segments := [][]byte{ + {1, 2, 3, 4, 5, 6, 7, 8}, + {1, 2, 3, 4, 5, 6, 7, 8}, + {1, 1, 2, 2, 3, 3}, + } + benchmarkKeyFormatBytes(b, NewKeyFormat('e', 8, 16, 32), segments...) +} diff --git a/sei-iavl/mock/db_mock.go b/sei-iavl/mock/db_mock.go new file mode 100644 index 0000000000..8120cc64f8 --- /dev/null +++ b/sei-iavl/mock/db_mock.go @@ -0,0 +1,420 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: /root/go/pkg/mod/github.com/tendermint/tm-db@v0.6.4/types.go + +// Package mock is a generated GoMock package. +package mock + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + db "github.com/tendermint/tm-db" +) + +// MockDB is a mock of DB interface. +type MockDB struct { + ctrl *gomock.Controller + recorder *MockDBMockRecorder +} + +// MockDBMockRecorder is the mock recorder for MockDB. +type MockDBMockRecorder struct { + mock *MockDB +} + +// NewMockDB creates a new mock instance. +func NewMockDB(ctrl *gomock.Controller) *MockDB { + mock := &MockDB{ctrl: ctrl} + mock.recorder = &MockDBMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDB) EXPECT() *MockDBMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockDB) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockDBMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDB)(nil).Close)) +} + +// Delete mocks base method. +func (m *MockDB) Delete(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockDBMockRecorder) Delete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDB)(nil).Delete), arg0) +} + +// DeleteSync mocks base method. +func (m *MockDB) DeleteSync(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSync", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteSync indicates an expected call of DeleteSync. +func (mr *MockDBMockRecorder) DeleteSync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSync", reflect.TypeOf((*MockDB)(nil).DeleteSync), arg0) +} + +// Get mocks base method. +func (m *MockDB) Get(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockDBMockRecorder) Get(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDB)(nil).Get), arg0) +} + +// Has mocks base method. +func (m *MockDB) Has(key []byte) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Has", key) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Has indicates an expected call of Has. +func (mr *MockDBMockRecorder) Has(key interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockDB)(nil).Has), key) +} + +// Iterator mocks base method. +func (m *MockDB) Iterator(start, end []byte) (db.Iterator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Iterator", start, end) + ret0, _ := ret[0].(db.Iterator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Iterator indicates an expected call of Iterator. +func (mr *MockDBMockRecorder) Iterator(start, end interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterator", reflect.TypeOf((*MockDB)(nil).Iterator), start, end) +} + +// NewBatch mocks base method. +func (m *MockDB) NewBatch() db.Batch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewBatch") + ret0, _ := ret[0].(db.Batch) + return ret0 +} + +// NewBatch indicates an expected call of NewBatch. +func (mr *MockDBMockRecorder) NewBatch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBatch", reflect.TypeOf((*MockDB)(nil).NewBatch)) +} + +// Print mocks base method. +func (m *MockDB) Print() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Print") + ret0, _ := ret[0].(error) + return ret0 +} + +// Print indicates an expected call of Print. +func (mr *MockDBMockRecorder) Print() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Print", reflect.TypeOf((*MockDB)(nil).Print)) +} + +// ReverseIterator mocks base method. +func (m *MockDB) ReverseIterator(start, end []byte) (db.Iterator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReverseIterator", start, end) + ret0, _ := ret[0].(db.Iterator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReverseIterator indicates an expected call of ReverseIterator. +func (mr *MockDBMockRecorder) ReverseIterator(start, end interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReverseIterator", reflect.TypeOf((*MockDB)(nil).ReverseIterator), start, end) +} + +// Set mocks base method. +func (m *MockDB) Set(arg0, arg1 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Set", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Set indicates an expected call of Set. +func (mr *MockDBMockRecorder) Set(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockDB)(nil).Set), arg0, arg1) +} + +// SetSync mocks base method. +func (m *MockDB) SetSync(arg0, arg1 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetSync", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetSync indicates an expected call of SetSync. +func (mr *MockDBMockRecorder) SetSync(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSync", reflect.TypeOf((*MockDB)(nil).SetSync), arg0, arg1) +} + +// Stats mocks base method. +func (m *MockDB) Stats() map[string]string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stats") + ret0, _ := ret[0].(map[string]string) + return ret0 +} + +// Stats indicates an expected call of Stats. +func (mr *MockDBMockRecorder) Stats() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stats", reflect.TypeOf((*MockDB)(nil).Stats)) +} + +// MockBatch is a mock of Batch interface. +type MockBatch struct { + ctrl *gomock.Controller + recorder *MockBatchMockRecorder +} + +// MockBatchMockRecorder is the mock recorder for MockBatch. +type MockBatchMockRecorder struct { + mock *MockBatch +} + +// NewMockBatch creates a new mock instance. +func NewMockBatch(ctrl *gomock.Controller) *MockBatch { + mock := &MockBatch{ctrl: ctrl} + mock.recorder = &MockBatchMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBatch) EXPECT() *MockBatchMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockBatch) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockBatchMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockBatch)(nil).Close)) +} + +// Delete mocks base method. +func (m *MockBatch) Delete(key []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", key) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockBatchMockRecorder) Delete(key interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockBatch)(nil).Delete), key) +} + +// Set mocks base method. +func (m *MockBatch) Set(key, value []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Set", key, value) + ret0, _ := ret[0].(error) + return ret0 +} + +// Set indicates an expected call of Set. +func (mr *MockBatchMockRecorder) Set(key, value interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockBatch)(nil).Set), key, value) +} + +// Write mocks base method. +func (m *MockBatch) Write() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Write") + ret0, _ := ret[0].(error) + return ret0 +} + +// Write indicates an expected call of Write. +func (mr *MockBatchMockRecorder) Write() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockBatch)(nil).Write)) +} + +// WriteSync mocks base method. +func (m *MockBatch) WriteSync() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteSync") + ret0, _ := ret[0].(error) + return ret0 +} + +// WriteSync indicates an expected call of WriteSync. +func (mr *MockBatchMockRecorder) WriteSync() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteSync", reflect.TypeOf((*MockBatch)(nil).WriteSync)) +} + +// MockIterator is a mock of Iterator interface. +type MockIterator struct { + ctrl *gomock.Controller + recorder *MockIteratorMockRecorder +} + +// MockIteratorMockRecorder is the mock recorder for MockIterator. +type MockIteratorMockRecorder struct { + mock *MockIterator +} + +// NewMockIterator creates a new mock instance. +func NewMockIterator(ctrl *gomock.Controller) *MockIterator { + mock := &MockIterator{ctrl: ctrl} + mock.recorder = &MockIteratorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIterator) EXPECT() *MockIteratorMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockIterator) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockIteratorMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIterator)(nil).Close)) +} + +// Domain mocks base method. +func (m *MockIterator) Domain() ([]byte, []byte) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Domain") + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].([]byte) + return ret0, ret1 +} + +// Domain indicates an expected call of Domain. +func (mr *MockIteratorMockRecorder) Domain() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Domain", reflect.TypeOf((*MockIterator)(nil).Domain)) +} + +// Error mocks base method. +func (m *MockIterator) Error() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Error") + ret0, _ := ret[0].(error) + return ret0 +} + +// Error indicates an expected call of Error. +func (mr *MockIteratorMockRecorder) Error() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockIterator)(nil).Error)) +} + +// Key mocks base method. +func (m *MockIterator) Key() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Key") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// Key indicates an expected call of Key. +func (mr *MockIteratorMockRecorder) Key() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Key", reflect.TypeOf((*MockIterator)(nil).Key)) +} + +// Next mocks base method. +func (m *MockIterator) Next() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Next") +} + +// Next indicates an expected call of Next. +func (mr *MockIteratorMockRecorder) Next() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Next", reflect.TypeOf((*MockIterator)(nil).Next)) +} + +// Valid mocks base method. +func (m *MockIterator) Valid() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Valid") + ret0, _ := ret[0].(bool) + return ret0 +} + +// Valid indicates an expected call of Valid. +func (mr *MockIteratorMockRecorder) Valid() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Valid", reflect.TypeOf((*MockIterator)(nil).Valid)) +} + +// Value mocks base method. +func (m *MockIterator) Value() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Value") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// Value indicates an expected call of Value. +func (mr *MockIteratorMockRecorder) Value() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Value", reflect.TypeOf((*MockIterator)(nil).Value)) +} diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go new file mode 100644 index 0000000000..4d352f680e --- /dev/null +++ b/sei-iavl/mutable_tree.go @@ -0,0 +1,1255 @@ +package iavl + +import ( + "bytes" + "crypto/sha256" + "fmt" + "sort" + "sync" + + "github.com/pkg/errors" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/iavl/internal/logger" +) + +// commitGap after upgrade/delete commitGap FastNodes when commit the batch +var commitGap uint64 = 5000000 + +// ErrVersionDoesNotExist is returned if a requested version does not exist. +var ErrVersionDoesNotExist = errors.New("version does not exist") + +// MutableTree is a persistent tree which keeps track of versions. It is not safe for concurrent +// use, and should be guarded by a Mutex or RWLock as appropriate. An immutable tree at a given +// version can be returned via GetImmutable, which is safe for concurrent access. +// +// Given and returned key/value byte slices must not be modified, since they may point to data +// located inside IAVL which would also be modified. +// +// The inner ImmutableTree should not be used directly by callers. +type MutableTree struct { + *ImmutableTree // The current, working tree. + lastSaved *ImmutableTree // The most recently saved tree. + orphans map[string]int64 // Nodes removed by changes to working tree. + versions map[int64]bool // The previous, saved versions of the tree. + allRootLoaded bool // Whether all roots are loaded or not(by LazyLoadVersion) + unsavedFastNodeAdditions map[string]*FastNode // FastNodes that have not yet been saved to disk + unsavedFastNodeRemovals map[string]interface{} // FastNodes that have not yet been removed from disk + ndb *nodeDB + skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage + + mtx sync.Mutex +} + +// NewMutableTree returns a new tree with the specified cache size and datastore. +func NewMutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) (*MutableTree, error) { + return NewMutableTreeWithOpts(db, cacheSize, nil, skipFastStorageUpgrade) +} + +// NewMutableTreeWithOpts returns a new tree with the specified options. +func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) (*MutableTree, error) { + ndb := newNodeDB(db, cacheSize, opts) + head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade} + + return &MutableTree{ + ImmutableTree: head, + lastSaved: head.clone(), + orphans: map[string]int64{}, + versions: map[int64]bool{}, + allRootLoaded: false, + unsavedFastNodeAdditions: make(map[string]*FastNode), + unsavedFastNodeRemovals: make(map[string]interface{}), + ndb: ndb, + skipFastStorageUpgrade: skipFastStorageUpgrade, + }, nil +} + +// IsEmpty returns whether or not the tree has any keys. Only trees that are +// not empty can be saved. +func (tree *MutableTree) IsEmpty() bool { + return tree.ImmutableTree.Size() == 0 +} + +// VersionExists returns whether or not a version exists. +func (tree *MutableTree) VersionExists(version int64) bool { + tree.mtx.Lock() + defer tree.mtx.Unlock() + + if tree.allRootLoaded { + return tree.versions[version] + } + + has, ok := tree.versions[version] + if ok { + return has + } + has, _ = tree.ndb.HasRoot(version) + tree.versions[version] = has + return has +} + +// AvailableVersions returns all available versions in ascending order +func (tree *MutableTree) AvailableVersions() []int { + tree.mtx.Lock() + defer tree.mtx.Unlock() + + res := make([]int, 0, len(tree.versions)) + for i, v := range tree.versions { + if v { + res = append(res, int(i)) + } + } + sort.Ints(res) + return res +} + +// Hash returns the hash of the latest saved version of the tree, as returned +// by SaveVersion. If no versions have been saved, Hash returns nil. +func (tree *MutableTree) Hash() ([]byte, error) { + return tree.lastSaved.Hash() +} + +// WorkingHash returns the hash of the current working tree. +func (tree *MutableTree) WorkingHash() ([]byte, error) { + return tree.ImmutableTree.Hash() +} + +// String returns a string representation of the tree. +func (tree *MutableTree) String() (string, error) { + return tree.ndb.String() +} + +// Set/Remove will orphan at most tree.Height nodes, +// balancing the tree after a Set/Remove will orphan at most 3 nodes. +func (tree *MutableTree) prepareOrphansSlice() []*Node { + return make([]*Node, 0, tree.Height()+3) +} + +// Set sets a key in the working tree. Nil values are invalid. The given +// key/value byte slices must not be modified after this call, since they point +// to slices stored within IAVL. It returns true when an existing value was +// updated, while false means it was a new key. +func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { + var orphaned []*Node + orphaned, updated, err = tree.set(key, value) + if err != nil { + return false, err + } + err = tree.addOrphans(orphaned) + if err != nil { + return updated, err + } + return updated, nil +} + +// Get returns the value of the specified key if it exists, or nil otherwise. +// The returned value must not be modified, since it may point to data stored within IAVL. +func (tree *MutableTree) Get(key []byte) ([]byte, error) { + if tree.root == nil { + return nil, nil + } + + if !tree.skipFastStorageUpgrade { + if fastNode, ok := tree.unsavedFastNodeAdditions[unsafeToStr(key)]; ok { + return fastNode.value, nil + } + // check if node was deleted + if _, ok := tree.unsavedFastNodeRemovals[string(key)]; ok { + return nil, nil + } + } + + return tree.ImmutableTree.Get(key) +} + +// Import returns an importer for tree nodes previously exported by ImmutableTree.Export(), +// producing an identical IAVL tree. The caller must call Close() on the importer when done. +// +// version should correspond to the version that was initially exported. It must be greater than +// or equal to the highest ExportNode version number given. +// +// Import can only be called on an empty tree. It is the callers responsibility that no other +// modifications are made to the tree while importing. +func (tree *MutableTree) Import(version int64) (*Importer, error) { + return newImporter(tree, version) +} + +// Iterate iterates over all keys of the tree. The keys and values must not be modified, +// since they may point to data stored within IAVL. Returns true if stopped by callnack, false otherwise +func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { + if tree.root == nil { + return false, nil + } + + if tree.skipFastStorageUpgrade { + return tree.ImmutableTree.Iterate(fn) + } + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + if err != nil { + return false, err + } + if !isFastCacheEnabled { + return tree.ImmutableTree.Iterate(fn) + } + + itr := NewUnsavedFastIterator(nil, nil, true, tree.ndb, tree.unsavedFastNodeAdditions, tree.unsavedFastNodeRemovals) + defer itr.Close() + for ; itr.Valid(); itr.Next() { + if fn(itr.Key(), itr.Value()) { + return true, nil + } + } + return false, nil +} + +// Iterator returns an iterator over the mutable tree. +// CONTRACT: no updates are made to the tree while an iterator is active. +func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { + if !tree.skipFastStorageUpgrade { + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + if err != nil { + return nil, err + } + + if isFastCacheEnabled { + return NewUnsavedFastIterator(start, end, ascending, tree.ndb, tree.unsavedFastNodeAdditions, tree.unsavedFastNodeRemovals), nil + } + } + + return tree.ImmutableTree.Iterator(start, end, ascending) +} + +func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated bool, err error) { + if value == nil { + return nil, updated, fmt.Errorf("attempt to store nil value at key '%s'", key) + } + + if tree.ImmutableTree.root == nil { + if !tree.skipFastStorageUpgrade { + tree.addUnsavedAddition(key, NewFastNode(key, value, tree.version+1)) + } + tree.ImmutableTree.root = NewNode(key, value, tree.version+1) + return nil, updated, nil + } + + orphans = tree.prepareOrphansSlice() + tree.ImmutableTree.root, updated, err = tree.recursiveSet(tree.ImmutableTree.root, key, value, &orphans) + return orphans, updated, err +} + +func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orphans *[]*Node) ( + newSelf *Node, updated bool, err error, +) { + version := tree.version + 1 + + if node.isLeaf() { + if !tree.skipFastStorageUpgrade { + tree.addUnsavedAddition(key, NewFastNode(key, value, version)) + } + + switch bytes.Compare(key, node.key) { + case -1: + return &Node{ + key: node.key, + height: 1, + size: 2, + leftNode: NewNode(key, value, version), + rightNode: node, + version: version, + }, false, nil + case 1: + return &Node{ + key: key, + height: 1, + size: 2, + leftNode: node, + rightNode: NewNode(key, value, version), + version: version, + }, false, nil + default: + *orphans = append(*orphans, node) + return NewNode(key, value, version), true, nil + } + } else { + *orphans = append(*orphans, node) + node, err = node.clone(version) + if err != nil { + return nil, false, err + } + + if bytes.Compare(key, node.key) < 0 { + leftNode, err := node.getLeftNode(tree.ImmutableTree) + if err != nil { + return nil, false, err + } + node.leftNode, updated, err = tree.recursiveSet(leftNode, key, value, orphans) + if err != nil { + return nil, updated, err + } + node.leftHash = nil // leftHash is yet unknown + } else { + rightNode, err := node.getRightNode(tree.ImmutableTree) + if err != nil { + return nil, false, err + } + node.rightNode, updated, err = tree.recursiveSet(rightNode, key, value, orphans) + if err != nil { + return nil, updated, err + } + node.rightHash = nil // rightHash is yet unknown + } + + if updated { + return node, updated, nil + } + err = node.calcHeightAndSize(tree.ImmutableTree) + if err != nil { + return nil, false, err + } + + newNode, err := tree.balance(node, orphans) + if err != nil { + return nil, false, err + } + return newNode, updated, err + } +} + +// Remove removes a key from the working tree. The given key byte slice should not be modified +// after this call, since it may point to data stored inside IAVL. +func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { + val, orphaned, removed, err := tree.remove(key) + if err != nil { + return nil, false, err + } + + err = tree.addOrphans(orphaned) + if err != nil { + return val, removed, err + } + return val, removed, nil +} + +// remove tries to remove a key from the tree and if removed, returns its +// value, nodes orphaned and 'true'. +func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, removed bool, err error) { + if tree.root == nil { + return nil, nil, false, nil + } + orphaned = tree.prepareOrphansSlice() + newRootHash, newRoot, _, value, err := tree.recursiveRemove(tree.root, key, &orphaned) + if err != nil { + return nil, nil, false, err + } + if len(orphaned) == 0 { + return nil, nil, false, nil + } + + if !tree.skipFastStorageUpgrade { + tree.addUnsavedRemoval(key) + } + + if newRoot == nil && newRootHash != nil { + tree.root, err = tree.ndb.GetNode(newRootHash) + if err != nil { + return nil, nil, false, err + } + } else { + tree.root = newRoot + } + return value, orphaned, true, nil +} + +// removes the node corresponding to the passed key and balances the tree. +// It returns: +// - the hash of the new node (or nil if the node is the one removed) +// - the node that replaces the orig. node after remove +// - new leftmost leaf key for tree after successfully removing 'key' if changed. +// - the removed value +// - the orphaned nodes. +func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Node) (newHash []byte, newSelf *Node, newKey []byte, newValue []byte, err error) { + version := tree.version + 1 + + if node.isLeaf() { + if bytes.Equal(key, node.key) { + *orphans = append(*orphans, node) + return nil, nil, nil, node.value, nil + } + return node.hash, node, nil, nil, nil + } + + // node.key < key; we go to the left to find the key: + if bytes.Compare(key, node.key) < 0 { + leftNode, err := node.getLeftNode(tree.ImmutableTree) + if err != nil { + return nil, nil, nil, nil, err + } + newLeftHash, newLeftNode, newKey, value, err := tree.recursiveRemove(leftNode, key, orphans) + if err != nil { + return nil, nil, nil, nil, err + } + + if len(*orphans) == 0 { + return node.hash, node, nil, value, nil + } + *orphans = append(*orphans, node) + if newLeftHash == nil && newLeftNode == nil { // left node held value, was removed + return node.rightHash, node.rightNode, node.key, value, nil + } + + newNode, err := node.clone(version) + if err != nil { + return nil, nil, nil, nil, err + } + + newNode.leftHash, newNode.leftNode = newLeftHash, newLeftNode + err = newNode.calcHeightAndSize(tree.ImmutableTree) + if err != nil { + return nil, nil, nil, nil, err + } + newNode, err = tree.balance(newNode, orphans) + if err != nil { + return nil, nil, nil, nil, err + } + + return newNode.hash, newNode, newKey, value, nil + } + // node.key >= key; either found or look to the right: + rightNode, err := node.getRightNode(tree.ImmutableTree) + if err != nil { + return nil, nil, nil, nil, err + } + newRightHash, newRightNode, newKey, value, err := tree.recursiveRemove(rightNode, key, orphans) + if err != nil { + return nil, nil, nil, nil, err + } + if len(*orphans) == 0 { + return node.hash, node, nil, value, nil + } + *orphans = append(*orphans, node) + if newRightHash == nil && newRightNode == nil { // right node held value, was removed + return node.leftHash, node.leftNode, nil, value, nil + } + + newNode, err := node.clone(version) + if err != nil { + return nil, nil, nil, nil, err + } + + newNode.rightHash, newNode.rightNode = newRightHash, newRightNode + if newKey != nil { + newNode.key = newKey + } + err = newNode.calcHeightAndSize(tree.ImmutableTree) + if err != nil { + return nil, nil, nil, nil, err + } + + newNode, err = tree.balance(newNode, orphans) + if err != nil { + return nil, nil, nil, nil, err + } + + return newNode.hash, newNode, nil, value, nil +} + +// Load the latest versioned tree from disk. +func (tree *MutableTree) Load() (int64, error) { + return tree.LoadVersion(int64(0)) +} + +// LazyLoadVersion attempts to lazy load only the specified target version +// without loading previous roots/versions. Lazy loading should be used in cases +// where only reads are expected. Any writes to a lazy loaded tree may result in +// unexpected behavior. If the targetVersion is non-positive, the latest version +// will be loaded by default. If the latest version is non-positive, this method +// performs a no-op. Otherwise, if the root does not exist, an error will be +// returned. +func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { + latestVersion, err := tree.ndb.getLatestVersion() + if err != nil { + return 0, err + } + if latestVersion < targetVersion { + return latestVersion, fmt.Errorf("wanted to load target %d but only found up to %d", targetVersion, latestVersion) + } + + // no versions have been saved if the latest version is non-positive + if latestVersion <= 0 { + if targetVersion <= 0 { + if !tree.skipFastStorageUpgrade { + tree.mtx.Lock() + defer tree.mtx.Unlock() + _, err := tree.enableFastStorageAndCommitIfNotEnabled() + return 0, err + } + return 0, nil + } + return 0, fmt.Errorf("no versions found while trying to load %v", targetVersion) + } + + // default to the latest version if the targeted version is non-positive + if targetVersion <= 0 { + targetVersion = latestVersion + } + + rootHash, err := tree.ndb.getRoot(targetVersion) + if err != nil { + return 0, err + } + if rootHash == nil { + return latestVersion, ErrVersionDoesNotExist + } + + tree.mtx.Lock() + defer tree.mtx.Unlock() + + tree.versions[targetVersion] = true + + iTree := &ImmutableTree{ + ndb: tree.ndb, + version: targetVersion, + skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + } + if len(rootHash) > 0 { + // If rootHash is empty then root of tree should be nil + // This makes `LazyLoadVersion` to do the same thing as `LoadVersion` + iTree.root, err = tree.ndb.GetNode(rootHash) + if err != nil { + return 0, err + } + } + + tree.orphans = map[string]int64{} + tree.ImmutableTree = iTree + tree.lastSaved = iTree.clone() + + if !tree.skipFastStorageUpgrade { + // Attempt to upgrade + if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { + return 0, err + } + } + + return targetVersion, nil +} + +// Returns the version number of the latest version found +func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { + roots, err := tree.ndb.getRoots() + if err != nil { + return 0, err + } + + if len(roots) == 0 { + if targetVersion <= 0 { + if !tree.skipFastStorageUpgrade { + tree.mtx.Lock() + defer tree.mtx.Unlock() + _, err := tree.enableFastStorageAndCommitIfNotEnabled() + return 0, err + } + return 0, nil + } + return 0, fmt.Errorf("no versions found while trying to load %v", targetVersion) + } + + firstVersion := int64(0) + latestVersion := int64(0) + + tree.mtx.Lock() + defer tree.mtx.Unlock() + + var latestRoot []byte + for version, r := range roots { + tree.versions[version] = true + if version > latestVersion && (targetVersion == 0 || version <= targetVersion) { + latestVersion = version + latestRoot = r + } + if firstVersion == 0 || version < firstVersion { + firstVersion = version + } + } + + if !(targetVersion == 0 || latestVersion == targetVersion) { + return latestVersion, fmt.Errorf("wanted to load target %v but only found up to %v", + targetVersion, latestVersion) + } + + if firstVersion > 0 && firstVersion < int64(tree.ndb.opts.InitialVersion) { + return latestVersion, fmt.Errorf("initial version set to %v, but found earlier version %v", + tree.ndb.opts.InitialVersion, firstVersion) + } + + t := &ImmutableTree{ + ndb: tree.ndb, + version: latestVersion, + skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + } + + if len(latestRoot) != 0 { + t.root, err = tree.ndb.GetNode(latestRoot) + if err != nil { + return 0, err + } + } + + tree.orphans = map[string]int64{} + tree.ImmutableTree = t + tree.lastSaved = t.clone() + tree.allRootLoaded = true + + if !tree.skipFastStorageUpgrade { + // Attempt to upgrade + if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { + return 0, err + } + } + + return latestVersion, nil +} + +// LoadVersionForOverwriting attempts to load a tree at a previously committed +// version, or the latest version below it. Any versions greater than targetVersion will be deleted. +func (tree *MutableTree) LoadVersionForOverwriting(targetVersion int64) (int64, error) { + latestVersion, err := tree.LoadVersion(targetVersion) + if err != nil { + return latestVersion, err + } + + if err = tree.ndb.DeleteVersionsFrom(targetVersion + 1); err != nil { + return latestVersion, err + } + + if !tree.skipFastStorageUpgrade { + if err := tree.enableFastStorageAndCommitLocked(); err != nil { + return latestVersion, err + } + } + + tree.ndb.resetLatestVersion(latestVersion) + + tree.mtx.Lock() + defer tree.mtx.Unlock() + + for v := range tree.versions { + if v > targetVersion { + delete(tree.versions, v) + } + } + + return latestVersion, nil +} + +// Returns true if the tree may be auto-upgraded, false otherwise +// An example of when an upgrade may be performed is when we are enaling fast storage for the first time or +// need to overwrite fast nodes due to mismatch with live state. +func (tree *MutableTree) IsUpgradeable() (bool, error) { + shouldForce, err := tree.ndb.shouldForceFastStorageUpgrade() + if err != nil { + return false, err + } + return !tree.skipFastStorageUpgrade && (!tree.ndb.hasUpgradedToFastStorage() || shouldForce), nil +} + +// enableFastStorageAndCommitIfNotEnabled if nodeDB doesn't mark fast storage as enabled, enable it, and commit the update. +// Checks whether the fast cache on disk matches latest live state. If not, deletes all existing fast nodes and repopulates them +// from latest tree. +// nolint: unparam +func (tree *MutableTree) enableFastStorageAndCommitIfNotEnabled() (bool, error) { + isUpgradeable, err := tree.IsUpgradeable() + if err != nil { + return false, err + } + + if !isUpgradeable { + return false, nil + } + + // If there is a mismatch between which fast nodes are on disk and the live state due to temporary + // downgrade and subsequent re-upgrade, we cannot know for sure which fast nodes have been removed while downgraded, + // Therefore, there might exist stale fast nodes on disk. As a result, to avoid persisting the stale state, it might + // be worth to delete the fast nodes from disk. + fastItr := NewFastIterator(nil, nil, true, tree.ndb) + defer fastItr.Close() + var deletedFastNodes uint64 + for ; fastItr.Valid(); fastItr.Next() { + deletedFastNodes++ + if err := tree.ndb.DeleteFastNode(fastItr.Key()); err != nil { + return false, err + } + if deletedFastNodes%commitGap == 0 { + if err := tree.ndb.Commit(); err != nil { + return false, err + } + } + } + if deletedFastNodes%commitGap != 0 { + if err := tree.ndb.Commit(); err != nil { + return false, err + } + } + + if err := tree.enableFastStorageAndCommit(); err != nil { + tree.ndb.storageVersion = defaultStorageVersionValue + return false, err + } + return true, nil +} + +func (tree *MutableTree) enableFastStorageAndCommitLocked() error { + tree.mtx.Lock() + defer tree.mtx.Unlock() + return tree.enableFastStorageAndCommit() +} + +func (tree *MutableTree) enableFastStorageAndCommit() error { + var err error + + itr := NewIterator(nil, nil, true, tree.ImmutableTree) + defer itr.Close() + var upgradedFastNodes uint64 + for ; itr.Valid(); itr.Next() { + upgradedFastNodes++ + if err = tree.ndb.SaveFastNodeNoCache(NewFastNode(itr.Key(), itr.Value(), tree.version)); err != nil { + return err + } + if upgradedFastNodes%commitGap == 0 { + tree.ndb.Commit() + } + } + + if err = itr.Error(); err != nil { + return err + } + + if err = tree.ndb.setFastStorageVersionToBatch(); err != nil { + return err + } + + return tree.ndb.Commit() +} + +// GetImmutable loads an ImmutableTree at a given version for querying. The returned tree is +// safe for concurrent access, provided the version is not deleted, e.g. via `DeleteVersion()`. +func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { + rootHash, err := tree.ndb.getRoot(version) + if err != nil { + return nil, err + } + if rootHash == nil { + return nil, ErrVersionDoesNotExist + } + + tree.mtx.Lock() + defer tree.mtx.Unlock() + if len(rootHash) == 0 { + tree.versions[version] = true + return &ImmutableTree{ + ndb: tree.ndb, + version: version, + skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + }, nil + } + tree.versions[version] = true + + root, err := tree.ndb.GetNode(rootHash) + if err != nil { + return nil, err + } + return &ImmutableTree{ + root: root, + ndb: tree.ndb, + version: version, + skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + }, nil +} + +// Rollback resets the working tree to the latest saved version, discarding +// any unsaved modifications. +func (tree *MutableTree) Rollback() { + if tree.version > 0 { + tree.ImmutableTree = tree.lastSaved.clone() + } else { + tree.ImmutableTree = &ImmutableTree{ + ndb: tree.ndb, + version: 0, + skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + } + } + tree.orphans = map[string]int64{} + if !tree.skipFastStorageUpgrade { + tree.unsavedFastNodeAdditions = map[string]*FastNode{} + tree.unsavedFastNodeRemovals = map[string]interface{}{} + } +} + +// GetVersioned gets the value at the specified key and version. The returned value must not be +// modified, since it may point to data stored within IAVL. +func (tree *MutableTree) GetVersioned(key []byte, version int64) ([]byte, error) { + if tree.VersionExists(version) { + if !tree.skipFastStorageUpgrade { + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + if err != nil { + return nil, err + } + + if isFastCacheEnabled { + fastNode, _ := tree.ndb.GetFastNode(key) + if fastNode == nil && version == tree.ndb.latestVersion { + return nil, nil + } + + if fastNode != nil && fastNode.versionLastUpdatedAt <= version { + return fastNode.value, nil + } + } + } + t, err := tree.GetImmutable(version) + if err != nil { + return nil, nil + } + value, err := t.Get(key) + if err != nil { + return nil, err + } + return value, nil + } + return nil, nil +} + +// SaveVersion saves a new tree version to disk, based on the current state of +// the tree. Returns the hash and new version number. +func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { + version := tree.version + 1 + if version == 1 && tree.ndb.opts.InitialVersion > 0 { + version = int64(tree.ndb.opts.InitialVersion) + } + + if tree.VersionExists(version) { + // If the version already exists, return an error as we're attempting to overwrite. + // However, the same hash means idempotent (i.e. no-op). + existingHash, err := tree.ndb.getRoot(version) + if err != nil { + return nil, version, err + } + + // If the existing root hash is empty (because the tree is empty), then we need to + // compare with the hash of an empty input which is what `WorkingHash()` returns. + if len(existingHash) == 0 { + existingHash = sha256.New().Sum(nil) + } + + newHash, err := tree.WorkingHash() + if err != nil { + return nil, version, err + } + + if bytes.Equal(existingHash, newHash) { + tree.version = version + tree.ImmutableTree = tree.ImmutableTree.clone() + tree.lastSaved = tree.ImmutableTree.clone() + tree.orphans = map[string]int64{} + return existingHash, version, nil + } + + return nil, version, fmt.Errorf("version %d was already saved to different hash %X (existing hash %X)", version, newHash, existingHash) + } + + if tree.root == nil { + // There can still be orphans, for example if the root is the node being + // removed. + logger.Debug("SAVE EMPTY TREE %v\n", version) + if err := tree.ndb.SaveOrphans(version, tree.orphans); err != nil { + return nil, 0, err + } + if err := tree.ndb.SaveEmptyRoot(version); err != nil { + return nil, 0, err + } + } else { + logger.Debug("SAVE TREE %v\n", version) + if _, err := tree.ndb.SaveBranch(tree.root); err != nil { + return nil, 0, err + } + if err := tree.ndb.SaveOrphans(version, tree.orphans); err != nil { + return nil, 0, err + } + if err := tree.ndb.SaveRoot(tree.root, version); err != nil { + return nil, 0, err + } + } + + if !tree.skipFastStorageUpgrade { + if err := tree.saveFastNodeVersion(); err != nil { + return nil, version, err + } + } + + if err := tree.ndb.Commit(); err != nil { + return nil, version, err + } + + tree.mtx.Lock() + defer tree.mtx.Unlock() + tree.version = version + tree.versions[version] = true + + // set new working tree + tree.ImmutableTree = tree.ImmutableTree.clone() + tree.lastSaved = tree.ImmutableTree.clone() + tree.orphans = map[string]int64{} + if !tree.skipFastStorageUpgrade { + tree.unsavedFastNodeAdditions = make(map[string]*FastNode) + tree.unsavedFastNodeRemovals = make(map[string]interface{}) + } + + hash, err := tree.Hash() + if err != nil { + return nil, version, err + } + + return hash, version, nil +} + +func (tree *MutableTree) saveFastNodeVersion() error { + if err := tree.saveFastNodeAdditions(); err != nil { + return err + } + if err := tree.saveFastNodeRemovals(); err != nil { + return err + } + return tree.ndb.setFastStorageVersionToBatch() +} + +// nolint: unused +func (tree *MutableTree) getUnsavedFastNodeAdditions() map[string]*FastNode { + return tree.unsavedFastNodeAdditions +} + +// getUnsavedFastNodeRemovals returns unsaved FastNodes to remove +// nolint: unused +func (tree *MutableTree) getUnsavedFastNodeRemovals() map[string]interface{} { + return tree.unsavedFastNodeRemovals +} + +func (tree *MutableTree) addUnsavedAddition(key []byte, node *FastNode) { + skey := unsafeToStr(key) + delete(tree.unsavedFastNodeRemovals, skey) + tree.unsavedFastNodeAdditions[skey] = node +} + +func (tree *MutableTree) saveFastNodeAdditions() error { + keysToSort := make([]string, 0, len(tree.unsavedFastNodeAdditions)) + for key := range tree.unsavedFastNodeAdditions { + keysToSort = append(keysToSort, key) + } + sort.Strings(keysToSort) + + for _, key := range keysToSort { + if err := tree.ndb.SaveFastNode(tree.unsavedFastNodeAdditions[key]); err != nil { + return err + } + } + return nil +} + +func (tree *MutableTree) addUnsavedRemoval(key []byte) { + skey := unsafeToStr(key) + delete(tree.unsavedFastNodeAdditions, skey) + tree.unsavedFastNodeRemovals[skey] = true +} + +func (tree *MutableTree) saveFastNodeRemovals() error { + keysToSort := make([]string, 0, len(tree.unsavedFastNodeRemovals)) + for key := range tree.unsavedFastNodeRemovals { + keysToSort = append(keysToSort, key) + } + sort.Strings(keysToSort) + + for _, key := range keysToSort { + if err := tree.ndb.DeleteFastNode(unsafeToBz(key)); err != nil { + return err + } + } + return nil +} + +func (tree *MutableTree) deleteVersion(version int64) error { + if version <= 0 { + return errors.New("version must be greater than 0") + } + if version == tree.version { + return errors.Errorf("cannot delete latest saved version (%d)", version) + } + if !tree.VersionExists(version) { + return errors.Wrap(ErrVersionDoesNotExist, "") + } + if err := tree.ndb.DeleteVersion(version, true); err != nil { + return err + } + + return nil +} + +// SetInitialVersion sets the initial version of the tree, replacing Options.InitialVersion. +// It is only used during the initial SaveVersion() call for a tree with no other versions, +// and is otherwise ignored. +func (tree *MutableTree) SetInitialVersion(version uint64) { + tree.ndb.opts.InitialVersion = version +} + +// DeleteVersions deletes a series of versions from the MutableTree. +// Deprecated: please use DeleteVersionsRange instead. +func (tree *MutableTree) DeleteVersions(versions ...int64) error { + logger.Debug("DELETING VERSIONS: %v\n", versions) + + if len(versions) == 0 { + return nil + } + + sort.Slice(versions, func(i, j int) bool { + return versions[i] < versions[j] + }) + + // Find ordered data and delete by interval + intervals := map[int64]int64{} + var fromVersion int64 + for _, version := range versions { + if version-fromVersion != intervals[fromVersion] { + fromVersion = version + } + intervals[fromVersion]++ + } + + for fromVersion, sortedBatchSize := range intervals { + if err := tree.DeleteVersionsRange(fromVersion, fromVersion+sortedBatchSize); err != nil { + return err + } + } + + return nil +} + +// DeleteVersionsRange removes versions from an interval from the MutableTree (not inclusive). +// An error is returned if any single version has active readers. +// All writes happen in a single batch with a single commit. +func (tree *MutableTree) DeleteVersionsRange(fromVersion, toVersion int64) error { + if err := tree.ndb.DeleteVersionsRange(fromVersion, toVersion); err != nil { + return err + } + + if err := tree.ndb.Commit(); err != nil { + return err + } + + tree.mtx.Lock() + defer tree.mtx.Unlock() + for version := fromVersion; version < toVersion; version++ { + delete(tree.versions, version) + } + + return nil +} + +// DeleteVersion deletes a tree version from disk. The version can then no +// longer be accessed. +func (tree *MutableTree) DeleteVersion(version int64) error { + logger.Debug("DELETE VERSION: %d\n", version) + + if err := tree.deleteVersion(version); err != nil { + return err + } + + if err := tree.ndb.Commit(); err != nil { + return err + } + + tree.mtx.Lock() + defer tree.mtx.Unlock() + delete(tree.versions, version) + return nil +} + +// Rotate right and return the new node and orphan. +func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { + version := tree.version + 1 + + var err error + // TODO: optimize balance & rotate. + node, err = node.clone(version) + if err != nil { + return nil, nil, err + } + + orphaned, err := node.getLeftNode(tree.ImmutableTree) + if err != nil { + return nil, nil, err + } + newNode, err := orphaned.clone(version) + if err != nil { + return nil, nil, err + } + + newNoderHash, newNoderCached := newNode.rightHash, newNode.rightNode + newNode.rightHash, newNode.rightNode = node.hash, node + node.leftHash, node.leftNode = newNoderHash, newNoderCached + + err = node.calcHeightAndSize(tree.ImmutableTree) + if err != nil { + return nil, nil, err + } + + err = newNode.calcHeightAndSize(tree.ImmutableTree) + if err != nil { + return nil, nil, err + } + + return newNode, orphaned, nil +} + +// Rotate left and return the new node and orphan. +func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { + version := tree.version + 1 + + var err error + // TODO: optimize balance & rotate. + node, err = node.clone(version) + if err != nil { + return nil, nil, err + } + + orphaned, err := node.getRightNode(tree.ImmutableTree) + if err != nil { + return nil, nil, err + } + newNode, err := orphaned.clone(version) + if err != nil { + return nil, nil, err + } + + newNodelHash, newNodelCached := newNode.leftHash, newNode.leftNode + newNode.leftHash, newNode.leftNode = node.hash, node + node.rightHash, node.rightNode = newNodelHash, newNodelCached + + err = node.calcHeightAndSize(tree.ImmutableTree) + if err != nil { + return nil, nil, err + } + + err = newNode.calcHeightAndSize(tree.ImmutableTree) + if err != nil { + return nil, nil, err + } + + return newNode, orphaned, nil +} + +// NOTE: assumes that node can be modified +// TODO: optimize balance & rotate +func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, err error) { + if node.persisted { + return nil, fmt.Errorf("unexpected balance() call on persisted node") + } + balance, err := node.calcBalance(tree.ImmutableTree) + if err != nil { + return nil, err + } + + if balance > 1 { + leftNode, err := node.getLeftNode(tree.ImmutableTree) + if err != nil { + return nil, err + } + + lftBalance, err := leftNode.calcBalance(tree.ImmutableTree) + if err != nil { + return nil, err + } + + if lftBalance >= 0 { + // Left Left Case + newNode, orphaned, err := tree.rotateRight(node) + if err != nil { + return nil, err + } + *orphans = append(*orphans, orphaned) + return newNode, nil + } + // Left Right Case + var leftOrphaned *Node + + left, err := node.getLeftNode(tree.ImmutableTree) + if err != nil { + return nil, err + } + node.leftHash = nil + node.leftNode, leftOrphaned, err = tree.rotateLeft(left) + if err != nil { + return nil, err + } + + newNode, rightOrphaned, err := tree.rotateRight(node) + if err != nil { + return nil, err + } + *orphans = append(*orphans, left, leftOrphaned, rightOrphaned) + return newNode, nil + } + if balance < -1 { + rightNode, err := node.getRightNode(tree.ImmutableTree) + if err != nil { + return nil, err + } + + rightBalance, err := rightNode.calcBalance(tree.ImmutableTree) + if err != nil { + return nil, err + } + if rightBalance <= 0 { + // Right Right Case + newNode, orphaned, err := tree.rotateLeft(node) + if err != nil { + return nil, err + } + *orphans = append(*orphans, orphaned) + return newNode, nil + } + // Right Left Case + var rightOrphaned *Node + + right, err := node.getRightNode(tree.ImmutableTree) + if err != nil { + return nil, err + } + node.rightHash = nil + node.rightNode, rightOrphaned, err = tree.rotateRight(right) + if err != nil { + return nil, err + } + newNode, leftOrphaned, err := tree.rotateLeft(node) + if err != nil { + return nil, err + } + + *orphans = append(*orphans, right, leftOrphaned, rightOrphaned) + return newNode, nil + } + // Nothing changed + return node, nil +} + +func (tree *MutableTree) addOrphans(orphans []*Node) error { + for _, node := range orphans { + if !node.persisted { + // We don't need to orphan nodes that were never persisted. + continue + } + if len(node.hash) == 0 { + return fmt.Errorf("expected to find node hash, but was empty") + } + tree.orphans[unsafeToStr(node.hash)] = node.version + } + return nil +} diff --git a/sei-iavl/mutable_tree_test.go b/sei-iavl/mutable_tree_test.go new file mode 100644 index 0000000000..b2c2c8ac50 --- /dev/null +++ b/sei-iavl/mutable_tree_test.go @@ -0,0 +1,1443 @@ +package iavl + +import ( + "bytes" + "errors" + "fmt" + "runtime" + "sort" + "strconv" + "testing" + + "github.com/cosmos/iavl/internal/encoding" + "github.com/cosmos/iavl/mock" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + db "github.com/tendermint/tm-db" +) + +var ( + tKey1 = []byte("k1") + tVal1 = []byte("v1") + + tKey2 = []byte("k2") + tVal2 = []byte("v2") +) + +func setupMutableTree(t *testing.T) *MutableTree { + memDB := db.NewMemDB() + tree, err := NewMutableTree(memDB, 0, false) + require.NoError(t, err) + return tree +} + +func TestDelete(t *testing.T) { + tree := setupMutableTree(t) + + tree.set([]byte("k1"), []byte("Fred")) + hash, version, err := tree.SaveVersion() + require.NoError(t, err) + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + require.NoError(t, tree.DeleteVersion(version)) + + k1Value, _, _ := tree.GetVersionedWithProof([]byte("k1"), version) + require.Nil(t, k1Value) + + key := tree.ndb.rootKey(version) + err = tree.ndb.db.Set(key, hash) + require.NoError(t, err) + tree.versions[version] = true + + k1Value, _, err = tree.GetVersionedWithProof([]byte("k1"), version) + require.Nil(t, err) + require.Equal(t, 0, bytes.Compare([]byte("Fred"), k1Value)) +} + +func TestGetRemove(t *testing.T) { + require := require.New(t) + tree := setupMutableTree(t) + testGet := func(exists bool) { + v, err := tree.Get(tKey1) + require.NoError(err) + if exists { + require.Equal(tVal1, v, "key should exist") + } else { + require.Nil(v, "key should not exist") + } + } + + testGet(false) + + ok, err := tree.Set(tKey1, tVal1) + require.NoError(err) + require.False(ok, "new key set: nothing to update") + + // add second key to avoid tree.root removal + ok, err = tree.Set(tKey2, tVal2) + require.NoError(err) + require.False(ok, "new key set: nothing to update") + + testGet(true) + + // Save to tree.ImmutableTree + _, version, err := tree.SaveVersion() + require.NoError(err) + require.Equal(int64(1), version) + + testGet(true) + + v, ok, err := tree.Remove(tKey1) + require.NoError(err) + require.True(ok, "key should be removed") + require.Equal(tVal1, v, "key should exist") + + testGet(false) +} + +func TestTraverse(t *testing.T) { + tree := setupMutableTree(t) + + for i := 0; i < 6; i++ { + tree.set([]byte(fmt.Sprintf("k%d", i)), []byte(fmt.Sprintf("v%d", i))) + } + + require.Equal(t, 11, tree.nodeSize(), "Size of tree unexpected") +} + +func TestMutableTree_DeleteVersions(t *testing.T) { + tree := setupMutableTree(t) + + type entry struct { + key []byte + value []byte + } + + versionEntries := make(map[int64][]entry) + + // create 10 tree versions, each with 1000 random key/value entries + for i := 0; i < 10; i++ { + entries := make([]entry, 1000) + + for j := 0; j < 1000; j++ { + k := randBytes(10) + v := randBytes(10) + + entries[j] = entry{k, v} + _, err := tree.Set(k, v) + require.NoError(t, err) + } + + _, v, err := tree.SaveVersion() + require.NoError(t, err) + + versionEntries[v] = entries + } + + // delete even versions + versionsToDelete := []int64{2, 4, 6, 8} + require.NoError(t, tree.DeleteVersions(versionsToDelete...)) + + // ensure even versions have been deleted + for _, v := range versionsToDelete { + require.False(t, tree.versions[v]) + + _, err := tree.LazyLoadVersion(v) + require.Error(t, err) + } + + // ensure odd number versions exist and we can query for all set entries + for _, v := range []int64{1, 3, 5, 7, 9, 10} { + require.True(t, tree.versions[v]) + + _, err := tree.LazyLoadVersion(v) + require.NoError(t, err) + + for _, e := range versionEntries[v] { + val, err := tree.Get(e.key) + require.NoError(t, err) + require.Equal(t, e.value, val) + } + } +} + +func TestMutableTree_LoadVersion_Empty(t *testing.T) { + tree := setupMutableTree(t) + + version, err := tree.LoadVersion(0) + require.NoError(t, err) + assert.EqualValues(t, 0, version) + + version, err = tree.LoadVersion(-1) + require.NoError(t, err) + assert.EqualValues(t, 0, version) + + _, err = tree.LoadVersion(3) + require.Error(t, err) +} + +func TestMutableTree_LazyLoadVersion_Empty(t *testing.T) { + memDB := db.NewMemDB() + tree, err := NewMutableTree(memDB, 0, false) + require.NoError(t, err) + + version, err := tree.LazyLoadVersion(0) + require.NoError(t, err) + assert.EqualValues(t, 0, version) + + version, err = tree.LazyLoadVersion(-1) + require.NoError(t, err) + assert.EqualValues(t, 0, version) + + _, err = tree.LazyLoadVersion(3) + require.Error(t, err) +} + +func TestMutableTree_DeleteVersionsRange(t *testing.T) { + require := require.New(t) + + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 0, false) + require.NoError(err) + const maxLength = 100 + const fromLength = 10 + + versions := make([]int64, 0, maxLength) + for count := 1; count <= maxLength; count++ { + versions = append(versions, int64(count)) + countStr := strconv.Itoa(count) + // Set kv pair and save version + tree.Set([]byte("aaa"), []byte("bbb")) + tree.Set([]byte("key"+countStr), []byte("value"+countStr)) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + } + + tree, err = NewMutableTree(mdb, 0, false) + require.NoError(err) + targetVersion, err := tree.LoadVersion(int64(maxLength)) + require.NoError(err) + require.Equal(targetVersion, int64(maxLength), "targetVersion shouldn't larger than the actual tree latest version") + + err = tree.DeleteVersionsRange(fromLength, int64(maxLength/2)) + require.NoError(err, "DeleteVersionsTo should not fail") + + for _, version := range versions[:fromLength-1] { + require.True(tree.versions[version], "versions %d no more than 10 should exist", version) + + v, err := tree.LazyLoadVersion(version) + require.NoError(err, version) + require.Equal(v, version) + + value, err := tree.Get([]byte("aaa")) + require.NoError(err) + require.Equal(string(value), "bbb") + + for _, count := range versions[:version] { + countStr := strconv.Itoa(int(count)) + value, err := tree.Get([]byte("key" + countStr)) + require.NoError(err) + require.Equal(string(value), "value"+countStr) + } + } + + for _, version := range versions[fromLength : int64(maxLength/2)-1] { + require.False(tree.versions[version], "versions %d more 10 and no more than 50 should have been deleted", version) + + _, err := tree.LazyLoadVersion(version) + require.Error(err) + } + + for _, version := range versions[int64(maxLength/2)-1:] { + require.True(tree.versions[version], "versions %d more than 50 should exist", version) + + v, err := tree.LazyLoadVersion(version) + require.NoError(err) + require.Equal(v, version) + + value, err := tree.Get([]byte("aaa")) + require.NoError(err) + require.Equal(string(value), "bbb") + + for _, count := range versions[:fromLength] { + countStr := strconv.Itoa(int(count)) + value, err := tree.Get([]byte("key" + countStr)) + require.NoError(err) + require.Equal(string(value), "value"+countStr) + } + for _, count := range versions[int64(maxLength/2)-1 : version] { + countStr := strconv.Itoa(int(count)) + value, err := tree.Get([]byte("key" + countStr)) + require.NoError(err) + require.Equal(string(value), "value"+countStr) + } + } +} + +func TestMutableTree_InitialVersion(t *testing.T) { + memDB := db.NewMemDB() + tree, err := NewMutableTreeWithOpts(memDB, 0, &Options{InitialVersion: 9}, false) + require.NoError(t, err) + + tree.Set([]byte("a"), []byte{0x01}) + _, version, err := tree.SaveVersion() + require.NoError(t, err) + assert.EqualValues(t, 9, version) + + tree.Set([]byte("b"), []byte{0x02}) + _, version, err = tree.SaveVersion() + require.NoError(t, err) + assert.EqualValues(t, 10, version) + + // Reloading the tree with the same initial version is fine + tree, err = NewMutableTreeWithOpts(memDB, 0, &Options{InitialVersion: 9}, false) + require.NoError(t, err) + version, err = tree.Load() + require.NoError(t, err) + assert.EqualValues(t, 10, version) + + // Reloading the tree with an initial version beyond the lowest should error + tree, err = NewMutableTreeWithOpts(memDB, 0, &Options{InitialVersion: 10}, false) + require.NoError(t, err) + _, err = tree.Load() + require.Error(t, err) + + // Reloading the tree with a lower initial version is fine, and new versions can be produced + tree, err = NewMutableTreeWithOpts(memDB, 0, &Options{InitialVersion: 3}, false) + require.NoError(t, err) + version, err = tree.Load() + require.NoError(t, err) + assert.EqualValues(t, 10, version) + + tree.Set([]byte("c"), []byte{0x03}) + _, version, err = tree.SaveVersion() + require.NoError(t, err) + assert.EqualValues(t, 11, version) +} + +func TestMutableTree_SetInitialVersion(t *testing.T) { + tree := setupMutableTree(t) + tree.SetInitialVersion(9) + + tree.Set([]byte("a"), []byte{0x01}) + _, version, err := tree.SaveVersion() + require.NoError(t, err) + assert.EqualValues(t, 9, version) +} + +func BenchmarkMutableTree_Set(b *testing.B) { + db, err := db.NewDB("test", db.MemDBBackend, "") + require.NoError(b, err) + t, err := NewMutableTree(db, 100000, false) + require.NoError(b, err) + for i := 0; i < 1000000; i++ { + t.Set(randBytes(10), []byte{}) + } + b.ReportAllocs() + runtime.GC() + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + t.Set(randBytes(10), []byte{}) + } +} + +func prepareTree(t *testing.T) *MutableTree { + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 1000, false) + require.NoError(t, err) + for i := 0; i < 100; i++ { + tree.Set([]byte{byte(i)}, []byte("a")) + } + _, ver, err := tree.SaveVersion() + require.True(t, ver == 1) + require.NoError(t, err) + for i := 0; i < 100; i++ { + tree.Set([]byte{byte(i)}, []byte("b")) + } + _, ver, err = tree.SaveVersion() + require.True(t, ver == 2) + require.NoError(t, err) + newTree, err := NewMutableTree(mdb, 1000, false) + require.NoError(t, err) + + return newTree +} + +func TestMutableTree_VersionExists(t *testing.T) { + tree := prepareTree(t) + require.True(t, tree.VersionExists(1)) + require.True(t, tree.VersionExists(2)) + require.False(t, tree.VersionExists(3)) +} + +func checkGetVersioned(t *testing.T, tree *MutableTree, version int64, key, value []byte) { + val, err := tree.GetVersioned(key, version) + require.NoError(t, err) + require.True(t, bytes.Equal(val, value)) +} + +func TestMutableTree_GetVersioned(t *testing.T) { + tree := prepareTree(t) + ver, err := tree.LazyLoadVersion(1) + require.True(t, ver == 1) + require.NoError(t, err) + // check key of unloaded version + checkGetVersioned(t, tree, 1, []byte{1}, []byte("a")) + checkGetVersioned(t, tree, 2, []byte{1}, []byte("b")) + checkGetVersioned(t, tree, 3, []byte{1}, nil) + + tree = prepareTree(t) + ver, err = tree.LazyLoadVersion(2) + require.True(t, ver == 2) + require.NoError(t, err) + checkGetVersioned(t, tree, 1, []byte{1}, []byte("a")) + checkGetVersioned(t, tree, 2, []byte{1}, []byte("b")) + checkGetVersioned(t, tree, 3, []byte{1}, nil) +} + +func TestMutableTree_DeleteVersion(t *testing.T) { + tree := prepareTree(t) + ver, err := tree.LazyLoadVersion(2) + require.True(t, ver == 2) + require.NoError(t, err) + + require.NoError(t, tree.DeleteVersion(1)) + + require.False(t, tree.VersionExists(1)) + require.True(t, tree.VersionExists(2)) + require.False(t, tree.VersionExists(3)) + + // cannot delete latest version + require.Error(t, tree.DeleteVersion(2)) +} + +func TestMutableTree_LazyLoadVersionWithEmptyTree(t *testing.T) { + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 1000, false) + require.NoError(t, err) + _, v1, err := tree.SaveVersion() + require.NoError(t, err) + + newTree1, err := NewMutableTree(mdb, 1000, false) + require.NoError(t, err) + v2, err := newTree1.LazyLoadVersion(1) + require.NoError(t, err) + require.True(t, v1 == v2) + + newTree2, err := NewMutableTree(mdb, 1000, false) + require.NoError(t, err) + v2, err = newTree1.LoadVersion(1) + require.NoError(t, err) + require.True(t, v1 == v2) + + require.True(t, newTree1.root == newTree2.root) +} + +func TestMutableTree_SetSimple(t *testing.T) { + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 0, false) + require.NoError(t, err) + + const testKey1 = "a" + const testVal1 = "test" + + isUpdated, err := tree.Set([]byte(testKey1), []byte(testVal1)) + require.NoError(t, err) + require.False(t, isUpdated) + + fastValue, err := tree.Get([]byte(testKey1)) + require.NoError(t, err) + _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + require.NoError(t, err) + + require.Equal(t, []byte(testVal1), fastValue) + require.Equal(t, []byte(testVal1), regularValue) + + fastNodeAdditions := tree.getUnsavedFastNodeAdditions() + require.Equal(t, 1, len(fastNodeAdditions)) + + fastNodeAddition := fastNodeAdditions[testKey1] + require.Equal(t, []byte(testKey1), fastNodeAddition.key) + require.Equal(t, []byte(testVal1), fastNodeAddition.value) + require.Equal(t, int64(1), fastNodeAddition.versionLastUpdatedAt) +} + +func TestMutableTree_SetTwoKeys(t *testing.T) { + tree := setupMutableTree(t) + + const testKey1 = "a" + const testVal1 = "test" + + const testKey2 = "b" + const testVal2 = "test2" + + isUpdated, err := tree.Set([]byte(testKey1), []byte(testVal1)) + require.NoError(t, err) + require.False(t, isUpdated) + + isUpdated, err = tree.Set([]byte(testKey2), []byte(testVal2)) + require.NoError(t, err) + require.False(t, isUpdated) + + fastValue, err := tree.Get([]byte(testKey1)) + require.NoError(t, err) + _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + require.NoError(t, err) + require.Equal(t, []byte(testVal1), fastValue) + require.Equal(t, []byte(testVal1), regularValue) + + fastValue2, err := tree.Get([]byte(testKey2)) + require.NoError(t, err) + _, regularValue2, err := tree.GetWithIndex([]byte(testKey2)) + require.NoError(t, err) + require.Equal(t, []byte(testVal2), fastValue2) + require.Equal(t, []byte(testVal2), regularValue2) + + fastNodeAdditions := tree.getUnsavedFastNodeAdditions() + require.Equal(t, 2, len(fastNodeAdditions)) + + fastNodeAddition := fastNodeAdditions[testKey1] + require.Equal(t, []byte(testKey1), fastNodeAddition.key) + require.Equal(t, []byte(testVal1), fastNodeAddition.value) + require.Equal(t, int64(1), fastNodeAddition.versionLastUpdatedAt) + + fastNodeAddition = fastNodeAdditions[testKey2] + require.Equal(t, []byte(testKey2), fastNodeAddition.key) + require.Equal(t, []byte(testVal2), fastNodeAddition.value) + require.Equal(t, int64(1), fastNodeAddition.versionLastUpdatedAt) +} + +func TestMutableTree_SetOverwrite(t *testing.T) { + tree := setupMutableTree(t) + const testKey1 = "a" + const testVal1 = "test" + const testVal2 = "test2" + + isUpdated, err := tree.Set([]byte(testKey1), []byte(testVal1)) + require.NoError(t, err) + require.False(t, isUpdated) + + isUpdated, err = tree.Set([]byte(testKey1), []byte(testVal2)) + require.NoError(t, err) + require.True(t, isUpdated) + + fastValue, err := tree.Get([]byte(testKey1)) + require.NoError(t, err) + _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + require.NoError(t, err) + require.Equal(t, []byte(testVal2), fastValue) + require.Equal(t, []byte(testVal2), regularValue) + + fastNodeAdditions := tree.getUnsavedFastNodeAdditions() + require.Equal(t, 1, len(fastNodeAdditions)) + + fastNodeAddition := fastNodeAdditions[testKey1] + require.Equal(t, []byte(testKey1), fastNodeAddition.key) + require.Equal(t, []byte(testVal2), fastNodeAddition.value) + require.Equal(t, int64(1), fastNodeAddition.versionLastUpdatedAt) +} + +func TestMutableTree_SetRemoveSet(t *testing.T) { + tree := setupMutableTree(t) + const testKey1 = "a" + const testVal1 = "test" + + // Set 1 + isUpdated, err := tree.Set([]byte(testKey1), []byte(testVal1)) + require.NoError(t, err) + require.False(t, isUpdated) + + fastValue, err := tree.Get([]byte(testKey1)) + require.NoError(t, err) + _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + require.Equal(t, []byte(testVal1), fastValue) + require.Equal(t, []byte(testVal1), regularValue) + + fastNodeAdditions := tree.getUnsavedFastNodeAdditions() + require.Equal(t, 1, len(fastNodeAdditions)) + + fastNodeAddition := fastNodeAdditions[testKey1] + require.Equal(t, []byte(testKey1), fastNodeAddition.key) + require.Equal(t, []byte(testVal1), fastNodeAddition.value) + require.Equal(t, int64(1), fastNodeAddition.versionLastUpdatedAt) + + // Remove + removedVal, isRemoved, err := tree.Remove([]byte(testKey1)) + require.NoError(t, err) + require.NotNil(t, removedVal) + require.True(t, isRemoved) + + fastNodeAdditions = tree.getUnsavedFastNodeAdditions() + require.Equal(t, 0, len(fastNodeAdditions)) + + fastNodeRemovals := tree.getUnsavedFastNodeRemovals() + require.Equal(t, 1, len(fastNodeRemovals)) + + fastValue, err = tree.Get([]byte(testKey1)) + require.NoError(t, err) + _, regularValue, err = tree.GetWithIndex([]byte(testKey1)) + require.NoError(t, err) + require.Nil(t, fastValue) + require.Nil(t, regularValue) + + // Set 2 + isUpdated, err = tree.Set([]byte(testKey1), []byte(testVal1)) + require.NoError(t, err) + require.False(t, isUpdated) + + fastValue, err = tree.Get([]byte(testKey1)) + require.NoError(t, err) + _, regularValue, err = tree.GetWithIndex([]byte(testKey1)) + require.NoError(t, err) + require.Equal(t, []byte(testVal1), fastValue) + require.Equal(t, []byte(testVal1), regularValue) + + fastNodeAdditions = tree.getUnsavedFastNodeAdditions() + require.Equal(t, 1, len(fastNodeAdditions)) + + fastNodeAddition = fastNodeAdditions[testKey1] + require.Equal(t, []byte(testKey1), fastNodeAddition.key) + require.Equal(t, []byte(testVal1), fastNodeAddition.value) + require.Equal(t, int64(1), fastNodeAddition.versionLastUpdatedAt) + + fastNodeRemovals = tree.getUnsavedFastNodeRemovals() + require.Equal(t, 0, len(fastNodeRemovals)) +} + +func TestMutableTree_FastNodeIntegration(t *testing.T) { + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 1000, false) + require.NoError(t, err) + + const key1 = "a" + const key2 = "b" + const key3 = "c" + + const testVal1 = "test" + const testVal2 = "test2" + + // Set key1 + res, err := tree.Set([]byte(key1), []byte(testVal1)) + require.NoError(t, err) + require.False(t, res) + + unsavedNodeAdditions := tree.getUnsavedFastNodeAdditions() + require.Equal(t, len(unsavedNodeAdditions), 1) + + // Set key2 + res, err = tree.Set([]byte(key2), []byte(testVal1)) + require.NoError(t, err) + require.False(t, res) + + unsavedNodeAdditions = tree.getUnsavedFastNodeAdditions() + require.Equal(t, len(unsavedNodeAdditions), 2) + + // Set key3 + res, err = tree.Set([]byte(key3), []byte(testVal1)) + require.NoError(t, err) + require.False(t, res) + + unsavedNodeAdditions = tree.getUnsavedFastNodeAdditions() + require.Equal(t, len(unsavedNodeAdditions), 3) + + // Set key3 with new value + res, err = tree.Set([]byte(key3), []byte(testVal2)) + require.NoError(t, err) + require.True(t, res) + + unsavedNodeAdditions = tree.getUnsavedFastNodeAdditions() + require.Equal(t, len(unsavedNodeAdditions), 3) + + // Remove key2 + removedVal, isRemoved, err := tree.Remove([]byte(key2)) + require.NoError(t, err) + require.True(t, isRemoved) + require.Equal(t, []byte(testVal1), removedVal) + + unsavedNodeAdditions = tree.getUnsavedFastNodeAdditions() + require.Equal(t, len(unsavedNodeAdditions), 2) + + unsavedNodeRemovals := tree.getUnsavedFastNodeRemovals() + require.Equal(t, len(unsavedNodeRemovals), 1) + + // Save + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + unsavedNodeAdditions = tree.getUnsavedFastNodeAdditions() + require.Equal(t, len(unsavedNodeAdditions), 0) + + unsavedNodeRemovals = tree.getUnsavedFastNodeRemovals() + require.Equal(t, len(unsavedNodeRemovals), 0) + + // Load + t2, err := NewMutableTree(mdb, 0, false) + require.NoError(t, err) + + _, err = t2.Load() + require.NoError(t, err) + + // Get and GetFast + fastValue, err := t2.Get([]byte(key1)) + require.NoError(t, err) + _, regularValue, err := tree.GetWithIndex([]byte(key1)) + require.NoError(t, err) + require.Equal(t, []byte(testVal1), fastValue) + require.Equal(t, []byte(testVal1), regularValue) + + fastValue, err = t2.Get([]byte(key2)) + require.NoError(t, err) + _, regularValue, err = t2.GetWithIndex([]byte(key2)) + require.NoError(t, err) + require.Nil(t, fastValue) + require.Nil(t, regularValue) + + fastValue, err = t2.Get([]byte(key3)) + require.NoError(t, err) + _, regularValue, err = tree.GetWithIndex([]byte(key3)) + require.NoError(t, err) + require.Equal(t, []byte(testVal2), fastValue) + require.Equal(t, []byte(testVal2), regularValue) +} + +func TestIterate_MutableTree_Unsaved(t *testing.T) { + tree, mirror := getRandomizedTreeAndMirror(t) + assertMutableMirrorIterate(t, tree, mirror) +} + +func TestIterate_MutableTree_Saved(t *testing.T) { + tree, mirror := getRandomizedTreeAndMirror(t) + + _, _, err := tree.SaveVersion() + require.NoError(t, err) + + assertMutableMirrorIterate(t, tree, mirror) +} + +func TestIterate_MutableTree_Unsaved_NextVersion(t *testing.T) { + tree, mirror := getRandomizedTreeAndMirror(t) + + _, _, err := tree.SaveVersion() + require.NoError(t, err) + + assertMutableMirrorIterate(t, tree, mirror) + + randomizeTreeAndMirror(t, tree, mirror) + + assertMutableMirrorIterate(t, tree, mirror) +} + +func TestIterator_MutableTree_Invalid(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + + itr, err := tree.Iterator([]byte("a"), []byte("b"), true) + require.NoError(t, err) + require.NotNil(t, itr) + require.False(t, itr.Valid()) +} + +func TestUpgradeStorageToFast_LatestVersion_Success(t *testing.T) { + // Setup + db := db.NewMemDB() + tree, err := NewMutableTree(db, 1000, false) + require.NoError(t, err) + + // Default version when storage key does not exist in the db + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + mirror := make(map[string]string) + // Fill with some data + randomizeTreeAndMirror(t, tree, mirror) + + // Enable fast storage + isUpgradeable, err := tree.IsUpgradeable() + require.True(t, isUpgradeable) + require.NoError(t, err) + enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() + require.NoError(t, err) + require.True(t, enabled) + isUpgradeable, err = tree.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) +} + +func TestUpgradeStorageToFast_AlreadyUpgraded_Success(t *testing.T) { + // Setup + db := db.NewMemDB() + tree, err := NewMutableTree(db, 1000, false) + require.NoError(t, err) + + // Default version when storage key does not exist in the db + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + mirror := make(map[string]string) + // Fill with some data + randomizeTreeAndMirror(t, tree, mirror) + + // Enable fast storage + isUpgradeable, err := tree.IsUpgradeable() + require.True(t, isUpgradeable) + require.NoError(t, err) + enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() + require.NoError(t, err) + require.True(t, enabled) + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + isUpgradeable, err = tree.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + // Test enabling fast storage when already enabled + enabled, err = tree.enableFastStorageAndCommitIfNotEnabled() + require.NoError(t, err) + require.False(t, enabled) + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + +} + +func TestUpgradeStorageToFast_DbErrorConstructor_Failure(t *testing.T) { + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + rIterMock := mock.NewMockIterator(ctrl) + + // rIterMock is used to get the latest version from disk. We are mocking that rIterMock returns latestTreeVersion from disk + rIterMock.EXPECT().Valid().Return(true).Times(1) + rIterMock.EXPECT().Key().Return(rootKeyFormat.Key([]byte(defaultStorageVersionValue))) + rIterMock.EXPECT().Close().Return(nil).Times(1) + + expectedError := errors.New("some db error") + + dbMock.EXPECT().Get(gomock.Any()).Return(nil, expectedError).Times(1) + dbMock.EXPECT().NewBatch().Return(nil).Times(1) + dbMock.EXPECT().ReverseIterator(gomock.Any(), gomock.Any()).Return(rIterMock, nil).Times(1) + + tree, err := NewMutableTree(dbMock, 0, false) + require.Nil(t, err) + require.NotNil(t, tree) + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) +} + +func TestUpgradeStorageToFast_DbErrorEnableFastStorage_Failure(t *testing.T) { + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + rIterMock := mock.NewMockIterator(ctrl) + + // rIterMock is used to get the latest version from disk. We are mocking that rIterMock returns latestTreeVersion from disk + rIterMock.EXPECT().Valid().Return(true).Times(1) + rIterMock.EXPECT().Key().Return(rootKeyFormat.Key([]byte(defaultStorageVersionValue))) + rIterMock.EXPECT().Close().Return(nil).Times(1) + + expectedError := errors.New("some db error") + + batchMock := mock.NewMockBatch(ctrl) + + dbMock.EXPECT().Get(gomock.Any()).Return(nil, nil).Times(1) + dbMock.EXPECT().NewBatch().Return(batchMock).Times(1) + dbMock.EXPECT().ReverseIterator(gomock.Any(), gomock.Any()).Return(rIterMock, nil).Times(1) + + iterMock := mock.NewMockIterator(ctrl) + dbMock.EXPECT().Iterator(gomock.Any(), gomock.Any()).Return(iterMock, nil) + iterMock.EXPECT().Error() + iterMock.EXPECT().Valid().Times(2) + iterMock.EXPECT().Close() + + batchMock.EXPECT().Set(gomock.Any(), gomock.Any()).Return(expectedError).Times(1) + + tree, err := NewMutableTree(dbMock, 0, false) + require.Nil(t, err) + require.NotNil(t, tree) + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() + require.ErrorIs(t, err, expectedError) + require.False(t, enabled) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) +} + +func TestFastStorageReUpgradeProtection_NoForceUpgrade_Success(t *testing.T) { + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + rIterMock := mock.NewMockIterator(ctrl) + + // We are trying to test downgrade and re-upgrade protection + // We need to set up a state where latest fast storage version is equal to latest tree version + const latestFastStorageVersionOnDisk = 1 + const latestTreeVersion = latestFastStorageVersionOnDisk + + // Setup fake reverse iterator db to traverse root versions, called by ndb's getLatestVersion + expectedStorageVersion := []byte(fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(latestFastStorageVersionOnDisk)) + + // rIterMock is used to get the latest version from disk. We are mocking that rIterMock returns latestTreeVersion from disk + rIterMock.EXPECT().Valid().Return(true).Times(1) + rIterMock.EXPECT().Key().Return(rootKeyFormat.Key(latestTreeVersion)) + rIterMock.EXPECT().Close().Return(nil).Times(1) + + batchMock := mock.NewMockBatch(ctrl) + + dbMock.EXPECT().Get(gomock.Any()).Return(expectedStorageVersion, nil).Times(1) + dbMock.EXPECT().NewBatch().Return(batchMock).Times(1) + dbMock.EXPECT().ReverseIterator(gomock.Any(), gomock.Any()).Return(rIterMock, nil).Times(1) // called to get latest version + + tree, err := NewMutableTree(dbMock, 0, false) + require.Nil(t, err) + require.NotNil(t, tree) + + // Pretend that we called Load and have the latest state in the tree + tree.version = latestTreeVersion + latestVersion, err := tree.ndb.getLatestVersion() + require.NoError(t, err) + require.Equal(t, latestVersion, int64(latestTreeVersion)) + + // Ensure that the right branch of enableFastStorageAndCommitIfNotEnabled will be triggered + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + shouldForce, err := tree.ndb.shouldForceFastStorageUpgrade() + require.False(t, shouldForce) + require.NoError(t, err) + + enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() + require.NoError(t, err) + require.False(t, enabled) +} + +func TestFastStorageReUpgradeProtection_ForceUpgradeFirstTime_NoForceSecondTime_Success(t *testing.T) { + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + batchMock := mock.NewMockBatch(ctrl) + iterMock := mock.NewMockIterator(ctrl) + rIterMock := mock.NewMockIterator(ctrl) + + // We are trying to test downgrade and re-upgrade protection + // We need to set up a state where latest fast storage version is of a lower version + // than tree version + const latestFastStorageVersionOnDisk = 1 + const latestTreeVersion = latestFastStorageVersionOnDisk + 1 + + // Setup db for iterator and reverse iterator mocks + expectedStorageVersion := []byte(fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(latestFastStorageVersionOnDisk)) + + // Setup fake reverse iterator db to traverse root versions, called by ndb's getLatestVersion + // rItr, err := db.ReverseIterator(rootKeyFormat.Key(1), rootKeyFormat.Key(latestTreeVersion + 1)) + // require.NoError(t, err) + + // dbMock represents the underlying database under the hood of nodeDB + dbMock.EXPECT().Get(gomock.Any()).Return(expectedStorageVersion, nil).Times(1) + dbMock.EXPECT().NewBatch().Return(batchMock).Times(3) + dbMock.EXPECT().ReverseIterator(gomock.Any(), gomock.Any()).Return(rIterMock, nil).Times(1) // called to get latest version + startFormat := fastKeyFormat.Key() + endFormat := fastKeyFormat.Key() + endFormat[0]++ + dbMock.EXPECT().Iterator(startFormat, endFormat).Return(iterMock, nil).Times(1) + + // rIterMock is used to get the latest version from disk. We are mocking that rIterMock returns latestTreeVersion from disk + rIterMock.EXPECT().Valid().Return(true).Times(1) + rIterMock.EXPECT().Key().Return(rootKeyFormat.Key(latestTreeVersion)) + rIterMock.EXPECT().Close().Return(nil).Times(1) + + fastNodeKeyToDelete := []byte("some_key") + + // batchMock represents a structure that receives all the updates related to + // upgrade and then commits them all in the end. + updatedExpectedStorageVersion := make([]byte, len(expectedStorageVersion)) + copy(updatedExpectedStorageVersion, expectedStorageVersion) + updatedExpectedStorageVersion[len(updatedExpectedStorageVersion)-1]++ + batchMock.EXPECT().Delete(fastKeyFormat.Key(fastNodeKeyToDelete)).Return(nil).Times(1) + batchMock.EXPECT().Set(metadataKeyFormat.Key([]byte(storageVersionKey)), updatedExpectedStorageVersion).Return(nil).Times(1) + batchMock.EXPECT().Write().Return(nil).Times(2) + batchMock.EXPECT().Close().Return(nil).Times(2) + + // iterMock is used to mock the underlying db iterator behing fast iterator + // Here, we want to mock the behavior of deleting fast nodes from disk when + // force upgrade is detected. + iterMock.EXPECT().Valid().Return(true).Times(1) + iterMock.EXPECT().Error().Return(nil).Times(1) + iterMock.EXPECT().Key().Return(fastKeyFormat.Key(fastNodeKeyToDelete)).Times(1) + // encode value + var buf bytes.Buffer + testValue := "test_value" + buf.Grow(encoding.EncodeVarintSize(int64(latestFastStorageVersionOnDisk)) + encoding.EncodeBytesSize([]byte(testValue))) + err := encoding.EncodeVarint(&buf, int64(latestFastStorageVersionOnDisk)) + require.NoError(t, err) + err = encoding.EncodeBytes(&buf, []byte(testValue)) + require.NoError(t, err) + iterMock.EXPECT().Value().Return(buf.Bytes()).Times(1) // this is encoded as version 1 with value "2" + iterMock.EXPECT().Valid().Return(true).Times(1) + // Call Next at the end of loop iteration + iterMock.EXPECT().Next().Return().Times(1) + iterMock.EXPECT().Error().Return(nil).Times(1) + iterMock.EXPECT().Valid().Return(false).Times(1) + // Call Valid after first iteraton + iterMock.EXPECT().Valid().Return(false).Times(1) + iterMock.EXPECT().Close().Return(nil).Times(1) + + tree, err := NewMutableTree(dbMock, 0, false) + require.Nil(t, err) + require.NotNil(t, tree) + + // Pretend that we called Load and have the latest state in the tree + tree.version = latestTreeVersion + latestVersion, err := tree.ndb.getLatestVersion() + require.NoError(t, err) + require.Equal(t, latestVersion, int64(latestTreeVersion)) + + // Ensure that the right branch of enableFastStorageAndCommitIfNotEnabled will be triggered + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + shouldForce, err := tree.ndb.shouldForceFastStorageUpgrade() + require.True(t, shouldForce) + require.NoError(t, err) + + // Actual method under test + enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() + require.NoError(t, err) + require.True(t, enabled) + + // Test that second time we call this, force upgrade does not happen + enabled, err = tree.enableFastStorageAndCommitIfNotEnabled() + require.NoError(t, err) + require.False(t, enabled) +} + +func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testing.T) { + // Setup + tree, mirror := setupTreeAndMirror(t, 100, false) + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err := tree.IsUpgradeable() + require.True(t, isUpgradeable) + require.NoError(t, err) + + // Should auto enable in save version + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + isUpgradeable, err = tree.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + sut, _ := NewMutableTree(tree.ndb.db, 1000, false) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err = sut.IsUpgradeable() + require.False(t, isUpgradeable) // upgraded in save version + require.NoError(t, err) + + // Load version - should auto enable fast storage + version, err := sut.Load() + require.NoError(t, err) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + + require.Equal(t, int64(1), version) + + // Test that upgraded mutable tree iterates as expected + t.Run("Mutable tree", func(t *testing.T) { + i := 0 + sut.Iterate(func(k, v []byte) bool { + require.Equal(t, []byte(mirror[i][0]), k) + require.Equal(t, []byte(mirror[i][1]), v) + i++ + return false + }) + }) + + // Test that upgraded immutable tree iterates as expected + t.Run("Immutable tree", func(t *testing.T) { + immutableTree, err := sut.GetImmutable(sut.version) + require.NoError(t, err) + + i := 0 + immutableTree.Iterate(func(k, v []byte) bool { + require.Equal(t, []byte(mirror[i][0]), k) + require.Equal(t, []byte(mirror[i][1]), v) + i++ + return false + }) + }) +} + +func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) { + // Setup + tree, mirror := setupTreeAndMirror(t, 100, false) + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err := tree.IsUpgradeable() + require.True(t, isUpgradeable) + require.NoError(t, err) + + // Should auto enable in save version + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + isUpgradeable, err = tree.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + sut, _ := NewMutableTree(tree.ndb.db, 1000, false) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err = sut.IsUpgradeable() + require.False(t, isUpgradeable) // upgraded in save version + require.NoError(t, err) + + // LazyLoadVersion - should auto enable fast storage + version, err := sut.LazyLoadVersion(1) + require.NoError(t, err) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + + require.Equal(t, int64(1), version) + + t.Run("Mutable tree", func(t *testing.T) { + for _, kv := range mirror { + v, err := sut.Get([]byte(kv[0])) + require.NoError(t, err) + require.Equal(t, []byte(kv[1]), v) + } + }) + + t.Run("Immutable tree", func(t *testing.T) { + immutableTree, err := sut.GetImmutable(sut.version) + require.NoError(t, err) + + for _, kv := range mirror { + v, err := immutableTree.Get([]byte(kv[0])) + require.NoError(t, err) + require.Equal(t, []byte(kv[1]), v) + } + }) +} + +func TestUpgradeStorageToFast_Success(t *testing.T) { + tmpCommitGap := commitGap + commitGap = 1000 + defer func() { + commitGap = tmpCommitGap + }() + + type fields struct { + nodeCount int + } + tests := []struct { + name string + fields fields + }{ + {"less than commit gap", fields{nodeCount: 100}}, + {"equal to commit gap", fields{nodeCount: int(commitGap)}}, + {"great than commit gap", fields{nodeCount: int(commitGap) + 100}}, + {"two times commit gap", fields{nodeCount: int(commitGap) * 2}}, + {"two times plus commit gap", fields{nodeCount: int(commitGap)*2 + 1}}, + } + + for _, tt := range tests { + tree, mirror := setupTreeAndMirror(t, tt.fields.nodeCount, false) + enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() + require.Nil(t, err) + require.True(t, enabled) + t.Run(tt.name, func(t *testing.T) { + i := 0 + iter := NewFastIterator(nil, nil, true, tree.ndb) + for ; iter.Valid(); iter.Next() { + require.Equal(t, []byte(mirror[i][0]), iter.Key()) + require.Equal(t, []byte(mirror[i][1]), iter.Value()) + i++ + } + require.Equal(t, len(mirror), i) + }) + } +} + +func TestUpgradeStorageToFast_Delete_Stale_Success(t *testing.T) { + // we delete fast node, in case of deadlock. we should limit the stale count lower than chBufferSize(64) + tmpCommitGap := commitGap + commitGap = 5 + defer func() { + commitGap = tmpCommitGap + }() + + valStale := "val_stale" + addStaleKey := func(ndb *nodeDB, staleCount int) { + var keyPrefix = "key" + for i := 0; i < staleCount; i++ { + key := fmt.Sprintf("%s_%d", keyPrefix, i) + + node := NewFastNode([]byte(key), []byte(valStale), 100) + var buf bytes.Buffer + buf.Grow(node.encodedSize()) + err := node.writeBytes(&buf) + require.NoError(t, err) + err = ndb.db.Set(ndb.fastNodeKey([]byte(key)), buf.Bytes()) + require.NoError(t, err) + } + } + type fields struct { + nodeCount int + staleCount int + } + + tests := []struct { + name string + fields fields + }{ + {"stale less than commit gap", fields{nodeCount: 100, staleCount: 4}}, + {"stale equal to commit gap", fields{nodeCount: int(commitGap), staleCount: int(commitGap)}}, + {"stale great than commit gap", fields{nodeCount: int(commitGap) + 100, staleCount: int(commitGap)*2 - 1}}, + {"stale twice commit gap", fields{nodeCount: int(commitGap) + 100, staleCount: int(commitGap) * 2}}, + {"stale great than twice commit gap", fields{nodeCount: int(commitGap), staleCount: int(commitGap)*2 + 1}}, + } + + for _, tt := range tests { + tree, mirror := setupTreeAndMirror(t, tt.fields.nodeCount, false) + addStaleKey(tree.ndb, tt.fields.staleCount) + enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() + require.Nil(t, err) + require.True(t, enabled) + t.Run(tt.name, func(t *testing.T) { + i := 0 + iter := NewFastIterator(nil, nil, true, tree.ndb) + for ; iter.Valid(); iter.Next() { + require.Equal(t, []byte(mirror[i][0]), iter.Key()) + require.Equal(t, []byte(mirror[i][1]), iter.Value()) + i++ + } + require.Equal(t, len(mirror), i) + }) + } +} + +func setupTreeAndMirror(t *testing.T, numEntries int, skipFastStorageUpgrade bool) (*MutableTree, [][]string) { + db := db.NewMemDB() + + tree, _ := NewMutableTree(db, 0, skipFastStorageUpgrade) + + var keyPrefix, valPrefix = "key", "val" + + mirror := make([][]string, 0, numEntries) + for i := 0; i < numEntries; i++ { + key := fmt.Sprintf("%s_%d", keyPrefix, i) + val := fmt.Sprintf("%s_%d", valPrefix, i) + mirror = append(mirror, []string{key, val}) + updated, err := tree.Set([]byte(key), []byte(val)) + require.False(t, updated) + require.NoError(t, err) + } + + // Delete fast nodes from database to mimic a version with no upgrade + for i := 0; i < numEntries; i++ { + key := fmt.Sprintf("%s_%d", keyPrefix, i) + require.NoError(t, db.Delete(fastKeyFormat.Key([]byte(key)))) + } + + sort.Slice(mirror, func(i, j int) bool { + return mirror[i][0] < mirror[j][0] + }) + return tree, mirror +} + +func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testing.T) { + // Setup + tree, mirror := setupTreeAndMirror(t, 100, true) + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err := tree.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + // Should Not auto enable in save version + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err = tree.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + sut, _ := NewMutableTree(tree.ndb.db, 1000, true) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err = sut.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + // LazyLoadVersion - should not auto enable fast storage + version, err := sut.LazyLoadVersion(1) + require.NoError(t, err) + require.Equal(t, int64(1), version) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + // Load - should not auto enable fast storage + version, err = sut.Load() + require.NoError(t, err) + require.Equal(t, int64(1), version) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + // LoadVersion - should not auto enable fast storage + version, err = sut.LoadVersion(1) + require.NoError(t, err) + require.Equal(t, int64(1), version) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + // LoadVersionForOverwriting - should not auto enable fast storage + version, err = sut.LoadVersionForOverwriting(1) + require.NoError(t, err) + require.Equal(t, int64(1), version) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + t.Run("Mutable tree", func(t *testing.T) { + for _, kv := range mirror { + v, err := sut.Get([]byte(kv[0])) + require.NoError(t, err) + require.Equal(t, []byte(kv[1]), v) + } + }) + + t.Run("Immutable tree", func(t *testing.T) { + immutableTree, err := sut.GetImmutable(sut.version) + require.NoError(t, err) + + for _, kv := range mirror { + v, err := immutableTree.Get([]byte(kv[0])) + require.NoError(t, err) + require.Equal(t, []byte(kv[1]), v) + } + }) +} + +func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *testing.T) { + // Setup + tree, mirror := setupTreeAndMirror(t, 100, true) + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err := tree.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + // Should Not auto enable in save version + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err = tree.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + sut, _ := NewMutableTree(tree.ndb.db, 1000, true) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + isUpgradeable, err = sut.IsUpgradeable() + require.False(t, isUpgradeable) + require.NoError(t, err) + + // Load - should not auto enable fast storage + version, err := sut.Load() + require.NoError(t, err) + require.Equal(t, int64(1), version) + + isFastCacheEnabled, err = sut.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + // Load - should not auto enable fast storage + version, err = sut.Load() + require.NoError(t, err) + require.Equal(t, int64(1), version) + + isFastCacheEnabled, err = tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + // Test that the mutable tree iterates as expected + t.Run("Mutable tree", func(t *testing.T) { + i := 0 + sut.Iterate(func(k, v []byte) bool { + require.Equal(t, []byte(mirror[i][0]), k) + require.Equal(t, []byte(mirror[i][1]), v) + i++ + return false + }) + }) + + // Test that the immutable tree iterates as expected + t.Run("Immutable tree", func(t *testing.T) { + immutableTree, err := sut.GetImmutable(sut.version) + require.NoError(t, err) + + i := 0 + immutableTree.Iterate(func(k, v []byte) bool { + require.Equal(t, []byte(mirror[i][0]), k) + require.Equal(t, []byte(mirror[i][1]), v) + i++ + return false + }) + }) +} diff --git a/sei-iavl/node.go b/sei-iavl/node.go new file mode 100644 index 0000000000..607a164d2c --- /dev/null +++ b/sei-iavl/node.go @@ -0,0 +1,556 @@ +package iavl + +// NOTE: This file favors int64 as opposed to int for size/counts. +// The Tree on the other hand favors int. This is intentional. + +import ( + "bytes" + "crypto/sha256" + "fmt" + "io" + "math" + + "github.com/cosmos/iavl/cache" + "github.com/pkg/errors" + + "github.com/cosmos/iavl/internal/encoding" +) + +// Node represents a node in a Tree. +type Node struct { + key []byte + value []byte + hash []byte + leftHash []byte + rightHash []byte + version int64 + size int64 + leftNode *Node + rightNode *Node + height int8 + persisted bool +} + +var _ cache.Node = (*Node)(nil) + +// NewNode returns a new node from a key, value and version. +func NewNode(key []byte, value []byte, version int64) *Node { + return &Node{ + key: key, + value: value, + height: 0, + size: 1, + version: version, + } +} + +// MakeNode constructs an *Node from an encoded byte slice. +// +// The new node doesn't have its hash saved or set. The caller must set it +// afterwards. +func MakeNode(buf []byte) (*Node, error) { + + // Read node header (height, size, version, key). + height, n, cause := encoding.DecodeVarint(buf) + if cause != nil { + return nil, errors.Wrap(cause, "decoding node.height") + } + buf = buf[n:] + if height < int64(math.MinInt8) || height > int64(math.MaxInt8) { + return nil, errors.New("invalid height, must be int8") + } + + size, n, cause := encoding.DecodeVarint(buf) + if cause != nil { + return nil, errors.Wrap(cause, "decoding node.size") + } + buf = buf[n:] + + ver, n, cause := encoding.DecodeVarint(buf) + if cause != nil { + return nil, errors.Wrap(cause, "decoding node.version") + } + buf = buf[n:] + + key, n, cause := encoding.DecodeBytes(buf) + if cause != nil { + return nil, errors.Wrap(cause, "decoding node.key") + } + buf = buf[n:] + + node := &Node{ + height: int8(height), + size: size, + version: ver, + key: key, + } + + // Read node body. + + if node.isLeaf() { + val, _, cause := encoding.DecodeBytes(buf) + if cause != nil { + return nil, errors.Wrap(cause, "decoding node.value") + } + node.value = val + } else { // Read children. + leftHash, n, cause := encoding.DecodeBytes(buf) + if cause != nil { + return nil, errors.Wrap(cause, "deocding node.leftHash") + } + buf = buf[n:] + + rightHash, _, cause := encoding.DecodeBytes(buf) + if cause != nil { + return nil, errors.Wrap(cause, "decoding node.rightHash") + } + node.leftHash = leftHash + node.rightHash = rightHash + } + return node, nil +} + +func (n *Node) GetKey() []byte { + return n.hash +} + +// String returns a string representation of the node. +func (node *Node) String() string { + hashstr := "" + if len(node.hash) > 0 { + hashstr = fmt.Sprintf("%X", node.hash) + } + return fmt.Sprintf("Node{%s:%s@%d %X;%X}#%s", + ColoredBytes(node.key, Green, Blue), + ColoredBytes(node.value, Cyan, Blue), + node.version, + node.leftHash, node.rightHash, + hashstr) +} + +// clone creates a shallow copy of a node with its hash set to nil. +func (node *Node) clone(version int64) (*Node, error) { + if node.isLeaf() { + return nil, ErrCloneLeafNode + } + return &Node{ + key: node.key, + height: node.height, + version: version, + size: node.size, + hash: nil, + leftHash: node.leftHash, + leftNode: node.leftNode, + rightHash: node.rightHash, + rightNode: node.rightNode, + persisted: false, + }, nil +} + +func (node *Node) isLeaf() bool { + return node.height == 0 +} + +// Check if the node has a descendant with the given key. +func (node *Node) has(t *ImmutableTree, key []byte) (has bool, err error) { + if bytes.Equal(node.key, key) { + return true, nil + } + if node.isLeaf() { + return false, nil + } + if bytes.Compare(key, node.key) < 0 { + leftNode, err := node.getLeftNode(t) + if err != nil { + return false, err + } + return leftNode.has(t, key) + } + + rightNode, err := node.getRightNode(t) + if err != nil { + return false, err + } + + return rightNode.has(t, key) +} + +// Get a key under the node. +// +// The index is the index in the list of leaf nodes sorted lexicographically by key. The leftmost leaf has index 0. +// It's neighbor has index 1 and so on. +func (node *Node) get(t *ImmutableTree, key []byte) (index int64, value []byte, err error) { + if node.isLeaf() { + switch bytes.Compare(node.key, key) { + case -1: + return 1, nil, nil + case 1: + return 0, nil, nil + default: + return 0, node.value, nil + } + } + + if bytes.Compare(key, node.key) < 0 { + leftNode, err := node.getLeftNode(t) + if err != nil { + return 0, nil, err + } + + return leftNode.get(t, key) + } + + rightNode, err := node.getRightNode(t) + if err != nil { + return 0, nil, err + } + + index, value, err = rightNode.get(t, key) + if err != nil { + return 0, nil, err + } + + index += node.size - rightNode.size + return index, value, nil +} + +func (node *Node) getByIndex(t *ImmutableTree, index int64) (key []byte, value []byte, err error) { + if node.isLeaf() { + if index == 0 { + return node.key, node.value, nil + } + return nil, nil, nil + } + // TODO: could improve this by storing the + // sizes as well as left/right hash. + leftNode, err := node.getLeftNode(t) + if err != nil { + return nil, nil, err + } + + if index < leftNode.size { + return leftNode.getByIndex(t, index) + } + + rightNode, err := node.getRightNode(t) + if err != nil { + return nil, nil, err + } + + return rightNode.getByIndex(t, index-leftNode.size) +} + +// Computes the hash of the node without computing its descendants. Must be +// called on nodes which have descendant node hashes already computed. +func (node *Node) _hash() ([]byte, error) { + if node.hash != nil { + return node.hash, nil + } + + h := sha256.New() + buf := new(bytes.Buffer) + if err := node.writeHashBytes(buf); err != nil { + return nil, err + } + _, err := h.Write(buf.Bytes()) + if err != nil { + return nil, err + } + node.hash = h.Sum(nil) + + return node.hash, nil +} + +// Hash the node and its descendants recursively. This usually mutates all +// descendant nodes. Returns the node hash and number of nodes hashed. +// If the tree is empty (i.e. the node is nil), returns the hash of an empty input, +// to conform with RFC-6962. +func (node *Node) hashWithCount() ([]byte, int64, error) { + if node == nil { + return sha256.New().Sum(nil), 0, nil + } + if node.hash != nil { + return node.hash, 0, nil + } + + h := sha256.New() + buf := new(bytes.Buffer) + hashCount, err := node.writeHashBytesRecursively(buf) + if err != nil { + return nil, 0, err + } + _, err = h.Write(buf.Bytes()) + if err != nil { + return nil, 0, err + } + node.hash = h.Sum(nil) + + return node.hash, hashCount + 1, nil +} + +// validate validates the node contents +func (node *Node) validate() error { + if node == nil { + return errors.New("node cannot be nil") + } + if node.key == nil { + return errors.New("key cannot be nil") + } + if node.version <= 0 { + return errors.New("version must be greater than 0") + } + if node.height < 0 { + return errors.New("height cannot be less than 0") + } + if node.size < 1 { + return errors.New("size must be at least 1") + } + + if node.height == 0 { + // Leaf nodes + if node.value == nil { + return errors.New("value cannot be nil for leaf node") + } + if node.leftHash != nil || node.leftNode != nil || node.rightHash != nil || node.rightNode != nil { + return errors.New("leaf node cannot have children") + } + if node.size != 1 { + return errors.New("leaf nodes must have size 1") + } + } else { + // Inner nodes + if node.value != nil { + return errors.New("value must be nil for non-leaf node") + } + if node.leftHash == nil && node.rightHash == nil { + return errors.New("inner node must have children") + } + } + return nil +} + +// Writes the node's hash to the given io.Writer. This function expects +// child hashes to be already set. +func (node *Node) writeHashBytes(w io.Writer) error { + err := encoding.EncodeVarint(w, int64(node.height)) + if err != nil { + return errors.Wrap(err, "writing height") + } + err = encoding.EncodeVarint(w, node.size) + if err != nil { + return errors.Wrap(err, "writing size") + } + err = encoding.EncodeVarint(w, node.version) + if err != nil { + return errors.Wrap(err, "writing version") + } + + // Key is not written for inner nodes, unlike writeBytes. + + if node.isLeaf() { + err = encoding.EncodeBytes(w, node.key) + if err != nil { + return errors.Wrap(err, "writing key") + } + + // Indirection needed to provide proofs without values. + // (e.g. ProofLeafNode.ValueHash) + valueHash := sha256.Sum256(node.value) + + err = encoding.EncodeBytes(w, valueHash[:]) + if err != nil { + return errors.Wrap(err, "writing value") + } + } else { + if node.leftHash == nil || node.rightHash == nil { + return ErrEmptyChildHash + } + err = encoding.EncodeBytes(w, node.leftHash) + if err != nil { + return errors.Wrap(err, "writing left hash") + } + err = encoding.EncodeBytes(w, node.rightHash) + if err != nil { + return errors.Wrap(err, "writing right hash") + } + } + + return nil +} + +// Writes the node's hash to the given io.Writer. +// This function has the side-effect of calling hashWithCount. +func (node *Node) writeHashBytesRecursively(w io.Writer) (hashCount int64, err error) { + if node.leftNode != nil { + leftHash, leftCount, err := node.leftNode.hashWithCount() + if err != nil { + return 0, err + } + node.leftHash = leftHash + hashCount += leftCount + } + if node.rightNode != nil { + rightHash, rightCount, err := node.rightNode.hashWithCount() + if err != nil { + return 0, err + } + node.rightHash = rightHash + hashCount += rightCount + } + err = node.writeHashBytes(w) + + return +} + +func (node *Node) encodedSize() int { + n := 1 + + encoding.EncodeVarintSize(node.size) + + encoding.EncodeVarintSize(node.version) + + encoding.EncodeBytesSize(node.key) + if node.isLeaf() { + n += encoding.EncodeBytesSize(node.value) + } else { + n += encoding.EncodeBytesSize(node.leftHash) + + encoding.EncodeBytesSize(node.rightHash) + } + return n +} + +// Writes the node as a serialized byte slice to the supplied io.Writer. +func (node *Node) writeBytes(w io.Writer) error { + if node == nil { + return errors.New("cannot write nil node") + } + cause := encoding.EncodeVarint(w, int64(node.height)) + if cause != nil { + return errors.Wrap(cause, "writing height") + } + cause = encoding.EncodeVarint(w, node.size) + if cause != nil { + return errors.Wrap(cause, "writing size") + } + cause = encoding.EncodeVarint(w, node.version) + if cause != nil { + return errors.Wrap(cause, "writing version") + } + + // Unlike writeHashBytes, key is written for inner nodes. + cause = encoding.EncodeBytes(w, node.key) + if cause != nil { + return errors.Wrap(cause, "writing key") + } + + if node.isLeaf() { + cause = encoding.EncodeBytes(w, node.value) + if cause != nil { + return errors.Wrap(cause, "writing value") + } + } else { + if node.leftHash == nil { + return ErrLeftHashIsNil + } + cause = encoding.EncodeBytes(w, node.leftHash) + if cause != nil { + return errors.Wrap(cause, "writing left hash") + } + + if node.rightHash == nil { + return ErrRightHashIsNil + } + cause = encoding.EncodeBytes(w, node.rightHash) + if cause != nil { + return errors.Wrap(cause, "writing right hash") + } + } + return nil +} + +func (node *Node) getLeftNode(t *ImmutableTree) (*Node, error) { + if node.leftNode != nil { + return node.leftNode, nil + } + leftNode, err := t.ndb.GetNode(node.leftHash) + if err != nil { + return nil, err + } + + return leftNode, nil +} + +func (node *Node) getRightNode(t *ImmutableTree) (*Node, error) { + if node.rightNode != nil { + return node.rightNode, nil + } + rightNode, err := t.ndb.GetNode(node.rightHash) + if err != nil { + return nil, err + } + + return rightNode, nil +} + +// NOTE: mutates height and size +func (node *Node) calcHeightAndSize(t *ImmutableTree) error { + leftNode, err := node.getLeftNode(t) + if err != nil { + return err + } + + rightNode, err := node.getRightNode(t) + if err != nil { + return err + } + + node.height = maxInt8(leftNode.height, rightNode.height) + 1 + node.size = leftNode.size + rightNode.size + return nil +} + +func (node *Node) calcBalance(t *ImmutableTree) (int, error) { + leftNode, err := node.getLeftNode(t) + if err != nil { + return 0, err + } + + rightNode, err := node.getRightNode(t) + if err != nil { + return 0, err + } + + return int(leftNode.height) - int(rightNode.height), nil +} + +// traverse is a wrapper over traverseInRange when we want the whole tree +// nolint: unparam +func (node *Node) traverse(t *ImmutableTree, ascending bool, cb func(*Node) bool) bool { + return node.traverseInRange(t, nil, nil, ascending, false, false, func(node *Node) bool { + return cb(node) + }) +} + +// traversePost is a wrapper over traverseInRange when we want the whole tree post-order +func (node *Node) traversePost(t *ImmutableTree, ascending bool, cb func(*Node) bool) bool { + return node.traverseInRange(t, nil, nil, ascending, false, true, func(node *Node) bool { + return cb(node) + }) +} + +func (node *Node) traverseInRange(tree *ImmutableTree, start, end []byte, ascending bool, inclusive bool, post bool, cb func(*Node) bool) bool { + stop := false + t := node.newTraversal(tree, start, end, ascending, inclusive, post) + // TODO: figure out how to handle these errors + for node2, err := t.next(); node2 != nil && err == nil; node2, err = t.next() { + stop = cb(node2) + if stop { + return stop + } + } + return stop +} + +var ( + ErrCloneLeafNode = fmt.Errorf("attempt to copy a leaf node") + ErrEmptyChildHash = fmt.Errorf("found an empty child hash") + ErrLeftHashIsNil = fmt.Errorf("node.leftHash was nil in writeBytes") + ErrRightHashIsNil = fmt.Errorf("node.rightHash was nil in writeBytes") +) diff --git a/sei-iavl/node_test.go b/sei-iavl/node_test.go new file mode 100644 index 0000000000..12d09fb796 --- /dev/null +++ b/sei-iavl/node_test.go @@ -0,0 +1,177 @@ +package iavl + +import ( + "bytes" + "encoding/hex" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNode_encodedSize(t *testing.T) { + node := &Node{ + key: randBytes(10), + value: randBytes(10), + version: 1, + height: 0, + size: 100, + hash: randBytes(20), + leftHash: randBytes(20), + leftNode: nil, + rightHash: randBytes(20), + rightNode: nil, + persisted: false, + } + + // leaf node + require.Equal(t, 26, node.encodedSize()) + + // non-leaf node + node.height = 1 + require.Equal(t, 57, node.encodedSize()) +} + +func TestNode_encode_decode(t *testing.T) { + testcases := map[string]struct { + node *Node + expectHex string + expectError bool + }{ + "nil": {nil, "", true}, + "empty": {&Node{}, "0000000000", false}, + "inner": {&Node{ + height: 3, + version: 2, + size: 7, + key: []byte("key"), + leftHash: []byte{0x70, 0x80, 0x90, 0xa0}, + rightHash: []byte{0x10, 0x20, 0x30, 0x40}, + }, "060e04036b657904708090a00410203040", false}, + "leaf": {&Node{ + height: 0, + version: 3, + size: 1, + key: []byte("key"), + value: []byte("value"), + }, "000206036b65790576616c7565", false}, + } + for name, tc := range testcases { + tc := tc + t.Run(name, func(t *testing.T) { + var buf bytes.Buffer + err := tc.node.writeBytes(&buf) + if tc.expectError { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tc.expectHex, hex.EncodeToString(buf.Bytes())) + + node, err := MakeNode(buf.Bytes()) + require.NoError(t, err) + // since key and value is always decoded to []byte{} we augment the expected struct here + if tc.node.key == nil { + tc.node.key = []byte{} + } + if tc.node.value == nil && tc.node.height == 0 { + tc.node.value = []byte{} + } + require.Equal(t, tc.node, node) + }) + } +} + +func TestNode_validate(t *testing.T) { + k := []byte("key") + v := []byte("value") + h := []byte{1, 2, 3} + c := &Node{key: []byte("child"), value: []byte("x"), version: 1, size: 1} + + testcases := map[string]struct { + node *Node + valid bool + }{ + "nil node": {nil, false}, + "leaf": {&Node{key: k, value: v, version: 1, size: 1}, true}, + "leaf with nil key": {&Node{key: nil, value: v, version: 1, size: 1}, false}, + "leaf with empty key": {&Node{key: []byte{}, value: v, version: 1, size: 1}, true}, + "leaf with nil value": {&Node{key: k, value: nil, version: 1, size: 1}, false}, + "leaf with empty value": {&Node{key: k, value: []byte{}, version: 1, size: 1}, true}, + "leaf with version 0": {&Node{key: k, value: v, version: 0, size: 1}, false}, + "leaf with version -1": {&Node{key: k, value: v, version: -1, size: 1}, false}, + "leaf with size 0": {&Node{key: k, value: v, version: 1, size: 0}, false}, + "leaf with size 2": {&Node{key: k, value: v, version: 1, size: 2}, false}, + "leaf with size -1": {&Node{key: k, value: v, version: 1, size: -1}, false}, + "leaf with left hash": {&Node{key: k, value: v, version: 1, size: 1, leftHash: h}, false}, + "leaf with left child": {&Node{key: k, value: v, version: 1, size: 1, leftNode: c}, false}, + "leaf with right hash": {&Node{key: k, value: v, version: 1, size: 1, rightNode: c}, false}, + "leaf with right child": {&Node{key: k, value: v, version: 1, size: 1, rightNode: c}, false}, + "inner": {&Node{key: k, version: 1, size: 1, height: 1, leftHash: h, rightHash: h}, true}, + "inner with nil key": {&Node{key: nil, value: v, version: 1, size: 1, height: 1, leftHash: h, rightHash: h}, false}, + "inner with value": {&Node{key: k, value: v, version: 1, size: 1, height: 1, leftHash: h, rightHash: h}, false}, + "inner with empty value": {&Node{key: k, value: []byte{}, version: 1, size: 1, height: 1, leftHash: h, rightHash: h}, false}, + "inner with left child": {&Node{key: k, version: 1, size: 1, height: 1, leftHash: h}, true}, + "inner with right child": {&Node{key: k, version: 1, size: 1, height: 1, rightHash: h}, true}, + "inner with no child": {&Node{key: k, version: 1, size: 1, height: 1}, false}, + "inner with height 0": {&Node{key: k, version: 1, size: 1, height: 0, leftHash: h, rightHash: h}, false}, + } + + for desc, tc := range testcases { + tc := tc // appease scopelint + t.Run(desc, func(t *testing.T) { + err := tc.node.validate() + if tc.valid { + assert.NoError(t, err) + } else { + assert.Error(t, err) + } + }) + } +} + +func BenchmarkNode_encodedSize(b *testing.B) { + node := &Node{ + key: randBytes(25), + value: randBytes(100), + version: rand.Int63n(10000000), + height: 1, + size: rand.Int63n(10000000), + leftHash: randBytes(20), + rightHash: randBytes(20), + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + node.encodedSize() + } +} + +func BenchmarkNode_WriteBytes(b *testing.B) { + node := &Node{ + key: randBytes(25), + value: randBytes(100), + version: rand.Int63n(10000000), + height: 1, + size: rand.Int63n(10000000), + leftHash: randBytes(20), + rightHash: randBytes(20), + } + b.ResetTimer() + b.Run("NoPreAllocate", func(sub *testing.B) { + sub.ReportAllocs() + for i := 0; i < sub.N; i++ { + var buf bytes.Buffer + _ = node.writeBytes(&buf) + } + }) + b.Run("PreAllocate", func(sub *testing.B) { + sub.ReportAllocs() + for i := 0; i < sub.N; i++ { + var buf bytes.Buffer + buf.Grow(node.encodedSize()) + _ = node.writeBytes(&buf) + } + }) +} diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go new file mode 100644 index 0000000000..2d4686fe62 --- /dev/null +++ b/sei-iavl/nodedb.go @@ -0,0 +1,1111 @@ +package iavl + +import ( + "bytes" + "crypto/sha256" + "fmt" + "math" + "sort" + "strconv" + "strings" + "sync" + + "github.com/pkg/errors" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/iavl/cache" + "github.com/cosmos/iavl/internal/logger" +) + +const ( + int64Size = 8 + hashSize = sha256.Size + genesisVersion = 1 + storageVersionKey = "storage_version" + // We store latest saved version together with storage version delimited by the constant below. + // This delimiter is valid only if fast storage is enabled (i.e. storageVersion >= fastStorageVersionValue). + // The latest saved version is needed for protection against downgrade and re-upgrade. In such a case, it would + // be possible to observe mismatch between the latest version state and the fast nodes on disk. + // Therefore, we would like to detect that and overwrite fast nodes on disk with the latest version state. + fastStorageVersionDelimiter = "-" + // Using semantic versioning: https://semver.org/ + defaultStorageVersionValue = "1.0.0" + fastStorageVersionValue = "1.1.0" + fastNodeCacheSize = 100000 +) + +var ( + // All node keys are prefixed with the byte 'n'. This ensures no collision is + // possible with the other keys, and makes them easier to traverse. They are indexed by the node hash. + nodeKeyFormat = NewKeyFormat('n', hashSize) // n + + // Orphans are keyed in the database by their expected lifetime. + // The first number represents the *last* version at which the orphan needs + // to exist, while the second number represents the *earliest* version at + // which it is expected to exist - which starts out by being the version + // of the node being orphaned. + // To clarify: + // When I write to key {X} with value V and old value O, we orphan O with =time of write + // and = version O was created at. + orphanKeyFormat = NewKeyFormat('o', int64Size, int64Size, hashSize) // o + + // Key Format for making reads and iterates go through a data-locality preserving db. + // The value at an entry will list what version it was written to. + // Then to query values, you first query state via this fast method. + // If its present, then check the tree version. If tree version >= result_version, + // return result_version. Else, go through old (slow) IAVL get method that walks through tree. + fastKeyFormat = NewKeyFormat('f', 0) // f + + // Key Format for storing metadata about the chain such as the vesion number. + // The value at an entry will be in a variable format and up to the caller to + // decide how to parse. + metadataKeyFormat = NewKeyFormat('m', 0) // v + + // Root nodes are indexed separately by their version + rootKeyFormat = NewKeyFormat('r', int64Size) // r +) + +var ( + errInvalidFastStorageVersion = fmt.Sprintf("Fast storage version must be in the format %s", fastStorageVersionDelimiter) +) + +type nodeDB struct { + mtx sync.Mutex // Read/write lock. + db dbm.DB // Persistent node storage. + batch dbm.Batch // Batched writing buffer. + opts Options // Options to customize for pruning/writing + versionReaders map[int64]uint32 // Number of active version readers + storageVersion string // Storage version + latestVersion int64 // Latest version of nodeDB. + nodeCache cache.Cache // Cache for nodes in the regular tree that consists of key-value pairs at any version. + fastNodeCache cache.Cache // Cache for nodes in the fast index that represents only key-value pairs at the latest version. +} + +func newNodeDB(db dbm.DB, cacheSize int, opts *Options) *nodeDB { + if opts == nil { + o := DefaultOptions() + opts = &o + } + + storeVersion, err := db.Get(metadataKeyFormat.Key(unsafeToBz(storageVersionKey))) + + if err != nil || storeVersion == nil { + storeVersion = []byte(defaultStorageVersionValue) + } + + return &nodeDB{ + db: db, + batch: db.NewBatch(), + opts: *opts, + latestVersion: 0, // initially invalid + nodeCache: cache.New(cacheSize), + fastNodeCache: cache.New(fastNodeCacheSize), + versionReaders: make(map[int64]uint32, 8), + storageVersion: string(storeVersion), + } +} + +// GetNode gets a node from memory or disk. If it is an inner node, it does not +// load its children. +func (ndb *nodeDB) GetNode(hash []byte) (*Node, error) { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + + if len(hash) == 0 { + return nil, ErrNodeMissingHash + } + + // Check the cache. + if cachedNode := ndb.nodeCache.Get(hash); cachedNode != nil { + ndb.opts.Stat.IncCacheHitCnt() + return cachedNode.(*Node), nil + } + + ndb.opts.Stat.IncCacheMissCnt() + + // Doesn't exist, load. + buf, err := ndb.db.Get(ndb.nodeKey(hash)) + if err != nil { + return nil, fmt.Errorf("can't get node %X: %v", hash, err) + } + if buf == nil { + return nil, fmt.Errorf("Value missing for hash %x corresponding to nodeKey %x", hash, ndb.nodeKey(hash)) + } + + node, err := MakeNode(buf) + if err != nil { + return nil, fmt.Errorf("Error reading Node. bytes: %x, error: %v", buf, err) + } + + node.hash = hash + node.persisted = true + ndb.nodeCache.Add(node) + + return node, nil +} + +func (ndb *nodeDB) GetFastNode(key []byte) (*FastNode, error) { + if !ndb.hasUpgradedToFastStorage() { + return nil, errors.New("storage version is not fast") + } + + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + + if len(key) == 0 { + return nil, fmt.Errorf("nodeDB.GetFastNode() requires key, len(key) equals 0") + } + + if cachedFastNode := ndb.fastNodeCache.Get(key); cachedFastNode != nil { + ndb.opts.Stat.IncFastCacheHitCnt() + return cachedFastNode.(*FastNode), nil + } + + ndb.opts.Stat.IncFastCacheMissCnt() + + // Doesn't exist, load. + buf, err := ndb.db.Get(ndb.fastNodeKey(key)) + if err != nil { + return nil, fmt.Errorf("can't get FastNode %X: %w", key, err) + } + if buf == nil { + return nil, nil + } + + fastNode, err := DeserializeFastNode(key, buf) + if err != nil { + return nil, fmt.Errorf("error reading FastNode. bytes: %x, error: %w", buf, err) + } + + ndb.fastNodeCache.Add(fastNode) + return fastNode, nil +} + +// SaveNode saves a node to disk. +func (ndb *nodeDB) SaveNode(node *Node) error { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + + if node.hash == nil { + return ErrNodeMissingHash + } + if node.persisted { + return ErrNodeAlreadyPersisted + } + + // Save node bytes to db. + var buf bytes.Buffer + buf.Grow(node.encodedSize()) + + if err := node.writeBytes(&buf); err != nil { + return err + } + + if err := ndb.batch.Set(ndb.nodeKey(node.hash), buf.Bytes()); err != nil { + return err + } + logger.Debug("BATCH SAVE %X %p\n", node.hash, node) + node.persisted = true + ndb.nodeCache.Add(node) + return nil +} + +// SaveNode saves a FastNode to disk and add to cache. +func (ndb *nodeDB) SaveFastNode(node *FastNode) error { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + return ndb.saveFastNodeUnlocked(node, true) +} + +// SaveNode saves a FastNode to disk without adding to cache. +func (ndb *nodeDB) SaveFastNodeNoCache(node *FastNode) error { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + return ndb.saveFastNodeUnlocked(node, false) +} + +// setFastStorageVersionToBatch sets storage version to fast where the version is +// 1.1.0-. Returns error if storage version is incorrect or on +// db error, nil otherwise. Requires changes to be committed after to be persisted. +func (ndb *nodeDB) setFastStorageVersionToBatch() error { + var newVersion string + if ndb.storageVersion >= fastStorageVersionValue { + // Storage version should be at index 0 and latest fast cache version at index 1 + versions := strings.Split(ndb.storageVersion, fastStorageVersionDelimiter) + + if len(versions) > 2 { + return errors.New(errInvalidFastStorageVersion) + } + + newVersion = versions[0] + } else { + newVersion = fastStorageVersionValue + } + + latestVersion, err := ndb.getLatestVersion() + if err != nil { + return err + } + + newVersion += fastStorageVersionDelimiter + strconv.Itoa(int(latestVersion)) + + if err := ndb.batch.Set(metadataKeyFormat.Key([]byte(storageVersionKey)), []byte(newVersion)); err != nil { + return err + } + ndb.storageVersion = newVersion + return nil +} + +func (ndb *nodeDB) getStorageVersion() string { + return ndb.storageVersion +} + +// Returns true if the upgrade to latest storage version has been performed, false otherwise. +func (ndb *nodeDB) hasUpgradedToFastStorage() bool { + return ndb.getStorageVersion() >= fastStorageVersionValue +} + +// Returns true if the upgrade to fast storage has occurred but it does not match the live state, false otherwise. +// When the live state is not matched, we must force reupgrade. +// We determine this by checking the version of the live state and the version of the live state when +// latest storage was updated on disk the last time. +func (ndb *nodeDB) shouldForceFastStorageUpgrade() (bool, error) { + versions := strings.Split(ndb.storageVersion, fastStorageVersionDelimiter) + + if len(versions) == 2 { + latestVersion, err := ndb.getLatestVersion() + if err != nil { + // TODO: should be true or false as default? (removed panic here) + return false, err + } + if versions[1] != strconv.Itoa(int(latestVersion)) { + return true, nil + } + } + return false, nil +} + +// SaveNode saves a FastNode to disk. +func (ndb *nodeDB) saveFastNodeUnlocked(node *FastNode, shouldAddToCache bool) error { + if node.key == nil { + return fmt.Errorf("cannot have FastNode with a nil value for key") + } + + // Save node bytes to db. + var buf bytes.Buffer + buf.Grow(node.encodedSize()) + + if err := node.writeBytes(&buf); err != nil { + return fmt.Errorf("error while writing fastnode bytes. Err: %w", err) + } + + if err := ndb.batch.Set(ndb.fastNodeKey(node.key), buf.Bytes()); err != nil { + return fmt.Errorf("error while writing key/val to nodedb batch. Err: %w", err) + } + if shouldAddToCache { + ndb.fastNodeCache.Add(node) + } + return nil +} + +// Has checks if a hash exists in the database. +func (ndb *nodeDB) Has(hash []byte) (bool, error) { + key := ndb.nodeKey(hash) + + if ldb, ok := ndb.db.(*dbm.GoLevelDB); ok { + exists, err := ldb.DB().Has(key, nil) + if err != nil { + return false, err + } + return exists, nil + } + value, err := ndb.db.Get(key) + if err != nil { + return false, err + } + + return value != nil, nil +} + +// SaveBranch saves the given node and all of its descendants. +// NOTE: This function clears leftNode/rigthNode recursively and +// calls _hash() on the given node. +// TODO refactor, maybe use hashWithCount() but provide a callback. +func (ndb *nodeDB) SaveBranch(node *Node) ([]byte, error) { + if node.persisted { + return node.hash, nil + } + + var err error + if node.leftNode != nil { + node.leftHash, err = ndb.SaveBranch(node.leftNode) + } + + if err != nil { + return nil, err + } + + if node.rightNode != nil { + node.rightHash, err = ndb.SaveBranch(node.rightNode) + } + + if err != nil { + return nil, err + } + + _, err = node._hash() + if err != nil { + return nil, err + } + + err = ndb.SaveNode(node) + if err != nil { + return nil, err + } + + // resetBatch only working on generate a genesis block + if node.version <= genesisVersion { + if err = ndb.resetBatch(); err != nil { + return nil, err + } + } + node.leftNode = nil + node.rightNode = nil + + return node.hash, nil +} + +// resetBatch reset the db batch, keep low memory used +func (ndb *nodeDB) resetBatch() error { + var err error + if ndb.opts.Sync { + err = ndb.batch.WriteSync() + } else { + err = ndb.batch.Write() + } + if err != nil { + return err + } + err = ndb.batch.Close() + if err != nil { + return err + } + + ndb.batch = ndb.db.NewBatch() + + return nil +} + +// DeleteVersion deletes a tree version from disk. +// calls deleteOrphans(version), deleteRoot(version, checkLatestVersion) +func (ndb *nodeDB) DeleteVersion(version int64, checkLatestVersion bool) error { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + + if ndb.versionReaders[version] > 0 { + return errors.Errorf("unable to delete version %v, it has %v active readers", version, ndb.versionReaders[version]) + } + + err := ndb.deleteOrphans(version) + if err != nil { + return err + } + + err = ndb.deleteRoot(version, checkLatestVersion) + if err != nil { + return err + } + return err +} + +// DeleteVersionsFrom permanently deletes all tree versions from the given version upwards. +func (ndb *nodeDB) DeleteVersionsFrom(version int64) error { + latest, err := ndb.getLatestVersion() + if err != nil { + return err + } + if latest < version { + return nil + } + root, err := ndb.getRoot(latest) + if err != nil { + return err + } + if root == nil { + return errors.Errorf("root for version %v not found", latest) + } + + for v, r := range ndb.versionReaders { + if v >= version && r != 0 { + return errors.Errorf("unable to delete version %v with %v active readers", v, r) + } + } + + // First, delete all active nodes in the current (latest) version whose node version is after + // the given version. + err = ndb.deleteNodesFrom(version, root) + if err != nil { + return err + } + + // Next, delete orphans: + // - Delete orphan entries *and referred nodes* with fromVersion >= version + // - Delete orphan entries with toVersion >= version-1 (since orphans at latest are not orphans) + err = ndb.traverseOrphans(func(key, hash []byte) error { + var fromVersion, toVersion int64 + orphanKeyFormat.Scan(key, &toVersion, &fromVersion) + + if fromVersion >= version { + if err = ndb.batch.Delete(key); err != nil { + return err + } + if err = ndb.batch.Delete(ndb.nodeKey(hash)); err != nil { + return err + } + ndb.nodeCache.Remove(hash) + } else if toVersion >= version-1 { + if err = ndb.batch.Delete(key); err != nil { + return err + } + } + return nil + }) + + if err != nil { + return err + } + + // Delete the version root entries + err = ndb.traverseRange(rootKeyFormat.Key(version), rootKeyFormat.Key(int64(math.MaxInt64)), func(k, v []byte) error { + if err = ndb.batch.Delete(k); err != nil { + return err + } + return nil + }) + + if err != nil { + return err + } + + // Delete fast node entries + err = ndb.traverseFastNodes(func(keyWithPrefix, v []byte) error { + key := keyWithPrefix[1:] + fastNode, err := DeserializeFastNode(key, v) + + if err != nil { + return err + } + + if version <= fastNode.versionLastUpdatedAt { + if err = ndb.batch.Delete(keyWithPrefix); err != nil { + return err + } + ndb.fastNodeCache.Remove(key) + } + return nil + }) + + if err != nil { + return err + } + + return nil +} + +// DeleteVersionsRange deletes versions from an interval (not inclusive). +func (ndb *nodeDB) DeleteVersionsRange(fromVersion, toVersion int64) error { + if fromVersion >= toVersion { + return errors.New("toVersion must be greater than fromVersion") + } + if toVersion == 0 { + return errors.New("toVersion must be greater than 0") + } + + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + + latest, err := ndb.getLatestVersion() + if err != nil { + return err + } + if latest < toVersion { + return errors.Errorf("cannot delete latest saved version (%d)", latest) + } + + predecessor, err := ndb.getPreviousVersion(fromVersion) + if err != nil { + return err + } + + for v, r := range ndb.versionReaders { + if v < toVersion && v > predecessor && r != 0 { + return errors.Errorf("unable to delete version %v with %v active readers", v, r) + } + } + + // If the predecessor is earlier than the beginning of the lifetime, we can delete the orphan. + // Otherwise, we shorten its lifetime, by moving its endpoint to the predecessor version. + for version := fromVersion; version < toVersion; version++ { + err := ndb.traverseOrphansVersion(version, func(key, hash []byte) error { + var from, to int64 + orphanKeyFormat.Scan(key, &to, &from) + if err := ndb.batch.Delete(key); err != nil { + return err + } + if from > predecessor { + if err := ndb.batch.Delete(ndb.nodeKey(hash)); err != nil { + return err + } + ndb.nodeCache.Remove(hash) + } else { + if err := ndb.saveOrphan(hash, from, predecessor); err != nil { + return err + } + } + return nil + }) + if err != nil { + return err + } + } + + // Delete the version root entries + err = ndb.traverseRange(rootKeyFormat.Key(fromVersion), rootKeyFormat.Key(toVersion), func(k, v []byte) error { + if err := ndb.batch.Delete(k); err != nil { + return err + } + return nil + }) + + if err != nil { + return err + } + return nil +} + +func (ndb *nodeDB) DeleteFastNode(key []byte) error { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + if err := ndb.batch.Delete(ndb.fastNodeKey(key)); err != nil { + return err + } + ndb.fastNodeCache.Remove(key) + return nil +} + +// deleteNodesFrom deletes the given node and any descendants that have versions after the given +// (inclusive). It is mainly used via LoadVersionForOverwriting, to delete the current version. +func (ndb *nodeDB) deleteNodesFrom(version int64, hash []byte) error { + if len(hash) == 0 { + return nil + } + + node, err := ndb.GetNode(hash) + if err != nil { + return err + } + + if node.leftHash != nil { + if err := ndb.deleteNodesFrom(version, node.leftHash); err != nil { + return err + } + } + if node.rightHash != nil { + if err := ndb.deleteNodesFrom(version, node.rightHash); err != nil { + return err + } + } + + if node.version >= version { + if err := ndb.batch.Delete(ndb.nodeKey(hash)); err != nil { + return err + } + + ndb.nodeCache.Remove(hash) + } + + return nil +} + +// Saves orphaned nodes to disk under a special prefix. +// version: the new version being saved. +// orphans: the orphan nodes created since version-1 +func (ndb *nodeDB) SaveOrphans(version int64, orphans map[string]int64) error { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + + toVersion, err := ndb.getPreviousVersion(version) + if err != nil { + return err + } + + for hash, fromVersion := range orphans { + logger.Debug("SAVEORPHAN %v-%v %X\n", fromVersion, toVersion, hash) + err := ndb.saveOrphan([]byte(hash), fromVersion, toVersion) + if err != nil { + return err + } + } + return nil +} + +// Saves a single orphan to disk. +func (ndb *nodeDB) saveOrphan(hash []byte, fromVersion, toVersion int64) error { + if fromVersion > toVersion { + return fmt.Errorf("orphan expires before it comes alive. %d > %d", fromVersion, toVersion) + } + key := ndb.orphanKey(fromVersion, toVersion, hash) + if err := ndb.batch.Set(key, hash); err != nil { + return err + } + return nil +} + +// deleteOrphans deletes orphaned nodes from disk, and the associated orphan +// entries. +func (ndb *nodeDB) deleteOrphans(version int64) error { + // Will be zero if there is no previous version. + predecessor, err := ndb.getPreviousVersion(version) + if err != nil { + return err + } + + // Traverse orphans with a lifetime ending at the version specified. + // TODO optimize. + return ndb.traverseOrphansVersion(version, func(key, hash []byte) error { + var fromVersion, toVersion int64 + + // See comment on `orphanKeyFmt`. Note that here, `version` and + // `toVersion` are always equal. + orphanKeyFormat.Scan(key, &toVersion, &fromVersion) + + // Delete orphan key and reverse-lookup key. + if err := ndb.batch.Delete(key); err != nil { + return err + } + + // If there is no predecessor, or the predecessor is earlier than the + // beginning of the lifetime (ie: negative lifetime), or the lifetime + // spans a single version and that version is the one being deleted, we + // can delete the orphan. Otherwise, we shorten its lifetime, by + // moving its endpoint to the previous version. + if predecessor < fromVersion || fromVersion == toVersion { + logger.Debug("DELETE predecessor:%v fromVersion:%v toVersion:%v %X\n", predecessor, fromVersion, toVersion, hash) + if err := ndb.batch.Delete(ndb.nodeKey(hash)); err != nil { + return err + } + ndb.nodeCache.Remove(hash) + } else { + logger.Debug("MOVE predecessor:%v fromVersion:%v toVersion:%v %X\n", predecessor, fromVersion, toVersion, hash) + ndb.saveOrphan(hash, fromVersion, predecessor) + } + return nil + }) +} + +func (ndb *nodeDB) nodeKey(hash []byte) []byte { + return nodeKeyFormat.KeyBytes(hash) +} + +func (ndb *nodeDB) fastNodeKey(key []byte) []byte { + return fastKeyFormat.KeyBytes(key) +} + +func (ndb *nodeDB) orphanKey(fromVersion, toVersion int64, hash []byte) []byte { + return orphanKeyFormat.Key(toVersion, fromVersion, hash) +} + +func (ndb *nodeDB) rootKey(version int64) []byte { + return rootKeyFormat.Key(version) +} + +func (ndb *nodeDB) getLatestVersion() (int64, error) { + if ndb.latestVersion == 0 { + var err error + ndb.latestVersion, err = ndb.getPreviousVersion(1<<63 - 1) + if err != nil { + return 0, err + } + } + return ndb.latestVersion, nil +} + +func (ndb *nodeDB) updateLatestVersion(version int64) { + if ndb.latestVersion < version { + ndb.latestVersion = version + } +} + +func (ndb *nodeDB) resetLatestVersion(version int64) { + ndb.latestVersion = version +} + +func (ndb *nodeDB) getPreviousVersion(version int64) (int64, error) { + itr, err := ndb.db.ReverseIterator( + rootKeyFormat.Key(1), + rootKeyFormat.Key(version), + ) + if err != nil { + return 0, err + } + defer itr.Close() + + pversion := int64(-1) + for ; itr.Valid(); itr.Next() { + k := itr.Key() + rootKeyFormat.Scan(k, &pversion) + return pversion, nil + } + + if err := itr.Error(); err != nil { + return 0, err + } + + return 0, nil +} + +// deleteRoot deletes the root entry from disk, but not the node it points to. +func (ndb *nodeDB) deleteRoot(version int64, checkLatestVersion bool) error { + latestVersion, err := ndb.getLatestVersion() + if err != nil { + return err + } + + if checkLatestVersion && version == latestVersion { + return errors.New("tried to delete latest version") + } + if err := ndb.batch.Delete(ndb.rootKey(version)); err != nil { + return err + } + return nil +} + +// Traverse orphans and return error if any, nil otherwise +func (ndb *nodeDB) traverseOrphans(fn func(keyWithPrefix, v []byte) error) error { + return ndb.traversePrefix(orphanKeyFormat.Key(), fn) +} + +// Traverse fast nodes and return error if any, nil otherwise +func (ndb *nodeDB) traverseFastNodes(fn func(k, v []byte) error) error { + return ndb.traversePrefix(fastKeyFormat.Key(), fn) +} + +// Traverse orphans ending at a certain version. return error if any, nil otherwise +func (ndb *nodeDB) traverseOrphansVersion(version int64, fn func(k, v []byte) error) error { + return ndb.traversePrefix(orphanKeyFormat.Key(version), fn) +} + +// Traverse all keys and return error if any, nil otherwise +// nolint: unused +func (ndb *nodeDB) traverse(fn func(key, value []byte) error) error { + return ndb.traverseRange(nil, nil, fn) +} + +// Traverse all keys between a given range (excluding end) and return error if any, nil otherwise +func (ndb *nodeDB) traverseRange(start []byte, end []byte, fn func(k, v []byte) error) error { + itr, err := ndb.db.Iterator(start, end) + if err != nil { + return err + } + defer itr.Close() + + for ; itr.Valid(); itr.Next() { + if err := fn(itr.Key(), itr.Value()); err != nil { + return err + } + } + + if err := itr.Error(); err != nil { + return err + } + + return nil +} + +// Traverse all keys with a certain prefix. Return error if any, nil otherwise +func (ndb *nodeDB) traversePrefix(prefix []byte, fn func(k, v []byte) error) error { + itr, err := dbm.IteratePrefix(ndb.db, prefix) + if err != nil { + return err + } + defer itr.Close() + + for ; itr.Valid(); itr.Next() { + if err := fn(itr.Key(), itr.Value()); err != nil { + return err + } + } + + return nil +} + +// Get iterator for fast prefix and error, if any +func (ndb *nodeDB) getFastIterator(start, end []byte, ascending bool) (dbm.Iterator, error) { + var startFormatted, endFormatted []byte + + if start != nil { + startFormatted = fastKeyFormat.KeyBytes(start) + } else { + startFormatted = fastKeyFormat.Key() + } + + if end != nil { + endFormatted = fastKeyFormat.KeyBytes(end) + } else { + endFormatted = fastKeyFormat.Key() + endFormatted[0]++ + } + + if ascending { + return ndb.db.Iterator(startFormatted, endFormatted) + } + + return ndb.db.ReverseIterator(startFormatted, endFormatted) +} + +// Write to disk. +func (ndb *nodeDB) Commit() error { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + + var err error + if ndb.opts.Sync { + err = ndb.batch.WriteSync() + } else { + err = ndb.batch.Write() + } + if err != nil { + return errors.Wrap(err, "failed to write batch") + } + + ndb.batch.Close() + ndb.batch = ndb.db.NewBatch() + + return nil +} + +func (ndb *nodeDB) HasRoot(version int64) (bool, error) { + return ndb.db.Has(ndb.rootKey(version)) +} + +func (ndb *nodeDB) getRoot(version int64) ([]byte, error) { + return ndb.db.Get(ndb.rootKey(version)) +} + +func (ndb *nodeDB) getRoots() (roots map[int64][]byte, err error) { + roots = make(map[int64][]byte) + err = ndb.traversePrefix(rootKeyFormat.Key(), func(k, v []byte) error { + var version int64 + rootKeyFormat.Scan(k, &version) + roots[version] = v + return nil + }) + return roots, err +} + +// SaveRoot creates an entry on disk for the given root, so that it can be +// loaded later. +func (ndb *nodeDB) SaveRoot(root *Node, version int64) error { + if len(root.hash) == 0 { + return ErrRootMissingHash + } + return ndb.saveRoot(root.hash, version) +} + +// SaveEmptyRoot creates an entry on disk for an empty root. +func (ndb *nodeDB) SaveEmptyRoot(version int64) error { + return ndb.saveRoot([]byte{}, version) +} + +func (ndb *nodeDB) saveRoot(hash []byte, version int64) error { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + + // We allow the initial version to be arbitrary + latest, err := ndb.getLatestVersion() + if err != nil { + return err + } + if latest > 0 && version != latest+1 { + return fmt.Errorf("must save consecutive versions; expected %d, got %d", latest+1, version) + } + + if err := ndb.batch.Set(ndb.rootKey(version), hash); err != nil { + return err + } + + ndb.updateLatestVersion(version) + + return nil +} + +func (ndb *nodeDB) incrVersionReaders(version int64) { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + ndb.versionReaders[version]++ +} + +func (ndb *nodeDB) decrVersionReaders(version int64) { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + if ndb.versionReaders[version] > 0 { + ndb.versionReaders[version]-- + } +} + +// Utility and test functions + +// nolint: unused +func (ndb *nodeDB) leafNodes() ([]*Node, error) { + leaves := []*Node{} + + err := ndb.traverseNodes(func(hash []byte, node *Node) error { + if node.isLeaf() { + leaves = append(leaves, node) + } + return nil + }) + + if err != nil { + return nil, err + } + + return leaves, nil +} + +// nolint: unused +func (ndb *nodeDB) nodes() ([]*Node, error) { + nodes := []*Node{} + + err := ndb.traverseNodes(func(hash []byte, node *Node) error { + nodes = append(nodes, node) + return nil + }) + + if err != nil { + return nil, err + } + + return nodes, nil +} + +// nolint: unused +func (ndb *nodeDB) orphans() ([][]byte, error) { + orphans := [][]byte{} + + err := ndb.traverseOrphans(func(k, v []byte) error { + orphans = append(orphans, v) + return nil + }) + + if err != nil { + return nil, err + } + + return orphans, nil +} + +// Not efficient. +// NOTE: DB cannot implement Size() because +// mutations are not always synchronous. +//nolint:unused +func (ndb *nodeDB) size() int { + size := 0 + err := ndb.traverse(func(k, v []byte) error { + size++ + return nil + }) + + if err != nil { + return -1 + } + return size +} + +func (ndb *nodeDB) traverseNodes(fn func(hash []byte, node *Node) error) error { + nodes := []*Node{} + + err := ndb.traversePrefix(nodeKeyFormat.Key(), func(key, value []byte) error { + node, err := MakeNode(value) + if err != nil { + return err + } + nodeKeyFormat.Scan(key, &node.hash) + nodes = append(nodes, node) + return nil + }) + + if err != nil { + return err + } + + sort.Slice(nodes, func(i, j int) bool { + return bytes.Compare(nodes[i].key, nodes[j].key) < 0 + }) + + for _, n := range nodes { + if err := fn(n.hash, n); err != nil { + return err + } + } + return nil +} + +func (ndb *nodeDB) String() (string, error) { + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + + index := 0 + + err := ndb.traversePrefix(rootKeyFormat.Key(), func(key, value []byte) error { + fmt.Fprintf(buf, "%s: %x\n", key, value) + return nil + }) + + if err != nil { + return "", err + } + + buf.WriteByte('\n') + + err = ndb.traverseOrphans(func(key, value []byte) error { + fmt.Fprintf(buf, "%s: %x\n", key, value) + return nil + }) + + if err != nil { + return "", err + } + + buf.WriteByte('\n') + + err = ndb.traverseNodes(func(hash []byte, node *Node) error { + switch { + case len(hash) == 0: + buf.WriteByte('\n') + case node == nil: + fmt.Fprintf(buf, "%s%40x: \n", nodeKeyFormat.Prefix(), hash) + case node.value == nil && node.height > 0: + fmt.Fprintf(buf, "%s%40x: %s %-16s h=%d version=%d\n", + nodeKeyFormat.Prefix(), hash, node.key, "", node.height, node.version) + default: + fmt.Fprintf(buf, "%s%40x: %s = %-16s h=%d version=%d\n", + nodeKeyFormat.Prefix(), hash, node.key, node.value, node.height, node.version) + } + index++ + return nil + }) + + if err != nil { + return "", err + } + + return "-" + "\n" + buf.String() + "-", nil +} + +var ( + ErrNodeMissingHash = fmt.Errorf("node does not have a hash") + ErrNodeAlreadyPersisted = fmt.Errorf("shouldn't be calling save on an already persisted node") + ErrRootMissingHash = fmt.Errorf("root hash must not be empty") +) diff --git a/sei-iavl/nodedb_test.go b/sei-iavl/nodedb_test.go new file mode 100644 index 0000000000..d889d6b1af --- /dev/null +++ b/sei-iavl/nodedb_test.go @@ -0,0 +1,295 @@ +package iavl + +import ( + "encoding/binary" + "errors" + "math/rand" + "strconv" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + db "github.com/tendermint/tm-db" + + "github.com/cosmos/iavl/mock" +) + +func BenchmarkNodeKey(b *testing.B) { + ndb := &nodeDB{} + hashes := makeHashes(b, 2432325) + for i := 0; i < b.N; i++ { + ndb.nodeKey(hashes[i]) + } +} + +func BenchmarkOrphanKey(b *testing.B) { + ndb := &nodeDB{} + hashes := makeHashes(b, 2432325) + for i := 0; i < b.N; i++ { + ndb.orphanKey(1234, 1239, hashes[i]) + } +} + +func BenchmarkTreeString(b *testing.B) { + tree := makeAndPopulateMutableTree(b) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + sink, _ = tree.String() + require.NotNil(b, sink) + } + + if sink == nil { + b.Fatal("Benchmark did not run") + } + sink = (interface{})(nil) +} + +func TestNewNoDbStorage_StorageVersionInDb_Success(t *testing.T) { + const expectedVersion = defaultStorageVersionValue + + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + + dbMock.EXPECT().Get(gomock.Any()).Return([]byte(expectedVersion), nil).Times(1) + dbMock.EXPECT().NewBatch().Return(nil).Times(1) + + ndb := newNodeDB(dbMock, 0, nil) + require.Equal(t, expectedVersion, ndb.storageVersion) +} + +func TestNewNoDbStorage_ErrorInConstructor_DefaultSet(t *testing.T) { + const expectedVersion = defaultStorageVersionValue + + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + + dbMock.EXPECT().Get(gomock.Any()).Return(nil, errors.New("some db error")).Times(1) + dbMock.EXPECT().NewBatch().Return(nil).Times(1) + + ndb := newNodeDB(dbMock, 0, nil) + require.Equal(t, expectedVersion, ndb.getStorageVersion()) +} + +func TestNewNoDbStorage_DoesNotExist_DefaultSet(t *testing.T) { + const expectedVersion = defaultStorageVersionValue + + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + + dbMock.EXPECT().Get(gomock.Any()).Return(nil, nil).Times(1) + dbMock.EXPECT().NewBatch().Return(nil).Times(1) + + ndb := newNodeDB(dbMock, 0, nil) + require.Equal(t, expectedVersion, ndb.getStorageVersion()) +} + +func TestSetStorageVersion_Success(t *testing.T) { + const expectedVersion = fastStorageVersionValue + + db := db.NewMemDB() + + ndb := newNodeDB(db, 0, nil) + require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion()) + + err := ndb.setFastStorageVersionToBatch() + require.NoError(t, err) + + latestVersion, err := ndb.getLatestVersion() + require.NoError(t, err) + require.Equal(t, expectedVersion+fastStorageVersionDelimiter+strconv.Itoa(int(latestVersion)), ndb.getStorageVersion()) + require.NoError(t, ndb.batch.Write()) +} + +func TestSetStorageVersion_DBFailure_OldKept(t *testing.T) { + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + batchMock := mock.NewMockBatch(ctrl) + rIterMock := mock.NewMockIterator(ctrl) + + expectedErrorMsg := "some db error" + + expectedFastCacheVersion := 2 + + dbMock.EXPECT().Get(gomock.Any()).Return([]byte(defaultStorageVersionValue), nil).Times(1) + dbMock.EXPECT().NewBatch().Return(batchMock).Times(1) + + // rIterMock is used to get the latest version from disk. We are mocking that rIterMock returns latestTreeVersion from disk + rIterMock.EXPECT().Valid().Return(true).Times(1) + rIterMock.EXPECT().Key().Return(rootKeyFormat.Key(expectedFastCacheVersion)).Times(1) + rIterMock.EXPECT().Close().Return(nil).Times(1) + + dbMock.EXPECT().ReverseIterator(gomock.Any(), gomock.Any()).Return(rIterMock, nil).Times(1) + batchMock.EXPECT().Set(metadataKeyFormat.Key([]byte(storageVersionKey)), []byte(fastStorageVersionValue+fastStorageVersionDelimiter+strconv.Itoa(expectedFastCacheVersion))).Return(errors.New(expectedErrorMsg)).Times(1) + + ndb := newNodeDB(dbMock, 0, nil) + require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion()) + + err := ndb.setFastStorageVersionToBatch() + require.Error(t, err) + require.Equal(t, expectedErrorMsg, err.Error()) + require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion()) +} + +func TestSetStorageVersion_InvalidVersionFailure_OldKept(t *testing.T) { + ctrl := gomock.NewController(t) + dbMock := mock.NewMockDB(ctrl) + batchMock := mock.NewMockBatch(ctrl) + + expectedErrorMsg := errInvalidFastStorageVersion + + invalidStorageVersion := fastStorageVersionValue + fastStorageVersionDelimiter + "1" + fastStorageVersionDelimiter + "2" + + dbMock.EXPECT().Get(gomock.Any()).Return([]byte(invalidStorageVersion), nil).Times(1) + dbMock.EXPECT().NewBatch().Return(batchMock).Times(1) + + ndb := newNodeDB(dbMock, 0, nil) + require.Equal(t, invalidStorageVersion, ndb.getStorageVersion()) + + err := ndb.setFastStorageVersionToBatch() + require.Error(t, err) + require.Equal(t, expectedErrorMsg, err.Error()) + require.Equal(t, invalidStorageVersion, ndb.getStorageVersion()) +} + +func TestSetStorageVersion_FastVersionFirst_VersionAppended(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.storageVersion = fastStorageVersionValue + ndb.latestVersion = 100 + + err := ndb.setFastStorageVersionToBatch() + require.NoError(t, err) + require.Equal(t, fastStorageVersionValue+fastStorageVersionDelimiter+strconv.Itoa(int(ndb.latestVersion)), ndb.storageVersion) +} + +func TestSetStorageVersion_FastVersionSecond_VersionAppended(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.latestVersion = 100 + + storageVersionBytes := []byte(fastStorageVersionValue) + storageVersionBytes[len(fastStorageVersionValue)-1]++ // increment last byte + ndb.storageVersion = string(storageVersionBytes) + + err := ndb.setFastStorageVersionToBatch() + require.NoError(t, err) + require.Equal(t, string(storageVersionBytes)+fastStorageVersionDelimiter+strconv.Itoa(int(ndb.latestVersion)), ndb.storageVersion) +} + +func TestSetStorageVersion_SameVersionTwice(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.latestVersion = 100 + + storageVersionBytes := []byte(fastStorageVersionValue) + storageVersionBytes[len(fastStorageVersionValue)-1]++ // increment last byte + ndb.storageVersion = string(storageVersionBytes) + + err := ndb.setFastStorageVersionToBatch() + require.NoError(t, err) + newStorageVersion := string(storageVersionBytes) + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestVersion)) + require.Equal(t, newStorageVersion, ndb.storageVersion) + + err = ndb.setFastStorageVersionToBatch() + require.NoError(t, err) + require.Equal(t, newStorageVersion, ndb.storageVersion) +} + +// Test case where version is incorrect and has some extra garbage at the end +func TestShouldForceFastStorageUpdate_DefaultVersion_True(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.storageVersion = defaultStorageVersionValue + ndb.latestVersion = 100 + + shouldForce, err := ndb.shouldForceFastStorageUpgrade() + require.False(t, shouldForce) + require.NoError(t, err) +} + +func TestShouldForceFastStorageUpdate_FastVersion_Greater_True(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.latestVersion = 100 + ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestVersion+1)) + + shouldForce, err := ndb.shouldForceFastStorageUpgrade() + require.True(t, shouldForce) + require.NoError(t, err) +} + +func TestShouldForceFastStorageUpdate_FastVersion_Smaller_True(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.latestVersion = 100 + ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestVersion-1)) + + shouldForce, err := ndb.shouldForceFastStorageUpgrade() + require.True(t, shouldForce) + require.NoError(t, err) +} + +func TestShouldForceFastStorageUpdate_FastVersion_Match_False(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.latestVersion = 100 + ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestVersion)) + + shouldForce, err := ndb.shouldForceFastStorageUpgrade() + require.False(t, shouldForce) + require.NoError(t, err) +} + +func TestIsFastStorageEnabled_True(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.latestVersion = 100 + ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestVersion)) + + require.True(t, ndb.hasUpgradedToFastStorage()) +} + +func TestIsFastStorageEnabled_False(t *testing.T) { + db := db.NewMemDB() + ndb := newNodeDB(db, 0, nil) + ndb.latestVersion = 100 + ndb.storageVersion = defaultStorageVersionValue + + shouldForce, err := ndb.shouldForceFastStorageUpgrade() + require.False(t, shouldForce) + require.NoError(t, err) +} + +func makeHashes(b *testing.B, seed int64) [][]byte { + b.StopTimer() + rnd := rand.NewSource(seed) + hashes := make([][]byte, b.N) + hashBytes := 8 * ((hashSize + 7) / 8) + for i := 0; i < b.N; i++ { + hashes[i] = make([]byte, hashBytes) + for b := 0; b < hashBytes; b += 8 { + binary.BigEndian.PutUint64(hashes[i][b:b+8], uint64(rnd.Int63())) + } + hashes[i] = hashes[i][:hashSize] + } + b.StartTimer() + return hashes +} + +func makeAndPopulateMutableTree(tb testing.TB) *MutableTree { + memDB := db.NewMemDB() + tree, err := NewMutableTreeWithOpts(memDB, 0, &Options{InitialVersion: 9}, false) + require.NoError(tb, err) + + for i := 0; i < 1e4; i++ { + buf := make([]byte, 0, (i/255)+1) + for j := 0; 1<>j)&0xff)) + } + tree.Set(buf, buf) + } + _, _, err = tree.SaveVersion() + require.Nil(tb, err, "Expected .SaveVersion to succeed") + return tree +} diff --git a/sei-iavl/options.go b/sei-iavl/options.go new file mode 100644 index 0000000000..7d5d24653a --- /dev/null +++ b/sei-iavl/options.go @@ -0,0 +1,89 @@ +package iavl + +import "sync/atomic" + +// Statisc about db runtime state +type Statistics struct { + // Each time GetNode operation hit cache + cacheHitCnt uint64 + + // Each time GetNode and GetFastNode operation miss cache + cacheMissCnt uint64 + + // Each time GetFastNode operation hit cache + fastCacheHitCnt uint64 + + // Each time GetFastNode operation miss cache + fastCacheMissCnt uint64 +} + +func (stat *Statistics) IncCacheHitCnt() { + if stat == nil { + return + } + atomic.AddUint64(&stat.cacheHitCnt, 1) +} + +func (stat *Statistics) IncCacheMissCnt() { + if stat == nil { + return + } + atomic.AddUint64(&stat.cacheMissCnt, 1) +} + +func (stat *Statistics) IncFastCacheHitCnt() { + if stat == nil { + return + } + atomic.AddUint64(&stat.fastCacheHitCnt, 1) +} + +func (stat *Statistics) IncFastCacheMissCnt() { + if stat == nil { + return + } + atomic.AddUint64(&stat.fastCacheMissCnt, 1) +} + +func (stat *Statistics) GetCacheHitCnt() uint64 { + return atomic.LoadUint64(&stat.cacheHitCnt) +} + +func (stat *Statistics) GetCacheMissCnt() uint64 { + return atomic.LoadUint64(&stat.cacheMissCnt) +} + +func (stat *Statistics) GetFastCacheHitCnt() uint64 { + return atomic.LoadUint64(&stat.fastCacheHitCnt) +} + +func (stat *Statistics) GetFastCacheMissCnt() uint64 { + return atomic.LoadUint64(&stat.fastCacheMissCnt) +} + +func (stat *Statistics) Reset() { + atomic.StoreUint64(&stat.cacheHitCnt, 0) + atomic.StoreUint64(&stat.cacheMissCnt, 0) + atomic.StoreUint64(&stat.fastCacheHitCnt, 0) + atomic.StoreUint64(&stat.fastCacheMissCnt, 0) +} + +// Options define tree options. +type Options struct { + // Sync synchronously flushes all writes to storage, using e.g. the fsync syscall. + // Disabling this significantly improves performance, but can lose data on e.g. power loss. + Sync bool + + // InitialVersion specifies the initial version number. If any versions already exist below + // this, an error is returned when loading the tree. Only used for the initial SaveVersion() + // call. + InitialVersion uint64 + + // When Stat is not nil, statistical logic needs to be executed + Stat *Statistics +} + +// DefaultOptions returns the default options for IAVL. +func DefaultOptions() Options { + return Options{} +} diff --git a/sei-iavl/proof.go b/sei-iavl/proof.go new file mode 100644 index 0000000000..d6dd5b77ff --- /dev/null +++ b/sei-iavl/proof.go @@ -0,0 +1,288 @@ +package iavl + +import ( + "bytes" + "crypto/sha256" + "fmt" + "math" + "sync" + + "github.com/pkg/errors" + + hexbytes "github.com/cosmos/iavl/internal/bytes" + "github.com/cosmos/iavl/internal/encoding" + iavlproto "github.com/cosmos/iavl/proto" +) + +var bufPool = &sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, +} + +var ( + // ErrInvalidProof is returned by Verify when a proof cannot be validated. + ErrInvalidProof = fmt.Errorf("invalid proof") + + // ErrInvalidInputs is returned when the inputs passed to the function are invalid. + ErrInvalidInputs = fmt.Errorf("invalid inputs") + + // ErrInvalidRoot is returned when the root passed in does not match the proof's. + ErrInvalidRoot = fmt.Errorf("invalid root") +) + +//---------------------------------------- +// ProofInnerNode +// Contract: Left and Right can never both be set. Will result in a empty `[]` roothash + +type ProofInnerNode struct { + Height int8 `json:"height"` + Size int64 `json:"size"` + Version int64 `json:"version"` + Left []byte `json:"left"` + Right []byte `json:"right"` +} + +func (pin ProofInnerNode) String() string { + return pin.stringIndented("") +} + +func (pin ProofInnerNode) stringIndented(indent string) string { + return fmt.Sprintf(`ProofInnerNode{ +%s Height: %v +%s Size: %v +%s Version: %v +%s Left: %X +%s Right: %X +%s}`, + indent, pin.Height, + indent, pin.Size, + indent, pin.Version, + indent, pin.Left, + indent, pin.Right, + indent) +} + +func (pin ProofInnerNode) Hash(childHash []byte) ([]byte, error) { + hasher := sha256.New() + + buf := bufPool.Get().(*bytes.Buffer) + buf.Reset() + defer bufPool.Put(buf) + + err := encoding.EncodeVarint(buf, int64(pin.Height)) + if err == nil { + err = encoding.EncodeVarint(buf, pin.Size) + } + if err == nil { + err = encoding.EncodeVarint(buf, pin.Version) + } + + if len(pin.Left) > 0 && len(pin.Right) > 0 { + return nil, errors.New("both left and right child hashes are set") + } + + if len(pin.Left) == 0 { + if err == nil { + err = encoding.EncodeBytes(buf, childHash) + } + if err == nil { + err = encoding.EncodeBytes(buf, pin.Right) + } + } else { + if err == nil { + err = encoding.EncodeBytes(buf, pin.Left) + } + if err == nil { + err = encoding.EncodeBytes(buf, childHash) + } + } + + if err != nil { + return nil, fmt.Errorf("failed to hash ProofInnerNode: %v", err) + } + + _, err = hasher.Write(buf.Bytes()) + if err != nil { + return nil, err + } + return hasher.Sum(nil), nil +} + +// toProto converts the inner node proof to Protobuf, for use in ProofOps. +func (pin ProofInnerNode) toProto() *iavlproto.ProofInnerNode { + return &iavlproto.ProofInnerNode{ + Height: int32(pin.Height), + Size_: pin.Size, + Version: pin.Version, + Left: pin.Left, + Right: pin.Right, + } +} + +// proofInnerNodeFromProto converts a Protobuf ProofInnerNode to a ProofInnerNode. +func proofInnerNodeFromProto(pbInner *iavlproto.ProofInnerNode) (ProofInnerNode, error) { + if pbInner == nil { + return ProofInnerNode{}, errors.New("inner node cannot be nil") + } + if pbInner.Height > math.MaxInt8 || pbInner.Height < math.MinInt8 { + return ProofInnerNode{}, fmt.Errorf("height must fit inside an int8, got %v", pbInner.Height) + } + return ProofInnerNode{ + Height: int8(pbInner.Height), + Size: pbInner.Size_, + Version: pbInner.Version, + Left: pbInner.Left, + Right: pbInner.Right, + }, nil +} + +//---------------------------------------- + +type ProofLeafNode struct { + Key hexbytes.HexBytes `json:"key"` + ValueHash hexbytes.HexBytes `json:"value"` + Version int64 `json:"version"` +} + +func (pln ProofLeafNode) String() string { + return pln.stringIndented("") +} + +func (pln ProofLeafNode) stringIndented(indent string) string { + return fmt.Sprintf(`ProofLeafNode{ +%s Key: %v +%s ValueHash: %X +%s Version: %v +%s}`, + indent, pln.Key, + indent, pln.ValueHash, + indent, pln.Version, + indent) +} + +func (pln ProofLeafNode) Hash() ([]byte, error) { + hasher := sha256.New() + + buf := bufPool.Get().(*bytes.Buffer) + buf.Reset() + defer bufPool.Put(buf) + + err := encoding.EncodeVarint(buf, 0) + if err == nil { + err = encoding.EncodeVarint(buf, 1) + } + if err == nil { + err = encoding.EncodeVarint(buf, pln.Version) + } + if err == nil { + err = encoding.EncodeBytes(buf, pln.Key) + } + if err == nil { + err = encoding.EncodeBytes(buf, pln.ValueHash) + } + if err != nil { + return nil, fmt.Errorf("failed to hash ProofLeafNode: %v", err) + } + _, err = hasher.Write(buf.Bytes()) + if err != nil { + return nil, err + + } + + return hasher.Sum(nil), nil +} + +// toProto converts the leaf node proof to Protobuf, for use in ProofOps. +func (pln ProofLeafNode) toProto() *iavlproto.ProofLeafNode { + return &iavlproto.ProofLeafNode{ + Key: pln.Key, + ValueHash: pln.ValueHash, + Version: pln.Version, + } +} + +// proofLeafNodeFromProto converts a Protobuf ProofLeadNode to a ProofLeafNode. +func proofLeafNodeFromProto(pbLeaf *iavlproto.ProofLeafNode) (ProofLeafNode, error) { + if pbLeaf == nil { + return ProofLeafNode{}, errors.New("leaf node cannot be nil") + } + return ProofLeafNode{ + Key: pbLeaf.Key, + ValueHash: pbLeaf.ValueHash, + Version: pbLeaf.Version, + }, nil +} + +//---------------------------------------- + +// If the key does not exist, returns the path to the next leaf left of key (w/ +// path), except when key is less than the least item, in which case it returns +// a path to the least item. +func (node *Node) PathToLeaf(t *ImmutableTree, key []byte) (PathToLeaf, *Node, error) { + path := new(PathToLeaf) + val, err := node.pathToLeaf(t, key, path) + return *path, val, err +} + +// pathToLeaf is a helper which recursively constructs the PathToLeaf. +// As an optimization the already constructed path is passed in as an argument +// and is shared among recursive calls. +func (node *Node) pathToLeaf(t *ImmutableTree, key []byte, path *PathToLeaf) (*Node, error) { + if node.height == 0 { + if bytes.Equal(node.key, key) { + return node, nil + } + return node, errors.New("key does not exist") + } + + // Note that we do not store the left child in the ProofInnerNode when we're going to add the + // left node as part of the path, similarly we don't store the right child info when going down + // the right child node. This is done as an optimization since the child info is going to be + // already stored in the next ProofInnerNode in PathToLeaf. + if bytes.Compare(key, node.key) < 0 { + // left side + rightNode, err := node.getRightNode(t) + if err != nil { + return nil, err + } + + pin := ProofInnerNode{ + Height: node.height, + Size: node.size, + Version: node.version, + Left: nil, + Right: rightNode.hash, + } + *path = append(*path, pin) + + leftNode, err := node.getLeftNode(t) + if err != nil { + return nil, err + } + n, err := leftNode.pathToLeaf(t, key, path) + return n, err + } + // right side + leftNode, err := node.getLeftNode(t) + if err != nil { + return nil, err + } + + pin := ProofInnerNode{ + Height: node.height, + Size: node.size, + Version: node.version, + Left: leftNode.hash, + Right: nil, + } + *path = append(*path, pin) + + rightNode, err := node.getRightNode(t) + if err != nil { + return nil, err + } + + n, err := rightNode.pathToLeaf(t, key, path) + return n, err +} diff --git a/sei-iavl/proof_forgery_test.go b/sei-iavl/proof_forgery_test.go new file mode 100644 index 0000000000..241db1cd77 --- /dev/null +++ b/sei-iavl/proof_forgery_test.go @@ -0,0 +1,106 @@ +package iavl_test + +import ( + "encoding/hex" + "math/rand" + "strings" + "testing" + + "github.com/cosmos/iavl" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/tmhash" + db "github.com/tendermint/tm-db" +) + +func TestProofFogery(t *testing.T) { + source := rand.NewSource(0) + r := rand.New(source) + cacheSize := 0 + tree, err := iavl.NewMutableTreeWithOpts(db.NewMemDB(), cacheSize, nil, false) + require.NoError(t, err) + + // two keys only + keys := []byte{0x11, 0x32} + values := make([][]byte, len(keys)) + // make random values and insert into tree + for i, ikey := range keys { + key := []byte{ikey} + v := r.Intn(255) + values[i] = []byte{byte(v)} + tree.Set(key, values[i]) + } + + // get root + root, err := tree.WorkingHash() + require.NoError(t, err) + // use the rightmost kv pair in the tree so the inner nodes will populate left + k := []byte{keys[1]} + v := values[1] + + val, proof, err := tree.GetWithProof(k) + require.NoError(t, err) + + err = proof.Verify(root) + require.NoError(t, err) + err = proof.VerifyItem(k, val) + require.NoError(t, err) + + // ------------------- FORGE PROOF ------------------- + + forgedPayloadBytes := mustDecode("0xabcd") + forgedValueHash := tmhash.Sum(forgedPayloadBytes) + // make a forgery of the proof by adding: + // - a new leaf node to the right + // - an empty inner node + // - a right entry in the path + _, proof2, _ := tree.GetWithProof(k) + forgedNode := proof2.Leaves[0] + forgedNode.Key = []byte{0xFF} + forgedNode.ValueHash = forgedValueHash + proof2.Leaves = append(proof2.Leaves, forgedNode) + proof2.InnerNodes = append(proof2.InnerNodes, iavl.PathToLeaf{}) + // figure out what hash we need via https://twitter.com/samczsun/status/1578181160345034752 + proof2.LeftPath[0].Right = mustDecode("82C36CED85E914DAE8FDF6DD11FD5833121AA425711EB126C470CE28FF6623D5") + + rootHashValid := proof.ComputeRootHash() + verifyErr := proof.Verify(rootHashValid) + require.NoError(t, verifyErr, "should verify") + // forgery gives empty root hash (previously it returned the same one!) + rootHashForged := proof2.ComputeRootHash() + require.Empty(t, rootHashForged, "roothash must be empty if both left and right are set") + verifyErr = proof2.Verify(rootHashForged) + require.Error(t, verifyErr, "should not verify") + + // verify proof two fails with valid proof + err = proof2.Verify(rootHashValid) + require.Error(t, err, "should not verify different root hash") + + { + // legit node verifies against legit proof (expected) + verifyErr = proof.VerifyItem(k, v) + require.NoError(t, verifyErr, "valid proof should verify") + // forged node fails to verify against legit proof (expected) + verifyErr = proof.VerifyItem(forgedNode.Key, forgedPayloadBytes) + require.Error(t, verifyErr, "forged proof should fail to verify") + } + { + // legit node fails to verify against forged proof (expected) + verifyErr = proof2.VerifyItem(k, v) + require.Error(t, verifyErr, "valid proof should verify, but has a forged sister node") + + // forged node fails to verify against forged proof (previously this succeeded!) + verifyErr = proof2.VerifyItem(forgedNode.Key, forgedPayloadBytes) + require.Error(t, verifyErr, "forged proof should fail verify") + } +} + +func mustDecode(str string) []byte { + if strings.HasPrefix(str, "0x") { + str = str[2:] + } + b, err := hex.DecodeString(str) + if err != nil { + panic(err) + } + return b +} diff --git a/sei-iavl/proof_iavl_absence.go b/sei-iavl/proof_iavl_absence.go new file mode 100644 index 0000000000..e18dbe3f40 --- /dev/null +++ b/sei-iavl/proof_iavl_absence.go @@ -0,0 +1,121 @@ +package iavl + +import ( + "fmt" + + proto "github.com/gogo/protobuf/proto" + "github.com/pkg/errors" + "github.com/tendermint/tendermint/crypto/merkle" + tmmerkle "github.com/tendermint/tendermint/proto/tendermint/crypto" + + "github.com/cosmos/iavl/internal/encoding" + iavlproto "github.com/cosmos/iavl/proto" +) + +const ProofOpIAVLAbsence = "iavl:a" + +// IAVLAbsenceOp takes a key as its only argument +// +// If the produced root hash matches the expected hash, the proof +// is good. +type AbsenceOp struct { + // Encoded in ProofOp.Key. + key []byte + + // To encode in ProofOp.Data. + // Proof is nil for an empty tree. + // The hash of an empty tree is nil. + Proof *RangeProof `json:"proof"` +} + +var _ merkle.ProofOperator = AbsenceOp{} + +func NewAbsenceOp(key []byte, proof *RangeProof) AbsenceOp { + return AbsenceOp{ + key: key, + Proof: proof, + } +} + +func AbsenceOpDecoder(pop tmmerkle.ProofOp) (merkle.ProofOperator, error) { + if pop.Type != ProofOpIAVLAbsence { + return nil, errors.Errorf("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpIAVLAbsence) + } + // Strip the varint length prefix, used for backwards compatibility with Amino. + bz, n, err := encoding.DecodeBytes(pop.Data) + if err != nil { + return nil, err + } + + if n != len(pop.Data) { + return nil, fmt.Errorf("unexpected bytes, expected %v got %v", n, len(pop.Data)) + } + + pbProofOp := &iavlproto.AbsenceOp{} + err = proto.Unmarshal(bz, pbProofOp) + if err != nil { + return nil, err + } + + proof, err := RangeProofFromProto(pbProofOp.Proof) + if err != nil { + return nil, err + } + + return NewAbsenceOp(pop.Key, &proof), nil +} + +func (op AbsenceOp) ProofOp() tmmerkle.ProofOp { + pbProof := iavlproto.AbsenceOp{Proof: op.Proof.ToProto()} + bz, err := proto.Marshal(&pbProof) + if err != nil { + panic(err) + } + // We length-prefix the byte slice to retain backwards compatibility with the Amino proofs. + bz, err = encoding.EncodeBytesSlice(bz) + if err != nil { + panic(err) + } + return tmmerkle.ProofOp{ + Type: ProofOpIAVLAbsence, + Key: op.key, + Data: bz, + } +} + +func (op AbsenceOp) String() string { + return fmt.Sprintf("IAVLAbsenceOp{%v}", op.GetKey()) +} + +func (op AbsenceOp) Run(args [][]byte) ([][]byte, error) { + if len(args) != 0 { + return nil, errors.Errorf("expected 0 args, got %v", len(args)) + } + + // If the tree is nil, the proof is nil, and all keys are absent. + if op.Proof == nil { + return [][]byte{[]byte(nil)}, nil + } + + // Compute the root hash and assume it is valid. + // The caller checks the ultimate root later. + root := op.Proof.ComputeRootHash() + err := op.Proof.Verify(root) + if err != nil { + return nil, errors.Wrap(err, "computing root hash") + } + + // XXX What is the encoding for keys? + // We should decode the key depending on whether it's a string or hex, + // maybe based on quotes and 0x prefix? + err = op.Proof.VerifyAbsence(op.key) + if err != nil { + return nil, errors.Wrap(err, "verifying absence") + } + + return [][]byte{root}, nil +} + +func (op AbsenceOp) GetKey() []byte { + return op.key +} diff --git a/sei-iavl/proof_iavl_test.go b/sei-iavl/proof_iavl_test.go new file mode 100644 index 0000000000..7047309cc0 --- /dev/null +++ b/sei-iavl/proof_iavl_test.go @@ -0,0 +1,100 @@ +package iavl + +import ( + "encoding/hex" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + tmmerkle "github.com/tendermint/tendermint/proto/tendermint/crypto" + db "github.com/tendermint/tm-db" +) + +func TestProofOp(t *testing.T) { + tree, err := NewMutableTreeWithOpts(db.NewMemDB(), 0, nil, false) + require.NoError(t, err) + keys := []byte{0x0a, 0x11, 0x2e, 0x32, 0x50, 0x72, 0x99, 0xa1, 0xe4, 0xf7} // 10 total. + for _, ikey := range keys { + key := []byte{ikey} + tree.Set(key, key) + } + root, err := tree.WorkingHash() + require.NoError(t, err) + + testcases := []struct { + key byte + expectPresent bool + expectProofOp string + }{ + {0x00, false, "aa010aa7010a280808100a18012a2022b4e34a1778d6a03aac39f00d89deb886e0cc37454e300b7aebeb4f4939c0790a280804100418012a20734fad809673ab2b9672453a8b2bc8c9591e2d1d97933df5b4c3b0531bf82e720a280802100218012a20154b101a72acffe0f5e65d1e144a57dc6f97758d2049821231f02b6a5b44fe811a270a010a122001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b1801"}, + {0x0a, true, "aa010aa7010a280808100a18012a2022b4e34a1778d6a03aac39f00d89deb886e0cc37454e300b7aebeb4f4939c0790a280804100418012a20734fad809673ab2b9672453a8b2bc8c9591e2d1d97933df5b4c3b0531bf82e720a280802100218012a20154b101a72acffe0f5e65d1e144a57dc6f97758d2049821231f02b6a5b44fe811a270a010a122001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b1801"}, + {0x0b, false, "d5010ad2010a280808100a18012a2022b4e34a1778d6a03aac39f00d89deb886e0cc37454e300b7aebeb4f4939c0790a280804100418012a20734fad809673ab2b9672453a8b2bc8c9591e2d1d97933df5b4c3b0531bf82e720a280802100218012a20154b101a72acffe0f5e65d1e144a57dc6f97758d2049821231f02b6a5b44fe8112001a270a010a122001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b18011a270a011112204a64a107f0cb32536e5bce6c98c393db21cca7f4ea187ba8c4dca8b51d4ea80a1801"}, + {0x11, true, "aa010aa7010a280808100a18012a2022b4e34a1778d6a03aac39f00d89deb886e0cc37454e300b7aebeb4f4939c0790a280804100418012a20734fad809673ab2b9672453a8b2bc8c9591e2d1d97933df5b4c3b0531bf82e720a28080210021801222053d2828f35e33aecab8e411a40afb0475288973b96aed2220e9894f43a5375ad1a270a011112204a64a107f0cb32536e5bce6c98c393db21cca7f4ea187ba8c4dca8b51d4ea80a1801"}, + {0x60, false, "d5010ad2010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a280806100618012a20631b10ce49ece4cc9130befac927865742fb11caf2e8fc08fc00a4a25e4bc7940a280802100218012a207a4a97f565ae0b3ea8abf175208f176ac8301665ac2d26c89be3664f90e23da612001a270a015012205c62e091b8c0565f1bafad0dad5934276143ae2ccef7a5381e8ada5b1a8d26d218011a270a01721220454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a11801"}, + {0x72, true, "aa010aa7010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a280806100618012a20631b10ce49ece4cc9130befac927865742fb11caf2e8fc08fc00a4a25e4bc7940a28080210021801222035f8ea805390e084854f399b42ccdeaea33a1dedc115638ac48d0600637dba1f1a270a01721220454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a11801"}, + {0x99, true, "d4010ad1010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a280804100418012a2043b83a6acefd4fd33970d1bc8fc47bed81220c752b8de7053e8ee082a2c7c1290a280802100218012a208f69a1db006c0ee9fad3c7c624b92acc88e9ed00771976ea24a64796c236fef01a270a01991220fd9528b920d6d3956e9e16114523e1889c751e8c1e040182116d4c906b43f5581801"}, + {0xaa, false, "a9020aa6020a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a280804100418012a2043b83a6acefd4fd33970d1bc8fc47bed81220c752b8de7053e8ee082a2c7c1290a280802100218012220a303930ca8831618ac7e4ddd10546cfc366fb730d6630c030a97226bbefc6935122a0a280802100218012a2077ad141b2010cf7107de941aac5b46f44fa4f41251076656a72308263a964fb91a270a01a112208a8950f7623663222542c9469c73be3c4c81bbdf019e2c577590a61f2ce9a15718011a270a01e412205e1effe9b7bab73dce628ccd9f0cbbb16c1e6efc6c4f311e59992a467bc119fd1801"}, + {0xe4, true, "d4010ad1010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a2808041004180122208bc4764843fdd745dc853fa62f2fac0001feae9e46136192f466c09773e2ed050a280802100218012a2077ad141b2010cf7107de941aac5b46f44fa4f41251076656a72308263a964fb91a270a01e412205e1effe9b7bab73dce628ccd9f0cbbb16c1e6efc6c4f311e59992a467bc119fd1801"}, + {0xf7, true, "d4010ad1010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a2808041004180122208bc4764843fdd745dc853fa62f2fac0001feae9e46136192f466c09773e2ed050a28080210021801222032af6e3eec2b63d5fe1bd992a89ef3467b3cee639c068cace942f01326098f171a270a01f7122050868f20258bbc9cce0da2719e8654c108733dd2f663b8737c574ec0ead93eb31801"}, + {0xff, false, "d4010ad1010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a2808041004180122208bc4764843fdd745dc853fa62f2fac0001feae9e46136192f466c09773e2ed050a28080210021801222032af6e3eec2b63d5fe1bd992a89ef3467b3cee639c068cace942f01326098f171a270a01f7122050868f20258bbc9cce0da2719e8654c108733dd2f663b8737c574ec0ead93eb31801"}, + } + + for _, tc := range testcases { + tc := tc + t.Run(fmt.Sprintf("%02x", tc.key), func(t *testing.T) { + key := []byte{tc.key} + value, proof, err := tree.GetWithProof(key) + require.NoError(t, err) + + // Verify that proof is valid. + err = proof.Verify(root) + require.NoError(t, err) + + // Encode and decode proof, either ValueOp or AbsentOp depending on key existence. + expectBytes, err := hex.DecodeString(tc.expectProofOp) + require.NoError(t, err) + + if tc.expectPresent { + require.NotNil(t, value) + err = proof.VerifyItem(key, value) + require.NoError(t, err) + + valueOp := NewValueOp(key, proof) + proofOp := valueOp.ProofOp() + assert.Equal(t, tmmerkle.ProofOp{ + Type: ProofOpIAVLValue, + Key: key, + Data: expectBytes, + }, proofOp) + + d, e := ValueOpDecoder(proofOp) + require.NoError(t, e) + decoded := d.(ValueOp) + err = decoded.Proof.Verify(root) + require.NoError(t, err) + assert.Equal(t, valueOp, decoded) + + } else { + require.Nil(t, value) + err = proof.VerifyAbsence(key) + require.NoError(t, err) + + absenceOp := NewAbsenceOp(key, proof) + proofOp := absenceOp.ProofOp() + assert.Equal(t, tmmerkle.ProofOp{ + Type: ProofOpIAVLAbsence, + Key: key, + Data: expectBytes, + }, proofOp) + + d, e := AbsenceOpDecoder(proofOp) + require.NoError(t, e) + decoded := d.(AbsenceOp) + err = decoded.Proof.Verify(root) + require.NoError(t, err) + assert.Equal(t, absenceOp, decoded) + } + }) + } +} diff --git a/sei-iavl/proof_iavl_value.go b/sei-iavl/proof_iavl_value.go new file mode 100644 index 0000000000..68dada259d --- /dev/null +++ b/sei-iavl/proof_iavl_value.go @@ -0,0 +1,112 @@ +package iavl + +import ( + "fmt" + + proto "github.com/gogo/protobuf/proto" + "github.com/pkg/errors" + "github.com/tendermint/tendermint/crypto/merkle" + tmmerkle "github.com/tendermint/tendermint/proto/tendermint/crypto" + + "github.com/cosmos/iavl/internal/encoding" + iavlproto "github.com/cosmos/iavl/proto" +) + +const ProofOpIAVLValue = "iavl:v" + +// IAVLValueOp takes a key and a single value as argument and +// produces the root hash. +// +// If the produced root hash matches the expected hash, the proof +// is good. +type ValueOp struct { + // Encoded in ProofOp.Key. + key []byte + + // To encode in ProofOp.Data. + // Proof is nil for an empty tree. + // The hash of an empty tree is nil. + Proof *RangeProof `json:"proof"` +} + +var _ merkle.ProofOperator = ValueOp{} + +func NewValueOp(key []byte, proof *RangeProof) ValueOp { + return ValueOp{ + key: key, + Proof: proof, + } +} + +func ValueOpDecoder(pop tmmerkle.ProofOp) (merkle.ProofOperator, error) { + if pop.Type != ProofOpIAVLValue { + return nil, errors.Errorf("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpIAVLValue) + } + // Strip the varint length prefix, used for backwards compatibility with Amino. + bz, n, err := encoding.DecodeBytes(pop.Data) + if err != nil { + return nil, err + } + if n != len(pop.Data) { + return nil, fmt.Errorf("unexpected bytes, expected %v got %v", n, len(pop.Data)) + } + pbProofOp := &iavlproto.ValueOp{} + err = proto.Unmarshal(bz, pbProofOp) + if err != nil { + return nil, err + } + proof, err := RangeProofFromProto(pbProofOp.Proof) + if err != nil { + return nil, err + } + return NewValueOp(pop.Key, &proof), nil +} + +func (op ValueOp) ProofOp() tmmerkle.ProofOp { + pbProof := iavlproto.ValueOp{Proof: op.Proof.ToProto()} + bz, err := proto.Marshal(&pbProof) + if err != nil { + panic(err) + } + // We length-prefix the byte slice to retain backwards compatibility with the Amino proofs. + bz, err = encoding.EncodeBytesSlice(bz) + if err != nil { + panic(err) + } + return tmmerkle.ProofOp{ + Type: ProofOpIAVLValue, + Key: op.key, + Data: bz, + } +} + +func (op ValueOp) String() string { + return fmt.Sprintf("IAVLValueOp{%v}", op.GetKey()) +} + +func (op ValueOp) Run(args [][]byte) ([][]byte, error) { + if len(args) != 1 { + return nil, errors.New("value size is not 1") + } + value := args[0] + + // Compute the root hash and assume it is valid. + // The caller checks the ultimate root later. + root := op.Proof.ComputeRootHash() + err := op.Proof.Verify(root) + if err != nil { + return nil, errors.Wrap(err, "computing root hash") + } + // XXX What is the encoding for keys? + // We should decode the key depending on whether it's a string or hex, + // maybe based on quotes and 0x prefix? + err = op.Proof.VerifyItem(op.key, value) + if err != nil { + return nil, errors.Wrap(err, "verifying value") + } + return [][]byte{root}, nil +} + +func (op ValueOp) GetKey() []byte { + return op.key +} diff --git a/sei-iavl/proof_ics23.go b/sei-iavl/proof_ics23.go new file mode 100644 index 0000000000..991359a790 --- /dev/null +++ b/sei-iavl/proof_ics23.go @@ -0,0 +1,168 @@ +package iavl + +import ( + "encoding/binary" + "fmt" + + ics23 "github.com/confio/ics23/go" +) + +/* +GetMembershipProof will produce a CommitmentProof that the given key (and queries value) exists in the iavl tree. +If the key doesn't exist in the tree, this will return an error. +*/ +func (t *ImmutableTree) GetMembershipProof(key []byte) (*ics23.CommitmentProof, error) { + exist, err := createExistenceProof(t, key) + if err != nil { + return nil, err + } + proof := &ics23.CommitmentProof{ + Proof: &ics23.CommitmentProof_Exist{ + Exist: exist, + }, + } + return proof, nil +} + +/* +GetNonMembershipProof will produce a CommitmentProof that the given key doesn't exist in the iavl tree. +If the key exists in the tree, this will return an error. +*/ +func (t *ImmutableTree) GetNonMembershipProof(key []byte) (*ics23.CommitmentProof, error) { + // idx is one node right of what we want.... + var err error + idx, val, err := t.GetWithIndex(key) + if err != nil { + return nil, err + } + + if val != nil { + return nil, fmt.Errorf("cannot create NonExistanceProof when Key in State") + } + + nonexist := &ics23.NonExistenceProof{ + Key: key, + } + + if idx >= 1 { + leftkey, _, err := t.GetByIndex(idx - 1) + if err != nil { + return nil, err + } + + nonexist.Left, err = createExistenceProof(t, leftkey) + if err != nil { + return nil, err + } + } + + // this will be nil if nothing right of the queried key + rightkey, _, err := t.GetByIndex(idx) + if err != nil { + return nil, err + } + + if rightkey != nil { + nonexist.Right, err = createExistenceProof(t, rightkey) + if err != nil { + return nil, err + } + } + + proof := &ics23.CommitmentProof{ + Proof: &ics23.CommitmentProof_Nonexist{ + Nonexist: nonexist, + }, + } + return proof, nil +} + +func createExistenceProof(tree *ImmutableTree, key []byte) (*ics23.ExistenceProof, error) { + value, proof, err := tree.GetWithProof(key) + if err != nil { + return nil, err + } + if value == nil { + return nil, fmt.Errorf("cannot create ExistanceProof when Key not in State") + } + return convertExistenceProof(proof, key, value) +} + +// convertExistenceProof will convert the given proof into a valid +// existence proof, if that's what it is. +// +// This is the simplest case of the range proof and we will focus on +// demoing compatibility here +func convertExistenceProof(p *RangeProof, key, value []byte) (*ics23.ExistenceProof, error) { + if len(p.Leaves) != 1 { + return nil, fmt.Errorf("existence proof requires RangeProof to have exactly one leaf") + } + return &ics23.ExistenceProof{ + Key: key, + Value: value, + Leaf: convertLeafOp(p.Leaves[0].Version), + Path: convertInnerOps(p.LeftPath), + }, nil +} + +func convertLeafOp(version int64) *ics23.LeafOp { + var varintBuf [binary.MaxVarintLen64]byte + // this is adapted from iavl/proof.go:proofLeafNode.Hash() + prefix := convertVarIntToBytes(0, varintBuf) + prefix = append(prefix, convertVarIntToBytes(1, varintBuf)...) + prefix = append(prefix, convertVarIntToBytes(version, varintBuf)...) + + return &ics23.LeafOp{ + Hash: ics23.HashOp_SHA256, + PrehashValue: ics23.HashOp_SHA256, + Length: ics23.LengthOp_VAR_PROTO, + Prefix: prefix, + } +} + +// we cannot get the proofInnerNode type, so we need to do the whole path in one function +func convertInnerOps(path PathToLeaf) []*ics23.InnerOp { + steps := make([]*ics23.InnerOp, 0, len(path)) + + // lengthByte is the length prefix prepended to each of the sha256 sub-hashes + var lengthByte byte = 0x20 + + var varintBuf [binary.MaxVarintLen64]byte + + // we need to go in reverse order, iavl starts from root to leaf, + // we want to go up from the leaf to the root + for i := len(path) - 1; i >= 0; i-- { + // this is adapted from iavl/proof.go:proofInnerNode.Hash() + prefix := convertVarIntToBytes(int64(path[i].Height), varintBuf) + prefix = append(prefix, convertVarIntToBytes(path[i].Size, varintBuf)...) + prefix = append(prefix, convertVarIntToBytes(path[i].Version, varintBuf)...) + + var suffix []byte + if len(path[i].Left) > 0 { + // length prefixed left side + prefix = append(prefix, lengthByte) + prefix = append(prefix, path[i].Left...) + // prepend the length prefix for child + prefix = append(prefix, lengthByte) + } else { + // prepend the length prefix for child + prefix = append(prefix, lengthByte) + // length-prefixed right side + suffix = []byte{lengthByte} + suffix = append(suffix, path[i].Right...) + } + + op := &ics23.InnerOp{ + Hash: ics23.HashOp_SHA256, + Prefix: prefix, + Suffix: suffix, + } + steps = append(steps, op) + } + return steps +} + +func convertVarIntToBytes(orig int64, buf [binary.MaxVarintLen64]byte) []byte { + n := binary.PutVarint(buf[:], orig) + return buf[:n] +} diff --git a/sei-iavl/proof_ics23_test.go b/sei-iavl/proof_ics23_test.go new file mode 100644 index 0000000000..fd0a6d1967 --- /dev/null +++ b/sei-iavl/proof_ics23_test.go @@ -0,0 +1,325 @@ +package iavl + +import ( + "bytes" + "fmt" + "math/rand" + "sort" + "testing" + + ics23 "github.com/confio/ics23/go" + "github.com/stretchr/testify/require" + + db "github.com/tendermint/tm-db" +) + +func TestConvertExistence(t *testing.T) { + proof, err := GenerateResult(200, Middle) + require.NoError(t, err) + + converted, err := convertExistenceProof(proof.Proof, proof.Key, proof.Value) + require.NoError(t, err) + + calc, err := converted.Calculate() + require.NoError(t, err) + + require.Equal(t, []byte(calc), proof.RootHash, "Calculated: %X\nExpected: %X", calc, proof.RootHash) +} + +func TestGetMembership(t *testing.T) { + cases := map[string]struct { + size int + loc Where + }{ + "small left": {size: 100, loc: Left}, + "small middle": {size: 100, loc: Middle}, + "small right": {size: 100, loc: Right}, + "big left": {size: 5431, loc: Left}, + "big middle": {size: 5431, loc: Middle}, + "big right": {size: 5431, loc: Right}, + } + + for name, tc := range cases { + tc := tc + t.Run(name, func(t *testing.T) { + tree, allkeys, err := BuildTree(tc.size, 0) + require.NoError(t, err, "Creating tree: %+v", err) + + key := GetKey(allkeys, tc.loc) + val, err := tree.Get(key) + require.NoError(t, err) + proof, err := tree.GetMembershipProof(key) + require.NoError(t, err, "Creating Proof: %+v", err) + + root, err := tree.Hash() + require.NoError(t, err) + valid := ics23.VerifyMembership(ics23.IavlSpec, root, proof, key, val) + if !valid { + require.NoError(t, err, "Membership Proof Invalid") + } + }) + } +} + +func TestGetNonMembership(t *testing.T) { + cases := map[string]struct { + size int + loc Where + }{ + "small left": {size: 100, loc: Left}, + "small middle": {size: 100, loc: Middle}, + "small right": {size: 100, loc: Right}, + "big left": {size: 5431, loc: Left}, + "big middle": {size: 5431, loc: Middle}, + "big right": {size: 5431, loc: Right}, + } + + performTest := func(tree *MutableTree, allKeys [][]byte, loc Where) { + key := GetNonKey(allKeys, loc) + + proof, err := tree.GetNonMembershipProof(key) + require.NoError(t, err, "Creating Proof: %+v", err) + + root, err := tree.Hash() + require.NoError(t, err) + valid := ics23.VerifyNonMembership(ics23.IavlSpec, root, proof, key) + if !valid { + require.NoError(t, err, "Non Membership Proof Invalid") + } + } + + for name, tc := range cases { + tc := tc + t.Run("fast-"+name, func(t *testing.T) { + tree, allkeys, err := BuildTree(tc.size, 0) + require.NoError(t, err, "Creating tree: %+v", err) + // Save version to enable fast cache + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + + performTest(tree, allkeys, tc.loc) + }) + + t.Run("regular-"+name, func(t *testing.T) { + tree, allkeys, err := BuildTree(tc.size, 0) + require.NoError(t, err, "Creating tree: %+v", err) + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(t, err) + require.False(t, isFastCacheEnabled) + + performTest(tree, allkeys, tc.loc) + }) + } +} + +func BenchmarkGetNonMembership(b *testing.B) { + cases := []struct { + size int + loc Where + }{ + {size: 100, loc: Left}, + {size: 100, loc: Middle}, + {size: 100, loc: Right}, + {size: 5431, loc: Left}, + {size: 5431, loc: Middle}, + {size: 5431, loc: Right}, + } + + performTest := func(tree *MutableTree, allKeys [][]byte, loc Where) { + key := GetNonKey(allKeys, loc) + + proof, err := tree.GetNonMembershipProof(key) + require.NoError(b, err, "Creating Proof: %+v", err) + + b.StopTimer() + root, err := tree.Hash() + require.NoError(b, err) + valid := ics23.VerifyNonMembership(ics23.IavlSpec, root, proof, key) + if !valid { + require.NoError(b, err, "Non Membership Proof Invalid") + } + b.StartTimer() + } + + b.Run("fast", func(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + caseIdx := rand.Intn(len(cases)) + tc := cases[caseIdx] + + tree, allkeys, err := BuildTree(tc.size, 100000) + require.NoError(b, err, "Creating tree: %+v", err) + // Save version to enable fast cache + _, _, err = tree.SaveVersion() + require.NoError(b, err) + + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(b, err) + require.True(b, isFastCacheEnabled) + b.StartTimer() + performTest(tree, allkeys, tc.loc) + } + }) + + b.Run("regular", func(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + caseIdx := rand.Intn(len(cases)) + tc := cases[caseIdx] + + tree, allkeys, err := BuildTree(tc.size, 100000) + require.NoError(b, err, "Creating tree: %+v", err) + isFastCacheEnabled, err := tree.IsFastCacheEnabled() + require.NoError(b, err) + require.False(b, isFastCacheEnabled) + + b.StartTimer() + performTest(tree, allkeys, tc.loc) + } + }) +} + +// Test Helpers + +// Result is the result of one match +type Result struct { + Key []byte + Value []byte + Proof *RangeProof + RootHash []byte +} + +// GenerateResult makes a tree of size and returns a range proof for one random element +// +// returns a range proof and the root hash of the tree +func GenerateResult(size int, loc Where) (*Result, error) { + tree, allkeys, err := BuildTree(size, 0) + if err != nil { + return nil, err + } + _, _, err = tree.SaveVersion() + if err != nil { + return nil, err + } + key := GetKey(allkeys, loc) + + value, proof, err := tree.GetWithProof(key) + if err != nil { + return nil, err + } + if value == nil { + return nil, fmt.Errorf("tree.GetWithProof returned nil value") + } + if len(proof.Leaves) != 1 { + return nil, fmt.Errorf("tree.GetWithProof returned %d leaves", len(proof.Leaves)) + } + root, err := tree.Hash() + if err != nil { + return nil, err + } + + res := &Result{ + Key: key, + Value: value, + Proof: proof, + RootHash: root, + } + return res, nil +} + +// Where selects a location for a key - Left, Right, or Middle +type Where int + +const ( + Left Where = iota + Right + Middle +) + +// GetKey this returns a key, on Left/Right/Middle +func GetKey(allkeys [][]byte, loc Where) []byte { + if loc == Left { + return allkeys[0] + } + if loc == Right { + return allkeys[len(allkeys)-1] + } + // select a random index between 1 and allkeys-2 + idx := rand.Int()%(len(allkeys)-2) + 1 + return allkeys[idx] +} + +// GetNonKey returns a missing key - Left of all, Right of all, or in the Middle +func GetNonKey(allkeys [][]byte, loc Where) []byte { + if loc == Left { + return []byte{0, 0, 0, 1} + } + if loc == Right { + return []byte{0xff, 0xff, 0xff, 0xff} + } + // otherwise, next to an existing key (copy before mod) + key := append([]byte{}, GetKey(allkeys, loc)...) + key[len(key)-2] = 255 + key[len(key)-1] = 255 + return key +} + +// BuildTree creates random key/values and stores in tree +// returns a list of all keys in sorted order +func BuildTree(size int, cacheSize int) (itree *MutableTree, keys [][]byte, err error) { + tree, _ := NewMutableTree(db.NewMemDB(), cacheSize, false) + + // insert lots of info and store the bytes + keys = make([][]byte, size) + for i := 0; i < size; i++ { + key := make([]byte, 4) + // create random 4 byte key + rand.Read(key) + value := "value_for_key:" + string(key) + tree.Set(key, []byte(value)) + keys[i] = key + } + sort.Slice(keys, func(i, j int) bool { + return bytes.Compare(keys[i], keys[j]) < 0 + }) + + return tree, keys, nil +} + +// sink is kept as a global to ensure that value checks and assignments to it can't be +// optimized away, and this will help us ensure that benchmarks successfully run. +var sink interface{} + +func BenchmarkConvertLeafOp(b *testing.B) { + var versions = []int64{ + 0, + 1, + 100, + 127, + 128, + 1 << 29, + -0, + -1, + -100, + -127, + -128, + -1 << 29, + } + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, version := range versions { + sink = convertLeafOp(version) + } + } + if sink == nil { + b.Fatal("Benchmark wasn't run") + } + sink = nil +} diff --git a/sei-iavl/proof_path.go b/sei-iavl/proof_path.go new file mode 100644 index 0000000000..690ce0ab32 --- /dev/null +++ b/sei-iavl/proof_path.go @@ -0,0 +1,119 @@ +package iavl + +import ( + "fmt" + "strings" +) + +// pathWithLeaf is a path to a leaf node and the leaf node itself. +type pathWithLeaf struct { + Path PathToLeaf `json:"path"` + Leaf ProofLeafNode `json:"leaf"` +} + +func (pwl pathWithLeaf) String() string { + return pwl.StringIndented("") +} + +func (pwl pathWithLeaf) StringIndented(indent string) string { + return fmt.Sprintf(`pathWithLeaf{ +%s Path: %v +%s Leaf: %v +%s}`, + indent, pwl.Path.stringIndented(indent+" "), + indent, pwl.Leaf.stringIndented(indent+" "), + indent) +} + +// `computeRootHash` computes the root hash with leaf node. +// Does not verify the root hash. +func (pwl pathWithLeaf) computeRootHash() ([]byte, error) { + leafHash, err := pwl.Leaf.Hash() + if err != nil { + return nil, err + } + return pwl.Path.computeRootHash(leafHash) +} + +//---------------------------------------- + +// PathToLeaf represents an inner path to a leaf node. +// Note that the nodes are ordered such that the last one is closest +// to the root of the tree. +type PathToLeaf []ProofInnerNode + +func (pl PathToLeaf) String() string { + return pl.stringIndented("") +} + +func (pl PathToLeaf) stringIndented(indent string) string { + if len(pl) == 0 { + return "empty-PathToLeaf" + } + strs := make([]string, 0, len(pl)) + for i, pin := range pl { + if i == 20 { + strs = append(strs, fmt.Sprintf("... (%v total)", len(pl))) + break + } + strs = append(strs, fmt.Sprintf("%v:%v", i, pin.stringIndented(indent+" "))) + } + return fmt.Sprintf(`PathToLeaf{ +%s %v +%s}`, + indent, strings.Join(strs, "\n"+indent+" "), + indent) +} + +// `computeRootHash` computes the root hash assuming some leaf hash. +// Does not verify the root hash. +// Contract: Caller must verify that the roothash is correct by calling `.verify()`. +func (pl PathToLeaf) computeRootHash(leafHash []byte) ([]byte, error) { + var err error + hash := leafHash + for i := len(pl) - 1; i >= 0; i-- { + pin := pl[i] + hash, err = pin.Hash(hash) + if err != nil { + return nil, err + } + } + return hash, nil +} + +func (pl PathToLeaf) isLeftmost() bool { + for _, node := range pl { + if len(node.Left) > 0 { + return false + } + } + return true +} + +func (pl PathToLeaf) isRightmost() bool { + for _, node := range pl { + if len(node.Right) > 0 { + return false + } + } + return true +} + +// returns -1 if invalid. +func (pl PathToLeaf) Index() (idx int64) { + for i, node := range pl { + switch { + case node.Left == nil: + continue + case node.Right == nil: + if i < len(pl)-1 { + idx += node.Size - pl[i+1].Size + } else { + idx += node.Size - 1 + } + default: + return -1 + } + } + return idx +} diff --git a/sei-iavl/proof_range.go b/sei-iavl/proof_range.go new file mode 100644 index 0000000000..79db502b0c --- /dev/null +++ b/sei-iavl/proof_range.go @@ -0,0 +1,584 @@ +package iavl + +import ( + "bytes" + "crypto/sha256" + "fmt" + "sort" + "strings" + + "github.com/pkg/errors" + + iavlproto "github.com/cosmos/iavl/proto" +) + +type RangeProof struct { + // You don't need the right path because + // it can be derived from what we have. + LeftPath PathToLeaf `json:"left_path"` + InnerNodes []PathToLeaf `json:"inner_nodes"` + Leaves []ProofLeafNode `json:"leaves"` + + // memoize + rootHash []byte // valid iff rootVerified is true + rootVerified bool + treeEnd bool // valid iff rootVerified is true +} + +// Keys returns all the keys in the RangeProof. NOTE: The keys here may +// include more keys than provided by tree.GetRangeWithProof or +// MutableTree.GetVersionedRangeWithProof. The keys returned there are only +// in the provided [startKey,endKey){limit} range. The keys returned here may +// include extra keys, such as: +// - the key before startKey if startKey is provided and doesn't exist; +// - the key after a queried key with tree.GetWithProof, when the key is absent. +func (proof *RangeProof) Keys() (keys [][]byte) { + if proof == nil { + return nil + } + for _, leaf := range proof.Leaves { + keys = append(keys, leaf.Key) + } + return keys +} + +// String returns a string representation of the proof. +func (proof *RangeProof) String() string { + if proof == nil { + return "" + } + return proof.StringIndented("") +} + +func (proof *RangeProof) StringIndented(indent string) string { + istrs := make([]string, 0, len(proof.InnerNodes)) + for _, ptl := range proof.InnerNodes { + istrs = append(istrs, ptl.stringIndented(indent+" ")) + } + lstrs := make([]string, 0, len(proof.Leaves)) + for _, leaf := range proof.Leaves { + lstrs = append(lstrs, leaf.stringIndented(indent+" ")) + } + return fmt.Sprintf(`RangeProof{ +%s LeftPath: %v +%s InnerNodes: +%s %v +%s Leaves: +%s %v +%s (rootVerified): %v +%s (rootHash): %X +%s (treeEnd): %v +%s}`, + indent, proof.LeftPath.stringIndented(indent+" "), + indent, + indent, strings.Join(istrs, "\n"+indent+" "), + indent, + indent, strings.Join(lstrs, "\n"+indent+" "), + indent, proof.rootVerified, + indent, proof.rootHash, + indent, proof.treeEnd, + indent) +} + +// The index of the first leaf (of the whole tree). +// Returns -1 if the proof is nil. +func (proof *RangeProof) LeftIndex() int64 { + if proof == nil { + return -1 + } + return proof.LeftPath.Index() +} + +// Also see LeftIndex(). +// Verify that a key has some value. +// Does not assume that the proof itself is valid, call Verify() first. +func (proof *RangeProof) VerifyItem(key, value []byte) error { + if proof == nil { + return errors.Wrap(ErrInvalidProof, "proof is nil") + } + + if !proof.rootVerified { + return errors.New("must call Verify(root) first") + } + + leaves := proof.Leaves + i := sort.Search(len(leaves), func(i int) bool { + return bytes.Compare(key, leaves[i].Key) <= 0 + }) + + if i >= len(leaves) || !bytes.Equal(leaves[i].Key, key) { + return errors.Wrap(ErrInvalidProof, "leaf key not found in proof") + } + + h := sha256.Sum256(value) + valueHash := h[:] + if !bytes.Equal(leaves[i].ValueHash, valueHash) { + return errors.Wrap(ErrInvalidProof, "leaf value hash not same") + } + + return nil +} + +// Verify that proof is valid absence proof for key. +// Does not assume that the proof itself is valid. +// For that, use Verify(root). +func (proof *RangeProof) VerifyAbsence(key []byte) error { + if proof == nil { + return errors.Wrap(ErrInvalidProof, "proof is nil") + } + if !proof.rootVerified { + return errors.New("must call Verify(root) first") + } + cmp := bytes.Compare(key, proof.Leaves[0].Key) + if cmp < 0 { + if proof.LeftPath.isLeftmost() { + return nil + } + return errors.New("absence not proved by left path") + + } else if cmp == 0 { + return errors.New("absence disproved via first item #0") + } + if len(proof.LeftPath) == 0 { + return nil // proof ok + } + if proof.LeftPath.isRightmost() { + return nil + } + + // See if any of the leaves are greater than key. + for i := 1; i < len(proof.Leaves); i++ { + leaf := proof.Leaves[i] + cmp := bytes.Compare(key, leaf.Key) + switch { + case cmp < 0: + return nil // proof ok + case cmp == 0: + return fmt.Errorf("absence disproved via item #%v", i) + default: + // if i == len(proof.Leaves)-1 { + // If last item, check whether + // it's the last item in the tree. + + // } + continue + } + } + + // It's still a valid proof if our last leaf is the rightmost child. + if proof.treeEnd { + return nil // OK! + } + + // It's not a valid absence proof. + if len(proof.Leaves) < 2 { + return errors.New("absence not proved by right leaf (need another leaf?)") + } + return errors.New("absence not proved by right leaf") + +} + +// Verify that proof is valid. +func (proof *RangeProof) Verify(root []byte) error { + if proof == nil { + return errors.Wrap(ErrInvalidProof, "proof is nil") + } + err := proof.verify(root) + return err +} + +func (proof *RangeProof) verify(root []byte) (err error) { + rootHash := proof.rootHash + if rootHash == nil { + derivedHash, err := proof.computeRootHash() + if err != nil { + return err + } + rootHash = derivedHash + } + if !bytes.Equal(rootHash, root) { + return errors.Wrap(ErrInvalidRoot, "root hash doesn't match") + } + proof.rootVerified = true + return nil +} + +// ComputeRootHash computes the root hash with leaves. +// Returns nil if error or proof is nil. +// Does not verify the root hash. +func (proof *RangeProof) ComputeRootHash() []byte { + if proof == nil { + return nil + } + + rootHash, _ := proof.computeRootHash() + + return rootHash +} + +func (proof *RangeProof) computeRootHash() (rootHash []byte, err error) { + rootHash, treeEnd, err := proof._computeRootHash() + if err == nil { + proof.rootHash = rootHash // memoize + proof.treeEnd = treeEnd // memoize + } + return rootHash, err +} + +func (proof *RangeProof) _computeRootHash() (rootHash []byte, treeEnd bool, err error) { + if len(proof.Leaves) == 0 { + return nil, false, errors.Wrap(ErrInvalidProof, "no leaves") + } + if len(proof.InnerNodes)+1 != len(proof.Leaves) { + return nil, false, errors.Wrap(ErrInvalidProof, "InnerNodes vs Leaves length mismatch, leaves should be 1 more.") //nolint:revive + } + + // Start from the left path and prove each leaf. + + // shared across recursive calls + var leaves = proof.Leaves + var innersq = proof.InnerNodes + var COMPUTEHASH func(path PathToLeaf, rightmost bool) (hash []byte, treeEnd bool, done bool, err error) + + // rightmost: is the root a rightmost child of the tree? + // treeEnd: true iff the last leaf is the last item of the tree. + // Returns the (possibly intermediate, possibly root) hash. + COMPUTEHASH = func(path PathToLeaf, rightmost bool) (hash []byte, treeEnd bool, done bool, err error) { + + // Pop next leaf. + nleaf, rleaves := leaves[0], leaves[1:] + leaves = rleaves + + // Compute hash. + hash, err = (pathWithLeaf{ + Path: path, + Leaf: nleaf, + }).computeRootHash() + + if err != nil { + return nil, treeEnd, false, err + } + + // If we don't have any leaves left, we're done. + if len(leaves) == 0 { + rightmost = rightmost && path.isRightmost() + return hash, rightmost, true, nil + } + + // Prove along path (until we run out of leaves). + for len(path) > 0 { + + // Drop the leaf-most (last-most) inner nodes from path + // until we encounter one with a left hash. + // We assume that the left side is already verified. + // rpath: rest of path + // lpath: last path item + rpath, lpath := path[:len(path)-1], path[len(path)-1] + path = rpath + if len(lpath.Right) == 0 { + continue + } + + // Pop next inners, a PathToLeaf (e.g. []ProofInnerNode). + inners, rinnersq := innersq[0], innersq[1:] + innersq = rinnersq + + // Recursively verify inners against remaining leaves. + derivedRoot, treeEnd, done, err := COMPUTEHASH(inners, rightmost && rpath.isRightmost()) + if err != nil { + return nil, treeEnd, false, errors.Wrap(err, "recursive COMPUTEHASH call") + } + + if !bytes.Equal(derivedRoot, lpath.Right) { + return nil, treeEnd, false, errors.Wrapf(ErrInvalidRoot, "intermediate root hash %X doesn't match, got %X", lpath.Right, derivedRoot) + } + + if done { + return hash, treeEnd, true, nil + } + } + + // We're not done yet (leaves left over). No error, not done either. + // Technically if rightmost, we know there's an error "left over leaves + // -- malformed proof", but we return that at the top level, below. + return hash, false, false, nil + } + + // Verify! + path := proof.LeftPath + rootHash, treeEnd, done, err := COMPUTEHASH(path, true) + if err != nil { + return nil, treeEnd, errors.Wrap(err, "root COMPUTEHASH call") + } else if !done { + return nil, treeEnd, errors.Wrap(ErrInvalidProof, "left over leaves -- malformed proof") + } + + // Ok! + return rootHash, treeEnd, nil +} + +// toProto converts the proof to a Protobuf representation, for use in ValueOp and AbsenceOp. +func (proof *RangeProof) ToProto() *iavlproto.RangeProof { + pb := &iavlproto.RangeProof{ + LeftPath: make([]*iavlproto.ProofInnerNode, 0, len(proof.LeftPath)), + InnerNodes: make([]*iavlproto.PathToLeaf, 0, len(proof.InnerNodes)), + Leaves: make([]*iavlproto.ProofLeafNode, 0, len(proof.Leaves)), + } + for _, inner := range proof.LeftPath { + pb.LeftPath = append(pb.LeftPath, inner.toProto()) + } + for _, path := range proof.InnerNodes { + pbPath := make([]*iavlproto.ProofInnerNode, 0, len(path)) + for _, inner := range path { + pbPath = append(pbPath, inner.toProto()) + } + pb.InnerNodes = append(pb.InnerNodes, &iavlproto.PathToLeaf{Inners: pbPath}) + } + for _, leaf := range proof.Leaves { + pb.Leaves = append(pb.Leaves, leaf.toProto()) + } + + return pb +} + +// rangeProofFromProto generates a RangeProof from a Protobuf RangeProof. +func RangeProofFromProto(pbProof *iavlproto.RangeProof) (RangeProof, error) { + proof := RangeProof{} + + for _, pbInner := range pbProof.LeftPath { + inner, err := proofInnerNodeFromProto(pbInner) + if err != nil { + return proof, err + } + proof.LeftPath = append(proof.LeftPath, inner) + } + + for _, pbPath := range pbProof.InnerNodes { + var path PathToLeaf // leave as nil unless populated, for Amino compatibility + if pbPath != nil { + for _, pbInner := range pbPath.Inners { + inner, err := proofInnerNodeFromProto(pbInner) + if err != nil { + return proof, err + } + path = append(path, inner) + } + } + proof.InnerNodes = append(proof.InnerNodes, path) + } + + for _, pbLeaf := range pbProof.Leaves { + leaf, err := proofLeafNodeFromProto(pbLeaf) + if err != nil { + return proof, err + } + proof.Leaves = append(proof.Leaves, leaf) + } + return proof, nil +} + +// keyStart is inclusive and keyEnd is exclusive. +// If keyStart or keyEnd don't exist, the leaf before keyStart +// or after keyEnd will also be included, but not be included in values. +// If keyEnd-1 exists, no later leaves will be included. +// If keyStart >= keyEnd and both not nil, errors out. +// Limit is never exceeded. + +func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof *RangeProof, keys, values [][]byte, err error) { + if keyStart != nil && keyEnd != nil && bytes.Compare(keyStart, keyEnd) >= 0 { + return nil, nil, nil, fmt.Errorf("if keyStart and keyEnd are present, need keyStart < keyEnd") + } + if limit < 0 { + return nil, nil, nil, fmt.Errorf("limit must be greater or equal to 0 -- 0 means no limit") + } + if t.root == nil { + return nil, nil, nil, nil + } + + _, _, err = t.root.hashWithCount() // Ensure that all hashes are calculated. + if err != nil { + return nil, nil, nil, err + } + + // Get the first key/value pair proof, which provides us with the left key. + path, left, err := t.root.PathToLeaf(t, keyStart) + if err != nil { + // Key doesn't exist, but instead we got the prev leaf (or the + // first or last leaf), which provides proof of absence). + err = nil + } + startOK := keyStart == nil || bytes.Compare(keyStart, left.key) <= 0 + endOK := keyEnd == nil || bytes.Compare(left.key, keyEnd) < 0 + // If left.key is in range, add it to key/values. + if startOK && endOK { + keys = append(keys, left.key) // == keyStart + values = append(values, left.value) + } + + h := sha256.Sum256(left.value) + var leaves = []ProofLeafNode{ + { + Key: left.key, + ValueHash: h[:], + Version: left.version, + }, + } + + // 1: Special case if limit is 1. + // 2: Special case if keyEnd is left.key+1. + _stop := false + if limit == 1 { + _stop = true // case 1 + } else if keyEnd != nil && bytes.Compare(cpIncr(left.key), keyEnd) >= 0 { + _stop = true // case 2 + } + if _stop { + return &RangeProof{ + LeftPath: path, + Leaves: leaves, + }, keys, values, nil + } + + // Get the key after left.key to iterate from. + afterLeft := cpIncr(left.key) + + // Traverse starting from afterLeft, until keyEnd or the next leaf + // after keyEnd. + var allPathToLeafs = []PathToLeaf(nil) + var currentPathToLeaf = PathToLeaf(nil) + var leafCount = 1 // from left above. + var pathCount = 0 + + t.root.traverseInRange(t, afterLeft, nil, true, false, false, + func(node *Node) (stop bool) { + + // Track when we diverge from path, or when we've exhausted path, + // since the first allPathToLeafs shouldn't include it. + if pathCount != -1 { + if len(path) <= pathCount { + // We're done with path counting. + pathCount = -1 + } else { + pn := path[pathCount] + if pn.Height != node.height || + pn.Left != nil && !bytes.Equal(pn.Left, node.leftHash) || + pn.Right != nil && !bytes.Equal(pn.Right, node.rightHash) { + + // We've diverged, so start appending to allPathToLeaf. + pathCount = -1 + } else { + pathCount++ + } + } + } + + if node.height == 0 { // Leaf node + // Append all paths that we tracked so far to get to this leaf node. + allPathToLeafs = append(allPathToLeafs, currentPathToLeaf) + // Start a new one to track as we traverse the tree. + currentPathToLeaf = PathToLeaf(nil) + + h := sha256.Sum256(node.value) + leaves = append(leaves, ProofLeafNode{ + Key: node.key, + ValueHash: h[:], + Version: node.version, + }) + + leafCount++ + + // Maybe terminate because we found enough leaves. + if limit > 0 && limit <= leafCount { + return true + } + + // Terminate if we've found keyEnd or after. + if keyEnd != nil && bytes.Compare(node.key, keyEnd) >= 0 { + return true + } + + // Value is in range, append to keys and values. + keys = append(keys, node.key) + values = append(values, node.value) + + // Terminate if we've found keyEnd-1 or after. + // We don't want to fetch any leaves for it. + if keyEnd != nil && bytes.Compare(cpIncr(node.key), keyEnd) >= 0 { + return true + } + + } else if pathCount < 0 { // Inner node. + // Only store if the node is not stored in currentPathToLeaf already. We track if we are + // still going through PathToLeaf using pathCount. When pathCount goes to -1, we + // start storing the other paths we took to get to the leaf nodes. Also we skip + // storing the left node, since we are traversing the tree starting from the left + // and don't need to store unnecessary info as we only need to go down the right + // path. + currentPathToLeaf = append(currentPathToLeaf, ProofInnerNode{ + Height: node.height, + Size: node.size, + Version: node.version, + Left: nil, + Right: node.rightHash, + }) + } + return false + }, + ) + + return &RangeProof{ + LeftPath: path, + InnerNodes: allPathToLeafs, + Leaves: leaves, + }, keys, values, nil +} + +//---------------------------------------- + +// GetWithProof gets the value under the key if it exists, or returns nil. +// A proof of existence or absence is returned alongside the value. +func (t *ImmutableTree) GetWithProof(key []byte) (value []byte, proof *RangeProof, err error) { + proof, _, values, err := t.getRangeProof(key, cpIncr(key), 2) + if err != nil { + return nil, nil, errors.Wrap(err, "constructing range proof") + } + if len(values) > 0 && bytes.Equal(proof.Leaves[0].Key, key) { + return values[0], proof, nil + } + return nil, proof, nil +} + +// GetRangeWithProof gets key/value pairs within the specified range and limit. +func (t *ImmutableTree) GetRangeWithProof(startKey []byte, endKey []byte, limit int) (keys, values [][]byte, proof *RangeProof, err error) { + proof, keys, values, err = t.getRangeProof(startKey, endKey, limit) + return +} + +// GetVersionedWithProof gets the value under the key at the specified version +// if it exists, or returns nil. +func (tree *MutableTree) GetVersionedWithProof(key []byte, version int64) ([]byte, *RangeProof, error) { + if tree.VersionExists(version) { + t, err := tree.GetImmutable(version) + if err != nil { + return nil, nil, err + } + + return t.GetWithProof(key) + } + return nil, nil, errors.Wrap(ErrVersionDoesNotExist, "") +} + +// GetVersionedRangeWithProof gets key/value pairs within the specified range +// and limit. +func (tree *MutableTree) GetVersionedRangeWithProof(startKey, endKey []byte, limit int, version int64) ( + keys, values [][]byte, proof *RangeProof, err error) { + + if tree.VersionExists(version) { + t, err := tree.GetImmutable(version) + if err != nil { + return nil, nil, nil, err + } + return t.GetRangeWithProof(startKey, endKey, limit) + } + return nil, nil, nil, errors.Wrap(ErrVersionDoesNotExist, "") +} diff --git a/sei-iavl/proof_test.go b/sei-iavl/proof_test.go new file mode 100644 index 0000000000..5e1c0ce488 --- /dev/null +++ b/sei-iavl/proof_test.go @@ -0,0 +1,324 @@ +// nolint: errcheck +package iavl + +import ( + "bytes" + "sort" + "testing" + + proto "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + iavlrand "github.com/cosmos/iavl/internal/rand" + iavlproto "github.com/cosmos/iavl/proto" +) + +func TestTreeGetWithProof(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + require := require.New(t) + for _, ikey := range []byte{0x11, 0x32, 0x50, 0x72, 0x99} { + key := []byte{ikey} + tree.Set(key, []byte(iavlrand.RandStr(8))) + } + root, err := tree.WorkingHash() + require.NoError(err) + + key := []byte{0x32} + val, proof, err := tree.GetWithProof(key) + require.NoError(err) + require.NotEmpty(val) + require.NotNil(proof) + + err = proof.VerifyItem(key, val) + require.Error(err, "%+v", err) // Verifying item before calling Verify(root) + + err = proof.Verify(root) + require.NoError(err, "%+v", err) + + err = proof.VerifyItem(key, val) + require.NoError(err, "%+v", err) + + key = []byte{0x1} + val, proof, err = tree.GetWithProof(key) + require.NoError(err) + require.Empty(val) + require.NotNil(proof) + + err = proof.VerifyAbsence(key) + require.Error(err, "%+v", err) // Verifying absence before calling Verify(root) + + err = proof.Verify(root) + require.NoError(err, "%+v", err) + + err = proof.VerifyAbsence(key) + require.NoError(err, "%+v", err) +} + +func TestTreeKeyExistsProof(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + root, err := tree.WorkingHash() + require.NoError(t, err) + + // should get false for proof with nil root + proof, keys, values, err := tree.getRangeProof([]byte("foo"), nil, 1) + assert.Nil(t, proof) + assert.Error(t, proof.Verify(root)) + assert.Nil(t, keys) + assert.Nil(t, values) + assert.NoError(t, err) + + // insert lots of info and store the bytes + allkeys := make([][]byte, 200) + for i := 0; i < 200; i++ { + key := iavlrand.RandStr(20) + value := "value_for_" + key + tree.Set([]byte(key), []byte(value)) + allkeys[i] = []byte(key) + } + sortByteSlices(allkeys) // Sort all keys + root, err = tree.WorkingHash() + require.NoError(t, err) + + // query random key fails + proof, _, _, err = tree.getRangeProof([]byte("foo"), nil, 2) + assert.Nil(t, err) + assert.Nil(t, proof.Verify(root)) + assert.Nil(t, proof.VerifyAbsence([]byte("foo")), proof.String()) + + // query min key fails + proof, _, _, err = tree.getRangeProof([]byte{0x00}, []byte{0x01}, 2) + assert.Nil(t, err) + assert.Nil(t, proof.Verify(root)) + assert.Nil(t, proof.VerifyAbsence([]byte{0x00})) + + // valid proof for real keys + for i, key := range allkeys { + var keys, values [][]byte + proof, keys, values, err = tree.getRangeProof(key, nil, 2) + require.Nil(t, err) + + require.Equal(t, + append([]byte("value_for_"), key...), + values[0], + ) + require.Equal(t, key, keys[0]) + require.Nil(t, proof.Verify(root)) + require.Nil(t, proof.VerifyAbsence(cpIncr(key))) + require.Equal(t, 1, len(keys), proof.String()) + require.Equal(t, 1, len(values), proof.String()) + if i < len(allkeys)-1 { + if i < len(allkeys)-2 { + // No last item... not a proof of absence of large key. + require.NotNil(t, proof.VerifyAbsence(bytes.Repeat([]byte{0xFF}, 20)), proof.String()) + } else { + // Last item is included. + require.Nil(t, proof.VerifyAbsence(bytes.Repeat([]byte{0xFF}, 20))) + } + } else { + // last item of tree... valid proof of absence of large key. + require.Nil(t, proof.VerifyAbsence(bytes.Repeat([]byte{0xFF}, 20))) + } + } + // TODO: Test with single value in tree. +} + +func TestTreeKeyInRangeProofs(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + require := require.New(t) + keys := []byte{0x0a, 0x11, 0x2e, 0x32, 0x50, 0x72, 0x99, 0xa1, 0xe4, 0xf7} // 10 total. + for _, ikey := range keys { + key := []byte{ikey} + tree.Set(key, key) + } + root, err := tree.WorkingHash() + require.NoError(err) + + // For spacing: + T := 10 + // disable: don't use underscores in Go names; var nil______ should be nil (golint) + // nolint + nil______ := []byte(nil) + + cases := []struct { // nolint:maligned + start byte + end byte + pkeys []byte // proof keys, one byte per key. + vals []byte // keys and values, one byte per key. + lidx int64 // proof left index (index of first proof key). + err bool // does error + }{ + {start: 0x0a, end: 0xf7, pkeys: keys[0:T], vals: keys[0:9], lidx: 0}, // #0 + {start: 0x0a, end: 0xf8, pkeys: keys[0:T], vals: keys[0:T], lidx: 0}, // #1 + {start: 0x00, end: 0xff, pkeys: keys[0:T], vals: keys[0:T], lidx: 0}, // #2 + {start: 0x14, end: 0xe4, pkeys: keys[1:9], vals: keys[2:8], lidx: 1}, // #3 + {start: 0x14, end: 0xe5, pkeys: keys[1:9], vals: keys[2:9], lidx: 1}, // #4 + {start: 0x14, end: 0xe6, pkeys: keys[1:T], vals: keys[2:9], lidx: 1}, // #5 + {start: 0x14, end: 0xf1, pkeys: keys[1:T], vals: keys[2:9], lidx: 1}, // #6 + {start: 0x14, end: 0xf7, pkeys: keys[1:T], vals: keys[2:9], lidx: 1}, // #7 + {start: 0x14, end: 0xff, pkeys: keys[1:T], vals: keys[2:T], lidx: 1}, // #8 + {start: 0x2e, end: 0x31, pkeys: keys[2:4], vals: keys[2:3], lidx: 2}, // #9 + {start: 0x2e, end: 0x32, pkeys: keys[2:4], vals: keys[2:3], lidx: 2}, // #10 + {start: 0x2f, end: 0x32, pkeys: keys[2:4], vals: nil______, lidx: 2}, // #11 + {start: 0x2e, end: 0x31, pkeys: keys[2:4], vals: keys[2:3], lidx: 2}, // #12 + {start: 0x2e, end: 0x2f, pkeys: keys[2:3], vals: keys[2:3], lidx: 2}, // #13 + {start: 0x12, end: 0x31, pkeys: keys[1:4], vals: keys[2:3], lidx: 1}, // #14 + {start: 0xf8, end: 0xff, pkeys: keys[9:T], vals: nil______, lidx: 9}, // #15 + {start: 0x12, end: 0x20, pkeys: keys[1:3], vals: nil______, lidx: 1}, // #16 + {start: 0x00, end: 0x09, pkeys: keys[0:1], vals: nil______, lidx: 0}, // #17 + {start: 0xf7, end: 0x00, err: true}, // #18 + {start: 0xf8, end: 0x00, err: true}, // #19 + {start: 0x10, end: 0x10, err: true}, // #20 + {start: 0x12, end: 0x12, err: true}, // #21 + {start: 0xff, end: 0xf7, err: true}, // #22 + } + + // fmt.Println("PRINT TREE") + // printNode(tree.ndb, tree.root, 0) + // fmt.Println("PRINT TREE END") + + for i, c := range cases { + t.Logf("case %v", i) + start := []byte{c.start} + end := []byte{c.end} + + // Compute range proof. + keys, values, proof, err := tree.GetRangeWithProof(start, end, 0) + + if c.err { + require.Error(err, "%+v", err) + } else { + require.NoError(err, "%+v", err) + require.Equal(c.pkeys, flatten(proof.Keys())) + require.Equal(c.vals, flatten(keys)) + require.Equal(c.vals, flatten(values)) + require.Equal(c.lidx, proof.LeftIndex()) + + // Verify that proof is valid. + err = proof.Verify(root) + require.NoError(err, "%+v", err) + verifyProof(t, proof, root) + + // Verify each value of pkeys. + for _, key := range c.pkeys { + err := proof.VerifyItem([]byte{key}, []byte{key}) + require.NoError(err) + } + + // Verify each value of vals. + for _, key := range c.vals { + err := proof.VerifyItem([]byte{key}, []byte{key}) + require.NoError(err) + } + } + + } +} + +func encodeProof(proof *RangeProof) ([]byte, error) { + return proto.Marshal(proof.ToProto()) +} + +func decodeProof(bz []byte) (*RangeProof, error) { + proofOp := &iavlproto.RangeProof{} + err := proto.Unmarshal(bz, proofOp) + if err != nil { + return nil, err + } + proof, err := RangeProofFromProto(proofOp) + return &proof, err +} + +func verifyProof(t *testing.T, proof *RangeProof, root []byte) { + // Proof must verify. + require.NoError(t, proof.Verify(root)) + + // Write/Read then verify. + proofBytes, err := encodeProof(proof) + require.NoError(t, err) + _, err = decodeProof(proofBytes) + require.NoError(t, err) + + // Random mutations must not verify + for i := 0; i < 1e4; i++ { + badProofBytes := MutateByteSlice(proofBytes) + badProof, err := decodeProof(badProofBytes) + if err != nil { + continue // couldn't even decode. + } + // re-encode to make sure it's actually different. + badProofBytes2, err := encodeProof(badProof) + if bytes.Equal(proofBytes, badProofBytes2) { + continue // didn't mutate successfully. + } + // may be invalid... errors are okay + if err == nil { + assert.Errorf(t, badProof.Verify(root), + "Proof was still valid after a random mutation:\n%X\n%X", + proofBytes, badProofBytes) + } + } +} + +//---------------------------------------- + +func flatten(bzz [][]byte) (res []byte) { + for _, bz := range bzz { + res = append(res, bz...) + } + return res +} + +// Contract: !bytes.Equal(input, output) && len(input) >= len(output) +func MutateByteSlice(bytez []byte) []byte { + // If bytez is empty, panic + if len(bytez) == 0 { + panic("Cannot mutate an empty bytez") + } + + // Copy bytez + mBytez := make([]byte, len(bytez)) + copy(mBytez, bytez) + bytez = mBytez + + // Try a random mutation + switch iavlrand.RandInt() % 2 { + case 0: // Mutate a single byte + bytez[iavlrand.RandInt()%len(bytez)] += byte(iavlrand.RandInt()%255 + 1) + case 1: // Remove an arbitrary byte + pos := iavlrand.RandInt() % len(bytez) + bytez = append(bytez[:pos], bytez[pos+1:]...) + } + return bytez +} + +func sortByteSlices(src [][]byte) [][]byte { + bzz := byteslices(src) + sort.Sort(bzz) + return bzz +} + +type byteslices [][]byte + +func (bz byteslices) Len() int { + return len(bz) +} + +func (bz byteslices) Less(i, j int) bool { + switch bytes.Compare(bz[i], bz[j]) { + case -1: + return true + case 0, 1: + return false + default: + panic("should not happen") + } +} + +//nolint:unused +func (bz byteslices) Swap(i, j int) { + bz[j], bz[i] = bz[i], bz[j] +} diff --git a/sei-iavl/proto/iavl/proof.proto b/sei-iavl/proto/iavl/proof.proto new file mode 100644 index 0000000000..dc94c2d35b --- /dev/null +++ b/sei-iavl/proto/iavl/proof.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; +package iavl; + +option go_package = "proto"; + +// ValueOp is a Protobuf representation of iavl.ValueOp. +message ValueOp { + RangeProof proof = 1; +} + +// AbsenceOp is a Protobuf representation of iavl.AbsenceOp. +message AbsenceOp { + RangeProof proof = 1; +} + +// RangeProof is a Protobuf representation of iavl.RangeProof. +message RangeProof { + repeated ProofInnerNode left_path = 1; + repeated PathToLeaf inner_nodes = 2; + repeated ProofLeafNode leaves = 3; +} + +// PathToLeaf is a Protobuf representation of iavl.PathToLeaf. +message PathToLeaf { + repeated ProofInnerNode inners = 1; +} + +// ProofInnerNode is a Protobuf representation of iavl.ProofInnerNode. +message ProofInnerNode { + sint32 height = 1; + int64 size = 2; + int64 version = 3; + bytes left = 4; + bytes right = 5; +} + +// ProofLeafNode is a Protobuf representation of iavl.ProofInnerNode. +message ProofLeafNode { + bytes key = 1; + bytes value_hash = 2; + int64 version = 3; +} diff --git a/sei-iavl/proto/proof.pb.go b/sei-iavl/proto/proof.pb.go new file mode 100644 index 0000000000..35bbbff0ac --- /dev/null +++ b/sei-iavl/proto/proof.pb.go @@ -0,0 +1,1618 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: iavl/proof.proto + +package proto + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ValueOp is a Protobuf representation of iavl.ValueOp. +type ValueOp struct { + Proof *RangeProof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof,omitempty"` +} + +func (m *ValueOp) Reset() { *m = ValueOp{} } +func (m *ValueOp) String() string { return proto.CompactTextString(m) } +func (*ValueOp) ProtoMessage() {} +func (*ValueOp) Descriptor() ([]byte, []int) { + return fileDescriptor_92b2514a05d2a2db, []int{0} +} +func (m *ValueOp) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValueOp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValueOp.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ValueOp) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValueOp.Merge(m, src) +} +func (m *ValueOp) XXX_Size() int { + return m.Size() +} +func (m *ValueOp) XXX_DiscardUnknown() { + xxx_messageInfo_ValueOp.DiscardUnknown(m) +} + +var xxx_messageInfo_ValueOp proto.InternalMessageInfo + +func (m *ValueOp) GetProof() *RangeProof { + if m != nil { + return m.Proof + } + return nil +} + +// AbsenceOp is a Protobuf representation of iavl.AbsenceOp. +type AbsenceOp struct { + Proof *RangeProof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof,omitempty"` +} + +func (m *AbsenceOp) Reset() { *m = AbsenceOp{} } +func (m *AbsenceOp) String() string { return proto.CompactTextString(m) } +func (*AbsenceOp) ProtoMessage() {} +func (*AbsenceOp) Descriptor() ([]byte, []int) { + return fileDescriptor_92b2514a05d2a2db, []int{1} +} +func (m *AbsenceOp) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AbsenceOp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AbsenceOp.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AbsenceOp) XXX_Merge(src proto.Message) { + xxx_messageInfo_AbsenceOp.Merge(m, src) +} +func (m *AbsenceOp) XXX_Size() int { + return m.Size() +} +func (m *AbsenceOp) XXX_DiscardUnknown() { + xxx_messageInfo_AbsenceOp.DiscardUnknown(m) +} + +var xxx_messageInfo_AbsenceOp proto.InternalMessageInfo + +func (m *AbsenceOp) GetProof() *RangeProof { + if m != nil { + return m.Proof + } + return nil +} + +// RangeProof is a Protobuf representation of iavl.RangeProof. +type RangeProof struct { + LeftPath []*ProofInnerNode `protobuf:"bytes,1,rep,name=left_path,json=leftPath,proto3" json:"left_path,omitempty"` + InnerNodes []*PathToLeaf `protobuf:"bytes,2,rep,name=inner_nodes,json=innerNodes,proto3" json:"inner_nodes,omitempty"` + Leaves []*ProofLeafNode `protobuf:"bytes,3,rep,name=leaves,proto3" json:"leaves,omitempty"` +} + +func (m *RangeProof) Reset() { *m = RangeProof{} } +func (m *RangeProof) String() string { return proto.CompactTextString(m) } +func (*RangeProof) ProtoMessage() {} +func (*RangeProof) Descriptor() ([]byte, []int) { + return fileDescriptor_92b2514a05d2a2db, []int{2} +} +func (m *RangeProof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RangeProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RangeProof.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RangeProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_RangeProof.Merge(m, src) +} +func (m *RangeProof) XXX_Size() int { + return m.Size() +} +func (m *RangeProof) XXX_DiscardUnknown() { + xxx_messageInfo_RangeProof.DiscardUnknown(m) +} + +var xxx_messageInfo_RangeProof proto.InternalMessageInfo + +func (m *RangeProof) GetLeftPath() []*ProofInnerNode { + if m != nil { + return m.LeftPath + } + return nil +} + +func (m *RangeProof) GetInnerNodes() []*PathToLeaf { + if m != nil { + return m.InnerNodes + } + return nil +} + +func (m *RangeProof) GetLeaves() []*ProofLeafNode { + if m != nil { + return m.Leaves + } + return nil +} + +// PathToLeaf is a Protobuf representation of iavl.PathToLeaf. +type PathToLeaf struct { + Inners []*ProofInnerNode `protobuf:"bytes,1,rep,name=inners,proto3" json:"inners,omitempty"` +} + +func (m *PathToLeaf) Reset() { *m = PathToLeaf{} } +func (m *PathToLeaf) String() string { return proto.CompactTextString(m) } +func (*PathToLeaf) ProtoMessage() {} +func (*PathToLeaf) Descriptor() ([]byte, []int) { + return fileDescriptor_92b2514a05d2a2db, []int{3} +} +func (m *PathToLeaf) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PathToLeaf) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PathToLeaf.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PathToLeaf) XXX_Merge(src proto.Message) { + xxx_messageInfo_PathToLeaf.Merge(m, src) +} +func (m *PathToLeaf) XXX_Size() int { + return m.Size() +} +func (m *PathToLeaf) XXX_DiscardUnknown() { + xxx_messageInfo_PathToLeaf.DiscardUnknown(m) +} + +var xxx_messageInfo_PathToLeaf proto.InternalMessageInfo + +func (m *PathToLeaf) GetInners() []*ProofInnerNode { + if m != nil { + return m.Inners + } + return nil +} + +// ProofInnerNode is a Protobuf representation of iavl.ProofInnerNode. +type ProofInnerNode struct { + Height int32 `protobuf:"zigzag32,1,opt,name=height,proto3" json:"height,omitempty"` + Size_ int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` + Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` + Left []byte `protobuf:"bytes,4,opt,name=left,proto3" json:"left,omitempty"` + Right []byte `protobuf:"bytes,5,opt,name=right,proto3" json:"right,omitempty"` +} + +func (m *ProofInnerNode) Reset() { *m = ProofInnerNode{} } +func (m *ProofInnerNode) String() string { return proto.CompactTextString(m) } +func (*ProofInnerNode) ProtoMessage() {} +func (*ProofInnerNode) Descriptor() ([]byte, []int) { + return fileDescriptor_92b2514a05d2a2db, []int{4} +} +func (m *ProofInnerNode) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ProofInnerNode) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ProofInnerNode.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ProofInnerNode) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProofInnerNode.Merge(m, src) +} +func (m *ProofInnerNode) XXX_Size() int { + return m.Size() +} +func (m *ProofInnerNode) XXX_DiscardUnknown() { + xxx_messageInfo_ProofInnerNode.DiscardUnknown(m) +} + +var xxx_messageInfo_ProofInnerNode proto.InternalMessageInfo + +func (m *ProofInnerNode) GetHeight() int32 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *ProofInnerNode) GetSize_() int64 { + if m != nil { + return m.Size_ + } + return 0 +} + +func (m *ProofInnerNode) GetVersion() int64 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *ProofInnerNode) GetLeft() []byte { + if m != nil { + return m.Left + } + return nil +} + +func (m *ProofInnerNode) GetRight() []byte { + if m != nil { + return m.Right + } + return nil +} + +// ProofLeafNode is a Protobuf representation of iavl.ProofInnerNode. +type ProofLeafNode struct { + Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + ValueHash []byte `protobuf:"bytes,2,opt,name=value_hash,json=valueHash,proto3" json:"value_hash,omitempty"` + Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` +} + +func (m *ProofLeafNode) Reset() { *m = ProofLeafNode{} } +func (m *ProofLeafNode) String() string { return proto.CompactTextString(m) } +func (*ProofLeafNode) ProtoMessage() {} +func (*ProofLeafNode) Descriptor() ([]byte, []int) { + return fileDescriptor_92b2514a05d2a2db, []int{5} +} +func (m *ProofLeafNode) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ProofLeafNode) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ProofLeafNode.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ProofLeafNode) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProofLeafNode.Merge(m, src) +} +func (m *ProofLeafNode) XXX_Size() int { + return m.Size() +} +func (m *ProofLeafNode) XXX_DiscardUnknown() { + xxx_messageInfo_ProofLeafNode.DiscardUnknown(m) +} + +var xxx_messageInfo_ProofLeafNode proto.InternalMessageInfo + +func (m *ProofLeafNode) GetKey() []byte { + if m != nil { + return m.Key + } + return nil +} + +func (m *ProofLeafNode) GetValueHash() []byte { + if m != nil { + return m.ValueHash + } + return nil +} + +func (m *ProofLeafNode) GetVersion() int64 { + if m != nil { + return m.Version + } + return 0 +} + +func init() { + proto.RegisterType((*ValueOp)(nil), "iavl.ValueOp") + proto.RegisterType((*AbsenceOp)(nil), "iavl.AbsenceOp") + proto.RegisterType((*RangeProof)(nil), "iavl.RangeProof") + proto.RegisterType((*PathToLeaf)(nil), "iavl.PathToLeaf") + proto.RegisterType((*ProofInnerNode)(nil), "iavl.ProofInnerNode") + proto.RegisterType((*ProofLeafNode)(nil), "iavl.ProofLeafNode") +} + +func init() { proto.RegisterFile("iavl/proof.proto", fileDescriptor_92b2514a05d2a2db) } + +var fileDescriptor_92b2514a05d2a2db = []byte{ + // 373 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xb1, 0x4e, 0xe3, 0x40, + 0x10, 0x86, 0xb3, 0x71, 0xec, 0x5c, 0x26, 0xb9, 0x53, 0x6e, 0x2f, 0x3a, 0x6d, 0x73, 0x3e, 0xcb, + 0x05, 0xb2, 0x04, 0x0a, 0x4a, 0xd2, 0xd1, 0x41, 0x05, 0x12, 0x82, 0x68, 0x85, 0x28, 0xd2, 0x44, + 0x1b, 0xb2, 0x89, 0x2d, 0x2c, 0xaf, 0xe5, 0x35, 0x96, 0xa0, 0xe2, 0x11, 0x78, 0x03, 0x5e, 0x87, + 0x32, 0x25, 0x25, 0x4a, 0x5e, 0x04, 0xed, 0xc4, 0x51, 0x48, 0x01, 0x12, 0x95, 0x67, 0xfe, 0xf9, + 0x66, 0xfe, 0xf1, 0xd8, 0xd0, 0x8e, 0x44, 0x11, 0x1f, 0xa6, 0x99, 0x52, 0xb3, 0x6e, 0x9a, 0xa9, + 0x5c, 0xd1, 0x9a, 0x51, 0xfc, 0x1e, 0xd4, 0xaf, 0x45, 0x7c, 0x27, 0x2f, 0x53, 0xba, 0x07, 0x36, + 0xd6, 0x19, 0xf1, 0x48, 0xd0, 0xec, 0xb7, 0xbb, 0x06, 0xe8, 0x72, 0x91, 0xcc, 0xe5, 0xd0, 0xe8, + 0x7c, 0x5d, 0xf6, 0x07, 0xd0, 0x38, 0x9e, 0x68, 0x99, 0xdc, 0x7c, 0xa7, 0xe9, 0x99, 0x00, 0x6c, + 0x55, 0xda, 0x83, 0x46, 0x2c, 0x67, 0xf9, 0x38, 0x15, 0x79, 0xc8, 0x88, 0x67, 0x05, 0xcd, 0x7e, + 0x67, 0xdd, 0x8a, 0xf5, 0xb3, 0x24, 0x91, 0xd9, 0x85, 0x9a, 0x4a, 0xfe, 0xc3, 0x60, 0x43, 0x91, + 0x87, 0xb4, 0x07, 0xcd, 0xc8, 0xc8, 0xe3, 0x44, 0x4d, 0xa5, 0x66, 0x55, 0x6c, 0x2a, 0xfd, 0x0c, + 0x70, 0xa5, 0xce, 0xa5, 0x98, 0x71, 0x88, 0x36, 0xbd, 0x9a, 0xee, 0x83, 0x13, 0x4b, 0x51, 0x48, + 0xcd, 0x2c, 0xa4, 0xff, 0x7c, 0xb0, 0x30, 0x30, 0x3a, 0x94, 0x88, 0x7f, 0x04, 0xb0, 0x1d, 0x43, + 0x0f, 0xc0, 0xc1, 0x41, 0xfa, 0xcb, 0xed, 0x4a, 0xc6, 0x7f, 0x24, 0xf0, 0x6b, 0xb7, 0x44, 0xff, + 0x82, 0x13, 0xca, 0x68, 0x1e, 0xe6, 0x78, 0x99, 0xdf, 0xbc, 0xcc, 0x28, 0x85, 0x9a, 0x8e, 0x1e, + 0x24, 0xab, 0x7a, 0x24, 0xb0, 0x38, 0xc6, 0x94, 0x41, 0xbd, 0x90, 0x99, 0x8e, 0x54, 0xc2, 0x2c, + 0x94, 0x37, 0xa9, 0xa1, 0xcd, 0x01, 0x58, 0xcd, 0x23, 0x41, 0x8b, 0x63, 0x4c, 0x3b, 0x60, 0x67, + 0x38, 0xd8, 0x46, 0x71, 0x9d, 0xf8, 0x23, 0xf8, 0xb9, 0xf3, 0x5e, 0xb4, 0x0d, 0xd6, 0xad, 0xbc, + 0x47, 0xf7, 0x16, 0x37, 0x21, 0xfd, 0x07, 0x50, 0x98, 0x6f, 0x3d, 0x0e, 0x85, 0x0e, 0x71, 0x81, + 0x16, 0x6f, 0xa0, 0x72, 0x2a, 0x74, 0xf8, 0xf9, 0x16, 0x27, 0xff, 0x5f, 0x96, 0x2e, 0x59, 0x2c, + 0x5d, 0xf2, 0xb6, 0x74, 0xc9, 0xd3, 0xca, 0xad, 0x2c, 0x56, 0x6e, 0xe5, 0x75, 0xe5, 0x56, 0x46, + 0x36, 0xfe, 0x4b, 0x13, 0x07, 0x1f, 0x83, 0xf7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x60, 0x25, + 0x89, 0x66, 0x02, 0x00, 0x00, +} + +func (m *ValueOp) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ValueOp) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValueOp) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Proof != nil { + { + size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProof(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AbsenceOp) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AbsenceOp) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AbsenceOp) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Proof != nil { + { + size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProof(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RangeProof) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RangeProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RangeProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Leaves) > 0 { + for iNdEx := len(m.Leaves) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Leaves[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProof(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.InnerNodes) > 0 { + for iNdEx := len(m.InnerNodes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InnerNodes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProof(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.LeftPath) > 0 { + for iNdEx := len(m.LeftPath) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.LeftPath[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProof(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *PathToLeaf) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PathToLeaf) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PathToLeaf) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Inners) > 0 { + for iNdEx := len(m.Inners) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Inners[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProof(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ProofInnerNode) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ProofInnerNode) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ProofInnerNode) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Right) > 0 { + i -= len(m.Right) + copy(dAtA[i:], m.Right) + i = encodeVarintProof(dAtA, i, uint64(len(m.Right))) + i-- + dAtA[i] = 0x2a + } + if len(m.Left) > 0 { + i -= len(m.Left) + copy(dAtA[i:], m.Left) + i = encodeVarintProof(dAtA, i, uint64(len(m.Left))) + i-- + dAtA[i] = 0x22 + } + if m.Version != 0 { + i = encodeVarintProof(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x18 + } + if m.Size_ != 0 { + i = encodeVarintProof(dAtA, i, uint64(m.Size_)) + i-- + dAtA[i] = 0x10 + } + if m.Height != 0 { + i = encodeVarintProof(dAtA, i, uint64((uint32(m.Height)<<1)^uint32((m.Height>>31)))) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ProofLeafNode) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ProofLeafNode) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ProofLeafNode) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintProof(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x18 + } + if len(m.ValueHash) > 0 { + i -= len(m.ValueHash) + copy(dAtA[i:], m.ValueHash) + i = encodeVarintProof(dAtA, i, uint64(len(m.ValueHash))) + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintProof(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintProof(dAtA []byte, offset int, v uint64) int { + offset -= sovProof(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ValueOp) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Proof != nil { + l = m.Proof.Size() + n += 1 + l + sovProof(uint64(l)) + } + return n +} + +func (m *AbsenceOp) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Proof != nil { + l = m.Proof.Size() + n += 1 + l + sovProof(uint64(l)) + } + return n +} + +func (m *RangeProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.LeftPath) > 0 { + for _, e := range m.LeftPath { + l = e.Size() + n += 1 + l + sovProof(uint64(l)) + } + } + if len(m.InnerNodes) > 0 { + for _, e := range m.InnerNodes { + l = e.Size() + n += 1 + l + sovProof(uint64(l)) + } + } + if len(m.Leaves) > 0 { + for _, e := range m.Leaves { + l = e.Size() + n += 1 + l + sovProof(uint64(l)) + } + } + return n +} + +func (m *PathToLeaf) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Inners) > 0 { + for _, e := range m.Inners { + l = e.Size() + n += 1 + l + sovProof(uint64(l)) + } + } + return n +} + +func (m *ProofInnerNode) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sozProof(uint64(m.Height)) + } + if m.Size_ != 0 { + n += 1 + sovProof(uint64(m.Size_)) + } + if m.Version != 0 { + n += 1 + sovProof(uint64(m.Version)) + } + l = len(m.Left) + if l > 0 { + n += 1 + l + sovProof(uint64(l)) + } + l = len(m.Right) + if l > 0 { + n += 1 + l + sovProof(uint64(l)) + } + return n +} + +func (m *ProofLeafNode) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovProof(uint64(l)) + } + l = len(m.ValueHash) + if l > 0 { + n += 1 + l + sovProof(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovProof(uint64(m.Version)) + } + return n +} + +func sovProof(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozProof(x uint64) (n int) { + return sovProof(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ValueOp) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ValueOp: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValueOp: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Proof == nil { + m.Proof = &RangeProof{} + } + if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProof(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AbsenceOp) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AbsenceOp: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AbsenceOp: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Proof == nil { + m.Proof = &RangeProof{} + } + if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProof(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RangeProof) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RangeProof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RangeProof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LeftPath", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LeftPath = append(m.LeftPath, &ProofInnerNode{}) + if err := m.LeftPath[len(m.LeftPath)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InnerNodes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InnerNodes = append(m.InnerNodes, &PathToLeaf{}) + if err := m.InnerNodes[len(m.InnerNodes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Leaves", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Leaves = append(m.Leaves, &ProofLeafNode{}) + if err := m.Leaves[len(m.Leaves)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProof(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PathToLeaf) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PathToLeaf: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PathToLeaf: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Inners", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Inners = append(m.Inners, &ProofInnerNode{}) + if err := m.Inners[len(m.Inners)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProof(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ProofInnerNode) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ProofInnerNode: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ProofInnerNode: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + v = int32((uint32(v) >> 1) ^ uint32(((v&1)<<31)>>31)) + m.Height = v + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) + } + m.Size_ = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size_ |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Left", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Left = append(m.Left[:0], dAtA[iNdEx:postIndex]...) + if m.Left == nil { + m.Left = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Right", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Right = append(m.Right[:0], dAtA[iNdEx:postIndex]...) + if m.Right == nil { + m.Right = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProof(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ProofLeafNode) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ProofLeafNode: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ProofLeafNode: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValueHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProof + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProof + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValueHash = append(m.ValueHash[:0], dAtA[iNdEx:postIndex]...) + if m.ValueHash == nil { + m.ValueHash = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProof + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipProof(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProof + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipProof(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProof + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProof + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProof + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthProof + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupProof + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthProof + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthProof = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowProof = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupProof = fmt.Errorf("proto: unexpected end of group") +) diff --git a/sei-iavl/repair.go b/sei-iavl/repair.go new file mode 100644 index 0000000000..952e9ff9bd --- /dev/null +++ b/sei-iavl/repair.go @@ -0,0 +1,69 @@ +package iavl + +import ( + "math" + + "github.com/pkg/errors" + dbm "github.com/tendermint/tm-db" +) + +// Repair013Orphans repairs incorrect orphan entries written by IAVL 0.13 pruning. To use it, close +// a database using IAVL 0.13, make a backup copy, and then run this function before opening the +// database with IAVL 0.14 or later. It returns the number of faulty orphan entries removed. If the +// 0.13 database was written with KeepEvery:1 (the default) or the last version _ever_ saved to the +// tree was a multiple of `KeepEvery` and thus saved to disk, this repair is not necessary. +// +// Note that this cannot be used directly on Cosmos SDK databases, since they store multiple IAVL +// trees in the same underlying database via a prefix scheme. +// +// The pruning functionality enabled with Options.KeepEvery > 1 would write orphans entries to disk +// for versions that should only have been saved in memory, and these orphan entries were clamped +// to the last version persisted to disk instead of the version that generated them (so a delete at +// version 749 might generate an orphan entry ending at version 700 for KeepEvery:100). If the +// database is reopened at the last persisted version and this version is later deleted, the +// orphaned nodes can be deleted prematurely or incorrectly, causing data loss and database +// corruption. +// +// This function removes these incorrect orphan entries by deleting all orphan entries that have a +// to-version equal to or greater than the latest persisted version. Correct orphans will never +// have this, since they must have been deleted in a future (non-existent) version for that to be +// the case. +func Repair013Orphans(db dbm.DB) (uint64, error) { + ndb := newNodeDB(db, 0, &Options{Sync: true}) + version, err := ndb.getLatestVersion() + if err != nil { + return 0, err + } + if version == 0 { + return 0, errors.New("no versions found") + } + + var repaired uint64 + batch := db.NewBatch() + defer batch.Close() + err = ndb.traverseRange(orphanKeyFormat.Key(version), orphanKeyFormat.Key(int64(math.MaxInt64)), func(k, v []byte) error { + // Sanity check so we don't remove stuff we shouldn't + var toVersion int64 + orphanKeyFormat.Scan(k, &toVersion) + if toVersion < version { + err = errors.Errorf("Found unexpected orphan with toVersion=%v, lesser than latest version %v", + toVersion, version) + return err + } + repaired++ + err = batch.Delete(k) + if err != nil { + return err + } + return nil + }) + if err != nil { + return 0, err + } + err = batch.WriteSync() + if err != nil { + return 0, err + } + + return repaired, nil +} diff --git a/sei-iavl/repair_test.go b/sei-iavl/repair_test.go new file mode 100644 index 0000000000..8d17355e0a --- /dev/null +++ b/sei-iavl/repair_test.go @@ -0,0 +1,197 @@ +package iavl + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" +) + +func TestRepair013Orphans(t *testing.T) { + dir, err := ioutil.TempDir("", "test-iavl-repair") + require.NoError(t, err) + defer os.RemoveAll(dir) + + // There is also 0.13-orphans-v6.db containing a database closed immediately after writing + // version 6, which should not contain any broken orphans. + err = copyDB("testdata/0.13-orphans.db", filepath.Join(dir, "0.13-orphans.db")) + require.NoError(t, err) + + db, err := dbm.NewGoLevelDB("0.13-orphans", dir) + require.NoError(t, err) + + // Repair the database. + repaired, err := Repair013Orphans(db) + require.NoError(t, err) + assert.EqualValues(t, 8, repaired) + + // Load the database. + tree, err := NewMutableTreeWithOpts(db, 0, &Options{Sync: true}, false) + require.NoError(t, err) + version, err := tree.Load() + require.NoError(t, err) + require.EqualValues(t, 6, version) + + // We now generate two empty versions, and check all persisted versions. + _, version, err = tree.SaveVersion() + require.NoError(t, err) + require.EqualValues(t, 7, version) + _, version, err = tree.SaveVersion() + require.NoError(t, err) + require.EqualValues(t, 8, version) + + // Check all persisted versions. + require.Equal(t, []int{3, 6, 7, 8}, tree.AvailableVersions()) + assertVersion(t, tree, 0) + assertVersion(t, tree, 3) + assertVersion(t, tree, 6) + assertVersion(t, tree, 7) + assertVersion(t, tree, 8) + + // We then delete version 6 (the last persisted one with 0.13). + err = tree.DeleteVersion(6) + require.NoError(t, err) + + // Reading "rm7" (which should not have been deleted now) would panic with a broken database. + value, err := tree.Get([]byte("rm7")) + require.NoError(t, err) + require.Equal(t, []byte{1}, value) + + // Check all persisted versions. + require.Equal(t, []int{3, 7, 8}, tree.AvailableVersions()) + assertVersion(t, tree, 0) + assertVersion(t, tree, 3) + assertVersion(t, tree, 7) + assertVersion(t, tree, 8) + + // Delete all historical versions, and check the latest. + err = tree.DeleteVersion(3) + require.NoError(t, err) + err = tree.DeleteVersion(7) + require.NoError(t, err) + + require.Equal(t, []int{8}, tree.AvailableVersions()) + assertVersion(t, tree, 0) + assertVersion(t, tree, 8) +} + +// assertVersion checks the given version (or current if 0) against the expected values. +func assertVersion(t *testing.T, tree *MutableTree, version int64) { + var err error + itree := tree.ImmutableTree + if version > 0 { + itree, err = tree.GetImmutable(version) + require.NoError(t, err) + } + version = itree.version + + // The "current" value should have the current version for <= 6, then 6 afterwards + value, err := itree.Get([]byte("current")) + require.NoError(t, err) + if version >= 6 { + require.EqualValues(t, []byte{6}, value) + } else { + require.EqualValues(t, []byte{byte(version)}, value) + } + + // The "addX" entries should exist for 1-6 in the respective versions, and the + // "rmX" entries should have been removed for 1-6 in the respective versions. + for i := byte(1); i < 8; i++ { + value, err = itree.Get([]byte(fmt.Sprintf("add%v", i))) + require.NoError(t, err) + if i <= 6 && int64(i) <= version { + require.Equal(t, []byte{i}, value) + } else { + require.Nil(t, value) + } + + value, err = itree.Get([]byte(fmt.Sprintf("rm%v", i))) + require.NoError(t, err) + if i <= 6 && version >= int64(i) { + require.Nil(t, value) + } else { + require.Equal(t, []byte{1}, value) + } + } +} + +// Generate013Orphans generates a GoLevelDB orphan database in testdata/0.13-orphans.db +// for testing Repair013Orphans(). It must be run with IAVL 0.13.x. +/*func TestGenerate013Orphans(t *testing.T) { + err := os.RemoveAll("testdata/0.13-orphans.db") + require.NoError(t, err) + db, err := dbm.NewGoLevelDB("0.13-orphans", "testdata") + require.NoError(t, err) + tree, err := NewMutableTreeWithOpts(db, dbm.NewMemDB(), 0, &Options{ + KeepEvery: 3, + KeepRecent: 1, + Sync: true, + }) + require.NoError(t, err) + version, err := tree.Load() + require.NoError(t, err) + require.EqualValues(t, 0, version) + + // We generate 8 versions. In each version, we create a "addX" key, delete a "rmX" key, + // and update the "current" key, where "X" is the current version. Values are the version in + // which the key was last set. + tree.Set([]byte("rm1"), []byte{1}) + tree.Set([]byte("rm2"), []byte{1}) + tree.Set([]byte("rm3"), []byte{1}) + tree.Set([]byte("rm4"), []byte{1}) + tree.Set([]byte("rm5"), []byte{1}) + tree.Set([]byte("rm6"), []byte{1}) + tree.Set([]byte("rm7"), []byte{1}) + tree.Set([]byte("rm8"), []byte{1}) + + for v := byte(1); v <= 8; v++ { + tree.Set([]byte("current"), []byte{v}) + tree.Set([]byte(fmt.Sprintf("add%v", v)), []byte{v}) + tree.Remove([]byte(fmt.Sprintf("rm%v", v))) + _, version, err = tree.SaveVersion() + require.NoError(t, err) + require.EqualValues(t, v, version) + } + + // At this point, the database will contain incorrect orphans in version 6 that, when + // version 6 is deleted, will cause "current", "rm7", and "rm8" to go missing. +}*/ + +// copyDB makes a shallow copy of the source database directory. +func copyDB(src, dest string) error { + entries, err := ioutil.ReadDir(src) + if err != nil { + return err + } + err = os.MkdirAll(dest, 0777) + if err != nil { + return err + } + for _, entry := range entries { + out, err := os.Create(filepath.Join(dest, entry.Name())) + if err != nil { + return err + } + defer out.Close() + + in, err := os.Open(filepath.Join(src, entry.Name())) + defer func() { + in.Close() + }() + if err != nil { + return err + } + + _, err = io.Copy(out, in) + if err != nil { + return err + } + } + return nil +} diff --git a/sei-iavl/scripts/protocgen.sh b/sei-iavl/scripts/protocgen.sh new file mode 100644 index 0000000000..4bf62a2f2e --- /dev/null +++ b/sei-iavl/scripts/protocgen.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -eo pipefail + +buf generate --path proto/iavl + +mv ./proto/iavl/*.go ./proto diff --git a/sei-iavl/testdata/0.13-orphans-v6.db/000001.log b/sei-iavl/testdata/0.13-orphans-v6.db/000001.log new file mode 100644 index 0000000000000000000000000000000000000000..13bc49ab48d66ec10f0a1aa9c3fadff3086764e5 GIT binary patch literal 3590 zcmds3TU1j=6y?Gt#1y4GjUloBvd1S41kQBYd} zu}~2#snnKAe4z+}C=qNxKrJZMl`bP7k0MwlC_(My8vKE^#^3h-+@F1B?{nsyGuw+^ zBUq-7VLER<6ZpgC3;SqWXg!-q741oON~828nKh9aDcRByb_>1LfjqDBC`CtC7w7T$ z?idEq+<`l?a=FDfBg2lhQGvU$*XpZ7hX$Pj_#~HxnliBhqHzt{1Ji|Qb+&{X{SbWR z=qwwIvOaN8u8wJ*U4MRp+}x)eeJ`mqKo=(wXn;}yP{fdJ%i_yzVS-IYT?ZyA>c+1< zll&6;pps{B%!Nly-y{}Gpf-YSA*Kh>;d@Uq7xd^Hxq7xQM=bMqcwSLu9{gSysNUCg_B4cFhHdNP_$54TkGMXc4l}i zHRJbxHf(%($r2QITiDH9?evC zF83(Zf|&%E?|-4E!=va?9MiVVZ2Z2?;%Jk?YpM(#16uW&)H1fTD$I zaQ_O<Q;Pe zbh}+)=KL&1ScCJDWkn8*{UB5e_9nnazg7u`eC=KtXH?s?o>HbsLg>p&Pxk*Aw<=-I z=`qC#x-=!FZo$v*3l~}&tiQd|O?g}uJhrWbg_AWk z^8%>i0+eh>ChT_TQq)}xO-`(~^!Ui8bL9>zd(dni{Pg~U%KEC9Fc#TF)71=s>PUc+ zjm;8i_o5y^u^LPGLR=R!)dr9>i_|@CDtzjX>TGoDPd^hmyePm7I#HVly{e|^#85i~ zy=11HsfW51BagORa*|tgup3AJ?{Tki=nc-wJbvB*OYL5t0~uOSWyEKvwF+FYQBAzN9R zSkRsNw5istc9A-&=J97NJlBj(izw%wON`OGToHhi4K-{F(N8!^IAjZn@J{VYtzZ~G z%xTwm4*%FLk?}149Phi;rRq6@^-k+yC5YS@m_9_`D0oDRpC?(Bb9SsKx!7j!iugd$ zgSBCe1J?`IKH)TaLNuX`iIE^WZF435+(lk}ynCyUoYPVg7adK{I6@sbbTn$Rtgv(* ztlJwjK&b#IV#p?l@He+wP1|hIAz62?rOv6hQE@lcmWplN*clk&XxImBqv4bbB;?H& zzc4ZD%h^0$?_%NT7b$BQkVl57Cisfz4>qX%={1_Z&cY@ x_C@x3sxD<<*4IE*d2y{^BtJHQY(n%91EA&xpmfi$c2VXL?JnP%7ZO0F@-G-${zm`+ literal 0 HcmV?d00001 diff --git a/sei-iavl/testdata/0.13-orphans-v6.db/CURRENT b/sei-iavl/testdata/0.13-orphans-v6.db/CURRENT new file mode 100644 index 0000000000..feda7d6b24 --- /dev/null +++ b/sei-iavl/testdata/0.13-orphans-v6.db/CURRENT @@ -0,0 +1 @@ +MANIFEST-000000 diff --git a/sei-iavl/testdata/0.13-orphans-v6.db/LOCK b/sei-iavl/testdata/0.13-orphans-v6.db/LOCK new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sei-iavl/testdata/0.13-orphans-v6.db/LOG b/sei-iavl/testdata/0.13-orphans-v6.db/LOG new file mode 100644 index 0000000000..f890e80b8f --- /dev/null +++ b/sei-iavl/testdata/0.13-orphans-v6.db/LOG @@ -0,0 +1,6 @@ +=============== Jun 25, 2020 (CEST) =============== +14:30:10.673317 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +14:30:10.688689 db@open opening +14:30:10.689548 version@stat F·[] S·0B[] Sc·[] +14:30:10.702481 db@janitor F·2 G·0 +14:30:10.702564 db@open done T·13.82376ms diff --git a/sei-iavl/testdata/0.13-orphans-v6.db/MANIFEST-000000 b/sei-iavl/testdata/0.13-orphans-v6.db/MANIFEST-000000 new file mode 100644 index 0000000000000000000000000000000000000000..9d54f6733b1364dc8d53dd15ca59a6ec36a1c29d GIT binary patch literal 54 zcmdmC5aOo9z{n_-lUkOVlai$8R9TW*o>`pgoS$2eSd>_jU&O?~%*ev9Y~pbaHU>r} JMrI}!1^~s!4paaD literal 0 HcmV?d00001 diff --git a/sei-iavl/testdata/0.13-orphans.db/000001.log b/sei-iavl/testdata/0.13-orphans.db/000001.log new file mode 100644 index 0000000000000000000000000000000000000000..95ef16dcaf9eb82f3f7e3d1fa4e6ab313229b121 GIT binary patch literal 4300 zcmds5Z8Vf=7@n6grdee}zM5m6Sl?EW8C2UkX|p4guid0DF;Uh>!-^)XNKx&U(z1z` z&9-YZm6V8-iFOFpQnrpgO~}WJwu~~WeP)bK=Ztgi-JiSj=lyd%&vo6`^W67)z2j(7 z&0V2J5TvP}7Jd*5qWc(I89kdRWo-$jV$HN=8P%cbNm+ssuV#}LbL#x^<1~_r3YilY zW=9Yh9XxPXSSr%{YGl}=Cfsv3@kV-W=*Xa@dl<#KzPgy-jnQNo+MZCsXlYhSaKt0@ zg@u)HFx>FeL6J1FX?ER(32IZHc=Wx54tEtYMUF<03Iq{jwyjIAv<7lFYjz%(D61X6 z{=DR;fQRKA^%K?{dfH|_zXWTOvn?i6F*<1PY1X11(y?n5ec61WoB4~fN?rf0I$nq7 zWoCSw*Kal(qt!#dtz>n})SFH0Gqy`DX__ zaWT^i5Tpe`^jM+Ui#J`xEyHoto&2mx6JgR_uh;D!%bmWLJjwFCaO(55v+&8N@}eB% z2a_Y{T|XLGb`YcK@t!| zi^~Z9!!N`8rA=xbY17V3=Rz;59Z#)x5AFHZrkl5~sWvlJq0CXP?6HlVCHK~xvxg0C z$0kR#ndW6I$YciATP<6WZ_eD00u*2;Iau@OO74)0>Fc@aRYomm#3?2ICM%0h_x~Q_ z5jSUa<;mTOGMo@30YS9549%nW8F#GgXbIPrCneP``tkkf#fIt|?yR;IpOpBGZ7*b# zsWQ(T5o9icWMi`EF7wXr+Die6@m2cv3ynHf?=&z&O}c*19xN)atBed}Q?+Ebnu(wr zi6Gg;ES_R6sv?Nhr>vewRw1+%3n;QdY8NxTT=68JK7t!fX-`#187N&@rz&V21ejq@ zsH@?&SFRl#To7OeozN5p$F%r*{aPwP7`$`%$}|KxJ|MshdxGr+0cO|}Y7(%E?2QN0 z3e*U?!VX!7;4X$>_S4Zpjh2grX zviRdbkg-d~ujZ~_dO{E_T~)Y46v^|xnpmf!swT)WBA4!(pcRO4Sfa_%aJYboFm zN7-#^RzV+`#xtMCp67hCrbs$xu+DM=c0yholTgFxo4Jn}vGYqjvMa{&6AO&?u8Q^K zJ@g4|7`Tz^^VGY+0i)&GSOf*5Q?`_oUs#K(PIhf`7I`-p#zaJzq#vUX96267S)5li zANw|iMvw{w5o0!Ph?}m#8pamA_LBAYn`sxGEj0RYY}A-efpU4X z`7gC}`m(o-*IDaXxP}Uw2SlO%l8LbHhz~YO-AsBs$&|MX5L63-=&?fRCI27E83tlb zkFQ&!An-%V70+OSB$f7?WxJtpZT)kO_W4WUQZ|LAA(8~7Mw7Ml8 zblw-*>ma$DP8eQCnWY6a+>ygk?o=)L9bzJ=ZxEz=hOrBUM>t)+4KEY~l_E%WlB`o9 z7Ai)xx@<(hec8&QjO<51mk5lKGwccFJ@}xMbW)&dK|7RnQlJz37e_qpCk4Eu5MTzK m&@6z5g|eUE0D=G&dOaQ?B!V?{k4UmV8`pgoS$2eSd>_jU&O?~%*ev9Y~pbaHU>r} JMrI}!1^~s!4paaD literal 0 HcmV?d00001 diff --git a/sei-iavl/testutils_test.go b/sei-iavl/testutils_test.go new file mode 100644 index 0000000000..85b0f1eeba --- /dev/null +++ b/sei-iavl/testutils_test.go @@ -0,0 +1,366 @@ +// nolint:errcheck +package iavl + +import ( + "bytes" + "fmt" + "runtime" + "sort" + "testing" + + "math/rand" + + "github.com/stretchr/testify/require" + db "github.com/tendermint/tm-db" + + "github.com/cosmos/iavl/internal/encoding" + iavlrand "github.com/cosmos/iavl/internal/rand" +) + +type iteratorTestConfig struct { + startIterate, endIterate []byte + startByteToSet, endByteToSet byte + ascending bool +} + +func randstr(length int) string { + return iavlrand.RandStr(length) +} + +func i2b(i int) []byte { + buf := new(bytes.Buffer) + encoding.EncodeVarint(buf, int64(i)) + return buf.Bytes() +} + +func b2i(bz []byte) int { + i, _, err := encoding.DecodeVarint(bz) + if err != nil { + panic(err) + } + return int(i) +} + +// Construct a MutableTree +func getTestTree(cacheSize int) (*MutableTree, error) { + return NewMutableTreeWithOpts(db.NewMemDB(), cacheSize, nil, false) +} + +// Convenience for a new node +func N(l, r interface{}) *Node { + var left, right *Node + if _, ok := l.(*Node); ok { + left = l.(*Node) + } else { + left = NewNode(i2b(l.(int)), nil, 0) + } + if _, ok := r.(*Node); ok { + right = r.(*Node) + } else { + right = NewNode(i2b(r.(int)), nil, 0) + } + + n := &Node{ + key: right.lmd(nil).key, + value: nil, + leftNode: left, + rightNode: right, + } + n.calcHeightAndSize(nil) + return n +} + +// Setup a deep node +func T(n *Node) (*MutableTree, error) { + t, _ := getTestTree(0) + + _, _, err := n.hashWithCount() + if err != nil { + return nil, err + } + t.root = n + return t, nil +} + +// Convenience for simple printing of keys & tree structure +func P(n *Node) string { + if n.height == 0 { + return fmt.Sprintf("%v", b2i(n.key)) + } + return fmt.Sprintf("(%v %v)", P(n.leftNode), P(n.rightNode)) +} + +func randBytes(length int) []byte { + return iavlrand.RandBytes(length) +} + +type traverser struct { + first string + last string + count int +} + +func (t *traverser) view(key, value []byte) bool { + if t.first == "" { + t.first = string(key) + } + t.last = string(key) + t.count++ + return false +} + +func expectTraverse(t *testing.T, trav traverser, start, end string, count int) { + if trav.first != start { + t.Error("Bad start", start, trav.first) + } + if trav.last != end { + t.Error("Bad end", end, trav.last) + } + if trav.count != count { + t.Error("Bad count", count, trav.count) + } +} + +func assertMutableMirrorIterate(t *testing.T, tree *MutableTree, mirror map[string]string) { + sortedMirrorKeys := make([]string, 0, len(mirror)) + for k := range mirror { + sortedMirrorKeys = append(sortedMirrorKeys, k) + } + sort.Strings(sortedMirrorKeys) + + curKeyIdx := 0 + tree.Iterate(func(k, v []byte) bool { + nextMirrorKey := sortedMirrorKeys[curKeyIdx] + nextMirrorValue := mirror[nextMirrorKey] + + require.Equal(t, []byte(nextMirrorKey), k) + require.Equal(t, []byte(nextMirrorValue), v) + + curKeyIdx++ + return false + }) +} + +func assertImmutableMirrorIterate(t *testing.T, tree *ImmutableTree, mirror map[string]string) { + sortedMirrorKeys := getSortedMirrorKeys(mirror) + + curKeyIdx := 0 + tree.Iterate(func(k, v []byte) bool { + nextMirrorKey := sortedMirrorKeys[curKeyIdx] + nextMirrorValue := mirror[nextMirrorKey] + + require.Equal(t, []byte(nextMirrorKey), k) + require.Equal(t, []byte(nextMirrorValue), v) + + curKeyIdx++ + return false + }) +} + +func getSortedMirrorKeys(mirror map[string]string) []string { + sortedMirrorKeys := make([]string, 0, len(mirror)) + for k := range mirror { + sortedMirrorKeys = append(sortedMirrorKeys, k) + } + sort.Strings(sortedMirrorKeys) + return sortedMirrorKeys +} + +func getRandomizedTreeAndMirror(t *testing.T) (*MutableTree, map[string]string) { + const cacheSize = 100 + + tree, err := getTestTree(cacheSize) + require.NoError(t, err) + + mirror := make(map[string]string) + + randomizeTreeAndMirror(t, tree, mirror) + return tree, mirror +} + +func randomizeTreeAndMirror(t *testing.T, tree *MutableTree, mirror map[string]string) { + if mirror == nil { + mirror = make(map[string]string) + } + const keyValLength = 5 + + numberOfSets := 1000 + numberOfUpdates := numberOfSets / 4 + numberOfRemovals := numberOfSets / 4 + + for numberOfSets > numberOfRemovals*3 { + key := randBytes(keyValLength) + value := randBytes(keyValLength) + + isUpdated, err := tree.Set(key, value) + require.NoError(t, err) + require.False(t, isUpdated) + mirror[string(key)] = string(value) + + numberOfSets-- + } + + for numberOfSets+numberOfRemovals+numberOfUpdates > 0 { + randOp := rand.Intn(3) + + switch randOp { + case 0: + if numberOfSets == 0 { + continue + } + + numberOfSets-- + + key := randBytes(keyValLength) + value := randBytes(keyValLength) + + isUpdated, err := tree.Set(key, value) + require.NoError(t, err) + require.False(t, isUpdated) + mirror[string(key)] = string(value) + case 1: + + if numberOfUpdates == 0 { + continue + } + numberOfUpdates-- + + key := getRandomKeyFrom(mirror) + value := randBytes(keyValLength) + + isUpdated, err := tree.Set([]byte(key), value) + require.NoError(t, err) + require.True(t, isUpdated) + mirror[key] = string(value) + case 2: + if numberOfRemovals == 0 { + continue + } + numberOfRemovals-- + + key := getRandomKeyFrom(mirror) + + val, isRemoved, err := tree.Remove([]byte(key)) + require.NoError(t, err) + require.True(t, isRemoved) + require.NotNil(t, val) + delete(mirror, key) + default: + t.Error("Invalid randOp", randOp) + } + } +} + +func getRandomKeyFrom(mirror map[string]string) string { + for k := range mirror { + return k + } + panic("no keys in mirror") +} + +func setupMirrorForIterator(t *testing.T, config *iteratorTestConfig, tree *MutableTree) [][]string { + var mirror [][]string + + startByteToSet := config.startByteToSet + endByteToSet := config.endByteToSet + + if !config.ascending { + startByteToSet, endByteToSet = endByteToSet, startByteToSet + } + + curByte := startByteToSet + for curByte != endByteToSet { + value := randBytes(5) + + if (config.startIterate == nil || curByte >= config.startIterate[0]) && (config.endIterate == nil || curByte < config.endIterate[0]) { + mirror = append(mirror, []string{string(curByte), string(value)}) + } + + isUpdated, err := tree.Set([]byte{curByte}, value) + require.NoError(t, err) + require.False(t, isUpdated) + + if config.ascending { + curByte++ + } else { + curByte-- + } + } + return mirror +} + +// assertIterator confirms that the iterator returns the expected values desribed by mirror in the same order. +// mirror is a slice containing slices of the form [key, value]. In other words, key at index 0 and value at index 1. +func assertIterator(t *testing.T, itr db.Iterator, mirror [][]string, ascending bool) { + startIdx, endIdx := 0, len(mirror)-1 + increment := 1 + mirrorIdx := startIdx + + // flip the iteration order over mirror if descending + if !ascending { + startIdx = endIdx - 1 + endIdx = -1 + increment *= -1 + } + + for startIdx != endIdx { + nextExpectedPair := mirror[mirrorIdx] + + require.True(t, itr.Valid()) + require.Equal(t, []byte(nextExpectedPair[0]), itr.Key()) + require.Equal(t, []byte(nextExpectedPair[1]), itr.Value()) + itr.Next() + require.NoError(t, itr.Error()) + + startIdx += increment + mirrorIdx++ + } +} + +func BenchmarkImmutableAvlTreeMemDB(b *testing.B) { + db, err := db.NewDB("test", db.MemDBBackend, "") + require.NoError(b, err) + benchmarkImmutableAvlTreeWithDB(b, db) +} + +func benchmarkImmutableAvlTreeWithDB(b *testing.B, db db.DB) { + defer db.Close() + + b.StopTimer() + + t, err := NewMutableTree(db, 100000, false) + require.NoError(b, err) + + value := []byte{} + for i := 0; i < 1000000; i++ { + t.Set(i2b(int(iavlrand.RandInt31())), value) + if i > 990000 && i%1000 == 999 { + t.SaveVersion() + } + } + b.ReportAllocs() + t.SaveVersion() + + runtime.GC() + + b.StartTimer() + for i := 0; i < b.N; i++ { + ri := i2b(int(iavlrand.RandInt31())) + t.Set(ri, value) + t.Remove(ri) + if i%100 == 99 { + t.SaveVersion() + } + } +} + +func (node *Node) lmd(t *ImmutableTree) *Node { + if node.isLeaf() { + return node + } + + // TODO: Should handle this error? + leftNode, _ := node.getLeftNode(t) + + return leftNode.lmd(t) +} diff --git a/sei-iavl/third_party/google/api/annotations.proto b/sei-iavl/third_party/google/api/annotations.proto new file mode 100644 index 0000000000..85c361b47f --- /dev/null +++ b/sei-iavl/third_party/google/api/annotations.proto @@ -0,0 +1,31 @@ +// Copyright (c) 2015, Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/http.proto"; +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "AnnotationsProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See `HttpRule`. + HttpRule http = 72295728; +} diff --git a/sei-iavl/third_party/google/api/http.proto b/sei-iavl/third_party/google/api/http.proto new file mode 100644 index 0000000000..a43cff771f --- /dev/null +++ b/sei-iavl/third_party/google/api/http.proto @@ -0,0 +1,376 @@ +// Copyright 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "HttpProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. +message Http { + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; +} + +// # gRPC Transcoding +// +// gRPC Transcoding is a feature for mapping between a gRPC method and one or +// more HTTP REST endpoints. It allows developers to build a single API service +// that supports both gRPC APIs and REST APIs. Many systems, including [Google +// APIs](https://github.com/googleapis/googleapis), +// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC +// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), +// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature +// and use it for large scale production services. +// +// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies +// how different portions of the gRPC request message are mapped to the URL +// path, URL query parameters, and HTTP request body. It also controls how the +// gRPC response message is mapped to the HTTP response body. `HttpRule` is +// typically specified as an `google.api.http` annotation on the gRPC method. +// +// Each mapping specifies a URL path template and an HTTP method. The path +// template may refer to one or more fields in the gRPC request message, as long +// as each field is a non-repeated field with a primitive (non-message) type. +// The path template controls how fields of the request message are mapped to +// the URL path. +// +// Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/{name=messages/*}" +// }; +// } +// } +// message GetMessageRequest { +// string name = 1; // Mapped to URL path. +// } +// message Message { +// string text = 1; // The resource content. +// } +// +// This enables an HTTP REST to gRPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +// +// Any fields in the request message which are not bound by the path template +// automatically become HTTP query parameters if there is no HTTP request body. +// For example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get:"/v1/messages/{message_id}" +// }; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // Mapped to URL path. +// int64 revision = 2; // Mapped to URL query parameter `revision`. +// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +// } +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | +// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: +// "foo"))` +// +// Note that fields which are mapped to URL query parameters must have a +// primitive type or a repeated primitive type or a non-repeated message type. +// In the case of a repeated type, the parameter can be repeated in the URL +// as `...?param=A¶m=B`. In the case of a message type, each field of the +// message is mapped to a separate parameter, such as +// `...?foo.a=A&foo.b=B&foo.c=C`. +// +// For HTTP methods that allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice when +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// This enables the following two alternative HTTP JSON to RPC mappings: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: +// "123456")` +// +// ## Rules for HTTP mapping +// +// 1. Leaf request fields (recursive expansion nested messages in the request +// message) are classified into three categories: +// - Fields referred by the path template. They are passed via the URL path. +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP +// request body. +// - All other fields are passed via the URL query parameters, and the +// parameter name is the field path in the request message. A repeated +// field can be represented as multiple query parameters under the same +// name. +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields +// are passed via URL path and HTTP request body. +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all +// fields are passed via URL path and URL query parameters. +// +// ### Path template syntax +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single URL path segment. The syntax `**` matches +// zero or more URL path segments, which must be the last part of the URL path +// except the `Verb`. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` +// contains any reserved character, such characters should be percent-encoded +// before the matching. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path on the client +// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The +// server side does the reverse decoding. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{var}`. +// +// If a variable contains multiple path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path on the +// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. +// The server side does the reverse decoding, except "%2F" and "%2f" are left +// unchanged. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{+var}`. +// +// ## Using gRPC API Service Configuration +// +// gRPC API Service Configuration (service config) is a configuration language +// for configuring a gRPC service to become a user-facing product. The +// service config is simply the YAML representation of the `google.api.Service` +// proto message. +// +// As an alternative to annotating your proto file, you can configure gRPC +// transcoding in your service config YAML files. You do this by specifying a +// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same +// effect as the proto annotation. This can be particularly useful if you +// have a proto that is reused in multiple services. Note that any transcoding +// specified in the service config will override any matching transcoding +// configuration in the proto. +// +// Example: +// +// http: +// rules: +// # Selects a gRPC method and applies HttpRule to it. +// - selector: example.v1.Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// ## Special notes +// +// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the +// proto to JSON conversion must follow the [proto3 +// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). +// +// While the single segment variable follows the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String +// Expansion, the multi segment variable **does not** follow RFC 6570 Section +// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding +// for multi segment variables. +// +// The path variables **must not** refer to any repeated or mapped field, +// because client libraries are not capable of handling such variable expansion. +// +// The path variables **must not** capture the leading "/" character. The reason +// is that the most common use case "{var}" does not capture the leading "/" +// character. For consistency, all path variables must share the same behavior. +// +// Repeated message fields must not be mapped to URL query parameters, because +// no client library can support such complicated mapping. +// +// If an API needs to use a JSON array for request or response body, it can map +// the request or response body to a repeated field. However, some gRPC +// Transcoding implementations may not support this feature. +message HttpRule { + // Selects a method to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + oneof pattern { + // Maps to HTTP GET. Used for listing and getting information about + // resources. + string get = 2; + + // Maps to HTTP PUT. Used for replacing a resource. + string put = 3; + + // Maps to HTTP POST. Used for creating a resource or performing an action. + string post = 4; + + // Maps to HTTP DELETE. Used for deleting a resource. + string delete = 5; + + // Maps to HTTP PATCH. Used for updating a resource. + string patch = 6; + + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + CustomHttpPattern custom = 8; + } + + // The name of the request field whose value is mapped to the HTTP request + // body, or `*` for mapping all request fields not captured by the path + // pattern to the HTTP body, or omitted for not having any HTTP request body. + // + // NOTE: the referred field must be present at the top-level of the request + // message type. + string body = 7; + + // Optional. The name of the response field whose value is mapped to the HTTP + // response body. When omitted, the entire response message will be used + // as the HTTP response body. + // + // NOTE: The referred field must be present at the top-level of the response + // message type. + string response_body = 12; + + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + repeated HttpRule additional_bindings = 11; +} + +// A custom pattern is used for defining custom HTTP verb. +message CustomHttpPattern { + // The name of this custom HTTP verb. + string kind = 1; + + // The path matched by this custom verb. + string path = 2; +} \ No newline at end of file diff --git a/sei-iavl/tree_dotgraph.go b/sei-iavl/tree_dotgraph.go new file mode 100644 index 0000000000..9aa1e8630f --- /dev/null +++ b/sei-iavl/tree_dotgraph.go @@ -0,0 +1,106 @@ +package iavl + +import ( + "bytes" + "fmt" + "io" + "text/template" +) + +type graphEdge struct { + From, To string +} + +type graphNode struct { + Hash string + Label string + Value string + Attrs map[string]string +} + +type graphContext struct { + Edges []*graphEdge + Nodes []*graphNode +} + +var graphTemplate = ` +strict graph { + {{- range $i, $edge := $.Edges}} + "{{ $edge.From }}" -- "{{ $edge.To }}"; + {{- end}} + + {{range $i, $node := $.Nodes}} + "{{ $node.Hash }}" [label=<{{ $node.Label }}>,{{ range $k, $v := $node.Attrs }}{{ $k }}={{ $v }},{{end}}]; + {{- end}} +} +` + +var tpl = template.Must(template.New("iavl").Parse(graphTemplate)) + +var defaultGraphNodeAttrs = map[string]string{ + "shape": "circle", +} + +func WriteDOTGraph(w io.Writer, tree *ImmutableTree, paths []PathToLeaf) { + ctx := &graphContext{} + + // TODO: handle error + tree.root.hashWithCount() + tree.root.traverse(tree, true, func(node *Node) bool { + graphNode := &graphNode{ + Attrs: map[string]string{}, + Hash: fmt.Sprintf("%x", node.hash), + } + for k, v := range defaultGraphNodeAttrs { + graphNode.Attrs[k] = v + } + shortHash := graphNode.Hash[:7] + + graphNode.Label = mkLabel(unsafeToStr(node.key), 16, "sans-serif") + graphNode.Label += mkLabel(shortHash, 10, "monospace") + graphNode.Label += mkLabel(fmt.Sprintf("version=%d", node.version), 10, "monospace") + + if node.value != nil { + graphNode.Label += mkLabel(unsafeToStr(node.value), 10, "sans-serif") + } + + if node.height == 0 { + graphNode.Attrs["fillcolor"] = "lightgrey" + graphNode.Attrs["style"] = "filled" + } + + for _, path := range paths { + for _, n := range path { + if bytes.Equal(n.Left, node.hash) || bytes.Equal(n.Right, node.hash) { + graphNode.Attrs["peripheries"] = "2" + graphNode.Attrs["style"] = "filled" + graphNode.Attrs["fillcolor"] = "lightblue" + break + } + } + } + ctx.Nodes = append(ctx.Nodes, graphNode) + + if node.leftNode != nil { + ctx.Edges = append(ctx.Edges, &graphEdge{ + From: graphNode.Hash, + To: fmt.Sprintf("%x", node.leftNode.hash), + }) + } + if node.rightNode != nil { + ctx.Edges = append(ctx.Edges, &graphEdge{ + From: graphNode.Hash, + To: fmt.Sprintf("%x", node.rightNode.hash), + }) + } + return false + }) + + if err := tpl.Execute(w, ctx); err != nil { + panic(err) + } +} + +func mkLabel(label string, pt int, face string) string { + return fmt.Sprintf("%s
", face, pt, label) +} diff --git a/sei-iavl/tree_dotgraph_test.go b/sei-iavl/tree_dotgraph_test.go new file mode 100644 index 0000000000..017bcaebd8 --- /dev/null +++ b/sei-iavl/tree_dotgraph_test.go @@ -0,0 +1,20 @@ +package iavl + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWriteDOTGraph(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + for _, ikey := range []byte{ + 0x0a, 0x11, 0x2e, 0x32, 0x50, 0x72, 0x99, 0xa1, 0xe4, 0xf7, + } { + key := []byte{ikey} + tree.Set(key, key) + } + WriteDOTGraph(ioutil.Discard, tree.ImmutableTree, []PathToLeaf{}) +} diff --git a/sei-iavl/tree_fuzz_test.go b/sei-iavl/tree_fuzz_test.go new file mode 100644 index 0000000000..6f760290b3 --- /dev/null +++ b/sei-iavl/tree_fuzz_test.go @@ -0,0 +1,128 @@ +// nolint:errcheck +package iavl + +import ( + "fmt" + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + iavlrand "github.com/cosmos/iavl/internal/rand" +) + +// This file implement fuzz testing by generating programs and then running +// them. If an error occurs, the program that had the error is printed. + +// A program is a list of instructions. +type program struct { + instructions []instruction +} + +func (p *program) Execute(tree *MutableTree) (err error) { + var errLine int + + defer func() { + if r := recover(); r != nil { + var str string + + for i, instr := range p.instructions { + prefix := " " + if i == errLine { + prefix = ">> " + } + str += prefix + instr.String() + "\n" + } + err = fmt.Errorf("program panicked with: %s\n%s", r, str) + } + }() + + for i, instr := range p.instructions { + errLine = i + instr.Execute(tree) + } + return +} + +func (p *program) addInstruction(i instruction) { + p.instructions = append(p.instructions, i) +} + +func (p *program) size() int { + return len(p.instructions) +} + +type instruction struct { + op string + k, v []byte + version int64 +} + +func (i instruction) Execute(tree *MutableTree) { + switch i.op { + case "SET": + tree.Set(i.k, i.v) + case "REMOVE": + tree.Remove(i.k) + case "SAVE": + tree.SaveVersion() + case "DELETE": + tree.DeleteVersion(i.version) + default: + panic("Unrecognized op: " + i.op) + } +} + +func (i instruction) String() string { + if i.version > 0 { + return fmt.Sprintf("%-8s %-8s %-8s %-8d", i.op, i.k, i.v, i.version) + } + return fmt.Sprintf("%-8s %-8s %-8s", i.op, i.k, i.v) +} + +// Generate a random program of the given size. +func genRandomProgram(size int) *program { + p := &program{} + nextVersion := 1 + + for p.size() < size { + k, v := []byte(iavlrand.RandStr(1)), []byte(iavlrand.RandStr(1)) + + switch rand.Int() % 7 { + case 0, 1, 2: + p.addInstruction(instruction{op: "SET", k: k, v: v}) + case 3, 4: + p.addInstruction(instruction{op: "REMOVE", k: k}) + case 5: + p.addInstruction(instruction{op: "SAVE", version: int64(nextVersion)}) + nextVersion++ + case 6: + if rv := rand.Int() % nextVersion; rv < nextVersion && rv > 0 { + p.addInstruction(instruction{op: "DELETE", version: int64(rv)}) + } + } + } + return p +} + +// Generate many programs and run them. +func TestMutableTreeFuzz(t *testing.T) { + maxIterations := testFuzzIterations + progsPerIteration := 100000 + iterations := 0 + + for size := 5; iterations < maxIterations; size++ { + for i := 0; i < progsPerIteration/size; i++ { + tree, err := getTestTree(0) + require.NoError(t, err) + program := genRandomProgram(size) + err = program.Execute(tree) + if err != nil { + str, err := tree.String() + require.Nil(t, err) + t.Fatalf("Error after %d iterations (size %d): %s\n%s", iterations, size, err.Error(), str) + } + iterations++ + } + } +} diff --git a/sei-iavl/tree_random_test.go b/sei-iavl/tree_random_test.go new file mode 100644 index 0000000000..f9aa3f6987 --- /dev/null +++ b/sei-iavl/tree_random_test.go @@ -0,0 +1,503 @@ +package iavl + +import ( + "encoding/base64" + "fmt" + "io/ioutil" + "math/rand" + "os" + "sort" + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/require" + + db "github.com/tendermint/tm-db" +) + +func TestRandomOperations(t *testing.T) { + // In short mode (specifically, when running in CI with the race detector), + // we only run the first couple of seeds. + seeds := []int64{ + 498727689, + 756509998, + 480459882, + 324736440, + 581827344, + 470870060, + 390970079, + 846023066, + 518638291, + 957382170, + } + + for i, seed := range seeds { + i, seed := i, seed + t.Run(fmt.Sprintf("Seed %v", seed), func(t *testing.T) { + if testing.Short() && i >= 2 { + t.Skip("Skipping seed in short mode") + } + t.Parallel() // comment out to disable parallel tests, or use -parallel 1 + testRandomOperations(t, seed) + }) + } +} + +// Randomized test that runs all sorts of random operations, mirrors them in a known-good +// map, and verifies the state of the tree against the map. +func testRandomOperations(t *testing.T, randSeed int64) { + const ( + keySize = 16 // before base64-encoding + valueSize = 16 // before base64-encoding + + versions = 32 // number of final versions to generate + reloadChance = 0.1 // chance of tree reload after save + deleteChance = 0.2 // chance of random version deletion after save + deleteRangeChance = 0.3 // chance of deleting a version range (DeleteVersionsRange) + deleteMultiChance = 0.3 // chance of deleting multiple versions (DeleteVersions) + deleteMax = 5 // max number of versions to delete + revertChance = 0.05 // chance to revert tree to random version with LoadVersionForOverwriting + syncChance = 0.2 // chance of enabling sync writes on tree load + cacheChance = 0.4 // chance of enabling caching + cacheSizeMax = 256 // maximum size of cache (will be random from 1) + + versionOps = 64 // number of operations (create/update/delete) per version + updateRatio = 0.4 // ratio of updates out of all operations + deleteRatio = 0.2 // ratio of deletes out of all operations + ) + + r := rand.New(rand.NewSource(randSeed)) + + // loadTree loads the last persisted version of a tree with random pruning settings. + loadTree := func(levelDB db.DB) (tree *MutableTree, version int64, options *Options) { + var err error + options = &Options{ + Sync: r.Float64() < syncChance, + } + // set the cache size regardless of whether caching is enabled. This ensures we always + // call the RNG the same number of times, such that changing settings does not affect + // the RNG sequence. + cacheSize := int(r.Int63n(cacheSizeMax + 1)) + if !(r.Float64() < cacheChance) { + cacheSize = 0 + } + tree, err = NewMutableTreeWithOpts(levelDB, cacheSize, options, false) + require.NoError(t, err) + version, err = tree.Load() + require.NoError(t, err) + t.Logf("Loaded version %v (sync=%v cache=%v)", version, options.Sync, cacheSize) + return + } + + // generates random keys and values + randString := func(size int) string { + buf := make([]byte, size) + r.Read(buf) + return base64.StdEncoding.EncodeToString(buf) + } + + // Use the same on-disk database for the entire run. + tempdir, err := ioutil.TempDir("", "iavl") + require.NoError(t, err) + defer os.RemoveAll(tempdir) + + levelDB, err := db.NewGoLevelDB("leveldb", tempdir) + require.NoError(t, err) + + tree, version, _ := loadTree(levelDB) + + // Set up a mirror of the current IAVL state, as well as the history of saved mirrors + // on disk and in memory. Since pruning was removed we currently persist all versions, + // thus memMirrors is never used, but it is left here for the future when it is re-introduces. + mirror := make(map[string]string, versionOps) + mirrorKeys := make([]string, 0, versionOps) + diskMirrors := make(map[int64]map[string]string) + memMirrors := make(map[int64]map[string]string) + + for version < versions { + for i := 0; i < versionOps; i++ { + switch { + case len(mirror) > 0 && r.Float64() < deleteRatio: + index := r.Intn(len(mirrorKeys)) + key := mirrorKeys[index] + mirrorKeys = append(mirrorKeys[:index], mirrorKeys[index+1:]...) + _, removed, err := tree.Remove([]byte(key)) + require.NoError(t, err) + require.True(t, removed) + delete(mirror, key) + + case len(mirror) > 0 && r.Float64() < updateRatio: + key := mirrorKeys[r.Intn(len(mirrorKeys))] + value := randString(valueSize) + updated, err := tree.Set([]byte(key), []byte(value)) + require.NoError(t, err) + require.True(t, updated) + mirror[key] = value + + default: + key := randString(keySize) + value := randString(valueSize) + for has, err := tree.Has([]byte(key)); has && err == nil; { + key = randString(keySize) + } + updated, err := tree.Set([]byte(key), []byte(value)) + require.NoError(t, err) + require.False(t, updated) + mirror[key] = value + mirrorKeys = append(mirrorKeys, key) + } + } + _, version, err = tree.SaveVersion() + require.NoError(t, err) + + t.Logf("Saved tree at version %v with %v keys and %v versions", + version, tree.Size(), len(tree.AvailableVersions())) + + // Verify that the version matches the mirror. + assertMirror(t, tree, mirror, 0) + + // Save the mirror as a disk mirror, since we currently persist all versions. + diskMirrors[version] = copyMirror(mirror) + + // Delete random versions if requested, but never the latest version. + if r.Float64() < deleteChance { + versions := getMirrorVersions(diskMirrors, memMirrors) + switch { + case len(versions) < 2: + + case r.Float64() < deleteRangeChance: + indexFrom := r.Intn(len(versions) - 1) + from := versions[indexFrom] + batch := r.Intn(deleteMax) + if batch > len(versions[indexFrom:])-2 { + batch = len(versions[indexFrom:]) - 2 + } + to := versions[indexFrom+batch] + 1 + t.Logf("Deleting versions %v-%v", from, to-1) + err = tree.DeleteVersionsRange(int64(from), int64(to)) + require.NoError(t, err) + for version := from; version < to; version++ { + delete(diskMirrors, int64(version)) + delete(memMirrors, int64(version)) + } + + // adjust probability to take into account probability of range delete not happening + case r.Float64() < deleteMultiChance/(1.0-deleteRangeChance): + deleteVersions := []int64{} + desc := "" + batchSize := 1 + r.Intn(deleteMax) + if batchSize > len(versions)-1 { + batchSize = len(versions) - 1 + } + for _, i := range r.Perm(len(versions) - 1)[:batchSize] { + deleteVersions = append(deleteVersions, int64(versions[i])) + delete(diskMirrors, int64(versions[i])) + delete(memMirrors, int64(versions[i])) + if len(desc) > 0 { + desc += "," + } + desc += fmt.Sprintf("%v", versions[i]) + } + t.Logf("Deleting versions %v", desc) + err = tree.DeleteVersions(deleteVersions...) + require.NoError(t, err) + + default: + i := r.Intn(len(versions) - 1) + deleteVersion := int64(versions[i]) + t.Logf("Deleting version %v", deleteVersion) + err = tree.DeleteVersion(deleteVersion) + require.NoError(t, err) + delete(diskMirrors, deleteVersion) + delete(memMirrors, deleteVersion) + } + } + + // Reload tree from last persisted version if requested, checking that it matches the + // latest disk mirror version and discarding memory mirrors. + if r.Float64() < reloadChance { + tree, version, _ = loadTree(levelDB) + assertMaxVersion(t, tree, version, diskMirrors) + memMirrors = make(map[int64]map[string]string) + mirror = copyMirror(diskMirrors[version]) + mirrorKeys = getMirrorKeys(mirror) + } + + // Revert tree to historical version if requested, deleting all subsequent versions. + if r.Float64() < revertChance { + versions := getMirrorVersions(diskMirrors, memMirrors) + if len(versions) > 1 { + version = int64(versions[r.Intn(len(versions)-1)]) + t.Logf("Reverting to version %v", version) + _, err = tree.LoadVersionForOverwriting(version) + require.NoError(t, err, "Failed to revert to version %v", version) + if m, ok := diskMirrors[version]; ok { + mirror = copyMirror(m) + } else if m, ok := memMirrors[version]; ok { + mirror = copyMirror(m) + } else { + t.Fatalf("Mirror not found for revert target %v", version) + } + mirrorKeys = getMirrorKeys(mirror) + for v := range diskMirrors { + if v > version { + delete(diskMirrors, v) + } + } + for v := range memMirrors { + if v > version { + delete(memMirrors, v) + } + } + } + } + + // Verify all historical versions. + assertVersions(t, tree, diskMirrors, memMirrors) + + for diskVersion, diskMirror := range diskMirrors { + assertMirror(t, tree, diskMirror, diskVersion) + } + + for memVersion, memMirror := range memMirrors { + assertMirror(t, tree, memMirror, memVersion) + } + } + + // Once we're done, delete all prior versions in random order, make sure all orphans have been + // removed, and check that the latest versions matches the mirror. + remaining := tree.AvailableVersions() + remaining = remaining[:len(remaining)-1] + + switch { + case len(remaining) == 0: + + case r.Float64() < deleteRangeChance: + t.Logf("Deleting versions %v-%v", remaining[0], remaining[len(remaining)-1]) + err = tree.DeleteVersionsRange(int64(remaining[0]), int64(remaining[len(remaining)-1]+1)) + require.NoError(t, err) + + // adjust probability to take into account probability of range delete not happening + case r.Float64() < deleteMultiChance/(1.0-deleteRangeChance): + deleteVersions := []int64{} + desc := "" + for _, i := range r.Perm(len(remaining)) { + deleteVersions = append(deleteVersions, int64(remaining[i])) + if len(desc) > 0 { + desc += "," + } + desc += fmt.Sprintf("%v", remaining[i]) + } + t.Logf("Deleting versions %v", desc) + err = tree.DeleteVersions(deleteVersions...) + require.NoError(t, err) + + default: + for len(remaining) > 0 { + i := r.Intn(len(remaining)) + deleteVersion := int64(remaining[i]) + remaining = append(remaining[:i], remaining[i+1:]...) + t.Logf("Deleting version %v", deleteVersion) + err = tree.DeleteVersion(deleteVersion) + require.NoError(t, err) + } + } + + require.EqualValues(t, []int{int(version)}, tree.AvailableVersions()) + assertMirror(t, tree, mirror, version) + assertMirror(t, tree, mirror, 0) + assertOrphans(t, tree, 0) + t.Logf("Final version %v is correct, with no stray orphans", version) + + // Now, let's delete all remaining key/value pairs, and make sure no stray + // data is left behind in the database. + prevVersion := tree.Version() + keys := [][]byte{} + tree.Iterate(func(key, value []byte) bool { + keys = append(keys, key) + return false + }) + for _, key := range keys { + _, removed, err := tree.Remove(key) + require.NoError(t, err) + require.True(t, removed) + } + _, _, err = tree.SaveVersion() + require.NoError(t, err) + err = tree.DeleteVersion(prevVersion) + require.NoError(t, err) + assertEmptyDatabase(t, tree) + t.Logf("Final version %v deleted, no stray database entries", prevVersion) +} + +// Checks that the database is empty, only containing a single root entry +// at the given version. +func assertEmptyDatabase(t *testing.T, tree *MutableTree) { + version := tree.Version() + iter, err := tree.ndb.db.Iterator(nil, nil) + require.NoError(t, err) + + var ( + foundKeys []string + ) + for ; iter.Valid(); iter.Next() { + foundKeys = append(foundKeys, string(iter.Key())) + } + require.NoError(t, iter.Error()) + require.EqualValues(t, 2, len(foundKeys), "Found %v database entries, expected 1", len(foundKeys)) // 1 for storage version and 1 for root + + firstKey := foundKeys[0] + secondKey := foundKeys[1] + + require.True(t, strings.HasPrefix(firstKey, metadataKeyFormat.Prefix())) + require.True(t, strings.HasPrefix(secondKey, rootKeyFormat.Prefix())) + + require.Equal(t, string(metadataKeyFormat.KeyBytes([]byte(storageVersionKey))), firstKey, "Unexpected storage version key") + + storageVersionValue, err := tree.ndb.db.Get([]byte(firstKey)) + require.NoError(t, err) + latestVersion, err := tree.ndb.getLatestVersion() + require.NoError(t, err) + require.Equal(t, fastStorageVersionValue+fastStorageVersionDelimiter+strconv.Itoa(int(latestVersion)), string(storageVersionValue)) + + var foundVersion int64 + rootKeyFormat.Scan([]byte(secondKey), &foundVersion) + require.Equal(t, version, foundVersion, "Unexpected root version") +} + +// Checks that the tree has the given number of orphan nodes. +func assertOrphans(t *testing.T, tree *MutableTree, expected int) { + count := 0 + err := tree.ndb.traverseOrphans(func(k, v []byte) error { + count++ + return nil + }) + require.Nil(t, err) + require.EqualValues(t, expected, count, "Expected %v orphans, got %v", expected, count) +} + +// Checks that a version is the maximum mirrored version. +func assertMaxVersion(t *testing.T, tree *MutableTree, version int64, mirrors map[int64]map[string]string) { + max := int64(0) + for v := range mirrors { + if v > max { + max = v + } + } + require.Equal(t, max, version) +} + +// Checks that a mirror, optionally for a given version, matches the tree contents. +func assertMirror(t *testing.T, tree *MutableTree, mirror map[string]string, version int64) { + var err error + itree := tree.ImmutableTree + if version > 0 { + itree, err = tree.GetImmutable(version) + require.NoError(t, err, "loading version %v", version) + } + // We check both ways: first check that iterated keys match the mirror, then iterate over the + // mirror and check with get. This is to exercise both the iteration and Get() code paths. + iterated := 0 + itree.Iterate(func(key, value []byte) bool { + require.Equal(t, string(value), mirror[string(key)], "Invalid value for key %q", key) + iterated++ + return false + }) + require.EqualValues(t, len(mirror), itree.Size()) + require.EqualValues(t, len(mirror), iterated) + for key, value := range mirror { + actualFast, err := itree.Get([]byte(key)) + require.NoError(t, err) + require.Equal(t, value, string(actualFast)) + _, actual, err := itree.GetWithIndex([]byte(key)) + require.NoError(t, err) + require.Equal(t, value, string(actual)) + } + + assertFastNodeCacheIsLive(t, tree, mirror, version) + assertFastNodeDiskIsLive(t, tree, mirror, version) +} + +// Checks that fast node cache matches live state. +func assertFastNodeCacheIsLive(t *testing.T, tree *MutableTree, mirror map[string]string, version int64) { + latestVersion, err := tree.ndb.getLatestVersion() + require.NoError(t, err) + if latestVersion != version { + // The fast node cache check should only be done to the latest version + return + } + + require.Equal(t, len(mirror), tree.ndb.fastNodeCache.Len()) + for k, v := range mirror { + require.True(t, tree.ndb.fastNodeCache.Has([]byte(k)), "cached fast node must be in live tree") + mirrorNode := tree.ndb.fastNodeCache.Get([]byte(k)) + require.Equal(t, []byte(v), mirrorNode.(*FastNode).value, "cached fast node's value must be equal to live state value") + } +} + +// Checks that fast nodes on disk match live state. +func assertFastNodeDiskIsLive(t *testing.T, tree *MutableTree, mirror map[string]string, version int64) { + latestVersion, err := tree.ndb.getLatestVersion() + require.NoError(t, err) + if latestVersion != version { + // The fast node disk check should only be done to the latest version + return + } + + count := 0 + err = tree.ndb.traverseFastNodes(func(keyWithPrefix, v []byte) error { + key := keyWithPrefix[1:] + count++ + fastNode, err := DeserializeFastNode(key, v) + require.Nil(t, err) + + mirrorVal := mirror[string(fastNode.key)] + + require.NotNil(t, mirrorVal) + require.Equal(t, []byte(mirrorVal), fastNode.value) + return nil + }) + require.NoError(t, err) + require.Equal(t, len(mirror), count) +} + +// Checks that all versions in the tree are present in the mirrors, and vice-versa. +func assertVersions(t *testing.T, tree *MutableTree, mirrors ...map[int64]map[string]string) { + require.Equal(t, getMirrorVersions(mirrors...), tree.AvailableVersions()) +} + +// copyMirror copies a mirror map. +func copyMirror(mirror map[string]string) map[string]string { + c := make(map[string]string, len(mirror)) + for k, v := range mirror { + c[k] = v + } + return c +} + +// getMirrorKeys returns the keys of a mirror, unsorted. +func getMirrorKeys(mirror map[string]string) []string { + keys := make([]string, 0, len(mirror)) + for key := range mirror { + keys = append(keys, key) + } + return keys +} + +// getMirrorVersions returns the versions of the given mirrors, sorted. Returns []int to +// match tree.AvailableVersions(). +func getMirrorVersions(mirrors ...map[int64]map[string]string) []int { + versionMap := make(map[int]bool) + for _, m := range mirrors { + for version := range m { + versionMap[int(version)] = true + } + } + versions := make([]int, 0, len(versionMap)) + for version := range versionMap { + versions = append(versions, version) + } + sort.Ints(versions) + return versions +} diff --git a/sei-iavl/tree_test.go b/sei-iavl/tree_test.go new file mode 100644 index 0000000000..c02b0de1a9 --- /dev/null +++ b/sei-iavl/tree_test.go @@ -0,0 +1,2044 @@ +// nolint:errcheck +package iavl + +import ( + "bytes" + "encoding/hex" + "flag" + "fmt" + "math/rand" + "os" + "runtime" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + db "github.com/tendermint/tm-db" + + iavlrand "github.com/cosmos/iavl/internal/rand" +) + +var testLevelDB bool +var testFuzzIterations int +var random *iavlrand.Rand + +func SetupTest() { + random = iavlrand.NewRand() + random.Seed(0) // for determinism + flag.BoolVar(&testLevelDB, "test.leveldb", false, "test leveldb backend") + flag.IntVar(&testFuzzIterations, "test.fuzz-iterations", 100000, "number of fuzz testing iterations") + flag.Parse() +} + +func getTestDB() (db.DB, func()) { + if testLevelDB { + d, err := db.NewGoLevelDB("test", ".") + if err != nil { + panic(err) + } + return d, func() { + d.Close() + os.RemoveAll("./test.db") + } + } + return db.NewMemDB(), func() {} +} + +func TestVersionedRandomTree(t *testing.T) { + require := require.New(t) + SetupTest() + d, closeDB := getTestDB() + defer closeDB() + + tree, err := NewMutableTree(d, 100, false) + require.NoError(err) + versions := 50 + keysPerVersion := 30 + + // Create a tree of size 1000 with 100 versions. + for i := 1; i <= versions; i++ { + for j := 0; j < keysPerVersion; j++ { + k := []byte(iavlrand.RandStr(8)) + v := []byte(iavlrand.RandStr(8)) + tree.Set(k, v) + } + tree.SaveVersion() + } + roots, err := tree.ndb.getRoots() + require.NoError(err) + require.Equal(versions, len(roots), "wrong number of roots") + + leafNodes, err := tree.ndb.leafNodes() + require.Nil(err) + require.Equal(versions*keysPerVersion, len(leafNodes), "wrong number of nodes") + + // Before deleting old versions, we should have equal or more nodes in the + // db than in the current tree version. + nodes, err := tree.ndb.nodes() + require.Nil(err) + require.True(len(nodes) >= tree.nodeSize()) + + // Ensure it returns all versions in sorted order + available := tree.AvailableVersions() + assert.Equal(t, versions, len(available)) + assert.Equal(t, 1, available[0]) + assert.Equal(t, versions, available[len(available)-1]) + + for i := 1; i < versions; i++ { + tree.DeleteVersion(int64(i)) + } + + require.Len(tree.versions, 1, "tree must have one version left") + tr, err := tree.GetImmutable(int64(versions)) + require.NoError(err, "GetImmutable should not error for version %d", versions) + require.Equal(tr.root, tree.root) + + // we should only have one available version now + available = tree.AvailableVersions() + assert.Equal(t, 1, len(available)) + assert.Equal(t, versions, available[0]) + + // After cleaning up all previous versions, we should have as many nodes + // in the db as in the current tree version. + leafNodes, err = tree.ndb.leafNodes() + require.Nil(err) + require.Len(leafNodes, int(tree.Size())) + + nodes, err = tree.ndb.nodes() + require.Nil(err) + require.Equal(tree.nodeSize(), len(nodes)) +} + +// nolint: dupl +func TestTreeHash(t *testing.T) { + const ( + randSeed = 49872768940 // For deterministic tests + keySize = 16 + valueSize = 16 + + versions = 4 // number of versions to generate + versionOps = 4096 // number of operations (create/update/delete) per version + updateRatio = 0.4 // ratio of updates out of all operations + deleteRatio = 0.2 // ratio of deletes out of all operations + ) + + // expected hashes for each version + expectHashes := []string{ + "58ec30fa27f338057e5964ed9ec3367e59b2b54bec4c194f10fde7fed16c2a1c", + "91ad3ace227372f0064b2d63e8493ce8f4bdcbd16c7a8e4f4d54029c9db9570c", + "92c25dce822c5968c228cfe7e686129ea281f79273d4a8fcf6f9130a47aa5421", + "e44d170925554f42e00263155c19574837a38e3efed8910daccc7fa12f560fa0", + } + require.Len(t, expectHashes, versions, "must have expected hashes for all versions") + + r := rand.New(rand.NewSource(randSeed)) + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + + keys := make([][]byte, 0, versionOps) + for i := 0; i < versions; i++ { + for j := 0; j < versionOps; j++ { + key := make([]byte, keySize) + value := make([]byte, valueSize) + + // The performance of this is likely to be terrible, but that's fine for small tests + switch { + case len(keys) > 0 && r.Float64() <= deleteRatio: + index := r.Intn(len(keys)) + key = keys[index] + keys = append(keys[:index], keys[index+1:]...) + _, removed, err := tree.Remove(key) + require.NoError(t, err) + require.True(t, removed) + + case len(keys) > 0 && r.Float64() <= updateRatio: + key = keys[r.Intn(len(keys))] + r.Read(value) + updated, err := tree.Set(key, value) + require.NoError(t, err) + require.True(t, updated) + + default: + r.Read(key) + r.Read(value) + // If we get an update, set again + for updated, err := tree.Set(key, value); err == nil && updated; { + key = make([]byte, keySize) + r.Read(key) + } + keys = append(keys, key) + } + } + hash, version, err := tree.SaveVersion() + require.NoError(t, err) + require.EqualValues(t, i+1, version) + require.Equal(t, expectHashes[i], hex.EncodeToString(hash)) + } + + require.EqualValues(t, versions, tree.Version()) +} + +func TestVersionedRandomTreeSmallKeys(t *testing.T) { + require := require.New(t) + d, closeDB := getTestDB() + defer closeDB() + + tree, err := NewMutableTree(d, 100, false) + require.NoError(err) + singleVersionTree, err := getTestTree(0) + require.NoError(err) + versions := 20 + keysPerVersion := 50 + + for i := 1; i <= versions; i++ { + for j := 0; j < keysPerVersion; j++ { + // Keys of size one are likely to be overwritten. + k := []byte(iavlrand.RandStr(1)) + v := []byte(iavlrand.RandStr(8)) + tree.Set(k, v) + singleVersionTree.Set(k, v) + } + tree.SaveVersion() + } + singleVersionTree.SaveVersion() + + for i := 1; i < versions; i++ { + tree.DeleteVersion(int64(i)) + } + + // After cleaning up all previous versions, we should have as many nodes + // in the db as in the current tree version. The simple tree must be equal + // too. + leafNodes, err := tree.ndb.leafNodes() + require.Nil(err) + + nodes, err := tree.ndb.nodes() + require.Nil(err) + + require.Len(leafNodes, int(tree.Size())) + require.Len(nodes, tree.nodeSize()) + require.Len(nodes, singleVersionTree.nodeSize()) + + // Try getting random keys. + for i := 0; i < keysPerVersion; i++ { + val, err := tree.Get([]byte(iavlrand.RandStr(1))) + require.NoError(err) + require.NotNil(val) + require.NotEmpty(val) + } +} + +func TestVersionedRandomTreeSmallKeysRandomDeletes(t *testing.T) { + require := require.New(t) + d, closeDB := getTestDB() + defer closeDB() + + tree, err := NewMutableTree(d, 100, false) + require.NoError(err) + singleVersionTree, err := getTestTree(0) + require.NoError(err) + versions := 30 + keysPerVersion := 50 + + for i := 1; i <= versions; i++ { + for j := 0; j < keysPerVersion; j++ { + // Keys of size one are likely to be overwritten. + k := []byte(iavlrand.RandStr(1)) + v := []byte(iavlrand.RandStr(8)) + tree.Set(k, v) + singleVersionTree.Set(k, v) + } + tree.SaveVersion() + } + singleVersionTree.SaveVersion() + + for _, i := range iavlrand.RandPerm(versions - 1) { + tree.DeleteVersion(int64(i + 1)) + } + + // After cleaning up all previous versions, we should have as many nodes + // in the db as in the current tree version. The simple tree must be equal + // too. + leafNodes, err := tree.ndb.leafNodes() + require.Nil(err) + + nodes, err := tree.ndb.nodes() + require.Nil(err) + + require.Len(leafNodes, int(tree.Size())) + require.Len(nodes, tree.nodeSize()) + require.Len(nodes, singleVersionTree.nodeSize()) + + // Try getting random keys. + for i := 0; i < keysPerVersion; i++ { + val, err := tree.Get([]byte(iavlrand.RandStr(1))) + require.NoError(err) + require.NotNil(val) + require.NotEmpty(val) + } +} + +func TestVersionedTreeSpecial1(t *testing.T) { + tree, err := getTestTree(100) + require.NoError(t, err) + + tree.Set([]byte("C"), []byte("so43QQFN")) + tree.SaveVersion() + + tree.Set([]byte("A"), []byte("ut7sTTAO")) + tree.SaveVersion() + + tree.Set([]byte("X"), []byte("AoWWC1kN")) + tree.SaveVersion() + + tree.Set([]byte("T"), []byte("MhkWjkVy")) + tree.SaveVersion() + + tree.DeleteVersion(1) + tree.DeleteVersion(2) + tree.DeleteVersion(3) + + nodes, err := tree.ndb.nodes() + require.Nil(t, err) + require.Equal(t, tree.nodeSize(), len(nodes)) +} + +func TestVersionedRandomTreeSpecial2(t *testing.T) { + require := require.New(t) + tree, err := getTestTree(100) + require.NoError(err) + + tree.Set([]byte("OFMe2Yvm"), []byte("ez2OtQtE")) + tree.Set([]byte("WEN4iN7Y"), []byte("kQNyUalI")) + tree.SaveVersion() + + tree.Set([]byte("1yY3pXHr"), []byte("udYznpII")) + tree.Set([]byte("7OSHNE7k"), []byte("ff181M2d")) + tree.SaveVersion() + + tree.DeleteVersion(1) + + nodes, err := tree.ndb.nodes() + require.NoError(err) + require.Len(nodes, tree.nodeSize()) +} + +func TestVersionedEmptyTree(t *testing.T) { + require := require.New(t) + d, closeDB := getTestDB() + defer closeDB() + + tree, err := NewMutableTree(d, 0, false) + require.NoError(err) + + hash, v, err := tree.SaveVersion() + require.NoError(err) + require.Equal("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) + require.EqualValues(1, v) + + hash, v, err = tree.SaveVersion() + require.NoError(err) + require.Equal("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) + require.EqualValues(2, v) + + hash, v, err = tree.SaveVersion() + require.NoError(err) + require.Equal("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) + require.EqualValues(3, v) + + hash, v, err = tree.SaveVersion() + require.NoError(err) + require.Equal("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) + require.EqualValues(4, v) + + require.EqualValues(4, tree.Version()) + + require.True(tree.VersionExists(1)) + require.True(tree.VersionExists(3)) + + require.NoError(tree.DeleteVersion(1)) + require.NoError(tree.DeleteVersion(3)) + + require.False(tree.VersionExists(1)) + require.False(tree.VersionExists(3)) + + tree.Set([]byte("k"), []byte("v")) + require.EqualValues(5, tree.root.version) + + // Now reload the tree. + + tree, err = NewMutableTree(d, 0, false) + require.NoError(err) + tree.Load() + + require.False(tree.VersionExists(1)) + require.True(tree.VersionExists(2)) + require.False(tree.VersionExists(3)) + + t2, err := tree.GetImmutable(2) + require.NoError(err, "GetImmutable should not fail for version 2") + + require.Empty(t2.root) +} + +func TestVersionedTree(t *testing.T) { + require := require.New(t) + d, closeDB := getTestDB() + defer closeDB() + + tree, err := NewMutableTree(d, 0, false) + require.NoError(err) + + // We start with empty database. + require.Equal(0, tree.ndb.size()) + require.True(tree.IsEmpty()) + require.False(tree.IsFastCacheEnabled()) + + // version 0 + + tree.Set([]byte("key1"), []byte("val0")) + tree.Set([]byte("key2"), []byte("val0")) + + // Still zero keys, since we haven't written them. + nodes, err := tree.ndb.leafNodes() + require.NoError(err) + require.Len(nodes, 0) + require.False(tree.IsEmpty()) + + // Now let's write the keys to storage. + hash1, v, err := tree.SaveVersion() + require.NoError(err) + require.False(tree.IsEmpty()) + require.EqualValues(1, v) + + // -----1----- + // key1 = val0 version=1 + // key2 = val0 version=1 + // key2 (root) version=1 + // ----------- + + nodes1, err := tree.ndb.leafNodes() + require.NoError(err) + require.Len(nodes1, 2, "db should have a size of 2") + + // version 1 + + tree.Set([]byte("key1"), []byte("val1")) + tree.Set([]byte("key2"), []byte("val1")) + tree.Set([]byte("key3"), []byte("val1")) + nodes, err = tree.ndb.leafNodes() + require.NoError(err) + require.Len(nodes, len(nodes1)) + + hash2, v2, err := tree.SaveVersion() + require.NoError(err) + require.False(bytes.Equal(hash1, hash2)) + require.EqualValues(v+1, v2) + + // Recreate a new tree and load it, to make sure it works in this + // scenario. + tree, err = NewMutableTree(d, 100, false) + require.NoError(err) + _, err = tree.Load() + require.NoError(err) + + require.Len(tree.versions, 2, "wrong number of versions") + require.EqualValues(v2, tree.Version()) + + // -----1----- + // key1 = val0 + // key2 = val0 + // -----2----- + // key1 = val1 + // key2 = val1 + // key3 = val1 + // ----------- + + nodes2, err := tree.ndb.leafNodes() + require.NoError(err) + require.Len(nodes2, 5, "db should have grown in size") + orphans, err := tree.ndb.orphans() + require.NoError(err) + require.Len(orphans, 3, "db should have three orphans") + + // Create three more orphans. + tree.Remove([]byte("key1")) // orphans both leaf node and inner node containing "key1" and "key2" + tree.Set([]byte("key2"), []byte("val2")) + + hash3, v3, _ := tree.SaveVersion() + require.EqualValues(3, v3) + + // -----1----- + // key1 = val0 (replaced) + // key2 = val0 (replaced) + // -----2----- + // key1 = val1 (removed) + // key2 = val1 (replaced) + // key3 = val1 + // -----3----- + // key2 = val2 + // ----------- + + nodes3, err := tree.ndb.leafNodes() + require.NoError(err) + require.Len(nodes3, 6, "wrong number of nodes") + + orphans, err = tree.ndb.orphans() + require.NoError(err) + require.Len(orphans, 7, "wrong number of orphans") + + hash4, _, _ := tree.SaveVersion() + require.EqualValues(hash3, hash4) + require.NotNil(hash4) + + tree, err = NewMutableTree(d, 100, false) + require.NoError(err) + _, err = tree.Load() + require.NoError(err) + + // ------------ + // DB UNCHANGED + // ------------ + + nodes4, err := tree.ndb.leafNodes() + require.NoError(err) + require.Len(nodes4, len(nodes3), "db should not have changed in size") + + tree.Set([]byte("key1"), []byte("val0")) + + // "key2" + val, err := tree.GetVersioned([]byte("key2"), 0) + require.NoError(err) + require.Nil(val) + + val, err = tree.GetVersioned([]byte("key2"), 1) + require.NoError(err) + require.Equal("val0", string(val)) + + val, err = tree.GetVersioned([]byte("key2"), 2) + require.NoError(err) + require.Equal("val1", string(val)) + + val, err = tree.Get([]byte("key2")) + require.NoError(err) + require.Equal("val2", string(val)) + + // "key1" + val, err = tree.GetVersioned([]byte("key1"), 1) + require.NoError(err) + require.Equal("val0", string(val)) + + val, err = tree.GetVersioned([]byte("key1"), 2) + require.NoError(err) + require.Equal("val1", string(val)) + + val, err = tree.GetVersioned([]byte("key1"), 3) + require.NoError(err) + require.Nil(val) + + val, err = tree.GetVersioned([]byte("key1"), 4) + require.NoError(err) + require.Nil(val) + + val, err = tree.Get([]byte("key1")) + require.NoError(err) + require.Equal("val0", string(val)) + + // "key3" + val, err = tree.GetVersioned([]byte("key3"), 0) + require.NoError(err) + require.Nil(val) + + val, err = tree.GetVersioned([]byte("key3"), 2) + require.NoError(err) + require.Equal("val1", string(val)) + + val, err = tree.GetVersioned([]byte("key3"), 3) + require.NoError(err) + require.Equal("val1", string(val)) + + // Delete a version. After this the keys in that version should not be found. + + tree.DeleteVersion(2) + + // -----1----- + // key1 = val0 + // key2 = val0 + // -----2----- + // key3 = val1 + // -----3----- + // key2 = val2 + // ----------- + + nodes5, err := tree.ndb.leafNodes() + require.NoError(err) + + require.True(len(nodes5) < len(nodes4), "db should have shrunk after delete %d !< %d", len(nodes5), len(nodes4)) + + val, err = tree.GetVersioned([]byte("key2"), 2) + require.Nil(val) + + val, err = tree.GetVersioned([]byte("key3"), 2) + require.Nil(val) + + // But they should still exist in the latest version. + + val, err = tree.Get([]byte("key2")) + require.NoError(err) + require.Equal("val2", string(val)) + + val, err = tree.Get([]byte("key3")) + require.NoError(err) + require.Equal("val1", string(val)) + + // Version 1 should still be available. + + val, err = tree.GetVersioned([]byte("key1"), 1) + require.NoError(err) + require.Equal("val0", string(val)) + + val, err = tree.GetVersioned([]byte("key2"), 1) + require.NoError(err) + require.Equal("val0", string(val)) +} + +func TestVersionedTreeVersionDeletingEfficiency(t *testing.T) { + d, closeDB := getTestDB() + defer closeDB() + + tree, err := NewMutableTree(d, 0, false) + require.NoError(t, err) + + tree.Set([]byte("key0"), []byte("val0")) + tree.Set([]byte("key1"), []byte("val0")) + tree.Set([]byte("key2"), []byte("val0")) + tree.SaveVersion() + + leafNodes, err := tree.ndb.leafNodes() + require.Nil(t, err) + require.Len(t, leafNodes, 3) + + tree.Set([]byte("key1"), []byte("val1")) + tree.Set([]byte("key2"), []byte("val1")) + tree.Set([]byte("key3"), []byte("val1")) + tree.SaveVersion() + + leafNodes, err = tree.ndb.leafNodes() + require.Nil(t, err) + require.Len(t, leafNodes, 6) + + tree.Set([]byte("key0"), []byte("val2")) + tree.Remove([]byte("key1")) + tree.Set([]byte("key2"), []byte("val2")) + tree.SaveVersion() + + leafNodes, err = tree.ndb.leafNodes() + require.Nil(t, err) + require.Len(t, leafNodes, 8) + + tree.DeleteVersion(2) + + leafNodes, err = tree.ndb.leafNodes() + require.Nil(t, err) + require.Len(t, leafNodes, 6) + + tree.DeleteVersion(1) + + leafNodes, err = tree.ndb.leafNodes() + require.Nil(t, err) + require.Len(t, leafNodes, 3) + + tree2, err := getTestTree(0) + require.NoError(t, err) + tree2.Set([]byte("key0"), []byte("val2")) + tree2.Set([]byte("key2"), []byte("val2")) + tree2.Set([]byte("key3"), []byte("val1")) + tree2.SaveVersion() + + require.Equal(t, tree2.nodeSize(), tree.nodeSize()) +} + +func TestVersionedTreeOrphanDeleting(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + + tree.Set([]byte("key0"), []byte("val0")) + tree.Set([]byte("key1"), []byte("val0")) + tree.Set([]byte("key2"), []byte("val0")) + tree.SaveVersion() + + tree.Set([]byte("key1"), []byte("val1")) + tree.Set([]byte("key2"), []byte("val1")) + tree.Set([]byte("key3"), []byte("val1")) + tree.SaveVersion() + + tree.Set([]byte("key0"), []byte("val2")) + tree.Remove([]byte("key1")) + tree.Set([]byte("key2"), []byte("val2")) + tree.SaveVersion() + + tree.DeleteVersion(2) + + val, err := tree.Get([]byte("key0")) + require.NoError(t, err) + require.Equal(t, val, []byte("val2")) + + val, err = tree.Get([]byte("key1")) + require.NoError(t, err) + require.Nil(t, val) + + val, err = tree.Get([]byte("key2")) + require.NoError(t, err) + require.Equal(t, val, []byte("val2")) + + val, err = tree.Get([]byte("key3")) + require.NoError(t, err) + require.Equal(t, val, []byte("val1")) + + tree.DeleteVersion(1) + + leafNodes, err := tree.ndb.leafNodes() + require.Nil(t, err) + require.Len(t, leafNodes, 3) +} + +func TestVersionedTreeSpecialCase(t *testing.T) { + require := require.New(t) + d, closeDB := getTestDB() + defer closeDB() + + tree, err := NewMutableTree(d, 0, false) + require.NoError(err) + + tree.Set([]byte("key1"), []byte("val0")) + tree.Set([]byte("key2"), []byte("val0")) + tree.SaveVersion() + + tree.Set([]byte("key1"), []byte("val1")) + tree.Set([]byte("key2"), []byte("val1")) + tree.SaveVersion() + + tree.Set([]byte("key2"), []byte("val2")) + tree.SaveVersion() + + tree.DeleteVersion(2) + + val, err := tree.GetVersioned([]byte("key2"), 1) + require.NoError(err) + require.Equal("val0", string(val)) +} + +func TestVersionedTreeSpecialCase2(t *testing.T) { + require := require.New(t) + + d := db.NewMemDB() + tree, err := NewMutableTree(d, 100, false) + require.NoError(err) + + tree.Set([]byte("key1"), []byte("val0")) + tree.Set([]byte("key2"), []byte("val0")) + tree.SaveVersion() + + tree.Set([]byte("key1"), []byte("val1")) + tree.Set([]byte("key2"), []byte("val1")) + tree.SaveVersion() + + tree.Set([]byte("key2"), []byte("val2")) + tree.SaveVersion() + + tree, err = NewMutableTree(d, 100, false) + require.NoError(err) + _, err = tree.Load() + require.NoError(err) + + require.NoError(tree.DeleteVersion(2)) + + val, err := tree.GetVersioned([]byte("key2"), 1) + require.NoError(err) + require.Equal("val0", string(val)) +} + +func TestVersionedTreeSpecialCase3(t *testing.T) { + require := require.New(t) + tree, err := getTestTree(0) + require.NoError(err) + + tree.Set([]byte("m"), []byte("liWT0U6G")) + tree.Set([]byte("G"), []byte("7PxRXwUA")) + tree.SaveVersion() + + tree.Set([]byte("7"), []byte("XRLXgf8C")) + tree.SaveVersion() + + tree.Set([]byte("r"), []byte("bBEmIXBU")) + tree.SaveVersion() + + tree.Set([]byte("i"), []byte("kkIS35te")) + tree.SaveVersion() + + tree.Set([]byte("k"), []byte("CpEnpzKJ")) + tree.SaveVersion() + + tree.DeleteVersion(1) + tree.DeleteVersion(2) + tree.DeleteVersion(3) + tree.DeleteVersion(4) + + nodes, err := tree.ndb.nodes() + require.NoError(err) + require.Equal(tree.nodeSize(), len(nodes)) +} + +func TestVersionedTreeSaveAndLoad(t *testing.T) { + require := require.New(t) + d := db.NewMemDB() + tree, err := NewMutableTree(d, 0, false) + require.NoError(err) + + // Loading with an empty root is a no-op. + tree.Load() + + tree.Set([]byte("C"), []byte("so43QQFN")) + tree.SaveVersion() + + tree.Set([]byte("A"), []byte("ut7sTTAO")) + tree.SaveVersion() + + tree.Set([]byte("X"), []byte("AoWWC1kN")) + tree.SaveVersion() + + tree.SaveVersion() + tree.SaveVersion() + tree.SaveVersion() + + preHash, err := tree.Hash() + require.NoError(err) + require.NotNil(preHash) + + require.Equal(int64(6), tree.Version()) + + // Reload the tree, to test that roots and orphans are properly loaded. + ntree, err := NewMutableTree(d, 0, false) + require.NoError(err) + ntree.Load() + + require.False(ntree.IsEmpty()) + require.Equal(int64(6), ntree.Version()) + + postHash, err := ntree.Hash() + require.NoError(err) + require.Equal(preHash, postHash) + + ntree.Set([]byte("T"), []byte("MhkWjkVy")) + ntree.SaveVersion() + + ntree.DeleteVersion(6) + ntree.DeleteVersion(5) + ntree.DeleteVersion(1) + ntree.DeleteVersion(2) + ntree.DeleteVersion(4) + ntree.DeleteVersion(3) + + require.False(ntree.IsEmpty()) + require.Equal(int64(4), ntree.Size()) + nodes, err := tree.ndb.nodes() + require.NoError(err) + require.Len(nodes, ntree.nodeSize()) +} + +func TestVersionedTreeErrors(t *testing.T) { + require := require.New(t) + tree, err := getTestTree(100) + require.NoError(err) + + // Can't delete non-existent versions. + require.Error(tree.DeleteVersion(1)) + require.Error(tree.DeleteVersion(99)) + + tree.Set([]byte("key"), []byte("val")) + + // Saving with content is ok. + _, _, err = tree.SaveVersion() + require.NoError(err) + + // Can't delete current version. + require.Error(tree.DeleteVersion(1)) + + // Trying to get a key from a version which doesn't exist. + val, err := tree.GetVersioned([]byte("key"), 404) + require.NoError(err) + require.Nil(val) + + // Same thing with proof. We get an error because a proof couldn't be + // constructed. + val, proof, err := tree.GetVersionedWithProof([]byte("key"), 404) + require.Nil(val) + require.Empty(proof) + require.Error(err) +} + +func TestVersionedCheckpoints(t *testing.T) { + require := require.New(t) + d, closeDB := getTestDB() + defer closeDB() + + tree, err := NewMutableTree(d, 100, false) + require.NoError(err) + versions := 50 + keysPerVersion := 10 + versionsPerCheckpoint := 5 + keys := map[int64]([][]byte){} + + for i := 1; i <= versions; i++ { + for j := 0; j < keysPerVersion; j++ { + k := []byte(iavlrand.RandStr(1)) + v := []byte(iavlrand.RandStr(8)) + keys[int64(i)] = append(keys[int64(i)], k) + tree.Set(k, v) + } + _, _, err = tree.SaveVersion() + require.NoError(err, "failed to save version") + } + + for i := 1; i <= versions; i++ { + if i%versionsPerCheckpoint != 0 { + err = tree.DeleteVersion(int64(i)) + require.NoError(err, "failed to delete") + } + } + + // Make sure all keys exist at least once. + for _, ks := range keys { + for _, k := range ks { + val, err := tree.Get(k) + require.NoError(err) + require.NotEmpty(val) + } + } + + // Make sure all keys from deleted versions aren't present. + for i := 1; i <= versions; i++ { + if i%versionsPerCheckpoint != 0 { + for _, k := range keys[int64(i)] { + val, err := tree.GetVersioned(k, int64(i)) + require.NoError(err) + require.Nil(val) + } + } + } + + // Make sure all keys exist at all checkpoints. + for i := 1; i <= versions; i++ { + for _, k := range keys[int64(i)] { + if i%versionsPerCheckpoint == 0 { + val, err := tree.GetVersioned(k, int64(i)) + require.NoError(err) + require.NotEmpty(val) + } + } + } +} + +func TestVersionedCheckpointsSpecialCase(t *testing.T) { + require := require.New(t) + tree, err := getTestTree(0) + require.NoError(err) + key := []byte("k") + + tree.Set(key, []byte("val1")) + + tree.SaveVersion() + // ... + tree.SaveVersion() + // ... + tree.SaveVersion() + // ... + // This orphans "k" at version 1. + tree.Set(key, []byte("val2")) + tree.SaveVersion() + + // When version 1 is deleted, the orphans should move to the next + // checkpoint, which is version 10. + tree.DeleteVersion(1) + + val, err := tree.GetVersioned(key, 2) + require.NotEmpty(val) + require.Equal([]byte("val1"), val) +} + +func TestVersionedCheckpointsSpecialCase2(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + + tree.Set([]byte("U"), []byte("XamDUtiJ")) + tree.Set([]byte("A"), []byte("UkZBuYIU")) + tree.Set([]byte("H"), []byte("7a9En4uw")) + tree.Set([]byte("V"), []byte("5HXU3pSI")) + tree.SaveVersion() + + tree.Set([]byte("U"), []byte("Replaced")) + tree.Set([]byte("A"), []byte("Replaced")) + tree.SaveVersion() + + tree.Set([]byte("X"), []byte("New")) + tree.SaveVersion() + + tree.DeleteVersion(1) + tree.DeleteVersion(2) +} + +func TestVersionedCheckpointsSpecialCase3(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + + tree.Set([]byte("n"), []byte("2wUCUs8q")) + tree.Set([]byte("l"), []byte("WQ7mvMbc")) + tree.SaveVersion() + + tree.Set([]byte("N"), []byte("ved29IqU")) + tree.Set([]byte("v"), []byte("01jquVXU")) + tree.SaveVersion() + + tree.Set([]byte("l"), []byte("bhIpltPM")) + tree.Set([]byte("B"), []byte("rj97IKZh")) + tree.SaveVersion() + + tree.DeleteVersion(2) + + tree.GetVersioned([]byte("m"), 1) +} + +func TestVersionedCheckpointsSpecialCase4(t *testing.T) { + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(t, err) + + tree.Set([]byte("U"), []byte("XamDUtiJ")) + tree.Set([]byte("A"), []byte("UkZBuYIU")) + tree.Set([]byte("H"), []byte("7a9En4uw")) + tree.Set([]byte("V"), []byte("5HXU3pSI")) + tree.SaveVersion() + + tree.Remove([]byte("U")) + tree.Remove([]byte("A")) + tree.SaveVersion() + + tree.Set([]byte("X"), []byte("New")) + tree.SaveVersion() + + val, err := tree.GetVersioned([]byte("A"), 2) + require.Nil(t, val) + + val, err = tree.GetVersioned([]byte("A"), 1) + require.NotEmpty(t, val) + + tree.DeleteVersion(1) + tree.DeleteVersion(2) + + val, err = tree.GetVersioned([]byte("A"), 2) + require.Nil(t, val) + + val, err = tree.GetVersioned([]byte("A"), 1) + require.Nil(t, val) +} + +func TestVersionedCheckpointsSpecialCase5(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + + tree.Set([]byte("R"), []byte("ygZlIzeW")) + tree.SaveVersion() + + tree.Set([]byte("j"), []byte("ZgmCWyo2")) + tree.SaveVersion() + + tree.Set([]byte("R"), []byte("vQDaoz6Z")) + tree.SaveVersion() + + tree.DeleteVersion(1) + + tree.GetVersioned([]byte("R"), 2) +} + +func TestVersionedCheckpointsSpecialCase6(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + + tree.Set([]byte("Y"), []byte("MW79JQeV")) + tree.Set([]byte("7"), []byte("Kp0ToUJB")) + tree.Set([]byte("Z"), []byte("I26B1jPG")) + tree.Set([]byte("6"), []byte("ZG0iXq3h")) + tree.Set([]byte("2"), []byte("WOR27LdW")) + tree.Set([]byte("4"), []byte("MKMvc6cn")) + tree.SaveVersion() + + tree.Set([]byte("1"), []byte("208dOu40")) + tree.Set([]byte("G"), []byte("7isI9OQH")) + tree.Set([]byte("8"), []byte("zMC1YwpH")) + tree.SaveVersion() + + tree.Set([]byte("7"), []byte("bn62vWbq")) + tree.Set([]byte("5"), []byte("wZuLGDkZ")) + tree.SaveVersion() + + tree.DeleteVersion(1) + tree.DeleteVersion(2) + + tree.GetVersioned([]byte("Y"), 1) + tree.GetVersioned([]byte("7"), 1) + tree.GetVersioned([]byte("Z"), 1) + tree.GetVersioned([]byte("6"), 1) + tree.GetVersioned([]byte("s"), 1) + tree.GetVersioned([]byte("2"), 1) + tree.GetVersioned([]byte("4"), 1) +} + +func TestVersionedCheckpointsSpecialCase7(t *testing.T) { + tree, err := getTestTree(100) + require.NoError(t, err) + + tree.Set([]byte("n"), []byte("OtqD3nyn")) + tree.Set([]byte("W"), []byte("kMdhJjF5")) + tree.Set([]byte("A"), []byte("BM3BnrIb")) + tree.Set([]byte("I"), []byte("QvtCH970")) + tree.Set([]byte("L"), []byte("txKgOTqD")) + tree.Set([]byte("Y"), []byte("NAl7PC5L")) + tree.SaveVersion() + + tree.Set([]byte("7"), []byte("qWcEAlyX")) + tree.SaveVersion() + + tree.Set([]byte("M"), []byte("HdQwzA64")) + tree.Set([]byte("3"), []byte("2Naa77fo")) + tree.Set([]byte("A"), []byte("SRuwKOTm")) + tree.Set([]byte("I"), []byte("oMX4aAOy")) + tree.Set([]byte("4"), []byte("dKfvbEOc")) + tree.SaveVersion() + + tree.Set([]byte("D"), []byte("3U4QbXCC")) + tree.Set([]byte("B"), []byte("FxExhiDq")) + tree.SaveVersion() + + tree.Set([]byte("A"), []byte("tWQgbFCY")) + tree.SaveVersion() + + tree.DeleteVersion(4) + + tree.GetVersioned([]byte("A"), 3) +} + +func TestVersionedTreeEfficiency(t *testing.T) { + require := require.New(t) + tree, err := NewMutableTree(db.NewMemDB(), 0, false) + require.NoError(err) + versions := 20 + keysPerVersion := 100 + keysAddedPerVersion := map[int]int{} + + keysAdded := 0 + for i := 1; i <= versions; i++ { + for j := 0; j < keysPerVersion; j++ { + // Keys of size one are likely to be overwritten. + tree.Set([]byte(iavlrand.RandStr(1)), []byte(iavlrand.RandStr(8))) + } + nodes, err := tree.ndb.nodes() + require.NoError(err) + sizeBefore := len(nodes) + tree.SaveVersion() + _, err = tree.ndb.nodes() + require.NoError(err) + nodes, err = tree.ndb.nodes() + require.NoError(err) + sizeAfter := len(nodes) + change := sizeAfter - sizeBefore + keysAddedPerVersion[i] = change + keysAdded += change + } + + keysDeleted := 0 + for i := 1; i < versions; i++ { + if tree.VersionExists(int64(i)) { + nodes, err := tree.ndb.nodes() + require.NoError(err) + sizeBefore := len(nodes) + tree.DeleteVersion(int64(i)) + nodes, err = tree.ndb.nodes() + require.NoError(err) + sizeAfter := len(nodes) + + change := sizeBefore - sizeAfter + keysDeleted += change + + require.InDelta(change, keysAddedPerVersion[i], float64(keysPerVersion)/5) + } + } + require.Equal(keysAdded-tree.nodeSize(), keysDeleted) +} + +func TestVersionedTreeProofs(t *testing.T) { + require := require.New(t) + tree, err := getTestTree(0) + require.NoError(err) + + tree.Set([]byte("k1"), []byte("v1")) + tree.Set([]byte("k2"), []byte("v1")) + tree.Set([]byte("k3"), []byte("v1")) + _, _, err = tree.SaveVersion() + require.NoError(err) + + // fmt.Println("TREE VERSION 1") + // printNode(tree.ndb, tree.root, 0) + // fmt.Println("TREE VERSION 1 END") + + root1, err := tree.Hash() + require.NoError(err) + + tree.Set([]byte("k2"), []byte("v2")) + tree.Set([]byte("k4"), []byte("v2")) + _, _, err = tree.SaveVersion() + require.NoError(err) + + // fmt.Println("TREE VERSION 2") + // printNode(tree.ndb, tree.root, 0) + // fmt.Println("TREE VERSION END") + + root2, err := tree.Hash() + require.NoError(err) + require.NotEqual(root1, root2) + + tree.Remove([]byte("k2")) + _, _, err = tree.SaveVersion() + require.NoError(err) + + root3, err := tree.Hash() + require.NoError(err) + require.NotEqual(root2, root3) + + val, proof, err := tree.GetVersionedWithProof([]byte("k2"), 1) + require.NoError(err) + require.EqualValues(val, []byte("v1")) + require.NoError(proof.Verify(root1), proof.String()) + require.NoError(proof.VerifyItem([]byte("k2"), val)) + + val, proof, err = tree.GetVersionedWithProof([]byte("k4"), 1) + require.NoError(err) + require.Nil(val) + require.NoError(proof.Verify(root1)) + require.NoError(proof.VerifyAbsence([]byte("k4"))) + + val, proof, err = tree.GetVersionedWithProof([]byte("k2"), 2) + require.NoError(err) + require.EqualValues(val, []byte("v2")) + require.NoError(proof.Verify(root2), proof.String()) + require.NoError(proof.VerifyItem([]byte("k2"), val)) + + val, proof, err = tree.GetVersionedWithProof([]byte("k1"), 2) + require.NoError(err) + require.EqualValues(val, []byte("v1")) + require.NoError(proof.Verify(root2)) + require.NoError(proof.VerifyItem([]byte("k1"), val)) + + val, proof, err = tree.GetVersionedWithProof([]byte("k2"), 3) + + require.NoError(err) + require.Nil(val) + require.NoError(proof.Verify(root3)) + require.NoError(proof.VerifyAbsence([]byte("k2"))) + require.Error(proof.Verify(root1)) + require.Error(proof.Verify(root2)) +} + +func TestOrphans(t *testing.T) { + // If you create a sequence of saved versions + // Then randomly delete versions other than the first and last until only those two remain + // Any remaining orphan nodes should either have fromVersion == firstVersion || toVersion == lastVersion + require := require.New(t) + tree, err := NewMutableTree(db.NewMemDB(), 100, false) + require.NoError(err) + + NUMVERSIONS := 100 + NUMUPDATES := 100 + + for i := 0; i < NUMVERSIONS; i++ { + for j := 1; j < NUMUPDATES; j++ { + tree.Set(randBytes(2), randBytes(2)) + } + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not error") + } + + idx := iavlrand.RandPerm(NUMVERSIONS - 2) + for _, v := range idx { + err = tree.DeleteVersion(int64(v + 1)) + require.NoError(err, "DeleteVersion should not error") + } + + err = tree.ndb.traverseOrphans(func(k, v []byte) error { + var fromVersion, toVersion int64 + orphanKeyFormat.Scan(k, &toVersion, &fromVersion) + require.True(fromVersion == int64(1) || toVersion == int64(99), fmt.Sprintf(`Unexpected orphan key exists: %v with fromVersion = %d and toVersion = %d.\n + Any orphan remaining in db should have either fromVersion == 1 or toVersion == 99. Since Version 1 and 99 are only versions in db`, k, fromVersion, toVersion)) + return nil + }) + require.Nil(err) +} + +func TestVersionedTreeHash(t *testing.T) { + require := require.New(t) + tree, err := getTestTree(0) + require.NoError(err) + + hash, err := tree.Hash() + require.NoError(err) + require.Equal("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) + tree.Set([]byte("I"), []byte("D")) + hash, err = tree.Hash() + require.NoError(err) + require.Equal("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) + + hash1, _, err := tree.SaveVersion() + require.NoError(err) + + tree.Set([]byte("I"), []byte("F")) + hash, err = tree.Hash() + require.NoError(err) + require.EqualValues(hash1, hash) + + hash2, _, err := tree.SaveVersion() + require.NoError(err) + + val, proof, err := tree.GetVersionedWithProof([]byte("I"), 2) + require.NoError(err) + require.EqualValues([]byte("F"), val) + require.NoError(proof.Verify(hash2)) + require.NoError(proof.VerifyItem([]byte("I"), val)) +} + +func TestNilValueSemantics(t *testing.T) { + require := require.New(t) + tree, err := getTestTree(0) + require.NoError(err) + + _, err = tree.Set([]byte("k"), nil) + require.Error(err) +} + +func TestCopyValueSemantics(t *testing.T) { + require := require.New(t) + + tree, err := getTestTree(0) + require.NoError(err) + + val := []byte("v1") + + tree.Set([]byte("k"), val) + v, err := tree.Get([]byte("k")) + require.NoError(err) + require.Equal([]byte("v1"), v) + + val[1] = '2' + + val, err = tree.Get([]byte("k")) + require.Equal([]byte("v2"), val) +} + +func TestRollback(t *testing.T) { + require := require.New(t) + + tree, err := getTestTree(0) + require.NoError(err) + + tree.Set([]byte("k"), []byte("v")) + tree.SaveVersion() + + tree.Set([]byte("r"), []byte("v")) + tree.Set([]byte("s"), []byte("v")) + + tree.Rollback() + + tree.Set([]byte("t"), []byte("v")) + + tree.SaveVersion() + + require.Equal(int64(2), tree.Size()) + + val, err := tree.Get([]byte("r")) + require.Nil(val) + + val, err = tree.Get([]byte("s")) + require.Nil(val) + + val, err = tree.Get([]byte("t")) + require.Equal([]byte("v"), val) +} + +func TestLazyLoadVersion(t *testing.T) { + tree, err := getTestTree(0) + require.NoError(t, err) + maxVersions := 10 + + version, err := tree.LazyLoadVersion(0) + require.NoError(t, err, "unexpected error") + require.Equal(t, version, int64(0), "expected latest version to be zero") + + for i := 0; i < maxVersions; i++ { + tree.Set([]byte(fmt.Sprintf("key_%d", i+1)), []byte(fmt.Sprintf("value_%d", i+1))) + + _, _, err = tree.SaveVersion() + require.NoError(t, err, "SaveVersion should not fail") + } + + // require the ability to lazy load the latest version + version, err = tree.LazyLoadVersion(int64(maxVersions)) + require.NoError(t, err, "unexpected error when lazy loading version") + require.Equal(t, version, int64(maxVersions)) + + value, err := tree.Get([]byte(fmt.Sprintf("key_%d", maxVersions))) + require.NoError(t, err) + require.Equal(t, value, []byte(fmt.Sprintf("value_%d", maxVersions)), "unexpected value") + + // require the ability to lazy load an older version + version, err = tree.LazyLoadVersion(int64(maxVersions - 1)) + require.NoError(t, err, "unexpected error when lazy loading version") + require.Equal(t, version, int64(maxVersions-1)) + + value, err = tree.Get([]byte(fmt.Sprintf("key_%d", maxVersions-1))) + require.NoError(t, err) + require.Equal(t, value, []byte(fmt.Sprintf("value_%d", maxVersions-1)), "unexpected value") + + // require the inability to lazy load a non-valid version + version, err = tree.LazyLoadVersion(int64(maxVersions + 1)) + require.Error(t, err, "expected error when lazy loading version") + require.Equal(t, version, int64(maxVersions)) +} + +func TestOverwrite(t *testing.T) { + require := require.New(t) + + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 0, false) + require.NoError(err) + + // Set one kv pair and save version 1 + tree.Set([]byte("key1"), []byte("value1")) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + + // Set another kv pair and save version 2 + tree.Set([]byte("key2"), []byte("value2")) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + + // Reload tree at version 1 + tree, err = NewMutableTree(mdb, 0, false) + require.NoError(err) + _, err = tree.LoadVersion(int64(1)) + require.NoError(err, "LoadVersion should not fail") + + // Attempt to put a different kv pair into the tree and save + tree.Set([]byte("key2"), []byte("different value 2")) + _, _, err = tree.SaveVersion() + require.Error(err, "SaveVersion should fail because of changed value") + + // Replay the original transition from version 1 to version 2 and attempt to save + tree.Set([]byte("key2"), []byte("value2")) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail, overwrite was idempotent") +} + +func TestOverwriteEmpty(t *testing.T) { + require := require.New(t) + + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 0, false) + require.NoError(err) + + // Save empty version 1 + _, _, err = tree.SaveVersion() + require.NoError(err) + + // Save empty version 2 + _, _, err = tree.SaveVersion() + require.NoError(err) + + // Save a key in version 3 + tree.Set([]byte("key"), []byte("value")) + _, _, err = tree.SaveVersion() + require.NoError(err) + + // Load version 1 and attempt to save a different key + _, err = tree.LoadVersion(1) + require.NoError(err) + tree.Set([]byte("foo"), []byte("bar")) + _, _, err = tree.SaveVersion() + require.Error(err) + + // However, deleting the key and saving an empty version should work, + // since it's the same as the existing version. + tree.Remove([]byte("foo")) + _, version, err := tree.SaveVersion() + require.NoError(err) + require.EqualValues(2, version) +} + +func TestLoadVersionForOverwriting(t *testing.T) { + require := require.New(t) + + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 0, false) + require.NoError(err) + + maxLength := 100 + for count := 1; count <= maxLength; count++ { + countStr := strconv.Itoa(count) + // Set one kv pair and save version + tree.Set([]byte("key"+countStr), []byte("value"+countStr)) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + } + + tree, err = NewMutableTree(mdb, 0, false) + require.NoError(err) + targetVersion, _ := tree.LoadVersionForOverwriting(int64(maxLength * 2)) + require.Equal(targetVersion, int64(maxLength), "targetVersion shouldn't larger than the actual tree latest version") + + tree, err = NewMutableTree(mdb, 0, false) + require.NoError(err) + _, err = tree.LoadVersionForOverwriting(int64(maxLength / 2)) + require.NoError(err, "LoadVersion should not fail") + + for version := 1; version <= maxLength/2; version++ { + exist := tree.VersionExists(int64(version)) + require.True(exist, "versions no more than 50 should exist") + } + + for version := (maxLength / 2) + 1; version <= maxLength; version++ { + exist := tree.VersionExists(int64(version)) + require.False(exist, "versions more than 50 should have been deleted") + } + + tree.Set([]byte("key49"), []byte("value49 different")) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail, overwrite was allowed") + + tree.Set([]byte("key50"), []byte("value50 different")) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail, overwrite was allowed") + + // Reload tree at version 50, the latest tree version is 52 + tree, err = NewMutableTree(mdb, 0, false) + require.NoError(err) + _, err = tree.LoadVersion(int64(maxLength / 2)) + require.NoError(err, "LoadVersion should not fail") + + tree.Set([]byte("key49"), []byte("value49 different")) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail, write the same value") + + tree.Set([]byte("key50"), []byte("value50 different different")) + _, _, err = tree.SaveVersion() + require.Error(err, "SaveVersion should fail, overwrite was not allowed") + + tree.Set([]byte("key50"), []byte("value50 different")) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail, write the same value") + + // The tree version now is 52 which is equal to latest version. + // Now any key value can be written into the tree + tree.Set([]byte("key any value"), []byte("value any value")) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail.") +} + +func TestDeleteVersionsCompare(t *testing.T) { + require := require.New(t) + + var databaseSizeDeleteVersionsRange, databaseSizeDeleteVersion, databaseSizeDeleteVersions string + + const maxLength = 100 + const fromLength = 5 + { + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 0, false) + require.NoError(err) + + versions := make([]int64, 0, maxLength) + for count := 1; count <= maxLength; count++ { + versions = append(versions, int64(count)) + countStr := strconv.Itoa(count) + // Set kv pair and save version + tree.Set([]byte("aaa"), []byte("bbb")) + tree.Set([]byte("key"+countStr), []byte("value"+countStr)) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + } + + tree, err = NewMutableTree(mdb, 0, false) + require.NoError(err) + targetVersion, err := tree.LoadVersion(int64(maxLength)) + require.NoError(err) + require.Equal(targetVersion, int64(maxLength), "targetVersion shouldn't larger than the actual tree latest version") + + err = tree.DeleteVersionsRange(versions[fromLength], versions[int64(maxLength/2)]) + require.NoError(err, "DeleteVersionsRange should not fail") + + databaseSizeDeleteVersionsRange = mdb.Stats()["database.size"] + } + { + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 0, false) + require.NoError(err) + + versions := make([]int64, 0, maxLength) + for count := 1; count <= maxLength; count++ { + versions = append(versions, int64(count)) + countStr := strconv.Itoa(count) + // Set kv pair and save version + tree.Set([]byte("aaa"), []byte("bbb")) + tree.Set([]byte("key"+countStr), []byte("value"+countStr)) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + } + + tree, err = NewMutableTree(mdb, 0, false) + require.NoError(err) + targetVersion, err := tree.LoadVersion(int64(maxLength)) + require.NoError(err) + require.Equal(targetVersion, int64(maxLength), "targetVersion shouldn't larger than the actual tree latest version") + + for _, version := range versions[fromLength:int64(maxLength/2)] { + err = tree.DeleteVersion(version) + require.NoError(err, "DeleteVersion should not fail for %v", version) + } + + databaseSizeDeleteVersion = mdb.Stats()["database.size"] + } + { + mdb := db.NewMemDB() + tree, err := NewMutableTree(mdb, 0, false) + require.NoError(err) + + versions := make([]int64, 0, maxLength) + for count := 1; count <= maxLength; count++ { + versions = append(versions, int64(count)) + countStr := strconv.Itoa(count) + // Set kv pair and save version + tree.Set([]byte("aaa"), []byte("bbb")) + tree.Set([]byte("key"+countStr), []byte("value"+countStr)) + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + } + + tree, err = NewMutableTree(mdb, 0, false) + require.NoError(err) + targetVersion, err := tree.LoadVersion(int64(maxLength)) + require.NoError(err) + require.Equal(targetVersion, int64(maxLength), "targetVersion shouldn't larger than the actual tree latest version") + + err = tree.DeleteVersions(versions[fromLength:int64(maxLength/2)]...) + require.NoError(err, "DeleteVersions should not fail") + + databaseSizeDeleteVersions = mdb.Stats()["database.size"] + } + + require.Equal(databaseSizeDeleteVersion, databaseSizeDeleteVersionsRange) + require.Equal(databaseSizeDeleteVersion, databaseSizeDeleteVersions) +} + +// BENCHMARKS + +func BenchmarkTreeLoadAndDelete(b *testing.B) { + numVersions := 5000 + numKeysPerVersion := 10 + + d, err := db.NewGoLevelDB("bench", ".") + if err != nil { + panic(err) + } + defer d.Close() + defer os.RemoveAll("./bench.db") + + tree, err := NewMutableTree(d, 0, false) + require.NoError(b, err) + for v := 1; v < numVersions; v++ { + for i := 0; i < numKeysPerVersion; i++ { + tree.Set([]byte(iavlrand.RandStr(16)), iavlrand.RandBytes(32)) + } + tree.SaveVersion() + } + + b.Run("LoadAndDelete", func(b *testing.B) { + for n := 0; n < b.N; n++ { + b.StopTimer() + tree, err = NewMutableTree(d, 0, false) + require.NoError(b, err) + runtime.GC() + b.StartTimer() + + // Load the tree from disk. + tree.Load() + + // Delete about 10% of the versions randomly. + // The trade-off is usually between load efficiency and delete + // efficiency, which is why we do both in this benchmark. + // If we can load quickly into a data-structure that allows for + // efficient deletes, we are golden. + for v := 0; v < numVersions/10; v++ { + version := (iavlrand.RandInt() % numVersions) + 1 + tree.DeleteVersion(int64(version)) + } + } + }) +} + +func TestLoadVersionForOverwritingCase2(t *testing.T) { + require := require.New(t) + + tree, _ := NewMutableTreeWithOpts(db.NewMemDB(), 0, nil, false) + + for i := byte(0); i < 20; i++ { + tree.Set([]byte{i}, []byte{i}) + } + + _, _, err := tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + + for i := byte(0); i < 20; i++ { + tree.Set([]byte{i}, []byte{i + 1}) + } + + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail with the same key") + + for i := byte(0); i < 20; i++ { + tree.Set([]byte{i}, []byte{i + 2}) + } + tree.SaveVersion() + + removedNodes := []*Node{} + + nodes, err := tree.ndb.nodes() + require.NoError(err) + for _, n := range nodes { + if n.version > 1 { + removedNodes = append(removedNodes, n) + } + } + + _, err = tree.LoadVersionForOverwriting(1) + require.NoError(err, "LoadVersionForOverwriting should not fail") + + for i := byte(0); i < 20; i++ { + v, err := tree.Get([]byte{i}) + require.NoError(err) + require.Equal([]byte{i}, v) + } + + for _, n := range removedNodes { + has, _ := tree.ndb.Has(n.hash) + require.False(has, "LoadVersionForOverwriting should remove useless nodes") + } + + tree.Set([]byte{0x2}, []byte{0x3}) + + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") + + err = tree.DeleteVersion(1) + require.NoError(err, "DeleteVersion should not fail") + + tree.Set([]byte{0x1}, []byte{0x3}) + + _, _, err = tree.SaveVersion() + require.NoError(err, "SaveVersion should not fail") +} + +func TestLoadVersionForOverwritingCase3(t *testing.T) { + require := require.New(t) + + tree, err := NewMutableTreeWithOpts(db.NewMemDB(), 0, nil, false) + require.NoError(err) + + for i := byte(0); i < 20; i++ { + tree.Set([]byte{i}, []byte{i}) + } + _, _, err = tree.SaveVersion() + require.NoError(err) + + for i := byte(0); i < 20; i++ { + tree.Set([]byte{i}, []byte{i + 1}) + } + _, _, err = tree.SaveVersion() + require.NoError(err) + + removedNodes := []*Node{} + + nodes, err := tree.ndb.nodes() + require.NoError(err) + for _, n := range nodes { + if n.version > 1 { + removedNodes = append(removedNodes, n) + } + } + + for i := byte(0); i < 20; i++ { + tree.Remove([]byte{i}) + } + _, _, err = tree.SaveVersion() + require.NoError(err) + + _, err = tree.LoadVersionForOverwriting(1) + require.NoError(err) + for _, n := range removedNodes { + has, err := tree.ndb.Has(n.hash) + require.NoError(err) + require.False(has, "LoadVersionForOverwriting should remove useless nodes") + } + + for i := byte(0); i < 20; i++ { + v, err := tree.Get([]byte{i}) + require.NoError(err) + require.Equal([]byte{i}, v) + } +} + +func TestIterate_ImmutableTree_Version1(t *testing.T) { + tree, mirror := getRandomizedTreeAndMirror(t) + + _, _, err := tree.SaveVersion() + require.NoError(t, err) + + immutableTree, err := tree.GetImmutable(1) + require.NoError(t, err) + + assertImmutableMirrorIterate(t, immutableTree, mirror) +} + +func TestIterate_ImmutableTree_Version2(t *testing.T) { + tree, mirror := getRandomizedTreeAndMirror(t) + + _, _, err := tree.SaveVersion() + require.NoError(t, err) + + randomizeTreeAndMirror(t, tree, mirror) + + _, _, err = tree.SaveVersion() + require.NoError(t, err) + + immutableTree, err := tree.GetImmutable(2) + require.NoError(t, err) + + assertImmutableMirrorIterate(t, immutableTree, mirror) +} + +func TestGetByIndex_ImmutableTree(t *testing.T) { + tree, mirror := getRandomizedTreeAndMirror(t) + mirrorKeys := getSortedMirrorKeys(mirror) + + _, _, err := tree.SaveVersion() + require.NoError(t, err) + + immutableTree, err := tree.GetImmutable(1) + require.NoError(t, err) + + isFastCacheEnabled, err := immutableTree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + + for index, expectedKey := range mirrorKeys { + expectedValue := mirror[expectedKey] + + actualKey, actualValue, err := immutableTree.GetByIndex(int64(index)) + require.NoError(t, err) + + require.Equal(t, expectedKey, string(actualKey)) + require.Equal(t, expectedValue, string(actualValue)) + } +} + +func TestGetWithIndex_ImmutableTree(t *testing.T) { + tree, mirror := getRandomizedTreeAndMirror(t) + mirrorKeys := getSortedMirrorKeys(mirror) + + _, _, err := tree.SaveVersion() + require.NoError(t, err) + + immutableTree, err := tree.GetImmutable(1) + require.NoError(t, err) + + isFastCacheEnabled, err := immutableTree.IsFastCacheEnabled() + require.NoError(t, err) + require.True(t, isFastCacheEnabled) + + for expectedIndex, key := range mirrorKeys { + expectedValue := mirror[key] + + actualIndex, actualValue, err := immutableTree.GetWithIndex([]byte(key)) + require.NoError(t, err) + + require.Equal(t, expectedValue, string(actualValue)) + require.Equal(t, int64(expectedIndex), actualIndex) + } +} + +func Benchmark_GetWithIndex(b *testing.B) { + db, err := db.NewDB("test", db.MemDBBackend, "") + require.NoError(b, err) + + const numKeyVals = 100000 + + t, err := NewMutableTree(db, numKeyVals, false) + require.NoError(b, err) + + keys := make([][]byte, 0, numKeyVals) + + for i := 0; i < numKeyVals; i++ { + key := randBytes(10) + keys = append(keys, key) + t.Set(key, randBytes(10)) + } + _, _, err = t.SaveVersion() + require.NoError(b, err) + + b.ReportAllocs() + runtime.GC() + + b.Run("fast", func(sub *testing.B) { + isFastCacheEnabled, err := t.IsFastCacheEnabled() + require.NoError(b, err) + require.True(b, isFastCacheEnabled) + b.ResetTimer() + for i := 0; i < sub.N; i++ { + randKey := rand.Intn(numKeyVals) + t.GetWithIndex(keys[randKey]) + } + }) + + b.Run("regular", func(sub *testing.B) { + // get non-latest version to force regular storage + _, latestVersion, err := t.SaveVersion() + require.NoError(b, err) + + itree, err := t.GetImmutable(latestVersion - 1) + require.NoError(b, err) + + isFastCacheEnabled, err := itree.IsFastCacheEnabled() + require.NoError(b, err) + require.False(b, isFastCacheEnabled) + b.ResetTimer() + for i := 0; i < sub.N; i++ { + randKey := rand.Intn(numKeyVals) + itree.GetWithIndex(keys[randKey]) + } + }) +} + +func Benchmark_GetByIndex(b *testing.B) { + db, err := db.NewDB("test", db.MemDBBackend, "") + require.NoError(b, err) + + const numKeyVals = 100000 + + t, err := NewMutableTree(db, numKeyVals, false) + require.NoError(b, err) + + for i := 0; i < numKeyVals; i++ { + key := randBytes(10) + t.Set(key, randBytes(10)) + } + _, _, err = t.SaveVersion() + require.NoError(b, err) + + b.ReportAllocs() + runtime.GC() + + b.Run("fast", func(sub *testing.B) { + isFastCacheEnabled, err := t.IsFastCacheEnabled() + require.NoError(b, err) + require.True(b, isFastCacheEnabled) + b.ResetTimer() + for i := 0; i < sub.N; i++ { + randIdx := rand.Intn(numKeyVals) + t.GetByIndex(int64(randIdx)) + } + }) + + b.Run("regular", func(sub *testing.B) { + // get non-latest version to force regular storage + _, latestVersion, err := t.SaveVersion() + require.NoError(b, err) + + itree, err := t.GetImmutable(latestVersion - 1) + require.NoError(b, err) + + isFastCacheEnabled, err := itree.IsFastCacheEnabled() + require.NoError(b, err) + require.False(b, isFastCacheEnabled) + + b.ResetTimer() + for i := 0; i < sub.N; i++ { + randIdx := rand.Intn(numKeyVals) + itree.GetByIndex(int64(randIdx)) + } + }) +} + +func TestNodeCacheStatisic(t *testing.T) { + const numKeyVals = 100000 + testcases := map[string]struct { + cacheSize int + expectFastCacheHitCnt int + expectFastCacheMissCnt int + expectCacheHitCnt int + expectCacheMissCnt int + }{ + "with_cache": { + cacheSize: numKeyVals, + expectFastCacheHitCnt: numKeyVals, + expectFastCacheMissCnt: 0, + expectCacheHitCnt: 1, + expectCacheMissCnt: 0, + }, + "without_cache": { + cacheSize: 0, + expectFastCacheHitCnt: 100000, // this value is hardcoded in nodedb for fast cache. + expectFastCacheMissCnt: 0, + expectCacheHitCnt: 0, + expectCacheMissCnt: 1, + }, + } + + for name, tc := range testcases { + tc := tc + t.Run(name, func(sub *testing.T) { + stat := &Statistics{} + opts := &Options{Stat: stat} + db, err := db.NewDB("test", db.MemDBBackend, "") + require.NoError(t, err) + mt, err := NewMutableTreeWithOpts(db, tc.cacheSize, opts, false) + require.NoError(t, err) + + for i := 0; i < numKeyVals; i++ { + key := []byte(strconv.Itoa(i)) + _, err := mt.Set(key, randBytes(10)) + require.NoError(t, err) + } + _, ver, _ := mt.SaveVersion() + it, err := mt.GetImmutable(ver) + require.NoError(t, err) + + for i := 0; i < numKeyVals; i++ { + key := []byte(strconv.Itoa(i)) + val, err := it.Get(key) + require.NoError(t, err) + require.NotNil(t, val) + require.NotEmpty(t, val) + } + require.Equal(t, tc.expectFastCacheHitCnt, int(opts.Stat.GetFastCacheHitCnt())) + require.Equal(t, tc.expectFastCacheMissCnt, int(opts.Stat.GetFastCacheMissCnt())) + require.Equal(t, tc.expectCacheHitCnt, int(opts.Stat.GetCacheHitCnt())) + require.Equal(t, tc.expectCacheMissCnt, int(opts.Stat.GetCacheMissCnt())) + }) + } + +} diff --git a/sei-iavl/unsafe.go b/sei-iavl/unsafe.go new file mode 100644 index 0000000000..2d00540d76 --- /dev/null +++ b/sei-iavl/unsafe.go @@ -0,0 +1,8 @@ +package iavl + +import ibytes "github.com/cosmos/iavl/internal/bytes" + +var ( + unsafeToStr = ibytes.UnsafeBytesToStr + unsafeToBz = ibytes.UnsafeStrToBytes +) diff --git a/sei-iavl/unsaved_fast_iterator.go b/sei-iavl/unsaved_fast_iterator.go new file mode 100644 index 0000000000..cbbff85fe3 --- /dev/null +++ b/sei-iavl/unsaved_fast_iterator.go @@ -0,0 +1,218 @@ +package iavl + +import ( + "bytes" + "errors" + "sort" + + dbm "github.com/tendermint/tm-db" +) + +var ( + errUnsavedFastIteratorNilAdditionsGiven = errors.New("unsaved fast iterator must be created with unsaved additions but they were nil") + + errUnsavedFastIteratorNilRemovalsGiven = errors.New("unsaved fast iterator must be created with unsaved removals but they were nil") +) + +// UnsavedFastIterator is a dbm.Iterator for ImmutableTree +// it iterates over the latest state via fast nodes, +// taking advantage of keys being located in sequence in the underlying database. +type UnsavedFastIterator struct { + start, end []byte + valid bool + ascending bool + err error + ndb *nodeDB + nextKey []byte + nextVal []byte + fastIterator dbm.Iterator + + nextUnsavedNodeIdx int + unsavedFastNodeAdditions map[string]*FastNode + unsavedFastNodeRemovals map[string]interface{} + unsavedFastNodesToSort []string +} + +var _ dbm.Iterator = (*UnsavedFastIterator)(nil) + +func NewUnsavedFastIterator(start, end []byte, ascending bool, ndb *nodeDB, unsavedFastNodeAdditions map[string]*FastNode, unsavedFastNodeRemovals map[string]interface{}) *UnsavedFastIterator { + iter := &UnsavedFastIterator{ + start: start, + end: end, + ascending: ascending, + ndb: ndb, + unsavedFastNodeAdditions: unsavedFastNodeAdditions, + unsavedFastNodeRemovals: unsavedFastNodeRemovals, + nextKey: nil, + nextVal: nil, + nextUnsavedNodeIdx: 0, + fastIterator: NewFastIterator(start, end, ascending, ndb), + } + + // We need to ensure that we iterate over saved and unsaved state in order. + // The strategy is to sort unsaved nodes, the fast node on disk are already sorted. + // Then, we keep a pointer to both the unsaved and saved nodes, and iterate over them in order efficiently. + for _, fastNode := range unsavedFastNodeAdditions { + if start != nil && bytes.Compare(fastNode.key, start) < 0 { + continue + } + + if end != nil && bytes.Compare(fastNode.key, end) >= 0 { + continue + } + + iter.unsavedFastNodesToSort = append(iter.unsavedFastNodesToSort, unsafeToStr(fastNode.key)) + } + + sort.Slice(iter.unsavedFastNodesToSort, func(i, j int) bool { + if ascending { + return iter.unsavedFastNodesToSort[i] < iter.unsavedFastNodesToSort[j] + } + return iter.unsavedFastNodesToSort[i] > iter.unsavedFastNodesToSort[j] + }) + + if iter.ndb == nil { + iter.err = errFastIteratorNilNdbGiven + iter.valid = false + return iter + } + + if iter.unsavedFastNodeAdditions == nil { + iter.err = errUnsavedFastIteratorNilAdditionsGiven + iter.valid = false + return iter + } + + if iter.unsavedFastNodeRemovals == nil { + iter.err = errUnsavedFastIteratorNilRemovalsGiven + iter.valid = false + return iter + } + + // Move to the first elemenet + iter.Next() + + return iter +} + +// Domain implements dbm.Iterator. +// Maps the underlying nodedb iterator domain, to the 'logical' keys involved. +func (iter *UnsavedFastIterator) Domain() ([]byte, []byte) { + return iter.start, iter.end +} + +// Valid implements dbm.Iterator. +func (iter *UnsavedFastIterator) Valid() bool { + if iter.start != nil && iter.end != nil { + if bytes.Compare(iter.end, iter.start) != 1 { + return false + } + } + + return iter.fastIterator.Valid() || iter.nextUnsavedNodeIdx < len(iter.unsavedFastNodesToSort) || (iter.nextKey != nil && iter.nextVal != nil) +} + +// Key implements dbm.Iterator +func (iter *UnsavedFastIterator) Key() []byte { + return iter.nextKey +} + +// Value implements dbm.Iterator +func (iter *UnsavedFastIterator) Value() []byte { + return iter.nextVal +} + +// Next implements dbm.Iterator +// Its effectively running the constant space overhead algorithm for streaming through sorted lists: +// the sorted lists being underlying fast nodes & unsavedFastNodeChanges +func (iter *UnsavedFastIterator) Next() { + if iter.ndb == nil { + iter.err = errFastIteratorNilNdbGiven + iter.valid = false + return + } + + diskKeyStr := unsafeToStr(iter.fastIterator.Key()) + if iter.fastIterator.Valid() && iter.nextUnsavedNodeIdx < len(iter.unsavedFastNodesToSort) { + + if iter.unsavedFastNodeRemovals[diskKeyStr] != nil { + // If next fast node from disk is to be removed, skip it. + iter.fastIterator.Next() + iter.Next() + return + } + + nextUnsavedKey := iter.unsavedFastNodesToSort[iter.nextUnsavedNodeIdx] + nextUnsavedNode := iter.unsavedFastNodeAdditions[nextUnsavedKey] + + var isUnsavedNext bool + if iter.ascending { + isUnsavedNext = diskKeyStr >= nextUnsavedKey + } else { + isUnsavedNext = diskKeyStr <= nextUnsavedKey + } + + if isUnsavedNext { + // Unsaved node is next + + if diskKeyStr == nextUnsavedKey { + // Unsaved update prevails over saved copy so we skip the copy from disk + iter.fastIterator.Next() + } + + iter.nextKey = nextUnsavedNode.key + iter.nextVal = nextUnsavedNode.value + + iter.nextUnsavedNodeIdx++ + return + } + // Disk node is next + iter.nextKey = iter.fastIterator.Key() + iter.nextVal = iter.fastIterator.Value() + + iter.fastIterator.Next() + return + } + + // if only nodes on disk are left, we return them + if iter.fastIterator.Valid() { + if iter.unsavedFastNodeRemovals[diskKeyStr] != nil { + // If next fast node from disk is to be removed, skip it. + iter.fastIterator.Next() + iter.Next() + return + } + + iter.nextKey = iter.fastIterator.Key() + iter.nextVal = iter.fastIterator.Value() + + iter.fastIterator.Next() + return + } + + // if only unsaved nodes are left, we can just iterate + if iter.nextUnsavedNodeIdx < len(iter.unsavedFastNodesToSort) { + nextUnsavedKey := iter.unsavedFastNodesToSort[iter.nextUnsavedNodeIdx] + nextUnsavedNode := iter.unsavedFastNodeAdditions[nextUnsavedKey] + + iter.nextKey = nextUnsavedNode.key + iter.nextVal = nextUnsavedNode.value + + iter.nextUnsavedNodeIdx++ + return + } + + iter.nextKey = nil + iter.nextVal = nil +} + +// Close implements dbm.Iterator +func (iter *UnsavedFastIterator) Close() error { + iter.valid = false + return iter.fastIterator.Close() +} + +// Error implements dbm.Iterator +func (iter *UnsavedFastIterator) Error() error { + return iter.err +} diff --git a/sei-iavl/util.go b/sei-iavl/util.go new file mode 100644 index 0000000000..676da1313f --- /dev/null +++ b/sei-iavl/util.go @@ -0,0 +1,151 @@ +package iavl + +import ( + "fmt" + "os" + "strings" +) + +// PrintTree prints the whole tree in an indented form. +func PrintTree(tree *ImmutableTree) { + ndb, root := tree.ndb, tree.root + printNode(ndb, root, 0) +} + +func printNode(ndb *nodeDB, node *Node, indent int) error { + indentPrefix := "" + for i := 0; i < indent; i++ { + indentPrefix += " " + } + + if node == nil { + fmt.Printf("%s\n", indentPrefix) + return nil + } + if node.rightNode != nil { + printNode(ndb, node.rightNode, indent+1) + } else if node.rightHash != nil { + rightNode, err := ndb.GetNode(node.rightHash) + if err != nil { + return err + } + printNode(ndb, rightNode, indent+1) + } + + hash, err := node._hash() + if err != nil { + return err + } + + fmt.Printf("%sh:%X\n", indentPrefix, hash) + if node.isLeaf() { + fmt.Printf("%s%X:%X (%v)\n", indentPrefix, node.key, node.value, node.height) + } + + if node.leftNode != nil { + printNode(ndb, node.leftNode, indent+1) + } else if node.leftHash != nil { + leftNode, err := ndb.GetNode(node.leftHash) + if err != nil { + return err + } + printNode(ndb, leftNode, indent+1) + } + return nil +} + +func maxInt8(a, b int8) int8 { + if a > b { + return a + } + return b +} + +func cp(bz []byte) (ret []byte) { + ret = make([]byte, len(bz)) + copy(ret, bz) + return ret +} + +// Returns a slice of the same length (big endian) +// except incremented by one. +// Appends 0x00 if bz is all 0xFF. +// CONTRACT: len(bz) > 0 +func cpIncr(bz []byte) (ret []byte) { + ret = cp(bz) + for i := len(bz) - 1; i >= 0; i-- { + if ret[i] < byte(0xFF) { + ret[i]++ + return + } + ret[i] = byte(0x00) + if i == 0 { + // here, the original bz is all 0xFF, so we keep the original and append 0x00 + // instead of returning all 0x00 + ret = cp(bz) + return append(ret, 0x00) + } + } + return []byte{0x00} +} + +// Colors: ------------------------------------------------ + +const ( + ANSIReset = "\x1b[0m" + ANSIBright = "\x1b[1m" + + ANSIFgGreen = "\x1b[32m" + ANSIFgBlue = "\x1b[34m" + ANSIFgCyan = "\x1b[36m" +) + +// color the string s with color 'color' +// unless s is already colored +func treat(s string, color string) string { + if len(s) > 2 && s[:2] == "\x1b[" { + return s + } + return color + s + ANSIReset +} + +func treatAll(color string, args ...interface{}) string { + parts := make([]string, 0, len(args)) + for _, arg := range args { + parts = append(parts, treat(fmt.Sprintf("%v", arg), color)) + } + return strings.Join(parts, "") +} + +func Green(args ...interface{}) string { + return treatAll(ANSIFgGreen, args...) +} + +func Blue(args ...interface{}) string { + return treatAll(ANSIFgBlue, args...) +} + +func Cyan(args ...interface{}) string { + return treatAll(ANSIFgCyan, args...) +} + +// ColoredBytes takes in the byte that you would like to show as a string and byte +// and will display them in a human readable format. +// If the environment variable TENDERMINT_IAVL_COLORS_ON is set to a non-empty string then different colors will be used for bytes and strings. +func ColoredBytes(data []byte, textColor, bytesColor func(...interface{}) string) string { + colors := os.Getenv("TENDERMINT_IAVL_COLORS_ON") + if colors == "" { + for _, b := range data { + return string(b) + } + } + s := "" + for _, b := range data { + if 0x21 <= b && b < 0x7F { + s += textColor(string(b)) + } else { + s += bytesColor(fmt.Sprintf("%02X", b)) + } + } + return s +} diff --git a/sei-iavl/version.go b/sei-iavl/version.go new file mode 100644 index 0000000000..9c6627b4b9 --- /dev/null +++ b/sei-iavl/version.go @@ -0,0 +1,37 @@ +package iavl + +import ( + "fmt" + "runtime" +) + +// Version of iavl. Fill in fields with build flags +var ( + Version = "" + Commit = "" + Branch = "" +) + +// VersionInfo contains useful versioning information in struct +type VersionInfo struct { + IAVL string `json:"iavl"` + GitCommit string `json:"commit"` + Branch string `json:"branch"` + GoVersion string `json:"go"` +} + +func (v VersionInfo) String() string { + return fmt.Sprintf(`iavl: %s +git commit: %s +git branch: %s +%s`, v.IAVL, v.GitCommit, v.Branch, v.GoVersion) +} + +// Returns VersionInfo with global vars filled in +func GetVersionInfo() VersionInfo { + return VersionInfo{ + Version, + Commit, + Branch, + fmt.Sprintf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)} +} diff --git a/sei-iavl/with_gcc_test.go b/sei-iavl/with_gcc_test.go new file mode 100644 index 0000000000..433ab3acb3 --- /dev/null +++ b/sei-iavl/with_gcc_test.go @@ -0,0 +1,19 @@ +//go:build gcc +// +build gcc + +// This file exists because some of the DBs e.g CLevelDB +// require gcc as the compiler before they can ran otherwise +// we'll encounter crashes such as in https://github.com/tendermint/merkleeyes/issues/39 + +package iavl + +import ( + "testing" + + db "github.com/tendermint/tm-db" +) + +func BenchmarkImmutableAvlTreeCLevelDB(b *testing.B) { + db := db.NewDB("test", db.CLevelDBBackendStr, "./") + benchmarkImmutableAvlTreeWithDB(b, db) +} From e17e37d31a08ac6885fa04b8e8e291365d8884b0 Mon Sep 17 00:00:00 2001 From: Philip Su Date: Thu, 26 Jan 2023 09:15:56 -0800 Subject: [PATCH 02/69] Rm dependabot --- sei-iavl/.github/dependabot.yml | 16 ---------------- sei-iavl/.gitignore | 5 ++++- 2 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 sei-iavl/.github/dependabot.yml diff --git a/sei-iavl/.github/dependabot.yml b/sei-iavl/.github/dependabot.yml deleted file mode 100644 index 49052502f9..0000000000 --- a/sei-iavl/.github/dependabot.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -updates: - - package-ecosystem: github-actions - directory: "/" - schedule: - interval: daily - time: "11:00" - open-pull-requests-limit: 10 - - package-ecosystem: gomod - directory: "/" - schedule: - interval: daily - time: "11:00" - open-pull-requests-limit: 10 - labels: - - T:dependencies diff --git a/sei-iavl/.gitignore b/sei-iavl/.gitignore index 8743c144c1..c55fa86937 100644 --- a/sei-iavl/.gitignore +++ b/sei-iavl/.gitignore @@ -14,4 +14,7 @@ cpu*.pdf mem*.pdf # IDE files -.idea/* \ No newline at end of file +.idea/* + +# Mac +.Ds_Store From 7f77b6f61d4210e4b857ad8bfbe81a66cd51a6de Mon Sep 17 00:00:00 2001 From: Philip Su Date: Thu, 26 Jan 2023 09:17:19 -0800 Subject: [PATCH 03/69] Add pr template --- sei-iavl/.github/pull_request_template.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 sei-iavl/.github/pull_request_template.md diff --git a/sei-iavl/.github/pull_request_template.md b/sei-iavl/.github/pull_request_template.md new file mode 100644 index 0000000000..bc2e1bf509 --- /dev/null +++ b/sei-iavl/.github/pull_request_template.md @@ -0,0 +1,4 @@ +## Describe your changes and provide context + +## Testing performed to validate your change + From 07c67c33df9142b49c44dbe577892f8dea3ed087 Mon Sep 17 00:00:00 2001 From: codchen Date: Fri, 27 Jan 2023 17:05:07 +0800 Subject: [PATCH 04/69] Add functions for rollback to commit without bumping version --- sei-iavl/mutable_tree.go | 114 +++++++++++++++++++++++++--------- sei-iavl/mutable_tree_test.go | 39 ++++++++++++ 2 files changed, 122 insertions(+), 31 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 4d352f680e..4a58174c1c 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -820,6 +820,50 @@ func (tree *MutableTree) GetVersioned(key []byte, version int64) ([]byte, error) return nil, nil } +// SaveCurrentVersion overwrites the current version without bumping. +// It will return an error if the version does not exist in tree, or if +// the hash being saved is different. In +// other words, only SaveVersion can insert new node into the tree. +func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { + version := tree.version + if version == 1 && tree.ndb.opts.InitialVersion > 0 { + version = int64(tree.ndb.opts.InitialVersion) + } + + if !tree.VersionExists(version) { + return nil, version, errors.New(fmt.Sprintf("attempting to overwrite non-existent version %d", version)) + } + + existingHash, err := tree.ndb.getRoot(version) + if err != nil { + return nil, version, err + } + + // If the existing root hash is empty (because the tree is empty), then we need to + // compare with the hash of an empty input which is what `WorkingHash()` returns. + if len(existingHash) == 0 { + existingHash = sha256.New().Sum(nil) + } + + newHash, err := tree.WorkingHash() + if err != nil { + return nil, version, err + } + + if bytes.Equal(existingHash, newHash) { + if v, err := tree.commitVersion(version, true); err != nil { + return nil, v, err + } + tree.version = version + tree.ImmutableTree = tree.ImmutableTree.clone() + tree.lastSaved = tree.ImmutableTree.clone() + tree.orphans = map[string]int64{} + return existingHash, version, nil + } + + return nil, version, fmt.Errorf("version %d was already saved to different hash %X (existing hash %X)", version, newHash, existingHash) +} + // SaveVersion saves a new tree version to disk, based on the current state of // the tree. Returns the hash and new version number. func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { @@ -858,37 +902,8 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { return nil, version, fmt.Errorf("version %d was already saved to different hash %X (existing hash %X)", version, newHash, existingHash) } - if tree.root == nil { - // There can still be orphans, for example if the root is the node being - // removed. - logger.Debug("SAVE EMPTY TREE %v\n", version) - if err := tree.ndb.SaveOrphans(version, tree.orphans); err != nil { - return nil, 0, err - } - if err := tree.ndb.SaveEmptyRoot(version); err != nil { - return nil, 0, err - } - } else { - logger.Debug("SAVE TREE %v\n", version) - if _, err := tree.ndb.SaveBranch(tree.root); err != nil { - return nil, 0, err - } - if err := tree.ndb.SaveOrphans(version, tree.orphans); err != nil { - return nil, 0, err - } - if err := tree.ndb.SaveRoot(tree.root, version); err != nil { - return nil, 0, err - } - } - - if !tree.skipFastStorageUpgrade { - if err := tree.saveFastNodeVersion(); err != nil { - return nil, version, err - } - } - - if err := tree.ndb.Commit(); err != nil { - return nil, version, err + if v, err := tree.commitVersion(version, false); err != nil { + return nil, v, err } tree.mtx.Lock() @@ -923,6 +938,43 @@ func (tree *MutableTree) saveFastNodeVersion() error { return tree.ndb.setFastStorageVersionToBatch() } +func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) (int64, error) { + if tree.root == nil { + // There can still be orphans, for example if the root is the node being + // removed. + logger.Debug("SAVE EMPTY TREE %v\n", version) + if err := tree.ndb.SaveOrphans(version, tree.orphans); err != nil { + return 0, err + } + if err := tree.ndb.SaveEmptyRoot(version); !silentSaveRootError && err != nil { + return 0, err + } + } else { + logger.Debug("SAVE TREE %v\n", version) + if _, err := tree.ndb.SaveBranch(tree.root); err != nil { + return 0, err + } + if err := tree.ndb.SaveOrphans(version, tree.orphans); err != nil { + return 0, err + } + if err := tree.ndb.SaveRoot(tree.root, version); !silentSaveRootError && err != nil { + return 0, err + } + } + + if !tree.skipFastStorageUpgrade { + if err := tree.saveFastNodeVersion(); err != nil { + return version, err + } + } + + if err := tree.ndb.Commit(); err != nil { + return version, err + } + + return version, nil +} + // nolint: unused func (tree *MutableTree) getUnsavedFastNodeAdditions() map[string]*FastNode { return tree.unsavedFastNodeAdditions diff --git a/sei-iavl/mutable_tree_test.go b/sei-iavl/mutable_tree_test.go index b2c2c8ac50..016de76ed0 100644 --- a/sei-iavl/mutable_tree_test.go +++ b/sei-iavl/mutable_tree_test.go @@ -1441,3 +1441,42 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te }) }) } + +func TestSaveCurrentVersion(t *testing.T) { + tree := setupMutableTree(t) + tree.SetInitialVersion(9) + + tree.Set([]byte("a"), []byte{0x01}) + _, version, err := tree.SaveVersion() + require.NoError(t, err) + assert.EqualValues(t, 9, version) + _, version, err = tree.SaveCurrentVersion() + require.NoError(t, err) + assert.EqualValues(t, 9, version) +} + +func TestSaveCurrentVersion_BadVersion(t *testing.T) { + tree := setupMutableTree(t) + tree.SetInitialVersion(9) + + tree.Set([]byte("a"), []byte{0x01}) + _, version, err := tree.SaveVersion() + require.NoError(t, err) + assert.EqualValues(t, 9, version) + tree.version = 10 + _, version, err = tree.SaveCurrentVersion() + require.Error(t, err) +} + +func TestSaveCurrentVersion_ChangedHash(t *testing.T) { + tree := setupMutableTree(t) + tree.SetInitialVersion(9) + + tree.Set([]byte("a"), []byte{0x01}) + _, version, err := tree.SaveVersion() + require.NoError(t, err) + assert.EqualValues(t, 9, version) + tree.Set([]byte("b"), []byte{0x02}) + _, version, err = tree.SaveCurrentVersion() + require.Error(t, err) +} From f5c9da7fda9a40194bf32bdeddffd8853dd722a9 Mon Sep 17 00:00:00 2001 From: Philip Su Date: Fri, 27 Jan 2023 14:59:08 -0800 Subject: [PATCH 05/69] codecov should not fail --- sei-iavl/.github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sei-iavl/.github/workflows/ci.yml b/sei-iavl/.github/workflows/ci.yml index c35030ff1d..3795814feb 100644 --- a/sei-iavl/.github/workflows/ci.yml +++ b/sei-iavl/.github/workflows/ci.yml @@ -39,4 +39,4 @@ jobs: - uses: codecov/codecov-action@v3.1.0 with: file: ./coverage.txt - fail_ci_if_error: true + fail_ci_if_error: false From a82011989d48e4c5e929b7387a95c7dd52d2c91e Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 30 Jan 2023 10:32:40 +0800 Subject: [PATCH 06/69] fix test --- sei-iavl/mutable_tree_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/sei-iavl/mutable_tree_test.go b/sei-iavl/mutable_tree_test.go index 016de76ed0..bd26463987 100644 --- a/sei-iavl/mutable_tree_test.go +++ b/sei-iavl/mutable_tree_test.go @@ -1466,6 +1466,7 @@ func TestSaveCurrentVersion_BadVersion(t *testing.T) { tree.version = 10 _, version, err = tree.SaveCurrentVersion() require.Error(t, err) + assert.EqualValues(t, 10, version) } func TestSaveCurrentVersion_ChangedHash(t *testing.T) { From 17d3aa53239c8fee4ab5c03df9733a6841cc3ea7 Mon Sep 17 00:00:00 2001 From: Yiming Zang Date: Sun, 5 Feb 2023 01:21:20 -0800 Subject: [PATCH 07/69] Improve IAVL Import speed to make state sync faster by 2x-3x --- sei-iavl/go.mod | 27 +++++-- sei-iavl/go.sum | 133 ++++++++++++++++++++++++++++-- sei-iavl/import.go | 197 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 309 insertions(+), 48 deletions(-) diff --git a/sei-iavl/go.mod b/sei-iavl/go.mod index 0badc8552b..9068f6edc6 100644 --- a/sei-iavl/go.mod +++ b/sei-iavl/go.mod @@ -4,33 +4,48 @@ go 1.18 require ( github.com/confio/ics23/go v0.7.0 + github.com/cosmos/cosmos-db v1.0.0-rc.1 github.com/gogo/protobuf v1.3.2 github.com/golang/mock v1.6.0 github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 github.com/tendermint/tendermint v0.34.20 github.com/tendermint/tm-db v0.6.6 golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e ) require ( - github.com/DataDog/zstd v1.4.1 // indirect + github.com/DataDog/zstd v1.4.5 // indirect + github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cockroachdb/errors v1.8.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect + github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 // indirect + github.com/cockroachdb/redact v1.0.8 // indirect + github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.3 // indirect - github.com/google/btree v1.0.0 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.1.2 // indirect github.com/jmhodges/levigo v1.0.0 // indirect + github.com/klauspost/compress v1.15.9 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/linxGnu/grocksdb v1.7.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.8.1 // indirect + github.com/spf13/cast v1.5.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 // indirect - golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect + golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect + golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect + golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sei-iavl/go.sum b/sei-iavl/go.sum index d42aada086..ce146be116 100644 --- a/sei-iavl/go.sum +++ b/sei-iavl/go.sum @@ -61,6 +61,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Antonboom/errname v0.1.6/go.mod h1:7lz79JAnuoMNDAWE9MeeIr1/c/VpSUWatBv2FH9NYpI= github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= @@ -73,14 +74,20 @@ github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v2 v2.1.0/go.mod h1:LGOGuvEgCfCQsy3JF2tRmpGDpzA53iZfyGEWSPwQ6/4= github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= @@ -92,6 +99,7 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -99,6 +107,7 @@ github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -127,6 +136,7 @@ github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -162,6 +172,7 @@ github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4/go.mod h1:W8EnPSQ8Nv4fUjc/v1/8tHFqhuOJXnRub0dTfuAQktU= @@ -185,6 +196,19 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= +github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 h1:qbb/AE938DFhOajUYh9+OXELpSF9KZw2ZivtmW6eX1Q= +github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677/go.mod h1:890yq1fUb9b6dGNwssgeUO5vQV9qfXnCPxAJhBQfXw0= +github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8= github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= @@ -199,6 +223,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/cosmos-db v1.0.0-rc.1 h1:SjnT8B6WKMW9WEIX32qMhnEEKcI7ZP0+G1Sa9HD3nmY= +github.com/cosmos/cosmos-db v1.0.0-rc.1/go.mod h1:Dnmk3flSf5lkwCqvvjNpoxjpXzhxnCAFzKHlbaForso= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -218,6 +244,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= @@ -239,6 +266,7 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -253,6 +281,7 @@ github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -260,19 +289,23 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/firefart/nonamedreturns v1.0.1/go.mod h1:D3dpIBojGGNh5UfElmwPu73SwDCm+VKhHYqwlNOk2uQ= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -281,8 +314,15 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -296,6 +336,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -315,16 +356,22 @@ github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2 github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= @@ -366,8 +413,9 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= @@ -378,9 +426,11 @@ github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZ github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -398,6 +448,7 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -446,6 +497,7 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= @@ -495,8 +547,10 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -514,6 +568,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= +github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -521,8 +576,13 @@ github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -556,22 +616,35 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -581,6 +654,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -590,6 +664,8 @@ github.com/kulti/thelper v0.6.2/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dq github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= @@ -601,6 +677,8 @@ github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/linxGnu/grocksdb v1.7.14 h1:8lMZzyWeNP5lI0BIppX05DzmQzXj/Tgu82bgWYtowLY= +github.com/linxGnu/grocksdb v1.7.14/go.mod h1:pY55D0o+r8yUYLq70QmhdudxYvoDb9F+9puf4m3/W+U= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= @@ -611,6 +689,7 @@ github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpAp github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -618,7 +697,9 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -629,10 +710,14 @@ github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= github.com/mgechev/revive v1.2.1/go.mod h1:+Ro3wqY4vakcYNtkBWdZC7dBg1xSB6sp054wWwmeFm0= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= @@ -667,6 +752,7 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= @@ -678,7 +764,9 @@ github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4N github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= @@ -700,6 +788,7 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= @@ -748,6 +837,8 @@ github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCr github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -812,6 +903,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= @@ -823,12 +915,14 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= @@ -862,6 +956,7 @@ github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -885,6 +980,7 @@ github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -895,8 +991,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= @@ -926,15 +1023,20 @@ github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoi github.com/tommy-muehle/go-mnd/v2 v2.5.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vektra/mockery/v2 v2.14.0/go.mod h1:bnD1T8tExSgPD1ripLkDbr60JA9VtQeu12P3wgLZd7M= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= @@ -948,6 +1050,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= @@ -1053,6 +1156,9 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -1094,6 +1200,7 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1103,6 +1210,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1149,8 +1257,9 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc= golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= +golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1183,6 +1292,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1205,6 +1315,7 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1274,6 +1385,7 @@ golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1300,8 +1412,9 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 h1:fqTvyMIIj+HRzMmnzr9NtpHP6uVpvB5fkHcgPDC4nu8= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1327,6 +1440,7 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1338,6 +1452,7 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1435,6 +1550,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= @@ -1488,6 +1604,7 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1575,6 +1692,7 @@ google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1639,9 +1757,12 @@ gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/sei-iavl/import.go b/sei-iavl/import.go index aff719bda9..0dcde67de9 100644 --- a/sei-iavl/import.go +++ b/sei-iavl/import.go @@ -2,14 +2,21 @@ package iavl import ( "bytes" - - "github.com/pkg/errors" + "errors" + "fmt" + "sync" + "sync/atomic" db "github.com/tendermint/tm-db" ) -// maxBatchSize is the maximum size of the import batch before flushing it to the database -const maxBatchSize = 10000 +// desiredBatchSize is the desired batch write size of the import batch before flushing it to the database. +// The actual batch write size could exceed this value when the previous batch is still flushing. +const defaultDesiredBatchSize = 20000 + +// If there's an ongoing pending batch write, we will keep batching more writes +// until the ongoing batch write completes or we reach maxBatchSize +const defaultMaxBatchSize = 400000 // ErrNoImport is returned when calling methods on a closed importer var ErrNoImport = errors.New("no import in progress") @@ -22,14 +29,29 @@ var ErrNoImport = errors.New("no import in progress") // Importer is not concurrency-safe, it is the caller's responsibility to ensure the tree is not // modified while performing an import. type Importer struct { - tree *MutableTree - version int64 - batch db.Batch - batchSize uint32 - stack []*Node + tree *MutableTree + version int64 + batch db.Batch + batchSize uint32 + stack []*Node + desiredBatchSize uint32 + maxBatchSize uint32 + batchMtx sync.RWMutex + chNodeData chan NodeData + chNodeDataWg sync.WaitGroup + chBatch chan db.Batch + chBatchWg sync.WaitGroup + chError chan error + allChannelClosed atomic.Bool +} + +type NodeData struct { + node *Node + data []byte } // newImporter creates a new Importer for an empty MutableTree. +// Underneath it spawns three goroutines to process the data import flow. // // version should correspond to the version that was initially exported. It must be greater than // or equal to the highest ExportNode version number given. @@ -38,25 +60,104 @@ func newImporter(tree *MutableTree, version int64) (*Importer, error) { return nil, errors.New("imported version cannot be negative") } if tree.ndb.latestVersion > 0 { - return nil, errors.Errorf("found database at version %d, must be 0", tree.ndb.latestVersion) + return nil, fmt.Errorf("found database at version %d, must be 0", tree.ndb.latestVersion) } if !tree.IsEmpty() { return nil, errors.New("tree must be empty") } - return &Importer{ - tree: tree, - version: version, - batch: tree.ndb.db.NewBatch(), - stack: make([]*Node, 0, 8), - }, nil + importer := &Importer{ + tree: tree, + version: version, + batch: tree.ndb.db.NewBatch(), + stack: make([]*Node, 0, 8), + batchMtx: sync.RWMutex{}, + desiredBatchSize: defaultDesiredBatchSize, + maxBatchSize: defaultMaxBatchSize, + chNodeData: make(chan NodeData, 2*defaultDesiredBatchSize), + chNodeDataWg: sync.WaitGroup{}, + chBatch: make(chan db.Batch, 1), + chBatchWg: sync.WaitGroup{}, + chError: make(chan error, 1), + allChannelClosed: atomic.Bool{}, + } + + importer.chNodeDataWg.Add(1) + go setBatchData(importer) + + importer.chBatchWg.Add(1) + go batchWrite(importer) + + return importer, nil + +} + +// WithDesiredBatchSize set the desired batch size for write +func (i *Importer) WithDesiredBatchSize(batchSize uint32) *Importer { + i.desiredBatchSize = batchSize + return i +} + +// WithMaxBatchSize set the maximum allowed batch size for write, should be greater than desired batch size. +// Consider increase max batch size to reduce overall import time. +func (i *Importer) WithMaxBatchSize(batchSize uint32) *Importer { + i.maxBatchSize = batchSize + return i +} + +// setBatchData get the next serialized node data from channel, and write the data to the current batch +func setBatchData(i *Importer) { + for i.batch != nil { + if nodeData, open := <-i.chNodeData; open { + i.batchMtx.RLock() + if i.batch != nil { + err := i.batch.Set(i.tree.ndb.nodeKey(nodeData.node.hash), nodeData.data) + if err != nil { + i.batchMtx.RUnlock() + i.chError <- err + break + } + } + i.batchMtx.RUnlock() + i.batchSize++ + // Only commit a new batch if size meet desiredBatchSize and there's no pending batch write + if (i.batchSize >= i.desiredBatchSize && len(i.chBatch) < 1) || i.batchSize >= i.maxBatchSize { + i.chBatch <- i.batch + i.batch = i.tree.ndb.db.NewBatch() + i.batchSize = 0 + } + } else { + break + } + } + i.chNodeDataWg.Done() +} + +// batchWrite get a new batch from the channel and execute the batch write to the underline DB. +func batchWrite(i *Importer) { + for i.batch != nil { + if nextBatch, open := <-i.chBatch; open { + err := nextBatch.Write() + if err != nil { + i.chError <- err + break + } + i.batchMtx.Lock() + nextBatch.Close() + i.batchMtx.Unlock() + } else { + break + } + } + i.chBatchWg.Done() } // Close frees all resources. It is safe to call multiple times. Uncommitted nodes may already have -// been flushed to the database, but will not be visible. +// been flushed to the database, but will not be visible. Errors are ignored in the close functions. func (i *Importer) Close() { + _ = i.waitAndCloseChannels() if i.batch != nil { - i.batch.Close() + _ = i.batch.Close() } i.batch = nil i.tree = nil @@ -73,7 +174,7 @@ func (i *Importer) Add(exportNode *ExportNode) error { return errors.New("node cannot be nil") } if exportNode.Version > i.version { - return errors.Errorf("node version %v can't be greater than import version %v", + return fmt.Errorf("node version %v can't be greater than import version %v", exportNode.Version, i.version) } @@ -125,28 +226,25 @@ func (i *Importer) Add(exportNode *ExportNode) error { buf := bufPool.Get().(*bytes.Buffer) buf.Reset() - defer bufPool.Put(buf) - - if err = node.writeBytes(buf); err != nil { - return err + if err := node.writeBytes(buf); err != nil { + panic(err) } bytesCopy := make([]byte, buf.Len()) copy(bytesCopy, buf.Bytes()) + bufPool.Put(buf) - if err = i.batch.Set(i.tree.ndb.nodeKey(node.hash), bytesCopy); err != nil { + // Check errors + select { + case err := <-i.chError: return err + default: } - i.batchSize++ - if i.batchSize >= maxBatchSize { - err = i.batch.Write() - if err != nil { - return err - } - i.batch.Close() - i.batch = i.tree.ndb.db.NewBatch() - i.batchSize = 0 + // Handle the remaining steps in a separate goroutine + i.chNodeData <- NodeData{ + node: node, + data: bytesCopy, } // Update the stack now that we know there were no errors @@ -156,7 +254,8 @@ func (i *Importer) Add(exportNode *ExportNode) error { case node.leftHash != nil || node.rightHash != nil: i.stack = i.stack[:stackSize-1] } - i.stack = append(i.stack, node) + // Only hash\height\size of the node will be used after it be pushed into the stack. + i.stack = append(i.stack, &Node{hash: node.hash, height: node.height, size: node.size}) return nil } @@ -169,6 +268,11 @@ func (i *Importer) Commit() error { return ErrNoImport } + err := i.waitAndCloseChannels() + if err != nil { + return err + } + switch len(i.stack) { case 0: if err := i.batch.Set(i.tree.ndb.rootKey(i.version), []byte{}); err != nil { @@ -179,11 +283,11 @@ func (i *Importer) Commit() error { return err } default: - return errors.Errorf("invalid node structure, found stack size %v when committing", + return fmt.Errorf("invalid node structure, found stack size %v when committing", len(i.stack)) } - err := i.batch.WriteSync() + err = i.batch.WriteSync() if err != nil { return err } @@ -197,3 +301,24 @@ func (i *Importer) Commit() error { i.Close() return nil } + +// waitAndCloseChannels will try to close all the channels for importer and wait for remaining work to be done. +// This function is guarded by atomic boolean, so it will only close the channels once. Closing channels usually +// should happen in the Commit or Close action. If any error happens when draining the remaining data in the channel, +// The error will be popped out and returned. +func (i *Importer) waitAndCloseChannels() error { + // Make sure all pending works are drained and close the channels in order + if i.allChannelClosed.CompareAndSwap(false, true) { + close(i.chNodeData) + i.chNodeDataWg.Wait() + close(i.chBatch) + i.chBatchWg.Wait() + // Check errors + select { + case err := <-i.chError: + return err + default: + } + } + return nil +} From 8c2096ed58e92726ea07d80d88ecc416e28d4b3a Mon Sep 17 00:00:00 2001 From: Yiming Zang Date: Sun, 5 Feb 2023 01:45:16 -0800 Subject: [PATCH 08/69] Fix unit test --- sei-iavl/import.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sei-iavl/import.go b/sei-iavl/import.go index 0dcde67de9..a65efa7e95 100644 --- a/sei-iavl/import.go +++ b/sei-iavl/import.go @@ -2,11 +2,10 @@ package iavl import ( "bytes" - "errors" "fmt" "sync" - "sync/atomic" + "github.com/pkg/errors" db "github.com/tendermint/tm-db" ) @@ -42,7 +41,7 @@ type Importer struct { chBatch chan db.Batch chBatchWg sync.WaitGroup chError chan error - allChannelClosed atomic.Bool + allChannelClosed bool } type NodeData struct { @@ -60,7 +59,7 @@ func newImporter(tree *MutableTree, version int64) (*Importer, error) { return nil, errors.New("imported version cannot be negative") } if tree.ndb.latestVersion > 0 { - return nil, fmt.Errorf("found database at version %d, must be 0", tree.ndb.latestVersion) + return nil, errors.Errorf("found database at version %d, must be 0", tree.ndb.latestVersion) } if !tree.IsEmpty() { return nil, errors.New("tree must be empty") @@ -79,7 +78,7 @@ func newImporter(tree *MutableTree, version int64) (*Importer, error) { chBatch: make(chan db.Batch, 1), chBatchWg: sync.WaitGroup{}, chError: make(chan error, 1), - allChannelClosed: atomic.Bool{}, + allChannelClosed: false, } importer.chNodeDataWg.Add(1) @@ -174,7 +173,7 @@ func (i *Importer) Add(exportNode *ExportNode) error { return errors.New("node cannot be nil") } if exportNode.Version > i.version { - return fmt.Errorf("node version %v can't be greater than import version %v", + return errors.Errorf("node version %v can't be greater than import version %v", exportNode.Version, i.version) } @@ -308,7 +307,8 @@ func (i *Importer) Commit() error { // The error will be popped out and returned. func (i *Importer) waitAndCloseChannels() error { // Make sure all pending works are drained and close the channels in order - if i.allChannelClosed.CompareAndSwap(false, true) { + if !i.allChannelClosed { + i.allChannelClosed = true close(i.chNodeData) i.chNodeDataWg.Wait() close(i.chBatch) From ab1baa1510ed68d3299efdd70763b4c8d682fa7d Mon Sep 17 00:00:00 2001 From: Yiming Zang Date: Sun, 5 Feb 2023 01:54:08 -0800 Subject: [PATCH 09/69] Fix comment --- sei-iavl/import.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sei-iavl/import.go b/sei-iavl/import.go index a65efa7e95..2e84eb8807 100644 --- a/sei-iavl/import.go +++ b/sei-iavl/import.go @@ -302,8 +302,7 @@ func (i *Importer) Commit() error { } // waitAndCloseChannels will try to close all the channels for importer and wait for remaining work to be done. -// This function is guarded by atomic boolean, so it will only close the channels once. Closing channels usually -// should happen in the Commit or Close action. If any error happens when draining the remaining data in the channel, +// This function should only be called in the Commit or Close action. If any error happens when draining the remaining data in the channel, // The error will be popped out and returned. func (i *Importer) waitAndCloseChannels() error { // Make sure all pending works are drained and close the channels in order From c14662ce3f7e14f711a84d1422645a4420eb29c2 Mon Sep 17 00:00:00 2001 From: codchen Date: Thu, 9 Feb 2023 16:26:06 +0800 Subject: [PATCH 10/69] Add mutex around Get/Set/Remove --- sei-iavl/mutable_tree.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 4a58174c1c..d46c7a4fb1 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -130,6 +130,10 @@ func (tree *MutableTree) prepareOrphansSlice() []*Node { // to slices stored within IAVL. It returns true when an existing value was // updated, while false means it was a new key. func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { + if !tree.mtx.TryLock() { + panic("TONYTEST: error acquiring lock on iavl Remove") + } + defer tree.mtx.Unlock() var orphaned []*Node orphaned, updated, err = tree.set(key, value) if err != nil { @@ -319,6 +323,11 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph // Remove removes a key from the working tree. The given key byte slice should not be modified // after this call, since it may point to data stored inside IAVL. func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { + if !tree.mtx.TryLock() { + panic("TONYTEST: error acquiring lock on iavl Remove") + } + defer tree.mtx.Unlock() + val, orphaned, removed, err := tree.remove(key) if err != nil { return nil, false, err From a9b173efd5b0cecdb35cbcfdc573bb32165138cd Mon Sep 17 00:00:00 2001 From: codchen Date: Sun, 12 Feb 2023 14:12:55 +0800 Subject: [PATCH 11/69] stack --- sei-iavl/mutable_tree.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index d46c7a4fb1..6a951418b7 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/sha256" "fmt" + "runtime/debug" "sort" "sync" @@ -38,7 +39,9 @@ type MutableTree struct { ndb *nodeDB skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage - mtx sync.Mutex + mtx sync.Mutex + entryMtx sync.Mutex + entryStack []byte } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -130,10 +133,12 @@ func (tree *MutableTree) prepareOrphansSlice() []*Node { // to slices stored within IAVL. It returns true when an existing value was // updated, while false means it was a new key. func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { - if !tree.mtx.TryLock() { - panic("TONYTEST: error acquiring lock on iavl Remove") + if !tree.entryMtx.TryLock() { + fmt.Println(string(tree.entryStack)) + panic("TONYTEST: error acquiring lock on iavl Set") } - defer tree.mtx.Unlock() + tree.entryStack = debug.Stack() + defer tree.entryMtx.Unlock() var orphaned []*Node orphaned, updated, err = tree.set(key, value) if err != nil { @@ -323,10 +328,12 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph // Remove removes a key from the working tree. The given key byte slice should not be modified // after this call, since it may point to data stored inside IAVL. func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { - if !tree.mtx.TryLock() { + if !tree.entryMtx.TryLock() { + fmt.Println(string(tree.entryStack)) panic("TONYTEST: error acquiring lock on iavl Remove") } - defer tree.mtx.Unlock() + tree.entryStack = debug.Stack() + defer tree.entryMtx.Unlock() val, orphaned, removed, err := tree.remove(key) if err != nil { From ebab78297b1a94912be7c624a2328b967d25fe43 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 15 Feb 2023 13:12:24 +0800 Subject: [PATCH 12/69] use RWLock --- sei-iavl/mutable_tree.go | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 6a951418b7..59a44e981c 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -40,7 +40,7 @@ type MutableTree struct { skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage mtx sync.Mutex - entryMtx sync.Mutex + entryMtx sync.RWMutex entryStack []byte } @@ -154,6 +154,12 @@ func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { // Get returns the value of the specified key if it exists, or nil otherwise. // The returned value must not be modified, since it may point to data stored within IAVL. func (tree *MutableTree) Get(key []byte) ([]byte, error) { + if !tree.entryMtx.TryRLock() { + fmt.Println(string(tree.entryStack)) + panic("TONYTEST: error acquiring lock on iavl Get") + } + defer tree.entryMtx.RUnlock() + if tree.root == nil { return nil, nil } @@ -186,6 +192,12 @@ func (tree *MutableTree) Import(version int64) (*Importer, error) { // Iterate iterates over all keys of the tree. The keys and values must not be modified, // since they may point to data stored within IAVL. Returns true if stopped by callnack, false otherwise func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { + if !tree.entryMtx.TryRLock() { + fmt.Println(string(tree.entryStack)) + panic("TONYTEST: error acquiring lock on iavl Iterate") + } + defer tree.entryMtx.RUnlock() + if tree.root == nil { return false, nil } @@ -215,6 +227,12 @@ func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stoppe // Iterator returns an iterator over the mutable tree. // CONTRACT: no updates are made to the tree while an iterator is active. func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { + if !tree.entryMtx.TryRLock() { + fmt.Println(string(tree.entryStack)) + panic("TONYTEST: error acquiring lock on iavl Iterator") + } + defer tree.entryMtx.RUnlock() + if !tree.skipFastStorageUpgrade { isFastCacheEnabled, err := tree.IsFastCacheEnabled() if err != nil { @@ -483,6 +501,12 @@ func (tree *MutableTree) Load() (int64, error) { // performs a no-op. Otherwise, if the root does not exist, an error will be // returned. func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { + if !tree.entryMtx.TryLock() { + fmt.Println(string(tree.entryStack)) + panic("TONYTEST: error acquiring lock on iavl LazyLoadVersion") + } + tree.entryStack = debug.Stack() + defer tree.entryMtx.Unlock() latestVersion, err := tree.ndb.getLatestVersion() if err != nil { return 0, err @@ -553,6 +577,13 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { // Returns the version number of the latest version found func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { + if !tree.entryMtx.TryLock() { + fmt.Println(string(tree.entryStack)) + panic("TONYTEST: error acquiring lock on iavl LoadVersion") + } + tree.entryStack = debug.Stack() + defer tree.entryMtx.Unlock() + roots, err := tree.ndb.getRoots() if err != nil { return 0, err From 02784f4f23f2e1fb9e41fc6b75d7e886c7df3ac5 Mon Sep 17 00:00:00 2001 From: codchen Date: Fri, 17 Feb 2023 10:10:12 +0800 Subject: [PATCH 13/69] reset stack upon return --- sei-iavl/mutable_tree.go | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 59a44e981c..96ae98e4a6 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -135,10 +135,13 @@ func (tree *MutableTree) prepareOrphansSlice() []*Node { func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { if !tree.entryMtx.TryLock() { fmt.Println(string(tree.entryStack)) - panic("TONYTEST: error acquiring lock on iavl Set") + panic("IAVL-MT: error acquiring lock on iavl Set") } tree.entryStack = debug.Stack() - defer tree.entryMtx.Unlock() + defer func() { + tree.entryStack = []byte{} + tree.entryMtx.Unlock() + }() var orphaned []*Node orphaned, updated, err = tree.set(key, value) if err != nil { @@ -156,7 +159,7 @@ func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { func (tree *MutableTree) Get(key []byte) ([]byte, error) { if !tree.entryMtx.TryRLock() { fmt.Println(string(tree.entryStack)) - panic("TONYTEST: error acquiring lock on iavl Get") + panic("IAVL-MT: error acquiring lock on iavl Get") } defer tree.entryMtx.RUnlock() @@ -194,7 +197,7 @@ func (tree *MutableTree) Import(version int64) (*Importer, error) { func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { if !tree.entryMtx.TryRLock() { fmt.Println(string(tree.entryStack)) - panic("TONYTEST: error acquiring lock on iavl Iterate") + panic("IAVL-MT: error acquiring lock on iavl Iterate") } defer tree.entryMtx.RUnlock() @@ -229,7 +232,7 @@ func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stoppe func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { if !tree.entryMtx.TryRLock() { fmt.Println(string(tree.entryStack)) - panic("TONYTEST: error acquiring lock on iavl Iterator") + panic("IAVL-MT: error acquiring lock on iavl Iterator") } defer tree.entryMtx.RUnlock() @@ -348,10 +351,13 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { if !tree.entryMtx.TryLock() { fmt.Println(string(tree.entryStack)) - panic("TONYTEST: error acquiring lock on iavl Remove") + panic("IAVL-MT: error acquiring lock on iavl Remove") } tree.entryStack = debug.Stack() - defer tree.entryMtx.Unlock() + defer func() { + tree.entryStack = []byte{} + tree.entryMtx.Unlock() + }() val, orphaned, removed, err := tree.remove(key) if err != nil { @@ -503,10 +509,13 @@ func (tree *MutableTree) Load() (int64, error) { func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { if !tree.entryMtx.TryLock() { fmt.Println(string(tree.entryStack)) - panic("TONYTEST: error acquiring lock on iavl LazyLoadVersion") + panic("IAVL-MT: error acquiring lock on iavl LazyLoadVersion") } tree.entryStack = debug.Stack() - defer tree.entryMtx.Unlock() + defer func() { + tree.entryStack = []byte{} + tree.entryMtx.Unlock() + }() latestVersion, err := tree.ndb.getLatestVersion() if err != nil { return 0, err @@ -579,10 +588,13 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { if !tree.entryMtx.TryLock() { fmt.Println(string(tree.entryStack)) - panic("TONYTEST: error acquiring lock on iavl LoadVersion") + panic("IAVL-MT: error acquiring lock on iavl LoadVersion") } tree.entryStack = debug.Stack() - defer tree.entryMtx.Unlock() + defer func() { + tree.entryStack = []byte{} + tree.entryMtx.Unlock() + }() roots, err := tree.ndb.getRoots() if err != nil { From a52a8e2d8f88d43143c4c9e993d74d47bd2a1230 Mon Sep 17 00:00:00 2001 From: codchen Date: Fri, 17 Feb 2023 10:16:06 +0800 Subject: [PATCH 14/69] print current goroutine --- sei-iavl/mutable_tree.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 96ae98e4a6..d11bf61d46 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -134,7 +134,8 @@ func (tree *MutableTree) prepareOrphansSlice() []*Node { // updated, while false means it was a new key. func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { if !tree.entryMtx.TryLock() { - fmt.Println(string(tree.entryStack)) + fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) + fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) panic("IAVL-MT: error acquiring lock on iavl Set") } tree.entryStack = debug.Stack() @@ -158,7 +159,8 @@ func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { // The returned value must not be modified, since it may point to data stored within IAVL. func (tree *MutableTree) Get(key []byte) ([]byte, error) { if !tree.entryMtx.TryRLock() { - fmt.Println(string(tree.entryStack)) + fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) + fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) panic("IAVL-MT: error acquiring lock on iavl Get") } defer tree.entryMtx.RUnlock() @@ -196,7 +198,8 @@ func (tree *MutableTree) Import(version int64) (*Importer, error) { // since they may point to data stored within IAVL. Returns true if stopped by callnack, false otherwise func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { if !tree.entryMtx.TryRLock() { - fmt.Println(string(tree.entryStack)) + fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) + fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) panic("IAVL-MT: error acquiring lock on iavl Iterate") } defer tree.entryMtx.RUnlock() @@ -231,7 +234,8 @@ func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stoppe // CONTRACT: no updates are made to the tree while an iterator is active. func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { if !tree.entryMtx.TryRLock() { - fmt.Println(string(tree.entryStack)) + fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) + fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) panic("IAVL-MT: error acquiring lock on iavl Iterator") } defer tree.entryMtx.RUnlock() @@ -350,7 +354,8 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph // after this call, since it may point to data stored inside IAVL. func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { if !tree.entryMtx.TryLock() { - fmt.Println(string(tree.entryStack)) + fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) + fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) panic("IAVL-MT: error acquiring lock on iavl Remove") } tree.entryStack = debug.Stack() @@ -508,7 +513,8 @@ func (tree *MutableTree) Load() (int64, error) { // returned. func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { if !tree.entryMtx.TryLock() { - fmt.Println(string(tree.entryStack)) + fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) + fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) panic("IAVL-MT: error acquiring lock on iavl LazyLoadVersion") } tree.entryStack = debug.Stack() @@ -587,7 +593,8 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { // Returns the version number of the latest version found func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { if !tree.entryMtx.TryLock() { - fmt.Println(string(tree.entryStack)) + fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) + fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) panic("IAVL-MT: error acquiring lock on iavl LoadVersion") } tree.entryStack = debug.Stack() From 043b19874b65e3080cfd46f739c1b609a331be14 Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 27 Feb 2023 23:56:23 +0800 Subject: [PATCH 15/69] Remove mutex TryLocks added for debugging --- sei-iavl/mutable_tree.go | 68 +--------------------------------------- 1 file changed, 1 insertion(+), 67 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index d11bf61d46..4a58174c1c 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -4,7 +4,6 @@ import ( "bytes" "crypto/sha256" "fmt" - "runtime/debug" "sort" "sync" @@ -39,9 +38,7 @@ type MutableTree struct { ndb *nodeDB skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage - mtx sync.Mutex - entryMtx sync.RWMutex - entryStack []byte + mtx sync.Mutex } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -133,16 +130,6 @@ func (tree *MutableTree) prepareOrphansSlice() []*Node { // to slices stored within IAVL. It returns true when an existing value was // updated, while false means it was a new key. func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { - if !tree.entryMtx.TryLock() { - fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) - fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) - panic("IAVL-MT: error acquiring lock on iavl Set") - } - tree.entryStack = debug.Stack() - defer func() { - tree.entryStack = []byte{} - tree.entryMtx.Unlock() - }() var orphaned []*Node orphaned, updated, err = tree.set(key, value) if err != nil { @@ -158,13 +145,6 @@ func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { // Get returns the value of the specified key if it exists, or nil otherwise. // The returned value must not be modified, since it may point to data stored within IAVL. func (tree *MutableTree) Get(key []byte) ([]byte, error) { - if !tree.entryMtx.TryRLock() { - fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) - fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) - panic("IAVL-MT: error acquiring lock on iavl Get") - } - defer tree.entryMtx.RUnlock() - if tree.root == nil { return nil, nil } @@ -197,13 +177,6 @@ func (tree *MutableTree) Import(version int64) (*Importer, error) { // Iterate iterates over all keys of the tree. The keys and values must not be modified, // since they may point to data stored within IAVL. Returns true if stopped by callnack, false otherwise func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { - if !tree.entryMtx.TryRLock() { - fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) - fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) - panic("IAVL-MT: error acquiring lock on iavl Iterate") - } - defer tree.entryMtx.RUnlock() - if tree.root == nil { return false, nil } @@ -233,13 +206,6 @@ func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stoppe // Iterator returns an iterator over the mutable tree. // CONTRACT: no updates are made to the tree while an iterator is active. func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { - if !tree.entryMtx.TryRLock() { - fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) - fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) - panic("IAVL-MT: error acquiring lock on iavl Iterator") - } - defer tree.entryMtx.RUnlock() - if !tree.skipFastStorageUpgrade { isFastCacheEnabled, err := tree.IsFastCacheEnabled() if err != nil { @@ -353,17 +319,6 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph // Remove removes a key from the working tree. The given key byte slice should not be modified // after this call, since it may point to data stored inside IAVL. func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { - if !tree.entryMtx.TryLock() { - fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) - fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) - panic("IAVL-MT: error acquiring lock on iavl Remove") - } - tree.entryStack = debug.Stack() - defer func() { - tree.entryStack = []byte{} - tree.entryMtx.Unlock() - }() - val, orphaned, removed, err := tree.remove(key) if err != nil { return nil, false, err @@ -512,16 +467,6 @@ func (tree *MutableTree) Load() (int64, error) { // performs a no-op. Otherwise, if the root does not exist, an error will be // returned. func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { - if !tree.entryMtx.TryLock() { - fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) - fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) - panic("IAVL-MT: error acquiring lock on iavl LazyLoadVersion") - } - tree.entryStack = debug.Stack() - defer func() { - tree.entryStack = []byte{} - tree.entryMtx.Unlock() - }() latestVersion, err := tree.ndb.getLatestVersion() if err != nil { return 0, err @@ -592,17 +537,6 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { // Returns the version number of the latest version found func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { - if !tree.entryMtx.TryLock() { - fmt.Printf("Competing goroutine: %s\n", string(tree.entryStack)) - fmt.Printf("Current goroutine: %s\n", string(debug.Stack())) - panic("IAVL-MT: error acquiring lock on iavl LoadVersion") - } - tree.entryStack = debug.Stack() - defer func() { - tree.entryStack = []byte{} - tree.entryMtx.Unlock() - }() - roots, err := tree.ndb.getRoots() if err != nil { return 0, err From 1c58f21005a986e33a089549d252d6c48c0d3559 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 15:46:50 +0800 Subject: [PATCH 16/69] Proper locking --- sei-iavl/immutable_tree.go | 7 ++++--- sei-iavl/iterator.go | 37 +++++++++++++++++++++++++------------ sei-iavl/mutable_tree.go | 36 +++++++++++++++++++++++++++--------- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index 5113873c86..f52fe3e4f1 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -3,6 +3,7 @@ package iavl import ( "fmt" "strings" + "sync" dbm "github.com/tendermint/tm-db" ) @@ -230,7 +231,7 @@ func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (bool, e return false, nil } - itr, err := t.Iterator(nil, nil, true) + itr, err := t.Iterator(nil, nil, true, nil) defer itr.Close() if err != nil { return false, err @@ -245,7 +246,7 @@ func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (bool, e } // Iterator returns an iterator over the immutable tree. -func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { +func (t *ImmutableTree) Iterator(start, end []byte, ascending bool, mtx *sync.RWMutex) (dbm.Iterator, error) { if !t.skipFastStorageUpgrade { isFastCacheEnabled, err := t.IsFastCacheEnabled() if err != nil { @@ -256,7 +257,7 @@ func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterato return NewFastIterator(start, end, ascending, t.ndb), nil } } - return NewIterator(start, end, ascending, t), nil + return NewIterator(start, end, ascending, t, mtx), nil } // IterateRange makes a callback for all nodes with key between start and end non-inclusive. diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index a509ed1ad4..8d64920592 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -6,6 +6,7 @@ package iavl import ( "bytes" "errors" + "sync" dbm "github.com/tendermint/tm-db" ) @@ -76,19 +77,19 @@ func (nodes *delayedNodes) length() int { // 1. If it is not an delayed node (node.delayed == false) it immediately returns it. // // A. If the `node` is a branch node: -// 1. If the traversal is postorder, then append the current node to the t.delayedNodes, -// with `delayed` set to false. This makes the current node returned *after* all the children -// are traversed, without being expanded. -// 2. Append the traversable children nodes into the `delayedNodes`, with `delayed` set to true. This -// makes the children nodes to be traversed, and expanded with their respective children. -// 3. If the traversal is preorder, (with the children to be traversed already pushed to the -// `delayedNodes`), returns the current node. -// 4. Call `traversal.next()` to further traverse through the `delayedNodes`. +// 1. If the traversal is postorder, then append the current node to the t.delayedNodes, +// with `delayed` set to false. This makes the current node returned *after* all the children +// are traversed, without being expanded. +// 2. Append the traversable children nodes into the `delayedNodes`, with `delayed` set to true. This +// makes the children nodes to be traversed, and expanded with their respective children. +// 3. If the traversal is preorder, (with the children to be traversed already pushed to the +// `delayedNodes`), returns the current node. +// 4. Call `traversal.next()` to further traverse through the `delayedNodes`. // // B. If the `node` is a leaf node, it will be returned without expand, by the following process: -// 1. If the traversal is postorder, the current node will be append to the `delayedNodes` with `delayed` -// set to false, and immediately returned at the subsequent call of `traversal.next()` at the last line. -// 2. If the traversal is preorder, the current node will be returned. +// 1. If the traversal is postorder, the current node will be append to the `delayedNodes` with `delayed` +// set to false, and immediately returned at the subsequent call of `traversal.next()` at the last line. +// 2. If the traversal is preorder, the current node will be returned. func (t *traversal) next() (*Node, error) { // End of traversal. if t.delayedNodes.length() == 0 { @@ -179,18 +180,24 @@ type Iterator struct { err error t *traversal + + mtx *sync.RWMutex } var _ dbm.Iterator = (*Iterator)(nil) // Returns a new iterator over the immutable tree. If the tree is nil, the iterator will be invalid. -func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree) dbm.Iterator { +func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree, mtx *sync.RWMutex) dbm.Iterator { iter := &Iterator{ start: start, end: end, + mtx: mtx, } if tree == nil { + if mtx != nil { + mtx.Unlock() + } iter.err = errIteratorNilTreeGiven } else { iter.valid = true @@ -232,6 +239,9 @@ func (iter *Iterator) Next() { if node == nil || err != nil { iter.t = nil iter.valid = false + if iter.mtx != nil { + iter.mtx.Unlock() + } return } @@ -247,6 +257,9 @@ func (iter *Iterator) Next() { func (iter *Iterator) Close() error { iter.t = nil iter.valid = false + if iter.mtx != nil { + iter.mtx.Unlock() + } return iter.err } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 4a58174c1c..076cd89e79 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -38,7 +38,7 @@ type MutableTree struct { ndb *nodeDB skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage - mtx sync.Mutex + mtx sync.RWMutex } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -67,6 +67,8 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto // IsEmpty returns whether or not the tree has any keys. Only trees that are // not empty can be saved. func (tree *MutableTree) IsEmpty() bool { + tree.mtx.RLock() + defer tree.mtx.RUnlock() return tree.ImmutableTree.Size() == 0 } @@ -130,6 +132,8 @@ func (tree *MutableTree) prepareOrphansSlice() []*Node { // to slices stored within IAVL. It returns true when an existing value was // updated, while false means it was a new key. func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { + tree.mtx.Lock() + defer tree.mtx.Unlock() var orphaned []*Node orphaned, updated, err = tree.set(key, value) if err != nil { @@ -145,6 +149,8 @@ func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { // Get returns the value of the specified key if it exists, or nil otherwise. // The returned value must not be modified, since it may point to data stored within IAVL. func (tree *MutableTree) Get(key []byte) ([]byte, error) { + tree.mtx.Lock() + defer tree.mtx.Unlock() if tree.root == nil { return nil, nil } @@ -177,6 +183,9 @@ func (tree *MutableTree) Import(version int64) (*Importer, error) { // Iterate iterates over all keys of the tree. The keys and values must not be modified, // since they may point to data stored within IAVL. Returns true if stopped by callnack, false otherwise func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { + tree.mtx.Lock() + defer tree.mtx.Unlock() + if tree.root == nil { return false, nil } @@ -217,7 +226,7 @@ func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterat } } - return tree.ImmutableTree.Iterator(start, end, ascending) + return tree.ImmutableTree.Iterator(start, end, ascending, &tree.mtx) } func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated bool, err error) { @@ -319,6 +328,8 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph // Remove removes a key from the working tree. The given key byte slice should not be modified // after this call, since it may point to data stored inside IAVL. func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { + tree.mtx.Lock() + defer tree.mtx.Unlock() val, orphaned, removed, err := tree.remove(key) if err != nil { return nil, false, err @@ -708,7 +719,7 @@ func (tree *MutableTree) enableFastStorageAndCommitLocked() error { func (tree *MutableTree) enableFastStorageAndCommit() error { var err error - itr := NewIterator(nil, nil, true, tree.ImmutableTree) + itr := NewIterator(nil, nil, true, tree.ImmutableTree, nil) defer itr.Close() var upgradedFastNodes uint64 for ; itr.Valid(); itr.Next() { @@ -873,6 +884,8 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { } if tree.VersionExists(version) { + tree.mtx.Lock() + defer tree.mtx.Unlock() // If the version already exists, return an error as we're attempting to overwrite. // However, the same hash means idempotent (i.e. no-op). existingHash, err := tree.ndb.getRoot(version) @@ -902,12 +915,13 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { return nil, version, fmt.Errorf("version %d was already saved to different hash %X (existing hash %X)", version, newHash, existingHash) } + tree.mtx.Lock() + defer tree.mtx.Unlock() + if v, err := tree.commitVersion(version, false); err != nil { return nil, v, err } - tree.mtx.Lock() - defer tree.mtx.Unlock() tree.version = version tree.versions[version] = true @@ -1055,6 +1069,9 @@ func (tree *MutableTree) SetInitialVersion(version uint64) { // DeleteVersions deletes a series of versions from the MutableTree. // Deprecated: please use DeleteVersionsRange instead. func (tree *MutableTree) DeleteVersions(versions ...int64) error { + tree.mtx.Lock() + defer tree.mtx.Unlock() + logger.Debug("DELETING VERSIONS: %v\n", versions) if len(versions) == 0 { @@ -1088,6 +1105,9 @@ func (tree *MutableTree) DeleteVersions(versions ...int64) error { // An error is returned if any single version has active readers. // All writes happen in a single batch with a single commit. func (tree *MutableTree) DeleteVersionsRange(fromVersion, toVersion int64) error { + tree.mtx.Lock() + defer tree.mtx.Unlock() + if err := tree.ndb.DeleteVersionsRange(fromVersion, toVersion); err != nil { return err } @@ -1096,8 +1116,6 @@ func (tree *MutableTree) DeleteVersionsRange(fromVersion, toVersion int64) error return err } - tree.mtx.Lock() - defer tree.mtx.Unlock() for version := fromVersion; version < toVersion; version++ { delete(tree.versions, version) } @@ -1109,6 +1127,8 @@ func (tree *MutableTree) DeleteVersionsRange(fromVersion, toVersion int64) error // longer be accessed. func (tree *MutableTree) DeleteVersion(version int64) error { logger.Debug("DELETE VERSION: %d\n", version) + tree.mtx.Lock() + defer tree.mtx.Unlock() if err := tree.deleteVersion(version); err != nil { return err @@ -1118,8 +1138,6 @@ func (tree *MutableTree) DeleteVersion(version int64) error { return err } - tree.mtx.Lock() - defer tree.mtx.Unlock() delete(tree.versions, version) return nil } From 7ed565e67574817f6a4435ce21cf94d09e8dbfdd Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 16:42:19 +0800 Subject: [PATCH 17/69] fix --- sei-iavl/benchmarks/bench_test.go | 2 +- sei-iavl/immutable_tree.go | 8 +++++--- sei-iavl/iterator_test.go | 6 +++--- sei-iavl/mutable_tree.go | 5 +---- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/sei-iavl/benchmarks/bench_test.go b/sei-iavl/benchmarks/bench_test.go index f845c02d4f..68b1cb3ed4 100644 --- a/sei-iavl/benchmarks/bench_test.go +++ b/sei-iavl/benchmarks/bench_test.go @@ -136,7 +136,7 @@ func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) { func runIterationSlow(b *testing.B, t *iavl.MutableTree, expectedSize int) { for i := 0; i < b.N; i++ { - itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree) // create slow iterator directly + itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree, nil) // create slow iterator directly iterate(b, itr, expectedSize) require.Nil(b, itr.Close(), ".Close should not error out") } diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index f52fe3e4f1..63e2f8fda5 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -19,6 +19,7 @@ type ImmutableTree struct { ndb *nodeDB version int64 skipFastStorageUpgrade bool + mtx sync.RWMutex } // NewImmutableTree creates both in-memory and persistent instances @@ -231,7 +232,7 @@ func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (bool, e return false, nil } - itr, err := t.Iterator(nil, nil, true, nil) + itr, err := t.Iterator(nil, nil, true) defer itr.Close() if err != nil { return false, err @@ -246,7 +247,7 @@ func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (bool, e } // Iterator returns an iterator over the immutable tree. -func (t *ImmutableTree) Iterator(start, end []byte, ascending bool, mtx *sync.RWMutex) (dbm.Iterator, error) { +func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { if !t.skipFastStorageUpgrade { isFastCacheEnabled, err := t.IsFastCacheEnabled() if err != nil { @@ -257,7 +258,8 @@ func (t *ImmutableTree) Iterator(start, end []byte, ascending bool, mtx *sync.RW return NewFastIterator(start, end, ascending, t.ndb), nil } } - return NewIterator(start, end, ascending, t, mtx), nil + t.mtx.Lock() + return NewIterator(start, end, ascending, t, &t.mtx), nil } // IterateRange makes a callback for all nodes with key between start and end non-inclusive. diff --git a/sei-iavl/iterator_test.go b/sei-iavl/iterator_test.go index 4164e055a8..4a3ae44ddb 100644 --- a/sei-iavl/iterator_test.go +++ b/sei-iavl/iterator_test.go @@ -23,7 +23,7 @@ func TestIterator_NewIterator_NilTree_Failure(t *testing.T) { } t.Run("Iterator", func(t *testing.T) { - itr := NewIterator(start, end, ascending, nil) + itr := NewIterator(start, end, ascending, nil, nil) performTest(t, itr) require.ErrorIs(t, errIteratorNilTreeGiven, itr.Error()) }) @@ -198,7 +198,7 @@ func TestIterator_WithDelete_Full_Ascending_Success(t *testing.T) { }) t.Run("Iterator", func(t *testing.T) { - itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree) + itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree, nil) require.True(t, itr.Valid()) assertIterator(t, itr, sortedMirror, config.ascending) }) @@ -259,7 +259,7 @@ func setupIteratorAndMirror(t *testing.T, config *iteratorTestConfig) (dbm.Itera immutableTree, err := tree.GetImmutable(latestVersion) require.NoError(t, err) - itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree) + itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree, nil) return itr, mirror } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 076cd89e79..9bffdb8c9d 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -5,7 +5,6 @@ import ( "crypto/sha256" "fmt" "sort" - "sync" "github.com/pkg/errors" dbm "github.com/tendermint/tm-db" @@ -37,8 +36,6 @@ type MutableTree struct { unsavedFastNodeRemovals map[string]interface{} // FastNodes that have not yet been removed from disk ndb *nodeDB skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage - - mtx sync.RWMutex } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -226,7 +223,7 @@ func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterat } } - return tree.ImmutableTree.Iterator(start, end, ascending, &tree.mtx) + return tree.ImmutableTree.Iterator(start, end, ascending) } func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated bool, err error) { From 349e7f0d57d54d712cf59e60b60e62655946d938 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 18:18:20 +0800 Subject: [PATCH 18/69] safe unlock --- sei-iavl/iterator.go | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index 8d64920592..f8b0e74b89 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -181,7 +181,8 @@ type Iterator struct { t *traversal - mtx *sync.RWMutex + mtx *sync.RWMutex + locked bool } var _ dbm.Iterator = (*Iterator)(nil) @@ -189,15 +190,14 @@ var _ dbm.Iterator = (*Iterator)(nil) // Returns a new iterator over the immutable tree. If the tree is nil, the iterator will be invalid. func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree, mtx *sync.RWMutex) dbm.Iterator { iter := &Iterator{ - start: start, - end: end, - mtx: mtx, + start: start, + end: end, + mtx: mtx, + locked: true, } if tree == nil { - if mtx != nil { - mtx.Unlock() - } + iter.unlock() iter.err = errIteratorNilTreeGiven } else { iter.valid = true @@ -239,9 +239,7 @@ func (iter *Iterator) Next() { if node == nil || err != nil { iter.t = nil iter.valid = false - if iter.mtx != nil { - iter.mtx.Unlock() - } + iter.unlock() return } @@ -257,9 +255,7 @@ func (iter *Iterator) Next() { func (iter *Iterator) Close() error { iter.t = nil iter.valid = false - if iter.mtx != nil { - iter.mtx.Unlock() - } + iter.unlock() return iter.err } @@ -272,3 +268,14 @@ func (iter *Iterator) Error() error { func (iter *Iterator) IsFast() bool { return false } + +func (iter *Iterator) unlock() { + if iter.mtx == nil { + return + } + if !iter.locked { + return + } + defer iter.mtx.Unlock() + iter.locked = false +} From 5c1ef59e9f119a27ea49d895dfd491dbd1e5a6aa Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 19:16:38 +0800 Subject: [PATCH 19/69] fix --- sei-iavl/immutable_tree.go | 4 ++-- sei-iavl/iterator.go | 18 +++++++++++------- sei-iavl/mutable_tree.go | 3 ++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index 63e2f8fda5..ef16ea8279 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -19,7 +19,7 @@ type ImmutableTree struct { ndb *nodeDB version int64 skipFastStorageUpgrade bool - mtx sync.RWMutex + mtx *sync.RWMutex } // NewImmutableTree creates both in-memory and persistent instances @@ -259,7 +259,7 @@ func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterato } } t.mtx.Lock() - return NewIterator(start, end, ascending, t, &t.mtx), nil + return NewIterator(start, end, ascending, t, t.mtx), nil } // IterateRange makes a callback for all nodes with key between start and end non-inclusive. diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index f8b0e74b89..b23c7c5331 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -181,8 +181,9 @@ type Iterator struct { t *traversal - mtx *sync.RWMutex - locked bool + mtx *sync.RWMutex + locked bool + unlockMtx *sync.Mutex } var _ dbm.Iterator = (*Iterator)(nil) @@ -190,10 +191,11 @@ var _ dbm.Iterator = (*Iterator)(nil) // Returns a new iterator over the immutable tree. If the tree is nil, the iterator will be invalid. func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree, mtx *sync.RWMutex) dbm.Iterator { iter := &Iterator{ - start: start, - end: end, - mtx: mtx, - locked: true, + start: start, + end: end, + mtx: mtx, + locked: true, + unlockMtx: &sync.Mutex{}, } if tree == nil { @@ -270,12 +272,14 @@ func (iter *Iterator) IsFast() bool { } func (iter *Iterator) unlock() { + iter.unlockMtx.Lock() + defer iter.unlockMtx.Unlock() if iter.mtx == nil { return } if !iter.locked { return } - defer iter.mtx.Unlock() + iter.mtx.Unlock() iter.locked = false } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 9bffdb8c9d..8fe214ba85 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "fmt" "sort" + "sync" "github.com/pkg/errors" dbm "github.com/tendermint/tm-db" @@ -46,7 +47,7 @@ func NewMutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) (*Mut // NewMutableTreeWithOpts returns a new tree with the specified options. func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) (*MutableTree, error) { ndb := newNodeDB(db, cacheSize, opts) - head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade} + head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade, mtx: &sync.RWMutex{}} return &MutableTree{ ImmutableTree: head, From 6da59ead47a63bd227f237c4cb260a9378ecd189 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 20:08:52 +0800 Subject: [PATCH 20/69] fix --- sei-iavl/immutable_tree.go | 2 +- sei-iavl/iterator.go | 4 ++-- sei-iavl/mutable_tree.go | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index ef16ea8279..e743dd8c51 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -19,7 +19,7 @@ type ImmutableTree struct { ndb *nodeDB version int64 skipFastStorageUpgrade bool - mtx *sync.RWMutex + mtx *sync.Mutex } // NewImmutableTree creates both in-memory and persistent instances diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index b23c7c5331..6754031bcb 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -181,7 +181,7 @@ type Iterator struct { t *traversal - mtx *sync.RWMutex + mtx *sync.Mutex locked bool unlockMtx *sync.Mutex } @@ -189,7 +189,7 @@ type Iterator struct { var _ dbm.Iterator = (*Iterator)(nil) // Returns a new iterator over the immutable tree. If the tree is nil, the iterator will be invalid. -func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree, mtx *sync.RWMutex) dbm.Iterator { +func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree, mtx *sync.Mutex) dbm.Iterator { iter := &Iterator{ start: start, end: end, diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 8fe214ba85..d43e75ebc7 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -47,7 +47,7 @@ func NewMutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) (*Mut // NewMutableTreeWithOpts returns a new tree with the specified options. func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) (*MutableTree, error) { ndb := newNodeDB(db, cacheSize, opts) - head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade, mtx: &sync.RWMutex{}} + head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade, mtx: &sync.Mutex{}} return &MutableTree{ ImmutableTree: head, @@ -65,8 +65,8 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto // IsEmpty returns whether or not the tree has any keys. Only trees that are // not empty can be saved. func (tree *MutableTree) IsEmpty() bool { - tree.mtx.RLock() - defer tree.mtx.RUnlock() + tree.mtx.Lock() + defer tree.mtx.Unlock() return tree.ImmutableTree.Size() == 0 } From 6179ba5d05aca03a21a8a79cf1e7f655f3f60309 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 20:50:01 +0800 Subject: [PATCH 21/69] fix --- sei-iavl/immutable_tree.go | 4 ++-- sei-iavl/iterator.go | 13 +++++-------- sei-iavl/mutable_tree.go | 4 ++-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index e743dd8c51..95ac9454e6 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -19,7 +19,7 @@ type ImmutableTree struct { ndb *nodeDB version int64 skipFastStorageUpgrade bool - mtx *sync.Mutex + mtx sync.Mutex } // NewImmutableTree creates both in-memory and persistent instances @@ -259,7 +259,7 @@ func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterato } } t.mtx.Lock() - return NewIterator(start, end, ascending, t, t.mtx), nil + return NewIterator(start, end, ascending, t, t.mtx, true), nil } // IterateRange makes a callback for all nodes with key between start and end non-inclusive. diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index 6754031bcb..5430361c77 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -181,21 +181,21 @@ type Iterator struct { t *traversal - mtx *sync.Mutex + mtx sync.Mutex locked bool - unlockMtx *sync.Mutex + unlockMtx sync.Mutex } var _ dbm.Iterator = (*Iterator)(nil) // Returns a new iterator over the immutable tree. If the tree is nil, the iterator will be invalid. -func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree, mtx *sync.Mutex) dbm.Iterator { +func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree, mtx sync.Mutex, locked bool) dbm.Iterator { iter := &Iterator{ start: start, end: end, mtx: mtx, - locked: true, - unlockMtx: &sync.Mutex{}, + locked: locked, + unlockMtx: sync.Mutex{}, } if tree == nil { @@ -274,9 +274,6 @@ func (iter *Iterator) IsFast() bool { func (iter *Iterator) unlock() { iter.unlockMtx.Lock() defer iter.unlockMtx.Unlock() - if iter.mtx == nil { - return - } if !iter.locked { return } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index d43e75ebc7..b368f82d68 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -47,7 +47,7 @@ func NewMutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) (*Mut // NewMutableTreeWithOpts returns a new tree with the specified options. func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) (*MutableTree, error) { ndb := newNodeDB(db, cacheSize, opts) - head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade, mtx: &sync.Mutex{}} + head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade} return &MutableTree{ ImmutableTree: head, @@ -717,7 +717,7 @@ func (tree *MutableTree) enableFastStorageAndCommitLocked() error { func (tree *MutableTree) enableFastStorageAndCommit() error { var err error - itr := NewIterator(nil, nil, true, tree.ImmutableTree, nil) + itr := NewIterator(nil, nil, true, tree.ImmutableTree, sync.Mutex{}, false) defer itr.Close() var upgradedFastNodes uint64 for ; itr.Valid(); itr.Next() { From 793185e9ff7bcc6140d3a86dcf523b5a1791be29 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 21:48:38 +0800 Subject: [PATCH 22/69] fix --- sei-iavl/benchmarks/bench_test.go | 2 +- sei-iavl/immutable_tree.go | 4 +-- sei-iavl/iterator.go | 57 +++++++++++++------------------ sei-iavl/iterator_test.go | 6 ++-- sei-iavl/mutable_tree.go | 3 +- 5 files changed, 31 insertions(+), 41 deletions(-) diff --git a/sei-iavl/benchmarks/bench_test.go b/sei-iavl/benchmarks/bench_test.go index 68b1cb3ed4..f845c02d4f 100644 --- a/sei-iavl/benchmarks/bench_test.go +++ b/sei-iavl/benchmarks/bench_test.go @@ -136,7 +136,7 @@ func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) { func runIterationSlow(b *testing.B, t *iavl.MutableTree, expectedSize int) { for i := 0; i < b.N; i++ { - itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree, nil) // create slow iterator directly + itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree) // create slow iterator directly iterate(b, itr, expectedSize) require.Nil(b, itr.Close(), ".Close should not error out") } diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index 95ac9454e6..2db9e99846 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -258,8 +258,8 @@ func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterato return NewFastIterator(start, end, ascending, t.ndb), nil } } - t.mtx.Lock() - return NewIterator(start, end, ascending, t, t.mtx, true), nil + + return NewIterator(start, end, ascending, t), nil } // IterateRange makes a callback for all nodes with key between start and end non-inclusive. diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index 5430361c77..bece91090e 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -6,7 +6,6 @@ package iavl import ( "bytes" "errors" - "sync" dbm "github.com/tendermint/tm-db" ) @@ -91,16 +90,29 @@ func (nodes *delayedNodes) length() int { // set to false, and immediately returned at the subsequent call of `traversal.next()` at the last line. // 2. If the traversal is preorder, the current node will be returned. func (t *traversal) next() (*Node, error) { + n, err, shouldReturn := t.doNext() + if shouldReturn { + return n, err + } + + // Keep traversing and expanding the remaning delayed nodes. A-4. + return t.next() +} + +func (t *traversal) doNext() (*Node, error, bool) { + t.tree.mtx.Lock() + defer t.tree.mtx.Unlock() + // End of traversal. if t.delayedNodes.length() == 0 { - return nil, nil + return nil, nil, true } node, delayed := t.delayedNodes.pop() // Already expanded, immediately return. if !delayed || node == nil { - return node, nil + return node, nil, true } afterStart := t.start == nil || bytes.Compare(t.start, node.key) < 0 @@ -125,7 +137,7 @@ func (t *traversal) next() (*Node, error) { // push the delayed traversal for the right nodes, rightNode, err := node.getRightNode(t.tree) if err != nil { - return nil, err + return nil, err, true } t.delayedNodes.push(rightNode, true) } @@ -133,7 +145,7 @@ func (t *traversal) next() (*Node, error) { // push the delayed traversal for the left nodes, leftNode, err := node.getLeftNode(t.tree) if err != nil { - return nil, err + return nil, err, true } t.delayedNodes.push(leftNode, true) } @@ -144,7 +156,7 @@ func (t *traversal) next() (*Node, error) { // push the delayed traversal for the left nodes, leftNode, err := node.getLeftNode(t.tree) if err != nil { - return nil, err + return nil, err, true } t.delayedNodes.push(leftNode, true) } @@ -152,7 +164,7 @@ func (t *traversal) next() (*Node, error) { // push the delayed traversal for the right nodes, rightNode, err := node.getRightNode(t.tree) if err != nil { - return nil, err + return nil, err, true } t.delayedNodes.push(rightNode, true) } @@ -162,11 +174,10 @@ func (t *traversal) next() (*Node, error) { // case of preorder traversal. A-3 and B-2. // Process root then (recursively) processing left child, then process right child if !t.post && (!node.isLeaf() || (startOrAfter && beforeEnd)) { - return node, nil + return node, nil, true } - // Keep traversing and expanding the remaning delayed nodes. A-4. - return t.next() + return nil, nil, false } // Iterator is a dbm.Iterator for ImmutableTree @@ -180,26 +191,18 @@ type Iterator struct { err error t *traversal - - mtx sync.Mutex - locked bool - unlockMtx sync.Mutex } var _ dbm.Iterator = (*Iterator)(nil) // Returns a new iterator over the immutable tree. If the tree is nil, the iterator will be invalid. -func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree, mtx sync.Mutex, locked bool) dbm.Iterator { +func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree) dbm.Iterator { iter := &Iterator{ - start: start, - end: end, - mtx: mtx, - locked: locked, - unlockMtx: sync.Mutex{}, + start: start, + end: end, } if tree == nil { - iter.unlock() iter.err = errIteratorNilTreeGiven } else { iter.valid = true @@ -241,7 +244,6 @@ func (iter *Iterator) Next() { if node == nil || err != nil { iter.t = nil iter.valid = false - iter.unlock() return } @@ -257,7 +259,6 @@ func (iter *Iterator) Next() { func (iter *Iterator) Close() error { iter.t = nil iter.valid = false - iter.unlock() return iter.err } @@ -270,13 +271,3 @@ func (iter *Iterator) Error() error { func (iter *Iterator) IsFast() bool { return false } - -func (iter *Iterator) unlock() { - iter.unlockMtx.Lock() - defer iter.unlockMtx.Unlock() - if !iter.locked { - return - } - iter.mtx.Unlock() - iter.locked = false -} diff --git a/sei-iavl/iterator_test.go b/sei-iavl/iterator_test.go index 4a3ae44ddb..4164e055a8 100644 --- a/sei-iavl/iterator_test.go +++ b/sei-iavl/iterator_test.go @@ -23,7 +23,7 @@ func TestIterator_NewIterator_NilTree_Failure(t *testing.T) { } t.Run("Iterator", func(t *testing.T) { - itr := NewIterator(start, end, ascending, nil, nil) + itr := NewIterator(start, end, ascending, nil) performTest(t, itr) require.ErrorIs(t, errIteratorNilTreeGiven, itr.Error()) }) @@ -198,7 +198,7 @@ func TestIterator_WithDelete_Full_Ascending_Success(t *testing.T) { }) t.Run("Iterator", func(t *testing.T) { - itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree, nil) + itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree) require.True(t, itr.Valid()) assertIterator(t, itr, sortedMirror, config.ascending) }) @@ -259,7 +259,7 @@ func setupIteratorAndMirror(t *testing.T, config *iteratorTestConfig) (dbm.Itera immutableTree, err := tree.GetImmutable(latestVersion) require.NoError(t, err) - itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree, nil) + itr := NewIterator(config.startIterate, config.endIterate, config.ascending, immutableTree) return itr, mirror } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index b368f82d68..e630063046 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -5,7 +5,6 @@ import ( "crypto/sha256" "fmt" "sort" - "sync" "github.com/pkg/errors" dbm "github.com/tendermint/tm-db" @@ -717,7 +716,7 @@ func (tree *MutableTree) enableFastStorageAndCommitLocked() error { func (tree *MutableTree) enableFastStorageAndCommit() error { var err error - itr := NewIterator(nil, nil, true, tree.ImmutableTree, sync.Mutex{}, false) + itr := NewIterator(nil, nil, true, tree.ImmutableTree) defer itr.Close() var upgradedFastNodes uint64 for ; itr.Valid(); itr.Next() { From 5248682ad0349c7a23592a2fa1961184cc9afeca Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 23:45:20 +0800 Subject: [PATCH 23/69] fix --- sei-iavl/immutable_tree.go | 3 ++- sei-iavl/mutable_tree.go | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index 2db9e99846..44af42fdb4 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -19,7 +19,7 @@ type ImmutableTree struct { ndb *nodeDB version int64 skipFastStorageUpgrade bool - mtx sync.Mutex + mtx *sync.Mutex } // NewImmutableTree creates both in-memory and persistent instances @@ -320,6 +320,7 @@ func (t *ImmutableTree) clone() *ImmutableTree { ndb: t.ndb, version: t.version, skipFastStorageUpgrade: t.skipFastStorageUpgrade, + mtx: t.mtx, } } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index e630063046..97ccf29e95 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -519,6 +519,7 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { ndb: tree.ndb, version: targetVersion, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + mtx: tree.mtx, } if len(rootHash) > 0 { // If rootHash is empty then root of tree should be nil @@ -595,6 +596,7 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { ndb: tree.ndb, version: latestVersion, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + mtx: tree.mtx, } if len(latestRoot) != 0 { @@ -759,6 +761,7 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { ndb: tree.ndb, version: version, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + mtx: tree.mtx, }, nil } tree.versions[version] = true @@ -772,6 +775,7 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { ndb: tree.ndb, version: version, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + mtx: tree.mtx, }, nil } @@ -785,6 +789,7 @@ func (tree *MutableTree) Rollback() { ndb: tree.ndb, version: 0, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + mtx: tree.mtx, } } tree.orphans = map[string]int64{} From 0d3d8000223bbdcc3fef9aed225d3478f5294922 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 23:49:19 +0800 Subject: [PATCH 24/69] fix --- sei-iavl/immutable_tree.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index 44af42fdb4..d70cd48e6e 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -32,6 +32,7 @@ func NewImmutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) *Im // NodeDB-backed Tree. ndb: newNodeDB(db, cacheSize, nil), skipFastStorageUpgrade: skipFastStorageUpgrade, + mtx: &sync.Mutex{}, } } @@ -41,6 +42,7 @@ func NewImmutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastS // NodeDB-backed Tree. ndb: newNodeDB(db, cacheSize, opts), skipFastStorageUpgrade: skipFastStorageUpgrade, + mtx: &sync.Mutex{}, } } From 80c1ea925094ccb825ddb7a42990649947832dbf Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 1 Mar 2023 23:51:47 +0800 Subject: [PATCH 25/69] fix --- sei-iavl/mutable_tree.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 97ccf29e95..e81c5f0b6e 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "fmt" "sort" + "sync" "github.com/pkg/errors" dbm "github.com/tendermint/tm-db" @@ -46,7 +47,7 @@ func NewMutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) (*Mut // NewMutableTreeWithOpts returns a new tree with the specified options. func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) (*MutableTree, error) { ndb := newNodeDB(db, cacheSize, opts) - head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade} + head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade, mtx: &sync.Mutex{}} return &MutableTree{ ImmutableTree: head, From 565140997b4dc38ccf2e699bcef6c4dfbcf0ac2c Mon Sep 17 00:00:00 2001 From: codchen Date: Thu, 2 Mar 2023 10:43:55 +0800 Subject: [PATCH 26/69] fix --- sei-iavl/mutable_tree.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index e81c5f0b6e..476912d220 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -181,9 +181,6 @@ func (tree *MutableTree) Import(version int64) (*Importer, error) { // Iterate iterates over all keys of the tree. The keys and values must not be modified, // since they may point to data stored within IAVL. Returns true if stopped by callnack, false otherwise func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { - tree.mtx.Lock() - defer tree.mtx.Unlock() - if tree.root == nil { return false, nil } From 79f31018495d9f9dbda76e9388ad729985d570e3 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:18:57 -0500 Subject: [PATCH 27/69] Use bigger job --- sei-iavl/.github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sei-iavl/.github/workflows/ci.yml b/sei-iavl/.github/workflows/ci.yml index 3795814feb..a6be0a6bd6 100644 --- a/sei-iavl/.github/workflows/ci.yml +++ b/sei-iavl/.github/workflows/ci.yml @@ -15,7 +15,9 @@ jobs: if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" Test: - runs-on: ubuntu-latest + runs-on: + group: ubuntu-runners + labels: ubuntu-20.04-16core steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 From 658c76a1844ed4dafddd65a09e2984df334aa1c4 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:22:21 -0500 Subject: [PATCH 28/69] 8cores --- sei-iavl/.github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sei-iavl/.github/workflows/ci.yml b/sei-iavl/.github/workflows/ci.yml index a6be0a6bd6..36a27e8d78 100644 --- a/sei-iavl/.github/workflows/ci.yml +++ b/sei-iavl/.github/workflows/ci.yml @@ -15,9 +15,7 @@ jobs: if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" Test: - runs-on: - group: ubuntu-runners - labels: ubuntu-20.04-16core + runs-on: ubuntu-latest-8-cores steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 From 4a0e89c471a61dcf160e8c43e7e35c1f43b354e9 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:38:11 -0500 Subject: [PATCH 29/69] Revert config --- sei-iavl/.github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sei-iavl/.github/workflows/ci.yml b/sei-iavl/.github/workflows/ci.yml index 36a27e8d78..3795814feb 100644 --- a/sei-iavl/.github/workflows/ci.yml +++ b/sei-iavl/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" Test: - runs-on: ubuntu-latest-8-cores + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 From 9e7c776b4557b282cd1363c207a8ba2b4a4977f0 Mon Sep 17 00:00:00 2001 From: codchen Date: Sat, 4 Mar 2023 12:35:02 +0800 Subject: [PATCH 30/69] fix --- sei-iavl/mutable_tree.go | 53 +++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 476912d220..58574bb3d5 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -472,7 +472,7 @@ func (tree *MutableTree) Load() (int64, error) { // will be loaded by default. If the latest version is non-positive, this method // performs a no-op. Otherwise, if the root does not exist, an error will be // returned. -func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { +func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, toErr error) { latestVersion, err := tree.ndb.getLatestVersion() if err != nil { return 0, err @@ -509,7 +509,16 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { } tree.mtx.Lock() - defer tree.mtx.Unlock() + defer func() { + tree.mtx.Unlock() + if !tree.skipFastStorageUpgrade { + // Attempt to upgrade + if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { + toReturn = 0 + toErr = err + } + } + }() tree.versions[targetVersion] = true @@ -532,18 +541,11 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) { tree.ImmutableTree = iTree tree.lastSaved = iTree.clone() - if !tree.skipFastStorageUpgrade { - // Attempt to upgrade - if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { - return 0, err - } - } - return targetVersion, nil } // Returns the version number of the latest version found -func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { +func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr error) { roots, err := tree.ndb.getRoots() if err != nil { return 0, err @@ -552,8 +554,6 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { if len(roots) == 0 { if targetVersion <= 0 { if !tree.skipFastStorageUpgrade { - tree.mtx.Lock() - defer tree.mtx.Unlock() _, err := tree.enableFastStorageAndCommitIfNotEnabled() return 0, err } @@ -566,7 +566,16 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { latestVersion := int64(0) tree.mtx.Lock() - defer tree.mtx.Unlock() + defer func() { + tree.mtx.Unlock() + if !tree.skipFastStorageUpgrade { + // Attempt to upgrade + if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { + toReturn = 0 + toErr = err + } + } + }() var latestRoot []byte for version, r := range roots { @@ -609,13 +618,6 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) { tree.lastSaved = t.clone() tree.allRootLoaded = true - if !tree.skipFastStorageUpgrade { - // Attempt to upgrade - if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { - return 0, err - } - } - return latestVersion, nil } @@ -632,7 +634,7 @@ func (tree *MutableTree) LoadVersionForOverwriting(targetVersion int64) (int64, } if !tree.skipFastStorageUpgrade { - if err := tree.enableFastStorageAndCommitLocked(); err != nil { + if err := tree.enableFastStorageAndCommit(); err != nil { return latestVersion, err } } @@ -707,12 +709,6 @@ func (tree *MutableTree) enableFastStorageAndCommitIfNotEnabled() (bool, error) return true, nil } -func (tree *MutableTree) enableFastStorageAndCommitLocked() error { - tree.mtx.Lock() - defer tree.mtx.Unlock() - return tree.enableFastStorageAndCommit() -} - func (tree *MutableTree) enableFastStorageAndCommit() error { var err error @@ -1069,9 +1065,6 @@ func (tree *MutableTree) SetInitialVersion(version uint64) { // DeleteVersions deletes a series of versions from the MutableTree. // Deprecated: please use DeleteVersionsRange instead. func (tree *MutableTree) DeleteVersions(versions ...int64) error { - tree.mtx.Lock() - defer tree.mtx.Unlock() - logger.Debug("DELETING VERSIONS: %v\n", versions) if len(versions) == 0 { From 5cf708a38b678d118cb5a7e498b27002154553ee Mon Sep 17 00:00:00 2001 From: codchen Date: Sat, 4 Mar 2023 13:36:22 +0800 Subject: [PATCH 31/69] deepcopy --- sei-iavl/iterator.go | 4 ++-- sei-iavl/node.go | 15 +++++++++++++++ sei-iavl/nodedb.go | 7 ++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index bece91090e..c2dda05033 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -100,8 +100,8 @@ func (t *traversal) next() (*Node, error) { } func (t *traversal) doNext() (*Node, error, bool) { - t.tree.mtx.Lock() - defer t.tree.mtx.Unlock() + // t.tree.mtx.Lock() + // defer t.tree.mtx.Unlock() // End of traversal. if t.delayedNodes.length() == 0 { diff --git a/sei-iavl/node.go b/sei-iavl/node.go index 607a164d2c..fdf386462d 100644 --- a/sei-iavl/node.go +++ b/sei-iavl/node.go @@ -147,6 +147,21 @@ func (node *Node) clone(version int64) (*Node, error) { }, nil } +func (node *Node) cloneAny() *Node { + return &Node{ + key: node.key, + height: node.height, + version: node.version, + size: node.size, + hash: nil, + leftHash: node.leftHash, + leftNode: node.leftNode, + rightHash: node.rightHash, + rightNode: node.rightNode, + persisted: false, + } +} + func (node *Node) isLeaf() bool { return node.height == 0 } diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index 2d4686fe62..98e81c8b8f 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -118,7 +118,7 @@ func (ndb *nodeDB) GetNode(hash []byte) (*Node, error) { // Check the cache. if cachedNode := ndb.nodeCache.Get(hash); cachedNode != nil { ndb.opts.Stat.IncCacheHitCnt() - return cachedNode.(*Node), nil + return cachedNode.(*Node).cloneAny(), nil } ndb.opts.Stat.IncCacheMissCnt() @@ -139,7 +139,7 @@ func (ndb *nodeDB) GetNode(hash []byte) (*Node, error) { node.hash = hash node.persisted = true - ndb.nodeCache.Add(node) + ndb.nodeCache.Add(node.cloneAny()) return node, nil } @@ -206,7 +206,7 @@ func (ndb *nodeDB) SaveNode(node *Node) error { } logger.Debug("BATCH SAVE %X %p\n", node.hash, node) node.persisted = true - ndb.nodeCache.Add(node) + ndb.nodeCache.Add(node.cloneAny()) return nil } @@ -1008,6 +1008,7 @@ func (ndb *nodeDB) orphans() ([][]byte, error) { // Not efficient. // NOTE: DB cannot implement Size() because // mutations are not always synchronous. +// //nolint:unused func (ndb *nodeDB) size() int { size := 0 From 706ce0684667d1cb0d788b3f901299357a4d2a6d Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 6 Mar 2023 15:00:52 +0800 Subject: [PATCH 32/69] fix deadlock for fast storage --- sei-iavl/iterator.go | 29 +++++++++++++++++++++++++---- sei-iavl/mutable_tree.go | 7 ++++--- sei-iavl/node.go | 17 +---------------- sei-iavl/nodedb.go | 6 +++--- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index c2dda05033..33722fcfae 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -17,11 +17,12 @@ type traversal struct { inclusive bool // end key inclusiveness post bool // postorder traversal delayedNodes *delayedNodes // delayed nodes to be traversed + unlocked bool // whether traversal should not lock tree's mutex } var errIteratorNilTreeGiven = errors.New("iterator must be created with an immutable tree but the tree was nil") -func (node *Node) newTraversal(tree *ImmutableTree, start, end []byte, ascending bool, inclusive bool, post bool) *traversal { +func (node *Node) newTraversal(tree *ImmutableTree, start, end []byte, ascending bool, inclusive bool, post bool, unlocked bool) *traversal { return &traversal{ tree: tree, start: start, @@ -30,6 +31,7 @@ func (node *Node) newTraversal(tree *ImmutableTree, start, end []byte, ascending inclusive: inclusive, post: post, delayedNodes: &delayedNodes{{node, true}}, // set initial traverse to the node + unlocked: unlocked, } } @@ -100,8 +102,10 @@ func (t *traversal) next() (*Node, error) { } func (t *traversal) doNext() (*Node, error, bool) { - // t.tree.mtx.Lock() - // defer t.tree.mtx.Unlock() + if !t.unlocked { + t.tree.mtx.Lock() + defer t.tree.mtx.Unlock() + } // End of traversal. if t.delayedNodes.length() == 0 { @@ -206,7 +210,24 @@ func NewIterator(start, end []byte, ascending bool, tree *ImmutableTree) dbm.Ite iter.err = errIteratorNilTreeGiven } else { iter.valid = true - iter.t = tree.root.newTraversal(tree, start, end, ascending, false, false) + iter.t = tree.root.newTraversal(tree, start, end, ascending, false, false, false) + // Move iterator before the first element + iter.Next() + } + return iter +} + +func NewIteratorUnlocked(start, end []byte, ascending bool, tree *ImmutableTree) dbm.Iterator { + iter := &Iterator{ + start: start, + end: end, + } + + if tree == nil { + iter.err = errIteratorNilTreeGiven + } else { + iter.valid = true + iter.t = tree.root.newTraversal(tree, start, end, ascending, false, false, true) // Move iterator before the first element iter.Next() } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 58574bb3d5..4b040804f0 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -712,7 +712,7 @@ func (tree *MutableTree) enableFastStorageAndCommitIfNotEnabled() (bool, error) func (tree *MutableTree) enableFastStorageAndCommit() error { var err error - itr := NewIterator(nil, nil, true, tree.ImmutableTree) + itr := NewIteratorUnlocked(nil, nil, true, tree.ImmutableTree) defer itr.Close() var upgradedFastNodes uint64 for ; itr.Valid(); itr.Next() { @@ -1120,13 +1120,14 @@ func (tree *MutableTree) DeleteVersionsRange(fromVersion, toVersion int64) error // longer be accessed. func (tree *MutableTree) DeleteVersion(version int64) error { logger.Debug("DELETE VERSION: %d\n", version) - tree.mtx.Lock() - defer tree.mtx.Unlock() if err := tree.deleteVersion(version); err != nil { return err } + tree.mtx.Lock() + defer tree.mtx.Unlock() + if err := tree.ndb.Commit(); err != nil { return err } diff --git a/sei-iavl/node.go b/sei-iavl/node.go index fdf386462d..a832bb408f 100644 --- a/sei-iavl/node.go +++ b/sei-iavl/node.go @@ -147,21 +147,6 @@ func (node *Node) clone(version int64) (*Node, error) { }, nil } -func (node *Node) cloneAny() *Node { - return &Node{ - key: node.key, - height: node.height, - version: node.version, - size: node.size, - hash: nil, - leftHash: node.leftHash, - leftNode: node.leftNode, - rightHash: node.rightHash, - rightNode: node.rightNode, - persisted: false, - } -} - func (node *Node) isLeaf() bool { return node.height == 0 } @@ -552,7 +537,7 @@ func (node *Node) traversePost(t *ImmutableTree, ascending bool, cb func(*Node) func (node *Node) traverseInRange(tree *ImmutableTree, start, end []byte, ascending bool, inclusive bool, post bool, cb func(*Node) bool) bool { stop := false - t := node.newTraversal(tree, start, end, ascending, inclusive, post) + t := node.newTraversal(tree, start, end, ascending, inclusive, post, false) // TODO: figure out how to handle these errors for node2, err := t.next(); node2 != nil && err == nil; node2, err = t.next() { stop = cb(node2) diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index 98e81c8b8f..d429bfa5aa 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -118,7 +118,7 @@ func (ndb *nodeDB) GetNode(hash []byte) (*Node, error) { // Check the cache. if cachedNode := ndb.nodeCache.Get(hash); cachedNode != nil { ndb.opts.Stat.IncCacheHitCnt() - return cachedNode.(*Node).cloneAny(), nil + return cachedNode.(*Node), nil } ndb.opts.Stat.IncCacheMissCnt() @@ -139,7 +139,7 @@ func (ndb *nodeDB) GetNode(hash []byte) (*Node, error) { node.hash = hash node.persisted = true - ndb.nodeCache.Add(node.cloneAny()) + ndb.nodeCache.Add(node) return node, nil } @@ -206,7 +206,7 @@ func (ndb *nodeDB) SaveNode(node *Node) error { } logger.Debug("BATCH SAVE %X %p\n", node.hash, node) node.persisted = true - ndb.nodeCache.Add(node.cloneAny()) + ndb.nodeCache.Add(node) return nil } From e5a9a3980f2ec044863da26fed2bb413881adda9 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 8 Mar 2023 21:40:09 +0800 Subject: [PATCH 33/69] Remove iterator lock and lock on Node level --- sei-iavl/cache/cache.go | 6 +- sei-iavl/cache/cache_test.go | 8 +- sei-iavl/export.go | 8 +- sei-iavl/fast_node.go | 2 +- sei-iavl/immutable_tree.go | 16 +-- sei-iavl/import.go | 38 +++--- sei-iavl/iterator.go | 17 +-- sei-iavl/mutable_tree.go | 78 ++++++----- sei-iavl/node.go | 254 +++++++++++++++++++++++++++-------- sei-iavl/nodedb.go | 77 +++++------ sei-iavl/proof.go | 22 +-- sei-iavl/proof_range.go | 48 +++---- sei-iavl/tree_dotgraph.go | 22 +-- sei-iavl/util.go | 18 +-- 14 files changed, 383 insertions(+), 231 deletions(-) diff --git a/sei-iavl/cache/cache.go b/sei-iavl/cache/cache.go index a4ca88d672..29ce3bd35d 100644 --- a/sei-iavl/cache/cache.go +++ b/sei-iavl/cache/cache.go @@ -8,7 +8,7 @@ import ( // Node represents a node eligible for caching. type Node interface { - GetKey() []byte + GetCacheKey() []byte } // Cache is an in-memory structure to persist nodes for quick access. @@ -61,7 +61,7 @@ func New(maxElementCount int) Cache { } func (c *lruCache) Add(node Node) Node { - keyStr := ibytes.UnsafeBytesToStr(node.GetKey()) + keyStr := ibytes.UnsafeBytesToStr(node.GetCacheKey()) if e, exists := c.dict[keyStr]; exists { c.ll.MoveToFront(e) old := e.Value @@ -105,6 +105,6 @@ func (c *lruCache) Remove(key []byte) Node { func (c *lruCache) remove(e *list.Element) Node { removed := c.ll.Remove(e).(Node) - delete(c.dict, ibytes.UnsafeBytesToStr(removed.GetKey())) + delete(c.dict, ibytes.UnsafeBytesToStr(removed.GetCacheKey())) return removed } diff --git a/sei-iavl/cache/cache_test.go b/sei-iavl/cache/cache_test.go index 7b2413ef3a..a29a2815d8 100644 --- a/sei-iavl/cache/cache_test.go +++ b/sei-iavl/cache/cache_test.go @@ -35,7 +35,7 @@ type testcase struct { expectedNodeIndexes []int // contents of the cache once test case completes represent by indexes in testNodes } -func (tn *testNode) GetKey() []byte { +func (tn *testNode) GetCacheKey() []byte { return tn.key } @@ -271,7 +271,7 @@ func Test_Cache_Remove(t *testing.T) { for _, op := range tc.cacheOps { - actualResult := cache.Remove(testNodes[op.testNodexIdx].GetKey()) + actualResult := cache.Remove(testNodes[op.testNodexIdx].GetCacheKey()) expectedResult := op.expectedResult @@ -296,8 +296,8 @@ func validateCacheContentsAfterTest(t *testing.T, tc testcase, cache cache.Cache require.Equal(t, len(tc.expectedNodeIndexes), cache.Len()) for _, idx := range tc.expectedNodeIndexes { expectedNode := testNodes[idx] - require.True(t, cache.Has(expectedNode.GetKey())) - require.Equal(t, expectedNode, cache.Get(expectedNode.GetKey())) + require.True(t, cache.Has(expectedNode.GetCacheKey())) + require.Equal(t, expectedNode, cache.Get(expectedNode.GetCacheKey())) } } diff --git a/sei-iavl/export.go b/sei-iavl/export.go index c65b81b210..387dc9121a 100644 --- a/sei-iavl/export.go +++ b/sei-iavl/export.go @@ -53,10 +53,10 @@ func newExporter(tree *ImmutableTree) *Exporter { func (e *Exporter) export(ctx context.Context) { e.tree.root.traversePost(e.tree, true, func(node *Node) bool { exportNode := &ExportNode{ - Key: node.key, - Value: node.value, - Version: node.version, - Height: node.height, + Key: node.GetNodeKey(), + Value: node.GetValue(), + Version: node.GetVersion(), + Height: node.GetHeight(), } select { diff --git a/sei-iavl/fast_node.go b/sei-iavl/fast_node.go index 2d03287abe..b32924551c 100644 --- a/sei-iavl/fast_node.go +++ b/sei-iavl/fast_node.go @@ -50,7 +50,7 @@ func DeserializeFastNode(key []byte, buf []byte) (*FastNode, error) { return fastNode, nil } -func (fn *FastNode) GetKey() []byte { +func (fn *FastNode) GetCacheKey() []byte { return fn.key } diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index d70cd48e6e..b67dbde15b 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -90,12 +90,12 @@ func (t *ImmutableTree) renderNode(node *Node, indent string, depth int, encoder } // handle leaf if node.isLeaf() { - here := fmt.Sprintf("%s%s", prefix, encoder(node.key, depth, true)) + here := fmt.Sprintf("%s%s", prefix, encoder(node.GetNodeKey(), depth, true)) return []string{here}, nil } // recurse on inner node - here := fmt.Sprintf("%s%s", prefix, encoder(node.hash, depth, false)) + here := fmt.Sprintf("%s%s", prefix, encoder(node.GetHash(), depth, false)) rightNode, err := node.getRightNode(t) if err != nil { @@ -127,7 +127,7 @@ func (t *ImmutableTree) Size() int64 { if t.root == nil { return 0 } - return t.root.size + return t.root.GetSize() } // Version returns the version of the tree. @@ -140,7 +140,7 @@ func (t *ImmutableTree) Height() int8 { if t.root == nil { return 0 } - return t.root.height + return t.root.GetHeight() } // Has returns whether or not a key exists. @@ -272,8 +272,8 @@ func (t *ImmutableTree) IterateRange(start, end []byte, ascending bool, fn func( return false } return t.root.traverseInRange(t, start, end, ascending, false, false, func(node *Node) bool { - if node.height == 0 { - return fn(node.key, node.value) + if node.GetHeight() == 0 { + return fn(node.GetNodeKey(), node.GetValue()) } return false }) @@ -287,8 +287,8 @@ func (t *ImmutableTree) IterateRangeInclusive(start, end []byte, ascending bool, return false } return t.root.traverseInRange(t, start, end, ascending, true, false, func(node *Node) bool { - if node.height == 0 { - return fn(node.key, node.value, node.version) + if node.GetHeight() == 0 { + return fn(node.GetNodeKey(), node.GetValue(), node.GetVersion()) } return false }) diff --git a/sei-iavl/import.go b/sei-iavl/import.go index 2e84eb8807..9687c3d3c6 100644 --- a/sei-iavl/import.go +++ b/sei-iavl/import.go @@ -110,7 +110,7 @@ func setBatchData(i *Importer) { if nodeData, open := <-i.chNodeData; open { i.batchMtx.RLock() if i.batch != nil { - err := i.batch.Set(i.tree.ndb.nodeKey(nodeData.node.hash), nodeData.data) + err := i.batch.Set(i.tree.ndb.nodeKey(nodeData.node.GetHash()), nodeData.data) if err != nil { i.batchMtx.RUnlock() i.chError <- err @@ -193,24 +193,24 @@ func (i *Importer) Add(exportNode *ExportNode) error { // importer in an inconsistent state when we return an error. stackSize := len(i.stack) switch { - case stackSize >= 2 && i.stack[stackSize-1].height < node.height && i.stack[stackSize-2].height < node.height: - node.leftNode = i.stack[stackSize-2] - node.leftHash = node.leftNode.hash - node.rightNode = i.stack[stackSize-1] - node.rightHash = node.rightNode.hash - case stackSize >= 1 && i.stack[stackSize-1].height < node.height: - node.leftNode = i.stack[stackSize-1] - node.leftHash = node.leftNode.hash + case stackSize >= 2 && i.stack[stackSize-1].GetHeight() < node.GetHeight() && i.stack[stackSize-2].GetHeight() < node.GetHeight(): + node.SetLeftNode(i.stack[stackSize-2]) + node.SetLeftHash(node.GetLeftNode().GetHash()) + node.SetRightNode(i.stack[stackSize-1]) + node.SetRightHash(node.GetRightNode().GetHash()) + case stackSize >= 1 && i.stack[stackSize-1].GetHeight() < node.GetHeight(): + node.SetLeftNode(i.stack[stackSize-1]) + node.SetLeftHash(node.GetLeftNode().GetHash()) } - if node.height == 0 { - node.size = 1 + if node.GetHeight() == 0 { + node.SetSize(1) } - if node.leftNode != nil { - node.size += node.leftNode.size + if node.GetLeftNode() != nil { + node.SetSize(node.GetSize() + node.GetLeftNode().GetSize()) } - if node.rightNode != nil { - node.size += node.rightNode.size + if node.GetRightNode() != nil { + node.SetSize(node.GetSize() + node.GetRightNode().GetSize()) } _, err := node._hash() @@ -248,13 +248,13 @@ func (i *Importer) Add(exportNode *ExportNode) error { // Update the stack now that we know there were no errors switch { - case node.leftHash != nil && node.rightHash != nil: + case node.GetLeftHash() != nil && node.GetRightHash() != nil: i.stack = i.stack[:stackSize-2] - case node.leftHash != nil || node.rightHash != nil: + case node.GetLeftHash() != nil || node.GetRightHash() != nil: i.stack = i.stack[:stackSize-1] } // Only hash\height\size of the node will be used after it be pushed into the stack. - i.stack = append(i.stack, &Node{hash: node.hash, height: node.height, size: node.size}) + i.stack = append(i.stack, &Node{hash: node.GetHash(), height: node.GetHeight(), size: node.GetSize()}) return nil } @@ -278,7 +278,7 @@ func (i *Importer) Commit() error { return err } case 1: - if err := i.batch.Set(i.tree.ndb.rootKey(i.version), i.stack[0].hash); err != nil { + if err := i.batch.Set(i.tree.ndb.rootKey(i.version), i.stack[0].GetHash()); err != nil { return err } default: diff --git a/sei-iavl/iterator.go b/sei-iavl/iterator.go index 33722fcfae..520d8f2167 100644 --- a/sei-iavl/iterator.go +++ b/sei-iavl/iterator.go @@ -102,11 +102,6 @@ func (t *traversal) next() (*Node, error) { } func (t *traversal) doNext() (*Node, error, bool) { - if !t.unlocked { - t.tree.mtx.Lock() - defer t.tree.mtx.Unlock() - } - // End of traversal. if t.delayedNodes.length() == 0 { return nil, nil, true @@ -119,11 +114,11 @@ func (t *traversal) doNext() (*Node, error, bool) { return node, nil, true } - afterStart := t.start == nil || bytes.Compare(t.start, node.key) < 0 - startOrAfter := afterStart || bytes.Equal(t.start, node.key) - beforeEnd := t.end == nil || bytes.Compare(node.key, t.end) < 0 + afterStart := t.start == nil || bytes.Compare(t.start, node.GetNodeKey()) < 0 + startOrAfter := afterStart || bytes.Equal(t.start, node.GetNodeKey()) + beforeEnd := t.end == nil || bytes.Compare(node.GetNodeKey(), t.end) < 0 if t.inclusive { - beforeEnd = beforeEnd || bytes.Equal(node.key, t.end) + beforeEnd = beforeEnd || bytes.Equal(node.GetNodeKey(), t.end) } // case of postorder. A-1 and B-1 @@ -268,8 +263,8 @@ func (iter *Iterator) Next() { return } - if node.height == 0 { - iter.key, iter.value = node.key, node.value + if node.GetHeight() == 0 { + iter.key, iter.value = node.GetNodeKey(), node.GetValue() return } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 4b040804f0..3152ffb079 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -252,10 +252,10 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph tree.addUnsavedAddition(key, NewFastNode(key, value, version)) } - switch bytes.Compare(key, node.key) { + switch bytes.Compare(key, node.GetNodeKey()) { case -1: return &Node{ - key: node.key, + key: node.GetNodeKey(), height: 1, size: 2, leftNode: NewNode(key, value, version), @@ -282,26 +282,28 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph return nil, false, err } - if bytes.Compare(key, node.key) < 0 { + if bytes.Compare(key, node.GetNodeKey()) < 0 { leftNode, err := node.getLeftNode(tree.ImmutableTree) if err != nil { return nil, false, err } - node.leftNode, updated, err = tree.recursiveSet(leftNode, key, value, orphans) + lNode, updated, err := tree.recursiveSet(leftNode, key, value, orphans) if err != nil { return nil, updated, err } - node.leftHash = nil // leftHash is yet unknown + node.SetLeftNode(lNode) + node.SetLeftHash(nil) // leftHash is yet unknown } else { rightNode, err := node.getRightNode(tree.ImmutableTree) if err != nil { return nil, false, err } - node.rightNode, updated, err = tree.recursiveSet(rightNode, key, value, orphans) + rNode, updated, err := tree.recursiveSet(rightNode, key, value, orphans) if err != nil { return nil, updated, err } - node.rightHash = nil // rightHash is yet unknown + node.SetRightNode(rNode) + node.SetRightHash(nil) // rightHash is yet unknown } if updated { @@ -378,15 +380,15 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod version := tree.version + 1 if node.isLeaf() { - if bytes.Equal(key, node.key) { + if bytes.Equal(key, node.GetNodeKey()) { *orphans = append(*orphans, node) - return nil, nil, nil, node.value, nil + return nil, nil, nil, node.GetValue(), nil } - return node.hash, node, nil, nil, nil + return node.GetHash(), node, nil, nil, nil } // node.key < key; we go to the left to find the key: - if bytes.Compare(key, node.key) < 0 { + if bytes.Compare(key, node.GetNodeKey()) < 0 { leftNode, err := node.getLeftNode(tree.ImmutableTree) if err != nil { return nil, nil, nil, nil, err @@ -397,11 +399,11 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod } if len(*orphans) == 0 { - return node.hash, node, nil, value, nil + return node.GetHash(), node, nil, value, nil } *orphans = append(*orphans, node) if newLeftHash == nil && newLeftNode == nil { // left node held value, was removed - return node.rightHash, node.rightNode, node.key, value, nil + return node.GetRightHash(), node.GetRightNode(), node.GetNodeKey(), value, nil } newNode, err := node.clone(version) @@ -409,7 +411,8 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod return nil, nil, nil, nil, err } - newNode.leftHash, newNode.leftNode = newLeftHash, newLeftNode + newNode.SetLeftHash(newLeftHash) + newNode.SetLeftNode(newLeftNode) err = newNode.calcHeightAndSize(tree.ImmutableTree) if err != nil { return nil, nil, nil, nil, err @@ -419,7 +422,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod return nil, nil, nil, nil, err } - return newNode.hash, newNode, newKey, value, nil + return newNode.GetHash(), newNode, newKey, value, nil } // node.key >= key; either found or look to the right: rightNode, err := node.getRightNode(tree.ImmutableTree) @@ -431,11 +434,11 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod return nil, nil, nil, nil, err } if len(*orphans) == 0 { - return node.hash, node, nil, value, nil + return node.GetHash(), node, nil, value, nil } *orphans = append(*orphans, node) if newRightHash == nil && newRightNode == nil { // right node held value, was removed - return node.leftHash, node.leftNode, nil, value, nil + return node.GetLeftHash(), node.GetLeftNode(), nil, value, nil } newNode, err := node.clone(version) @@ -443,9 +446,10 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod return nil, nil, nil, nil, err } - newNode.rightHash, newNode.rightNode = newRightHash, newRightNode + newNode.SetRightHash(newRightHash) + newNode.SetRightNode(newRightNode) if newKey != nil { - newNode.key = newKey + newNode.SetKey(newKey) } err = newNode.calcHeightAndSize(tree.ImmutableTree) if err != nil { @@ -457,7 +461,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod return nil, nil, nil, nil, err } - return newNode.hash, newNode, nil, value, nil + return newNode.GetHash(), newNode, nil, value, nil } // Load the latest versioned tree from disk. @@ -1156,9 +1160,11 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { return nil, nil, err } - newNoderHash, newNoderCached := newNode.rightHash, newNode.rightNode - newNode.rightHash, newNode.rightNode = node.hash, node - node.leftHash, node.leftNode = newNoderHash, newNoderCached + newNoderHash, newNoderCached := newNode.GetRightHash(), newNode.GetRightNode() + newNode.SetRightHash(node.GetHash()) + newNode.SetRightNode(node) + node.SetLeftHash(newNoderHash) + node.SetLeftNode(newNoderCached) err = node.calcHeightAndSize(tree.ImmutableTree) if err != nil { @@ -1193,9 +1199,11 @@ func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { return nil, nil, err } - newNodelHash, newNodelCached := newNode.leftHash, newNode.leftNode - newNode.leftHash, newNode.leftNode = node.hash, node - node.rightHash, node.rightNode = newNodelHash, newNodelCached + newNodelHash, newNodelCached := newNode.GetLeftHash(), newNode.GetLeftNode() + newNode.SetLeftHash(node.GetHash()) + newNode.SetLeftNode(node) + node.SetRightHash(newNodelHash) + node.SetRightNode(newNodelCached) err = node.calcHeightAndSize(tree.ImmutableTree) if err != nil { @@ -1213,7 +1221,7 @@ func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { // NOTE: assumes that node can be modified // TODO: optimize balance & rotate func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, err error) { - if node.persisted { + if node.GetPersisted() { return nil, fmt.Errorf("unexpected balance() call on persisted node") } balance, err := node.calcBalance(tree.ImmutableTree) @@ -1248,11 +1256,12 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e if err != nil { return nil, err } - node.leftHash = nil - node.leftNode, leftOrphaned, err = tree.rotateLeft(left) + node.SetLeftHash(nil) + lNode, leftOrphaned, err := tree.rotateLeft(left) if err != nil { return nil, err } + node.SetLeftNode(lNode) newNode, rightOrphaned, err := tree.rotateRight(node) if err != nil { @@ -1287,11 +1296,12 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e if err != nil { return nil, err } - node.rightHash = nil - node.rightNode, rightOrphaned, err = tree.rotateRight(right) + node.SetRightHash(nil) + rNode, rightOrphaned, err := tree.rotateRight(right) if err != nil { return nil, err } + node.SetRightNode(rNode) newNode, leftOrphaned, err := tree.rotateLeft(node) if err != nil { return nil, err @@ -1306,14 +1316,14 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e func (tree *MutableTree) addOrphans(orphans []*Node) error { for _, node := range orphans { - if !node.persisted { + if !node.GetPersisted() { // We don't need to orphan nodes that were never persisted. continue } - if len(node.hash) == 0 { + if len(node.GetHash()) == 0 { return fmt.Errorf("expected to find node hash, but was empty") } - tree.orphans[unsafeToStr(node.hash)] = node.version + tree.orphans[unsafeToStr(node.GetHash())] = node.GetVersion() } return nil } diff --git a/sei-iavl/node.go b/sei-iavl/node.go index a832bb408f..263db9d752 100644 --- a/sei-iavl/node.go +++ b/sei-iavl/node.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "math" + "sync" "github.com/cosmos/iavl/cache" "github.com/pkg/errors" @@ -29,6 +30,8 @@ type Node struct { rightNode *Node height int8 persisted bool + + mtx sync.RWMutex } var _ cache.Node = (*Node)(nil) @@ -110,12 +113,143 @@ func MakeNode(buf []byte) (*Node, error) { return node, nil } -func (n *Node) GetKey() []byte { +// to conform with interface name +func (n *Node) GetCacheKey() []byte { + n.mtx.RLock() + defer n.mtx.RUnlock() + return n.hash +} + +func (n *Node) GetHash() []byte { + n.mtx.RLock() + defer n.mtx.RUnlock() return n.hash } +func (node *Node) GetNodeKey() []byte { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.key +} + +func (node *Node) GetValue() []byte { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.value +} + +func (node *Node) GetSize() int64 { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.size +} + +func (node *Node) GetHeight() int8 { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.height +} + +func (node *Node) GetVersion() int64 { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.version +} + +func (node *Node) GetLeftHash() []byte { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.leftHash +} + +func (node *Node) GetRightHash() []byte { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.rightHash +} + +func (node *Node) GetLeftNode() *Node { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.leftNode +} + +func (node *Node) GetRightNode() *Node { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.rightNode +} + +func (node *Node) GetPersisted() bool { + node.mtx.RLock() + defer node.mtx.RUnlock() + return node.persisted +} + +func (node *Node) SetKey(k []byte) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.key = k +} + +func (node *Node) SetLeftHash(h []byte) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.leftHash = h +} + +func (node *Node) SetRightHash(h []byte) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.rightHash = h +} + +func (node *Node) SetLeftNode(n *Node) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.leftNode = n +} + +func (node *Node) SetRightNode(n *Node) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.rightNode = n +} + +func (node *Node) SetHeight(h int8) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.height = h +} + +func (node *Node) SetVersion(v int64) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.version = v +} + +func (node *Node) SetSize(s int64) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.size = s +} + +func (node *Node) SetHash(h []byte) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.hash = h +} + +func (node *Node) SetPersisted(p bool) { + node.mtx.Lock() + defer node.mtx.Unlock() + node.persisted = p +} + // String returns a string representation of the node. func (node *Node) String() string { + node.mtx.RLock() + defer node.mtx.RUnlock() hashstr := "" if len(node.hash) > 0 { hashstr = fmt.Sprintf("%X", node.hash) @@ -133,6 +267,8 @@ func (node *Node) clone(version int64) (*Node, error) { if node.isLeaf() { return nil, ErrCloneLeafNode } + node.mtx.RLock() + defer node.mtx.RUnlock() return &Node{ key: node.key, height: node.height, @@ -148,18 +284,20 @@ func (node *Node) clone(version int64) (*Node, error) { } func (node *Node) isLeaf() bool { + node.mtx.RLock() + defer node.mtx.RUnlock() return node.height == 0 } // Check if the node has a descendant with the given key. func (node *Node) has(t *ImmutableTree, key []byte) (has bool, err error) { - if bytes.Equal(node.key, key) { + if bytes.Equal(node.GetNodeKey(), key) { return true, nil } if node.isLeaf() { return false, nil } - if bytes.Compare(key, node.key) < 0 { + if bytes.Compare(key, node.GetNodeKey()) < 0 { leftNode, err := node.getLeftNode(t) if err != nil { return false, err @@ -181,17 +319,17 @@ func (node *Node) has(t *ImmutableTree, key []byte) (has bool, err error) { // It's neighbor has index 1 and so on. func (node *Node) get(t *ImmutableTree, key []byte) (index int64, value []byte, err error) { if node.isLeaf() { - switch bytes.Compare(node.key, key) { + switch bytes.Compare(node.GetNodeKey(), key) { case -1: return 1, nil, nil case 1: return 0, nil, nil default: - return 0, node.value, nil + return 0, node.GetValue(), nil } } - if bytes.Compare(key, node.key) < 0 { + if bytes.Compare(key, node.GetNodeKey()) < 0 { leftNode, err := node.getLeftNode(t) if err != nil { return 0, nil, err @@ -210,14 +348,14 @@ func (node *Node) get(t *ImmutableTree, key []byte) (index int64, value []byte, return 0, nil, err } - index += node.size - rightNode.size + index += node.GetSize() - rightNode.GetSize() return index, value, nil } func (node *Node) getByIndex(t *ImmutableTree, index int64) (key []byte, value []byte, err error) { if node.isLeaf() { if index == 0 { - return node.key, node.value, nil + return node.GetNodeKey(), node.GetValue(), nil } return nil, nil, nil } @@ -228,7 +366,7 @@ func (node *Node) getByIndex(t *ImmutableTree, index int64) (key []byte, value [ return nil, nil, err } - if index < leftNode.size { + if index < leftNode.GetSize() { return leftNode.getByIndex(t, index) } @@ -237,14 +375,14 @@ func (node *Node) getByIndex(t *ImmutableTree, index int64) (key []byte, value [ return nil, nil, err } - return rightNode.getByIndex(t, index-leftNode.size) + return rightNode.getByIndex(t, index-leftNode.GetSize()) } // Computes the hash of the node without computing its descendants. Must be // called on nodes which have descendant node hashes already computed. func (node *Node) _hash() ([]byte, error) { - if node.hash != nil { - return node.hash, nil + if node.GetHash() != nil { + return node.GetHash(), nil } h := sha256.New() @@ -256,9 +394,11 @@ func (node *Node) _hash() ([]byte, error) { if err != nil { return nil, err } + node.mtx.Lock() + defer node.mtx.Unlock() node.hash = h.Sum(nil) - return node.hash, nil + return node.GetHash(), nil } // Hash the node and its descendants recursively. This usually mutates all @@ -269,8 +409,8 @@ func (node *Node) hashWithCount() ([]byte, int64, error) { if node == nil { return sha256.New().Sum(nil), 0, nil } - if node.hash != nil { - return node.hash, 0, nil + if node.GetHash() != nil { + return node.GetHash(), 0, nil } h := sha256.New() @@ -283,13 +423,17 @@ func (node *Node) hashWithCount() ([]byte, int64, error) { if err != nil { return nil, 0, err } + node.mtx.Lock() + defer node.mtx.Unlock() node.hash = h.Sum(nil) - return node.hash, hashCount + 1, nil + return node.GetHash(), hashCount + 1, nil } // validate validates the node contents func (node *Node) validate() error { + node.mtx.RLock() + defer node.mtx.RUnlock() if node == nil { return errors.New("node cannot be nil") } @@ -332,15 +476,15 @@ func (node *Node) validate() error { // Writes the node's hash to the given io.Writer. This function expects // child hashes to be already set. func (node *Node) writeHashBytes(w io.Writer) error { - err := encoding.EncodeVarint(w, int64(node.height)) + err := encoding.EncodeVarint(w, int64(node.GetHeight())) if err != nil { return errors.Wrap(err, "writing height") } - err = encoding.EncodeVarint(w, node.size) + err = encoding.EncodeVarint(w, node.GetSize()) if err != nil { return errors.Wrap(err, "writing size") } - err = encoding.EncodeVarint(w, node.version) + err = encoding.EncodeVarint(w, node.GetVersion()) if err != nil { return errors.Wrap(err, "writing version") } @@ -348,28 +492,28 @@ func (node *Node) writeHashBytes(w io.Writer) error { // Key is not written for inner nodes, unlike writeBytes. if node.isLeaf() { - err = encoding.EncodeBytes(w, node.key) + err = encoding.EncodeBytes(w, node.GetNodeKey()) if err != nil { return errors.Wrap(err, "writing key") } // Indirection needed to provide proofs without values. // (e.g. ProofLeafNode.ValueHash) - valueHash := sha256.Sum256(node.value) + valueHash := sha256.Sum256(node.GetValue()) err = encoding.EncodeBytes(w, valueHash[:]) if err != nil { return errors.Wrap(err, "writing value") } } else { - if node.leftHash == nil || node.rightHash == nil { + if node.GetLeftHash() == nil || node.GetRightHash() == nil { return ErrEmptyChildHash } - err = encoding.EncodeBytes(w, node.leftHash) + err = encoding.EncodeBytes(w, node.GetLeftHash()) if err != nil { return errors.Wrap(err, "writing left hash") } - err = encoding.EncodeBytes(w, node.rightHash) + err = encoding.EncodeBytes(w, node.GetRightHash()) if err != nil { return errors.Wrap(err, "writing right hash") } @@ -381,20 +525,20 @@ func (node *Node) writeHashBytes(w io.Writer) error { // Writes the node's hash to the given io.Writer. // This function has the side-effect of calling hashWithCount. func (node *Node) writeHashBytesRecursively(w io.Writer) (hashCount int64, err error) { - if node.leftNode != nil { - leftHash, leftCount, err := node.leftNode.hashWithCount() + if node.GetLeftNode() != nil { + leftHash, leftCount, err := node.GetLeftNode().hashWithCount() if err != nil { return 0, err } - node.leftHash = leftHash + node.SetLeftHash(leftHash) hashCount += leftCount } - if node.rightNode != nil { - rightHash, rightCount, err := node.rightNode.hashWithCount() + if node.GetRightNode() != nil { + rightHash, rightCount, err := node.GetRightNode().hashWithCount() if err != nil { return 0, err } - node.rightHash = rightHash + node.SetRightHash(rightHash) hashCount += rightCount } err = node.writeHashBytes(w) @@ -404,14 +548,14 @@ func (node *Node) writeHashBytesRecursively(w io.Writer) (hashCount int64, err e func (node *Node) encodedSize() int { n := 1 + - encoding.EncodeVarintSize(node.size) + - encoding.EncodeVarintSize(node.version) + - encoding.EncodeBytesSize(node.key) + encoding.EncodeVarintSize(node.GetSize()) + + encoding.EncodeVarintSize(node.GetVersion()) + + encoding.EncodeBytesSize(node.GetNodeKey()) if node.isLeaf() { - n += encoding.EncodeBytesSize(node.value) + n += encoding.EncodeBytesSize(node.GetValue()) } else { - n += encoding.EncodeBytesSize(node.leftHash) + - encoding.EncodeBytesSize(node.rightHash) + n += encoding.EncodeBytesSize(node.GetLeftHash()) + + encoding.EncodeBytesSize(node.GetRightHash()) } return n } @@ -421,43 +565,43 @@ func (node *Node) writeBytes(w io.Writer) error { if node == nil { return errors.New("cannot write nil node") } - cause := encoding.EncodeVarint(w, int64(node.height)) + cause := encoding.EncodeVarint(w, int64(node.GetHeight())) if cause != nil { return errors.Wrap(cause, "writing height") } - cause = encoding.EncodeVarint(w, node.size) + cause = encoding.EncodeVarint(w, node.GetSize()) if cause != nil { return errors.Wrap(cause, "writing size") } - cause = encoding.EncodeVarint(w, node.version) + cause = encoding.EncodeVarint(w, node.GetVersion()) if cause != nil { return errors.Wrap(cause, "writing version") } // Unlike writeHashBytes, key is written for inner nodes. - cause = encoding.EncodeBytes(w, node.key) + cause = encoding.EncodeBytes(w, node.GetNodeKey()) if cause != nil { return errors.Wrap(cause, "writing key") } if node.isLeaf() { - cause = encoding.EncodeBytes(w, node.value) + cause = encoding.EncodeBytes(w, node.GetValue()) if cause != nil { return errors.Wrap(cause, "writing value") } } else { - if node.leftHash == nil { + if node.GetLeftHash() == nil { return ErrLeftHashIsNil } - cause = encoding.EncodeBytes(w, node.leftHash) + cause = encoding.EncodeBytes(w, node.GetLeftHash()) if cause != nil { return errors.Wrap(cause, "writing left hash") } - if node.rightHash == nil { + if node.GetRightHash() == nil { return ErrRightHashIsNil } - cause = encoding.EncodeBytes(w, node.rightHash) + cause = encoding.EncodeBytes(w, node.GetRightHash()) if cause != nil { return errors.Wrap(cause, "writing right hash") } @@ -466,10 +610,10 @@ func (node *Node) writeBytes(w io.Writer) error { } func (node *Node) getLeftNode(t *ImmutableTree) (*Node, error) { - if node.leftNode != nil { - return node.leftNode, nil + if node.GetLeftNode() != nil { + return node.GetLeftNode(), nil } - leftNode, err := t.ndb.GetNode(node.leftHash) + leftNode, err := t.ndb.GetNode(node.GetLeftHash()) if err != nil { return nil, err } @@ -478,10 +622,10 @@ func (node *Node) getLeftNode(t *ImmutableTree) (*Node, error) { } func (node *Node) getRightNode(t *ImmutableTree) (*Node, error) { - if node.rightNode != nil { - return node.rightNode, nil + if node.GetRightNode() != nil { + return node.GetRightNode(), nil } - rightNode, err := t.ndb.GetNode(node.rightHash) + rightNode, err := t.ndb.GetNode(node.GetRightHash()) if err != nil { return nil, err } @@ -501,8 +645,10 @@ func (node *Node) calcHeightAndSize(t *ImmutableTree) error { return err } - node.height = maxInt8(leftNode.height, rightNode.height) + 1 - node.size = leftNode.size + rightNode.size + height := maxInt8(leftNode.GetHeight(), rightNode.GetHeight()) + 1 + size := leftNode.GetSize() + rightNode.GetSize() + node.SetHeight(height) + node.SetSize(size) return nil } @@ -517,7 +663,7 @@ func (node *Node) calcBalance(t *ImmutableTree) (int, error) { return 0, err } - return int(leftNode.height) - int(rightNode.height), nil + return int(leftNode.GetHeight()) - int(rightNode.GetHeight()), nil } // traverse is a wrapper over traverseInRange when we want the whole tree diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index d429bfa5aa..be94099a5f 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -137,8 +137,8 @@ func (ndb *nodeDB) GetNode(hash []byte) (*Node, error) { return nil, fmt.Errorf("Error reading Node. bytes: %x, error: %v", buf, err) } - node.hash = hash - node.persisted = true + node.SetHash(hash) + node.SetPersisted(true) ndb.nodeCache.Add(node) return node, nil @@ -186,10 +186,10 @@ func (ndb *nodeDB) SaveNode(node *Node) error { ndb.mtx.Lock() defer ndb.mtx.Unlock() - if node.hash == nil { + if node.GetHash() == nil { return ErrNodeMissingHash } - if node.persisted { + if node.GetPersisted() { return ErrNodeAlreadyPersisted } @@ -201,11 +201,11 @@ func (ndb *nodeDB) SaveNode(node *Node) error { return err } - if err := ndb.batch.Set(ndb.nodeKey(node.hash), buf.Bytes()); err != nil { + if err := ndb.batch.Set(ndb.nodeKey(node.GetHash()), buf.Bytes()); err != nil { return err } - logger.Debug("BATCH SAVE %X %p\n", node.hash, node) - node.persisted = true + logger.Debug("BATCH SAVE %X %p\n", node.GetHash(), node) + node.SetPersisted(true) ndb.nodeCache.Add(node) return nil } @@ -332,25 +332,25 @@ func (ndb *nodeDB) Has(hash []byte) (bool, error) { // calls _hash() on the given node. // TODO refactor, maybe use hashWithCount() but provide a callback. func (ndb *nodeDB) SaveBranch(node *Node) ([]byte, error) { - if node.persisted { - return node.hash, nil + if node.GetPersisted() { + return node.GetHash(), nil } var err error - if node.leftNode != nil { - node.leftHash, err = ndb.SaveBranch(node.leftNode) - } - - if err != nil { - return nil, err - } - - if node.rightNode != nil { - node.rightHash, err = ndb.SaveBranch(node.rightNode) + if node.GetLeftNode() != nil { + leftHash, err := ndb.SaveBranch(node.GetLeftNode()) + if err != nil { + return nil, err + } + node.SetLeftHash(leftHash) } - if err != nil { - return nil, err + if node.GetRightNode() != nil { + rightHash, err := ndb.SaveBranch(node.GetRightNode()) + if err != nil { + return nil, err + } + node.SetRightHash(rightHash) } _, err = node._hash() @@ -364,15 +364,15 @@ func (ndb *nodeDB) SaveBranch(node *Node) ([]byte, error) { } // resetBatch only working on generate a genesis block - if node.version <= genesisVersion { + if node.GetVersion() <= genesisVersion { if err = ndb.resetBatch(); err != nil { return nil, err } } - node.leftNode = nil - node.rightNode = nil + node.SetLeftNode(nil) + node.SetRightNode(nil) - return node.hash, nil + return node.GetHash(), nil } // resetBatch reset the db batch, keep low memory used @@ -605,18 +605,18 @@ func (ndb *nodeDB) deleteNodesFrom(version int64, hash []byte) error { return err } - if node.leftHash != nil { - if err := ndb.deleteNodesFrom(version, node.leftHash); err != nil { + if node.GetLeftHash() != nil { + if err := ndb.deleteNodesFrom(version, node.GetLeftHash()); err != nil { return err } } - if node.rightHash != nil { - if err := ndb.deleteNodesFrom(version, node.rightHash); err != nil { + if node.GetRightHash() != nil { + if err := ndb.deleteNodesFrom(version, node.GetRightHash()); err != nil { return err } } - if node.version >= version { + if node.GetVersion() >= version { if err := ndb.batch.Delete(ndb.nodeKey(hash)); err != nil { return err } @@ -906,10 +906,10 @@ func (ndb *nodeDB) getRoots() (roots map[int64][]byte, err error) { // SaveRoot creates an entry on disk for the given root, so that it can be // loaded later. func (ndb *nodeDB) SaveRoot(root *Node, version int64) error { - if len(root.hash) == 0 { + if len(root.GetHash()) == 0 { return ErrRootMissingHash } - return ndb.saveRoot(root.hash, version) + return ndb.saveRoot(root.GetHash(), version) } // SaveEmptyRoot creates an entry on disk for an empty root. @@ -1031,7 +1031,8 @@ func (ndb *nodeDB) traverseNodes(fn func(hash []byte, node *Node) error) error { if err != nil { return err } - nodeKeyFormat.Scan(key, &node.hash) + h := node.GetHash() + nodeKeyFormat.Scan(key, &h) nodes = append(nodes, node) return nil }) @@ -1041,11 +1042,11 @@ func (ndb *nodeDB) traverseNodes(fn func(hash []byte, node *Node) error) error { } sort.Slice(nodes, func(i, j int) bool { - return bytes.Compare(nodes[i].key, nodes[j].key) < 0 + return bytes.Compare(nodes[i].GetNodeKey(), nodes[j].GetNodeKey()) < 0 }) for _, n := range nodes { - if err := fn(n.hash, n); err != nil { + if err := fn(n.GetHash(), n); err != nil { return err } } @@ -1087,12 +1088,12 @@ func (ndb *nodeDB) String() (string, error) { buf.WriteByte('\n') case node == nil: fmt.Fprintf(buf, "%s%40x: \n", nodeKeyFormat.Prefix(), hash) - case node.value == nil && node.height > 0: + case node.GetValue() == nil && node.GetHeight() > 0: fmt.Fprintf(buf, "%s%40x: %s %-16s h=%d version=%d\n", - nodeKeyFormat.Prefix(), hash, node.key, "", node.height, node.version) + nodeKeyFormat.Prefix(), hash, node.GetNodeKey(), "", node.GetHeight(), node.GetVersion()) default: fmt.Fprintf(buf, "%s%40x: %s = %-16s h=%d version=%d\n", - nodeKeyFormat.Prefix(), hash, node.key, node.value, node.height, node.version) + nodeKeyFormat.Prefix(), hash, node.GetNodeKey(), node.GetValue(), node.GetHeight(), node.GetVersion()) } index++ return nil diff --git a/sei-iavl/proof.go b/sei-iavl/proof.go index d6dd5b77ff..a379e444f9 100644 --- a/sei-iavl/proof.go +++ b/sei-iavl/proof.go @@ -229,8 +229,8 @@ func (node *Node) PathToLeaf(t *ImmutableTree, key []byte) (PathToLeaf, *Node, e // As an optimization the already constructed path is passed in as an argument // and is shared among recursive calls. func (node *Node) pathToLeaf(t *ImmutableTree, key []byte, path *PathToLeaf) (*Node, error) { - if node.height == 0 { - if bytes.Equal(node.key, key) { + if node.GetHeight() == 0 { + if bytes.Equal(node.GetNodeKey(), key) { return node, nil } return node, errors.New("key does not exist") @@ -240,7 +240,7 @@ func (node *Node) pathToLeaf(t *ImmutableTree, key []byte, path *PathToLeaf) (*N // left node as part of the path, similarly we don't store the right child info when going down // the right child node. This is done as an optimization since the child info is going to be // already stored in the next ProofInnerNode in PathToLeaf. - if bytes.Compare(key, node.key) < 0 { + if bytes.Compare(key, node.GetNodeKey()) < 0 { // left side rightNode, err := node.getRightNode(t) if err != nil { @@ -248,11 +248,11 @@ func (node *Node) pathToLeaf(t *ImmutableTree, key []byte, path *PathToLeaf) (*N } pin := ProofInnerNode{ - Height: node.height, - Size: node.size, - Version: node.version, + Height: node.GetHeight(), + Size: node.GetSize(), + Version: node.GetVersion(), Left: nil, - Right: rightNode.hash, + Right: rightNode.GetHash(), } *path = append(*path, pin) @@ -270,10 +270,10 @@ func (node *Node) pathToLeaf(t *ImmutableTree, key []byte, path *PathToLeaf) (*N } pin := ProofInnerNode{ - Height: node.height, - Size: node.size, - Version: node.version, - Left: leftNode.hash, + Height: node.GetHeight(), + Size: node.GetSize(), + Version: node.GetVersion(), + Left: leftNode.GetHash(), Right: nil, } *path = append(*path, pin) diff --git a/sei-iavl/proof_range.go b/sei-iavl/proof_range.go index 79db502b0c..866e913da4 100644 --- a/sei-iavl/proof_range.go +++ b/sei-iavl/proof_range.go @@ -407,20 +407,20 @@ func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof // first or last leaf), which provides proof of absence). err = nil } - startOK := keyStart == nil || bytes.Compare(keyStart, left.key) <= 0 - endOK := keyEnd == nil || bytes.Compare(left.key, keyEnd) < 0 + startOK := keyStart == nil || bytes.Compare(keyStart, left.GetNodeKey()) <= 0 + endOK := keyEnd == nil || bytes.Compare(left.GetNodeKey(), keyEnd) < 0 // If left.key is in range, add it to key/values. if startOK && endOK { - keys = append(keys, left.key) // == keyStart - values = append(values, left.value) + keys = append(keys, left.GetNodeKey()) // == keyStart + values = append(values, left.GetValue()) } - h := sha256.Sum256(left.value) + h := sha256.Sum256(left.GetValue()) var leaves = []ProofLeafNode{ { - Key: left.key, + Key: left.GetNodeKey(), ValueHash: h[:], - Version: left.version, + Version: left.GetVersion(), }, } @@ -429,7 +429,7 @@ func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof _stop := false if limit == 1 { _stop = true // case 1 - } else if keyEnd != nil && bytes.Compare(cpIncr(left.key), keyEnd) >= 0 { + } else if keyEnd != nil && bytes.Compare(cpIncr(left.GetNodeKey()), keyEnd) >= 0 { _stop = true // case 2 } if _stop { @@ -440,7 +440,7 @@ func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof } // Get the key after left.key to iterate from. - afterLeft := cpIncr(left.key) + afterLeft := cpIncr(left.GetNodeKey()) // Traverse starting from afterLeft, until keyEnd or the next leaf // after keyEnd. @@ -460,9 +460,9 @@ func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof pathCount = -1 } else { pn := path[pathCount] - if pn.Height != node.height || - pn.Left != nil && !bytes.Equal(pn.Left, node.leftHash) || - pn.Right != nil && !bytes.Equal(pn.Right, node.rightHash) { + if pn.Height != node.GetHeight() || + pn.Left != nil && !bytes.Equal(pn.Left, node.GetLeftHash()) || + pn.Right != nil && !bytes.Equal(pn.Right, node.GetRightHash()) { // We've diverged, so start appending to allPathToLeaf. pathCount = -1 @@ -472,17 +472,17 @@ func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof } } - if node.height == 0 { // Leaf node + if node.GetHeight() == 0 { // Leaf node // Append all paths that we tracked so far to get to this leaf node. allPathToLeafs = append(allPathToLeafs, currentPathToLeaf) // Start a new one to track as we traverse the tree. currentPathToLeaf = PathToLeaf(nil) - h := sha256.Sum256(node.value) + h := sha256.Sum256(node.GetValue()) leaves = append(leaves, ProofLeafNode{ - Key: node.key, + Key: node.GetNodeKey(), ValueHash: h[:], - Version: node.version, + Version: node.GetVersion(), }) leafCount++ @@ -493,17 +493,17 @@ func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof } // Terminate if we've found keyEnd or after. - if keyEnd != nil && bytes.Compare(node.key, keyEnd) >= 0 { + if keyEnd != nil && bytes.Compare(node.GetNodeKey(), keyEnd) >= 0 { return true } // Value is in range, append to keys and values. - keys = append(keys, node.key) - values = append(values, node.value) + keys = append(keys, node.GetNodeKey()) + values = append(values, node.GetValue()) // Terminate if we've found keyEnd-1 or after. // We don't want to fetch any leaves for it. - if keyEnd != nil && bytes.Compare(cpIncr(node.key), keyEnd) >= 0 { + if keyEnd != nil && bytes.Compare(cpIncr(node.GetNodeKey()), keyEnd) >= 0 { return true } @@ -515,11 +515,11 @@ func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof // and don't need to store unnecessary info as we only need to go down the right // path. currentPathToLeaf = append(currentPathToLeaf, ProofInnerNode{ - Height: node.height, - Size: node.size, - Version: node.version, + Height: node.GetHeight(), + Size: node.GetSize(), + Version: node.GetVersion(), Left: nil, - Right: node.rightHash, + Right: node.GetRightHash(), }) } return false diff --git a/sei-iavl/tree_dotgraph.go b/sei-iavl/tree_dotgraph.go index 9aa1e8630f..1701f9cad7 100644 --- a/sei-iavl/tree_dotgraph.go +++ b/sei-iavl/tree_dotgraph.go @@ -49,29 +49,29 @@ func WriteDOTGraph(w io.Writer, tree *ImmutableTree, paths []PathToLeaf) { tree.root.traverse(tree, true, func(node *Node) bool { graphNode := &graphNode{ Attrs: map[string]string{}, - Hash: fmt.Sprintf("%x", node.hash), + Hash: fmt.Sprintf("%x", node.GetHash()), } for k, v := range defaultGraphNodeAttrs { graphNode.Attrs[k] = v } shortHash := graphNode.Hash[:7] - graphNode.Label = mkLabel(unsafeToStr(node.key), 16, "sans-serif") + graphNode.Label = mkLabel(unsafeToStr(node.GetNodeKey()), 16, "sans-serif") graphNode.Label += mkLabel(shortHash, 10, "monospace") - graphNode.Label += mkLabel(fmt.Sprintf("version=%d", node.version), 10, "monospace") + graphNode.Label += mkLabel(fmt.Sprintf("version=%d", node.GetVersion()), 10, "monospace") - if node.value != nil { - graphNode.Label += mkLabel(unsafeToStr(node.value), 10, "sans-serif") + if node.GetValue() != nil { + graphNode.Label += mkLabel(unsafeToStr(node.GetValue()), 10, "sans-serif") } - if node.height == 0 { + if node.GetHeight() == 0 { graphNode.Attrs["fillcolor"] = "lightgrey" graphNode.Attrs["style"] = "filled" } for _, path := range paths { for _, n := range path { - if bytes.Equal(n.Left, node.hash) || bytes.Equal(n.Right, node.hash) { + if bytes.Equal(n.Left, node.GetHash()) || bytes.Equal(n.Right, node.GetHash()) { graphNode.Attrs["peripheries"] = "2" graphNode.Attrs["style"] = "filled" graphNode.Attrs["fillcolor"] = "lightblue" @@ -81,16 +81,16 @@ func WriteDOTGraph(w io.Writer, tree *ImmutableTree, paths []PathToLeaf) { } ctx.Nodes = append(ctx.Nodes, graphNode) - if node.leftNode != nil { + if node.GetLeftNode() != nil { ctx.Edges = append(ctx.Edges, &graphEdge{ From: graphNode.Hash, - To: fmt.Sprintf("%x", node.leftNode.hash), + To: fmt.Sprintf("%x", node.GetLeftNode().GetHash()), }) } - if node.rightNode != nil { + if node.GetRightNode() != nil { ctx.Edges = append(ctx.Edges, &graphEdge{ From: graphNode.Hash, - To: fmt.Sprintf("%x", node.rightNode.hash), + To: fmt.Sprintf("%x", node.GetRightNode().GetHash()), }) } return false diff --git a/sei-iavl/util.go b/sei-iavl/util.go index 676da1313f..ab46646a66 100644 --- a/sei-iavl/util.go +++ b/sei-iavl/util.go @@ -22,10 +22,10 @@ func printNode(ndb *nodeDB, node *Node, indent int) error { fmt.Printf("%s\n", indentPrefix) return nil } - if node.rightNode != nil { - printNode(ndb, node.rightNode, indent+1) - } else if node.rightHash != nil { - rightNode, err := ndb.GetNode(node.rightHash) + if node.GetRightNode() != nil { + printNode(ndb, node.GetRightNode(), indent+1) + } else if node.GetRightHash() != nil { + rightNode, err := ndb.GetNode(node.GetRightHash()) if err != nil { return err } @@ -39,13 +39,13 @@ func printNode(ndb *nodeDB, node *Node, indent int) error { fmt.Printf("%sh:%X\n", indentPrefix, hash) if node.isLeaf() { - fmt.Printf("%s%X:%X (%v)\n", indentPrefix, node.key, node.value, node.height) + fmt.Printf("%s%X:%X (%v)\n", indentPrefix, node.GetNodeKey(), node.GetValue(), node.GetHeight()) } - if node.leftNode != nil { - printNode(ndb, node.leftNode, indent+1) - } else if node.leftHash != nil { - leftNode, err := ndb.GetNode(node.leftHash) + if node.GetLeftNode() != nil { + printNode(ndb, node.GetLeftNode(), indent+1) + } else if node.GetLeftHash() != nil { + leftNode, err := ndb.GetNode(node.GetLeftHash()) if err != nil { return err } From 6b11fb08c2ae492ed7a7d1abc2db823dd3d4fadf Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 8 Mar 2023 21:48:44 +0800 Subject: [PATCH 34/69] fix deadlock --- sei-iavl/node.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sei-iavl/node.go b/sei-iavl/node.go index 263db9d752..247ec73ecc 100644 --- a/sei-iavl/node.go +++ b/sei-iavl/node.go @@ -398,7 +398,7 @@ func (node *Node) _hash() ([]byte, error) { defer node.mtx.Unlock() node.hash = h.Sum(nil) - return node.GetHash(), nil + return node.hash, nil } // Hash the node and its descendants recursively. This usually mutates all @@ -427,7 +427,7 @@ func (node *Node) hashWithCount() ([]byte, int64, error) { defer node.mtx.Unlock() node.hash = h.Sum(nil) - return node.GetHash(), hashCount + 1, nil + return node.hash, hashCount + 1, nil } // validate validates the node contents From 5076caec410b8b3d62cfd9111802a61457ad9751 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 8 Mar 2023 21:58:47 +0800 Subject: [PATCH 35/69] fix tests --- sei-iavl/mutable_tree.go | 20 ++++++++++++-------- sei-iavl/node.go | 4 ++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 3152ffb079..21f012e766 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -287,10 +287,11 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph if err != nil { return nil, false, err } - lNode, updated, err := tree.recursiveSet(leftNode, key, value, orphans) - if err != nil { - return nil, updated, err + lNode, u, e := tree.recursiveSet(leftNode, key, value, orphans) + if e != nil { + return nil, u, e } + updated = u node.SetLeftNode(lNode) node.SetLeftHash(nil) // leftHash is yet unknown } else { @@ -298,10 +299,11 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph if err != nil { return nil, false, err } - rNode, updated, err := tree.recursiveSet(rightNode, key, value, orphans) - if err != nil { - return nil, updated, err + rNode, u, e := tree.recursiveSet(rightNode, key, value, orphans) + if e != nil { + return nil, u, e } + updated = u node.SetRightNode(rNode) node.SetRightHash(nil) // rightHash is yet unknown } @@ -1257,10 +1259,11 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e return nil, err } node.SetLeftHash(nil) - lNode, leftOrphaned, err := tree.rotateLeft(left) + lNode, lOrphaned, err := tree.rotateLeft(left) if err != nil { return nil, err } + leftOrphaned = lOrphaned node.SetLeftNode(lNode) newNode, rightOrphaned, err := tree.rotateRight(node) @@ -1297,10 +1300,11 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e return nil, err } node.SetRightHash(nil) - rNode, rightOrphaned, err := tree.rotateRight(right) + rNode, rOrphaned, err := tree.rotateRight(right) if err != nil { return nil, err } + rightOrphaned = rOrphaned node.SetRightNode(rNode) newNode, leftOrphaned, err := tree.rotateLeft(node) if err != nil { diff --git a/sei-iavl/node.go b/sei-iavl/node.go index 247ec73ecc..898602ea22 100644 --- a/sei-iavl/node.go +++ b/sei-iavl/node.go @@ -432,11 +432,11 @@ func (node *Node) hashWithCount() ([]byte, int64, error) { // validate validates the node contents func (node *Node) validate() error { - node.mtx.RLock() - defer node.mtx.RUnlock() if node == nil { return errors.New("node cannot be nil") } + node.mtx.RLock() + defer node.mtx.RUnlock() if node.key == nil { return errors.New("key cannot be nil") } From 2fab42cc7e6867b597484218d1d433818a2a6504 Mon Sep 17 00:00:00 2001 From: codchen Date: Fri, 10 Mar 2023 12:25:02 +0800 Subject: [PATCH 36/69] Fix mutable tree race condition --- sei-iavl/immutable_tree.go | 5 ----- sei-iavl/mutable_tree.go | 9 +++------ 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index b67dbde15b..3f6fe52a0b 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -3,7 +3,6 @@ package iavl import ( "fmt" "strings" - "sync" dbm "github.com/tendermint/tm-db" ) @@ -19,7 +18,6 @@ type ImmutableTree struct { ndb *nodeDB version int64 skipFastStorageUpgrade bool - mtx *sync.Mutex } // NewImmutableTree creates both in-memory and persistent instances @@ -32,7 +30,6 @@ func NewImmutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) *Im // NodeDB-backed Tree. ndb: newNodeDB(db, cacheSize, nil), skipFastStorageUpgrade: skipFastStorageUpgrade, - mtx: &sync.Mutex{}, } } @@ -42,7 +39,6 @@ func NewImmutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastS // NodeDB-backed Tree. ndb: newNodeDB(db, cacheSize, opts), skipFastStorageUpgrade: skipFastStorageUpgrade, - mtx: &sync.Mutex{}, } } @@ -322,7 +318,6 @@ func (t *ImmutableTree) clone() *ImmutableTree { ndb: t.ndb, version: t.version, skipFastStorageUpgrade: t.skipFastStorageUpgrade, - mtx: t.mtx, } } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 21f012e766..6abb1ff134 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -37,6 +37,7 @@ type MutableTree struct { unsavedFastNodeRemovals map[string]interface{} // FastNodes that have not yet been removed from disk ndb *nodeDB skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage + mtx *sync.Mutex } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -47,7 +48,7 @@ func NewMutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) (*Mut // NewMutableTreeWithOpts returns a new tree with the specified options. func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) (*MutableTree, error) { ndb := newNodeDB(db, cacheSize, opts) - head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade, mtx: &sync.Mutex{}} + head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade} return &MutableTree{ ImmutableTree: head, @@ -59,6 +60,7 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto unsavedFastNodeRemovals: make(map[string]interface{}), ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade, + mtx: &sync.Mutex{}, }, nil } @@ -532,7 +534,6 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t ndb: tree.ndb, version: targetVersion, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, - mtx: tree.mtx, } if len(rootHash) > 0 { // If rootHash is empty then root of tree should be nil @@ -609,7 +610,6 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr ndb: tree.ndb, version: latestVersion, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, - mtx: tree.mtx, } if len(latestRoot) != 0 { @@ -761,7 +761,6 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { ndb: tree.ndb, version: version, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, - mtx: tree.mtx, }, nil } tree.versions[version] = true @@ -775,7 +774,6 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { ndb: tree.ndb, version: version, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, - mtx: tree.mtx, }, nil } @@ -789,7 +787,6 @@ func (tree *MutableTree) Rollback() { ndb: tree.ndb, version: 0, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, - mtx: tree.mtx, } } tree.orphans = map[string]int64{} From c9f8cb32ab601fa77ae4964c59b4f6011eab36db Mon Sep 17 00:00:00 2001 From: codchen Date: Thu, 27 Apr 2023 10:54:37 +0800 Subject: [PATCH 37/69] Add command that print size of tree --- sei-iavl/cmd/iaviewer/main.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go index 871e512aed..6d2cddcff3 100644 --- a/sei-iavl/cmd/iaviewer/main.go +++ b/sei-iavl/cmd/iaviewer/main.go @@ -22,8 +22,8 @@ const ( func main() { args := os.Args[1:] - if len(args) < 3 || (args[0] != "data" && args[0] != "shape" && args[0] != "versions") { - fmt.Fprintln(os.Stderr, "Usage: iaviewer [version number]") + if len(args) < 3 || (args[0] != "data" && args[0] != "shape" && args[0] != "versions" && args[0] != "size") { + fmt.Fprintln(os.Stderr, "Usage: iaviewer [version number]") fmt.Fprintln(os.Stderr, " is the prefix of db, and the iavl tree of different modules in cosmos-sdk uses ") fmt.Fprintln(os.Stderr, "different to identify, just like \"s/k:gov/\" represents the prefix of gov module") os.Exit(1) @@ -59,6 +59,8 @@ func main() { PrintShape(tree) case "versions": PrintVersions(tree) + case "size": + PrintSize(tree) } } @@ -186,3 +188,24 @@ func PrintVersions(tree *iavl.MutableTree) { fmt.Printf(" %d\n", v) } } + +func PrintSize(tree *iavl.MutableTree) { + count, totalKeySize, totalValueSize := 0, 0, 0 + keySizeByPrefix, valSizeByPrefix := map[byte]int{}, map[byte]int{} + tree.Iterate(func(key []byte, value []byte) bool { + count += 1 + totalKeySize += len(key) + totalValueSize += len(value) + if _, ok := keySizeByPrefix[key[0]]; !ok { + keySizeByPrefix[key[0]] = 0 + valSizeByPrefix[key[0]] = 0 + } + keySizeByPrefix[key[0]] += len(key) + valSizeByPrefix[key[0]] += len(value) + return false + }) + fmt.Printf("Total entry count: %d. Total key bytes: %d. Total value bytes: %d\n", count, totalKeySize, totalValueSize) + for p := range keySizeByPrefix { + fmt.Printf("prefix %d has key bytes %d and value bytes %d\n", p, keySizeByPrefix[p], valSizeByPrefix[p]) + } +} From 0f64ad7c2ee62448f24b571d206f69516cef7651 Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 15 May 2023 14:50:53 +0800 Subject: [PATCH 38/69] Skip orphan metadata if versioning is not needed --- sei-iavl/mutable_tree.go | 7 +++++++ sei-iavl/nodedb.go | 24 ++++++++++++++++++++++++ sei-iavl/options.go | 4 ++++ 3 files changed, 35 insertions(+) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 6abb1ff134..f374a0e92f 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -1070,6 +1070,13 @@ func (tree *MutableTree) SetInitialVersion(version uint64) { func (tree *MutableTree) DeleteVersions(versions ...int64) error { logger.Debug("DELETING VERSIONS: %v\n", versions) + if tree.ndb.ShouldNotUseVersion() { + // no need to delete versions since there is no version to be + // deleted except the current one, which shouldn't be deleted + // in any circumstance + return nil + } + if len(versions) == 0 { return nil } diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index be94099a5f..49bc846876 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -634,6 +634,18 @@ func (ndb *nodeDB) SaveOrphans(version int64, orphans map[string]int64) error { ndb.mtx.Lock() defer ndb.mtx.Unlock() + // instead of saving orphan metadata and later read orphan metadata->delete + // orphan data->delete orphan metadata, we directly delete orphan data here + // without doing anything for orphan metadata, if versioning is not needed. + if ndb.ShouldNotUseVersion() { + for orphan := range orphans { + if err := ndb.deleteOrphanedData([]byte(orphan)); err != nil { + return err + } + } + return nil + } + toVersion, err := ndb.getPreviousVersion(version) if err != nil { return err @@ -649,6 +661,14 @@ func (ndb *nodeDB) SaveOrphans(version int64, orphans map[string]int64) error { return nil } +func (ndb *nodeDB) deleteOrphanedData(hash []byte) error { + if err := ndb.batch.Delete(ndb.nodeKey(hash)); err != nil { + return err + } + ndb.nodeCache.Remove(hash) + return nil +} + // Saves a single orphan to disk. func (ndb *nodeDB) saveOrphan(hash []byte, fromVersion, toVersion int64) error { if fromVersion > toVersion { @@ -1053,6 +1073,10 @@ func (ndb *nodeDB) traverseNodes(fn func(hash []byte, node *Node) error) error { return nil } +func (ndb *nodeDB) ShouldNotUseVersion() bool { + return ndb.opts.NoVersioning +} + func (ndb *nodeDB) String() (string, error) { buf := bufPool.Get().(*bytes.Buffer) defer bufPool.Put(buf) diff --git a/sei-iavl/options.go b/sei-iavl/options.go index 7d5d24653a..58dfcabea7 100644 --- a/sei-iavl/options.go +++ b/sei-iavl/options.go @@ -81,6 +81,10 @@ type Options struct { // When Stat is not nil, statistical logic needs to be executed Stat *Statistics + + // When set to true, the DB will only keep the most recent version and immediately delete + // obsolete data upon new data's commit + NoVersioning bool } // DefaultOptions returns the default options for IAVL. From be5ead9f61c1f27822ced4e38c2e87af7ba1faf6 Mon Sep 17 00:00:00 2001 From: Yiming Zang Date: Sat, 20 May 2023 13:45:16 -0700 Subject: [PATCH 39/69] Speed up IavlViewer and add more info --- sei-iavl/Makefile | 2 -- sei-iavl/cmd/iaviewer/main.go | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/sei-iavl/Makefile b/sei-iavl/Makefile index 0364b73506..ecba766696 100644 --- a/sei-iavl/Makefile +++ b/sei-iavl/Makefile @@ -15,10 +15,8 @@ all: lint test install install: ifeq ($(COLORS_ON),) go install ./cmd/iaviewer - go install ./cmd/iavlserver else go install $(CMDFLAGS) ./cmd/iaviewer - go install $(CMDFLAGS) ./cmd/iavlserver endif .PHONY: install diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go index 6d2cddcff3..d7eeb410a8 100644 --- a/sei-iavl/cmd/iaviewer/main.go +++ b/sei-iavl/cmd/iaviewer/main.go @@ -44,6 +44,12 @@ func main() { fmt.Fprintf(os.Stderr, "Error reading data: %s\n", err) os.Exit(1) } + treeHash, err := tree.Hash() + if err != nil { + fmt.Fprintf(os.Stderr, "Error hashing tree: %s\n", err) + os.Exit(1) + } + fmt.Printf("Tree hash is %X, tree size is %X\n", treeHash, tree.Size()) switch args[0] { case "data": @@ -122,7 +128,7 @@ func ReadTree(dir string, version int, prefix []byte) (*iavl.MutableTree, error) db = dbm.NewPrefixDB(db, prefix) } - tree, err := iavl.NewMutableTree(db, DefaultCacheSize, false) + tree, err := iavl.NewMutableTree(db, DefaultCacheSize, true) if err != nil { return nil, err } @@ -133,12 +139,21 @@ func ReadTree(dir string, version int, prefix []byte) (*iavl.MutableTree, error) func PrintKeys(tree *iavl.MutableTree) { fmt.Println("Printing all keys with hashed values (to detect diff)") + totalKeySize := 0 + totalValSize := 0 + count := 0 + keyPrefixMap := map[string]int{} tree.Iterate(func(key []byte, value []byte) bool { printKey := parseWeaveKey(key) digest := sha256.Sum256(value) fmt.Printf(" %s\n %X\n", printKey, digest) + totalKeySize += len(key) + totalValSize += len(value) + count++ + keyPrefixMap[fmt.Sprintf("%x", key[0])]++ return false }) + fmt.Printf("Total key count %d, total key bytes %d, total value bytes %d, prefix map %v\n", count, totalKeySize, totalValSize, keyPrefixMap) } // parseWeaveKey assumes a separating : where all in front should be ascii, From 00100eae0f7ce0cae6007114bd288e4a66ea1271 Mon Sep 17 00:00:00 2001 From: Yiming Zang Date: Sat, 20 May 2023 14:49:25 -0700 Subject: [PATCH 40/69] Fix some variable name --- sei-iavl/cmd/iaviewer/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go index d7eeb410a8..d674a8b405 100644 --- a/sei-iavl/cmd/iaviewer/main.go +++ b/sei-iavl/cmd/iaviewer/main.go @@ -141,7 +141,7 @@ func PrintKeys(tree *iavl.MutableTree) { fmt.Println("Printing all keys with hashed values (to detect diff)") totalKeySize := 0 totalValSize := 0 - count := 0 + totalNumKeys := 0 keyPrefixMap := map[string]int{} tree.Iterate(func(key []byte, value []byte) bool { printKey := parseWeaveKey(key) @@ -149,11 +149,11 @@ func PrintKeys(tree *iavl.MutableTree) { fmt.Printf(" %s\n %X\n", printKey, digest) totalKeySize += len(key) totalValSize += len(value) - count++ + totalNumKeys++ keyPrefixMap[fmt.Sprintf("%x", key[0])]++ return false }) - fmt.Printf("Total key count %d, total key bytes %d, total value bytes %d, prefix map %v\n", count, totalKeySize, totalValSize, keyPrefixMap) + fmt.Printf("Total key count %d, total key bytes %d, total value bytes %d, prefix map %v\n", totalNumKeys, totalKeySize, totalValSize, keyPrefixMap) } // parseWeaveKey assumes a separating : where all in front should be ascii, From 67793561a28fc4db3c85f761380fbe440bc07961 Mon Sep 17 00:00:00 2001 From: codchen Date: Tue, 30 May 2023 17:07:45 +0800 Subject: [PATCH 41/69] no orphan multi version --- sei-iavl/mutable_tree.go | 39 +++++++++++++++++---- sei-iavl/nodedb.go | 16 --------- sei-iavl/options.go | 12 ++++--- sei-iavl/orphandb.go | 75 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 26 deletions(-) create mode 100644 sei-iavl/orphandb.go diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index f374a0e92f..7301f3755e 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -37,6 +37,8 @@ type MutableTree struct { unsavedFastNodeRemovals map[string]interface{} // FastNodes that have not yet been removed from disk ndb *nodeDB skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage + versionsToKeep int64 + orphandb *orphanDB mtx *sync.Mutex } @@ -60,6 +62,8 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto unsavedFastNodeRemovals: make(map[string]interface{}), ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade, + versionsToKeep: opts.VersionsToKeep, + orphandb: NewOrphanDB(opts), mtx: &sync.Mutex{}, }, nil } @@ -951,12 +955,38 @@ func (tree *MutableTree) saveFastNodeVersion() error { return tree.ndb.setFastStorageVersionToBatch() } +func (tree *MutableTree) handleOrphans(version int64) error { + if tree.versionsToKeep == 0 { + return tree.ndb.SaveOrphans(version, tree.orphans) + } + + if tree.versionsToKeep == 1 { + for orphan := range tree.orphans { + if err := tree.ndb.deleteOrphanedData([]byte(orphan)); err != nil { + return err + } + } + return nil + } + + if err := tree.orphandb.SaveOrphans(version, tree.orphans); err != nil { + return err + } + oldOrphans := tree.orphandb.GetOrphans(version - tree.versionsToKeep + 1) + for orphan := range oldOrphans { + if err := tree.ndb.deleteOrphanedData([]byte(orphan)); err != nil { + return err + } + } + return tree.orphandb.DeleteOrphans(version - tree.versionsToKeep + 1) +} + func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) (int64, error) { if tree.root == nil { // There can still be orphans, for example if the root is the node being // removed. logger.Debug("SAVE EMPTY TREE %v\n", version) - if err := tree.ndb.SaveOrphans(version, tree.orphans); err != nil { + if err := tree.handleOrphans(version); err != nil { return 0, err } if err := tree.ndb.SaveEmptyRoot(version); !silentSaveRootError && err != nil { @@ -967,7 +997,7 @@ func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) if _, err := tree.ndb.SaveBranch(tree.root); err != nil { return 0, err } - if err := tree.ndb.SaveOrphans(version, tree.orphans); err != nil { + if err := tree.handleOrphans(version); err != nil { return 0, err } if err := tree.ndb.SaveRoot(tree.root, version); !silentSaveRootError && err != nil { @@ -1070,10 +1100,7 @@ func (tree *MutableTree) SetInitialVersion(version uint64) { func (tree *MutableTree) DeleteVersions(versions ...int64) error { logger.Debug("DELETING VERSIONS: %v\n", versions) - if tree.ndb.ShouldNotUseVersion() { - // no need to delete versions since there is no version to be - // deleted except the current one, which shouldn't be deleted - // in any circumstance + if tree.versionsToKeep > 0 { return nil } diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index 49bc846876..18bd44aec5 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -634,18 +634,6 @@ func (ndb *nodeDB) SaveOrphans(version int64, orphans map[string]int64) error { ndb.mtx.Lock() defer ndb.mtx.Unlock() - // instead of saving orphan metadata and later read orphan metadata->delete - // orphan data->delete orphan metadata, we directly delete orphan data here - // without doing anything for orphan metadata, if versioning is not needed. - if ndb.ShouldNotUseVersion() { - for orphan := range orphans { - if err := ndb.deleteOrphanedData([]byte(orphan)); err != nil { - return err - } - } - return nil - } - toVersion, err := ndb.getPreviousVersion(version) if err != nil { return err @@ -1073,10 +1061,6 @@ func (ndb *nodeDB) traverseNodes(fn func(hash []byte, node *Node) error) error { return nil } -func (ndb *nodeDB) ShouldNotUseVersion() bool { - return ndb.opts.NoVersioning -} - func (ndb *nodeDB) String() (string, error) { buf := bufPool.Get().(*bytes.Buffer) defer bufPool.Put(buf) diff --git a/sei-iavl/options.go b/sei-iavl/options.go index 58dfcabea7..a1ad60de6f 100644 --- a/sei-iavl/options.go +++ b/sei-iavl/options.go @@ -82,12 +82,16 @@ type Options struct { // When Stat is not nil, statistical logic needs to be executed Stat *Statistics - // When set to true, the DB will only keep the most recent version and immediately delete - // obsolete data upon new data's commit - NoVersioning bool + VersionsToKeep int64 + + NumOrphansPerFile int + + OrphanDirectory string } // DefaultOptions returns the default options for IAVL. func DefaultOptions() Options { - return Options{} + return Options{ + NumOrphansPerFile: 100000, + } } diff --git a/sei-iavl/orphandb.go b/sei-iavl/orphandb.go new file mode 100644 index 0000000000..fb714e19a7 --- /dev/null +++ b/sei-iavl/orphandb.go @@ -0,0 +1,75 @@ +package iavl + +import ( + "fmt" + "io/fs" + "io/ioutil" + "os" + "path" + "strings" +) + +type orphanDB struct { + cache map[int64]map[string]int64 // key: version, value: orphans + directory string + numOrphansPerFile int +} + +func NewOrphanDB(opts *Options) *orphanDB { + return &orphanDB{ + cache: map[int64]map[string]int64{}, + directory: opts.OrphanDirectory, + numOrphansPerFile: opts.NumOrphansPerFile, + } +} + +func (o *orphanDB) SaveOrphans(version int64, orphans map[string]int64) error { + o.cache[version] = orphans + chunks := [][]string{{}} + for orphan := range orphans { + if len(chunks[len(chunks)-1]) == o.numOrphansPerFile { + chunks = append(chunks, []string{}) + } + chunks[len(chunks)-1] = append(chunks[len(chunks)-1], orphan) + } + dir := path.Join(o.directory, fmt.Sprintf("%d", version)) + os.RemoveAll(dir) + os.MkdirAll(dir, fs.ModePerm) + for i, chunk := range chunks { + f, err := os.Create(path.Join(dir, fmt.Sprintf("%d", i))) + if err != nil { + return err + } + f.WriteString(strings.Join(chunk, "\n")) + f.Close() + } + return nil +} + +func (o *orphanDB) GetOrphans(version int64) map[string]int64 { + if _, ok := o.cache[version]; !ok { + o.cache[version] = map[string]int64{} + dir := path.Join(o.directory, fmt.Sprintf("%d", version)) + files, err := ioutil.ReadDir(dir) + if err != nil { + // no orphans found + return o.cache[version] + } + for _, file := range files { + content, err := ioutil.ReadFile(path.Join(dir, file.Name())) + if err != nil { + return o.cache[version] + } + for _, orphan := range strings.Split(string(content), "\n") { + o.cache[version][orphan] = version + } + } + } + return o.cache[version] +} + +func (o *orphanDB) DeleteOrphans(version int64) error { + delete(o.cache, version) + dir := path.Join(o.directory, fmt.Sprintf("%d", version)) + return os.RemoveAll(dir) +} From ace4ab6fac29aec6b58e038254b143637262a2a6 Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 5 Jun 2023 11:38:38 +0800 Subject: [PATCH 42/69] polish & tests --- sei-iavl/mutable_tree.go | 75 ++++++++++++++++++++++++--------------- sei-iavl/options.go | 12 ++++++- sei-iavl/orphandb_test.go | 73 +++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 sei-iavl/orphandb_test.go diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 7301f3755e..293090bbb6 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -28,18 +28,19 @@ var ErrVersionDoesNotExist = errors.New("version does not exist") // // The inner ImmutableTree should not be used directly by callers. type MutableTree struct { - *ImmutableTree // The current, working tree. - lastSaved *ImmutableTree // The most recently saved tree. - orphans map[string]int64 // Nodes removed by changes to working tree. - versions map[int64]bool // The previous, saved versions of the tree. - allRootLoaded bool // Whether all roots are loaded or not(by LazyLoadVersion) - unsavedFastNodeAdditions map[string]*FastNode // FastNodes that have not yet been saved to disk - unsavedFastNodeRemovals map[string]interface{} // FastNodes that have not yet been removed from disk - ndb *nodeDB - skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage - versionsToKeep int64 - orphandb *orphanDB - mtx *sync.Mutex + *ImmutableTree // The current, working tree. + lastSaved *ImmutableTree // The most recently saved tree. + orphans map[string]int64 // Nodes removed by changes to working tree. + versions map[int64]bool // The previous, saved versions of the tree. + allRootLoaded bool // Whether all roots are loaded or not(by LazyLoadVersion) + unsavedFastNodeAdditions map[string]*FastNode // FastNodes that have not yet been saved to disk + unsavedFastNodeRemovals map[string]interface{} // FastNodes that have not yet been removed from disk + ndb *nodeDB + skipFastStorageUpgrade bool // If true, the tree will work like no fast storage and always not upgrade fast storage + separateOrphanStorage bool + separateOrphanVersionsToKeep int64 + orphandb *orphanDB + mtx *sync.Mutex } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -51,20 +52,29 @@ func NewMutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) (*Mut func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) (*MutableTree, error) { ndb := newNodeDB(db, cacheSize, opts) head := &ImmutableTree{ndb: ndb, skipFastStorageUpgrade: skipFastStorageUpgrade} + if opts == nil { + defaultOpts := DefaultOptions() + opts = &defaultOpts + } + var orphandb *orphanDB + if opts.SeparateOrphanStorage { + orphandb = NewOrphanDB(opts) + } return &MutableTree{ - ImmutableTree: head, - lastSaved: head.clone(), - orphans: map[string]int64{}, - versions: map[int64]bool{}, - allRootLoaded: false, - unsavedFastNodeAdditions: make(map[string]*FastNode), - unsavedFastNodeRemovals: make(map[string]interface{}), - ndb: ndb, - skipFastStorageUpgrade: skipFastStorageUpgrade, - versionsToKeep: opts.VersionsToKeep, - orphandb: NewOrphanDB(opts), - mtx: &sync.Mutex{}, + ImmutableTree: head, + lastSaved: head.clone(), + orphans: map[string]int64{}, + versions: map[int64]bool{}, + allRootLoaded: false, + unsavedFastNodeAdditions: make(map[string]*FastNode), + unsavedFastNodeRemovals: make(map[string]interface{}), + ndb: ndb, + skipFastStorageUpgrade: skipFastStorageUpgrade, + separateOrphanStorage: opts.SeparateOrphanStorage, + separateOrphanVersionsToKeep: opts.SeparateOphanVersionsToKeep, + orphandb: orphandb, + mtx: &sync.Mutex{}, }, nil } @@ -956,11 +966,17 @@ func (tree *MutableTree) saveFastNodeVersion() error { } func (tree *MutableTree) handleOrphans(version int64) error { - if tree.versionsToKeep == 0 { + if !tree.separateOrphanStorage { + // store orphan in the same levelDB as application data return tree.ndb.SaveOrphans(version, tree.orphans) } - if tree.versionsToKeep == 1 { + if tree.separateOrphanVersionsToKeep == 0 { + panic("must keep at least one version") + } + + // optimization for the 1 version case so that we don't have to save and immediately delete the same version + if tree.separateOrphanVersionsToKeep == 1 { for orphan := range tree.orphans { if err := tree.ndb.deleteOrphanedData([]byte(orphan)); err != nil { return err @@ -972,13 +988,13 @@ func (tree *MutableTree) handleOrphans(version int64) error { if err := tree.orphandb.SaveOrphans(version, tree.orphans); err != nil { return err } - oldOrphans := tree.orphandb.GetOrphans(version - tree.versionsToKeep + 1) + oldOrphans := tree.orphandb.GetOrphans(version - tree.separateOrphanVersionsToKeep + 1) for orphan := range oldOrphans { if err := tree.ndb.deleteOrphanedData([]byte(orphan)); err != nil { return err } } - return tree.orphandb.DeleteOrphans(version - tree.versionsToKeep + 1) + return tree.orphandb.DeleteOrphans(version - tree.separateOrphanVersionsToKeep + 1) } func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) (int64, error) { @@ -1100,7 +1116,8 @@ func (tree *MutableTree) SetInitialVersion(version uint64) { func (tree *MutableTree) DeleteVersions(versions ...int64) error { logger.Debug("DELETING VERSIONS: %v\n", versions) - if tree.versionsToKeep > 0 { + if tree.separateOrphanStorage { + // no need to delete versions if we are keeping orphans separately return nil } diff --git a/sei-iavl/options.go b/sei-iavl/options.go index a1ad60de6f..e42defdabb 100644 --- a/sei-iavl/options.go +++ b/sei-iavl/options.go @@ -82,10 +82,20 @@ type Options struct { // When Stat is not nil, statistical logic needs to be executed Stat *Statistics - VersionsToKeep int64 + // When true, orphan data will be stored in separate directory than application data, and + // the pruning of application data will happen during commit (rather than after commit) + SeparateOrphanStorage bool + // Only meaningful if SeparateOrphanStorage is true. + // The number of application data versions to keep in the application database. + SeparateOphanVersionsToKeep int64 + + // Only meaningful if SeparateOrphanStorage is true. + // The max number of orphan entries to store in the separate orphan files. NumOrphansPerFile int + // Only meaningful if SeparateOrphanStorage is true. + // The directory to store orphan files. OrphanDirectory string } diff --git a/sei-iavl/orphandb_test.go b/sei-iavl/orphandb_test.go new file mode 100644 index 0000000000..51a7dd8df6 --- /dev/null +++ b/sei-iavl/orphandb_test.go @@ -0,0 +1,73 @@ +package iavl + +import ( + "fmt" + "io/ioutil" + "path" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestOrphanDBSaveGet(t *testing.T) { + dir := t.TempDir() + db := NewOrphanDB(&Options{ + NumOrphansPerFile: 2, + OrphanDirectory: dir, + }) + err := db.SaveOrphans(123, map[string]int64{ + "o1": 123, + "o2": 123, + "o3": 123, + }) + require.Nil(t, err) + files, err := ioutil.ReadDir(path.Join(dir, fmt.Sprintf("%d", 123))) + require.Nil(t, err) + require.Equal(t, 2, len(files)) // 3 orphans would result in 2 files + orphans := db.GetOrphans(123) + require.Equal(t, map[string]int64{ + "o1": 123, + "o2": 123, + "o3": 123, + }, orphans) + orphans = db.GetOrphans(456) // not exist + require.Equal(t, map[string]int64{}, orphans) + + // flush cache + db = NewOrphanDB(&Options{ + NumOrphansPerFile: 2, + OrphanDirectory: dir, + }) + orphans = db.GetOrphans(123) // would load from disk + require.Equal(t, map[string]int64{ + "o1": 123, + "o2": 123, + "o3": 123, + }, orphans) +} + +func TestOrphanDelete(t *testing.T) { + dir := t.TempDir() + db := NewOrphanDB(&Options{ + NumOrphansPerFile: 2, + OrphanDirectory: dir, + }) + err := db.SaveOrphans(123, map[string]int64{ + "o1": 123, + "o2": 123, + "o3": 123, + }) + require.Nil(t, err) + err = db.DeleteOrphans(123) + require.Nil(t, err) + orphans := db.GetOrphans(123) // not exist in cache + require.Equal(t, map[string]int64{}, orphans) + + // flush cache + db = NewOrphanDB(&Options{ + NumOrphansPerFile: 2, + OrphanDirectory: dir, + }) + orphans = db.GetOrphans(123) // would load from disk + require.Equal(t, map[string]int64{}, orphans) +} From 9887353152b052133658fcae071cfd4b00898e37 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 14 Jun 2023 13:14:02 +0800 Subject: [PATCH 43/69] Synchronize potential concurrent access to mutable tree --- sei-iavl/basic_test.go | 62 +++++----- sei-iavl/benchmarks/bench_test.go | 10 +- sei-iavl/cmd/iaviewer/main.go | 6 +- sei-iavl/export_test.go | 6 +- sei-iavl/mutable_tree.go | 194 ++++++++++++++++++------------ sei-iavl/mutable_tree_test.go | 98 +++++++-------- sei-iavl/proof_forgery_test.go | 4 +- sei-iavl/proof_iavl_test.go | 2 +- sei-iavl/proof_ics23_test.go | 16 +-- sei-iavl/proof_test.go | 14 +-- sei-iavl/repair_test.go | 2 +- sei-iavl/testutils_test.go | 2 +- sei-iavl/tree_dotgraph_test.go | 2 +- sei-iavl/tree_random_test.go | 4 +- sei-iavl/tree_test.go | 48 ++++---- 15 files changed, 252 insertions(+), 218 deletions(-) diff --git a/sei-iavl/basic_test.go b/sei-iavl/basic_test.go index 13996c7dd4..228809c06a 100644 --- a/sei-iavl/basic_test.go +++ b/sei-iavl/basic_test.go @@ -42,7 +42,7 @@ func TestBasic(t *testing.T) { key := []byte{0x00} expected := "" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val != nil { t.Error("Expected no value to exist") @@ -68,7 +68,7 @@ func TestBasic(t *testing.T) { key := []byte("1") expected := "one" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val == nil { t.Error("Expected value to exist") @@ -95,7 +95,7 @@ func TestBasic(t *testing.T) { key := []byte("2") expected := "TWO" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val == nil { t.Error("Expected value to exist") @@ -121,7 +121,7 @@ func TestBasic(t *testing.T) { key := []byte("4") expected := "" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val != nil { t.Error("Expected no value to exist") @@ -147,7 +147,7 @@ func TestBasic(t *testing.T) { key := []byte("6") expected := "" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val != nil { t.Error("Expected no value to exist") @@ -192,31 +192,31 @@ func TestUnit(t *testing.T) { } expectSet := func(tree *MutableTree, i int, repr string, hashCount int64) { - origNode := tree.root + origNode := tree.ImmutableTree().root updated, err := tree.Set(i2b(i), []byte{}) require.NoError(t, err) // ensure node was added & structure is as expected. - if updated || P(tree.root) != repr { + if updated || P(tree.ImmutableTree().root) != repr { t.Fatalf("Adding %v to %v:\nExpected %v\nUnexpectedly got %v updated:%v", - i, P(origNode), repr, P(tree.root), updated) + i, P(origNode), repr, P(tree.ImmutableTree().root), updated) } // ensure hash calculation requirements - expectHash(tree.ImmutableTree, hashCount) - tree.root = origNode + expectHash(tree.ImmutableTree(), hashCount) + tree.ImmutableTree().root = origNode } expectRemove := func(tree *MutableTree, i int, repr string, hashCount int64) { - origNode := tree.root + origNode := tree.ImmutableTree().root value, removed, err := tree.Remove(i2b(i)) require.NoError(t, err) // ensure node was added & structure is as expected. - if len(value) != 0 || !removed || P(tree.root) != repr { + if len(value) != 0 || !removed || P(tree.ImmutableTree().root) != repr { t.Fatalf("Removing %v from %v:\nExpected %v\nUnexpectedly got %v value:%v removed:%v", - i, P(origNode), repr, P(tree.root), value, removed) + i, P(origNode), repr, P(tree.ImmutableTree().root), value, removed) } // ensure hash calculation requirements - expectHash(tree.ImmutableTree, hashCount) - tree.root = origNode + expectHash(tree.ImmutableTree(), hashCount) + tree.ImmutableTree().root = origNode } // Test Set cases: @@ -317,8 +317,8 @@ func TestIntegration(t *testing.T) { if !updated { t.Error("should have been updated") } - if tree.Size() != int64(i+1) { - t.Error("size was wrong", tree.Size(), i+1) + if tree.ImmutableTree().Size() != int64(i+1) { + t.Error("size was wrong", tree.ImmutableTree().Size(), i+1) } } @@ -370,8 +370,8 @@ func TestIntegration(t *testing.T) { t.Error("wrong value") } } - if tree.Size() != int64(len(records)-(i+1)) { - t.Error("size was wrong", tree.Size(), (len(records) - (i + 1))) + if tree.ImmutableTree().Size() != int64(len(records)-(i+1)) { + t.Error("size was wrong", tree.ImmutableTree().Size(), (len(records) - (i + 1))) } } } @@ -427,38 +427,38 @@ func TestIterateRange(t *testing.T) { } trav := traverser{} - tree.IterateRange([]byte("foo"), []byte("goo"), true, trav.view) + tree.ImmutableTree().IterateRange([]byte("foo"), []byte("goo"), true, trav.view) expectTraverse(t, trav, "foo", "food", 5) trav = traverser{} - tree.IterateRange([]byte("aaa"), []byte("abb"), true, trav.view) + tree.ImmutableTree().IterateRange([]byte("aaa"), []byte("abb"), true, trav.view) expectTraverse(t, trav, "", "", 0) trav = traverser{} - tree.IterateRange(nil, []byte("flap"), true, trav.view) + tree.ImmutableTree().IterateRange(nil, []byte("flap"), true, trav.view) expectTraverse(t, trav, "abc", "fan", 2) trav = traverser{} - tree.IterateRange([]byte("foob"), nil, true, trav.view) + tree.ImmutableTree().IterateRange([]byte("foob"), nil, true, trav.view) expectTraverse(t, trav, "foobang", "low", 6) trav = traverser{} - tree.IterateRange([]byte("very"), nil, true, trav.view) + tree.ImmutableTree().IterateRange([]byte("very"), nil, true, trav.view) expectTraverse(t, trav, "", "", 0) // make sure it doesn't include end trav = traverser{} - tree.IterateRange([]byte("fooba"), []byte("food"), true, trav.view) + tree.ImmutableTree().IterateRange([]byte("fooba"), []byte("food"), true, trav.view) expectTraverse(t, trav, "foobang", "foobaz", 3) // make sure backwards also works... (doesn't include end) trav = traverser{} - tree.IterateRange([]byte("fooba"), []byte("food"), false, trav.view) + tree.ImmutableTree().IterateRange([]byte("fooba"), []byte("food"), false, trav.view) expectTraverse(t, trav, "foobaz", "foobang", 3) // make sure backwards also works... trav = traverser{} - tree.IterateRange([]byte("g"), nil, false, trav.view) + tree.ImmutableTree().IterateRange([]byte("g"), nil, false, trav.view) expectTraverse(t, trav, "low", "good", 2) } @@ -513,7 +513,7 @@ func TestProof(t *testing.T) { // Now for each item, construct a proof and verify tree.Iterate(func(key []byte, value []byte) bool { - value2, proof, err := tree.GetWithProof(key) + value2, proof, err := tree.ImmutableTree().GetWithProof(key) assert.NoError(t, err) assert.Equal(t, value, value2) if assert.NotNil(t, proof) { @@ -534,7 +534,7 @@ func TestTreeProof(t *testing.T) { assert.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) // should get false for proof with nil root - value, proof, err := tree.GetWithProof([]byte("foo")) + value, proof, err := tree.ImmutableTree().GetWithProof([]byte("foo")) assert.Nil(t, value) assert.Nil(t, proof) assert.Error(t, proof.Verify([]byte(nil))) @@ -551,7 +551,7 @@ func TestTreeProof(t *testing.T) { tree.SaveVersion() // query random key fails - value, proof, err = tree.GetWithProof([]byte("foo")) + value, proof, err = tree.ImmutableTree().GetWithProof([]byte("foo")) assert.Nil(t, value) assert.NotNil(t, proof) assert.NoError(t, err) @@ -564,7 +564,7 @@ func TestTreeProof(t *testing.T) { root, err := tree.WorkingHash() assert.NoError(t, err) for _, key := range keys { - value, proof, err := tree.GetWithProof(key) + value, proof, err := tree.ImmutableTree().GetWithProof(key) if assert.NoError(t, err) { require.Nil(t, err, "Failed to read proof from bytes: %v", err) assert.Equal(t, key, value) diff --git a/sei-iavl/benchmarks/bench_test.go b/sei-iavl/benchmarks/bench_test.go index f845c02d4f..a38828170f 100644 --- a/sei-iavl/benchmarks/bench_test.go +++ b/sei-iavl/benchmarks/bench_test.go @@ -58,7 +58,7 @@ func commitTree(b *testing.B, t *iavl.MutableTree) { // queries random keys against live state. Keys are almost certainly not in the tree. func runQueriesFast(b *testing.B, t *iavl.MutableTree, keyLen int) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) for i := 0; i < b.N; i++ { @@ -69,7 +69,7 @@ func runQueriesFast(b *testing.B, t *iavl.MutableTree, keyLen int) { // queries keys that are known to be in state func runKnownQueriesFast(b *testing.B, t *iavl.MutableTree, keys [][]byte) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() // to ensure fast storage is enabled + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() // to ensure fast storage is enabled require.NoError(b, err) require.True(b, isFastCacheEnabled) l := int32(len(keys)) @@ -123,11 +123,11 @@ func runKnownQueriesSlow(b *testing.B, t *iavl.MutableTree, keys [][]byte) { } func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) // to ensure fast storage is enabled for i := 0; i < b.N; i++ { - itr, err := t.ImmutableTree.Iterator(nil, nil, false) + itr, err := t.ImmutableTree().Iterator(nil, nil, false) require.NoError(b, err) iterate(b, itr, expectedSize) require.Nil(b, itr.Close(), ".Close should not error out") @@ -136,7 +136,7 @@ func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) { func runIterationSlow(b *testing.B, t *iavl.MutableTree, expectedSize int) { for i := 0; i < b.N; i++ { - itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree) // create slow iterator directly + itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree()) // create slow iterator directly iterate(b, itr, expectedSize) require.Nil(b, itr.Close(), ".Close should not error out") } diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go index d674a8b405..471fd85429 100644 --- a/sei-iavl/cmd/iaviewer/main.go +++ b/sei-iavl/cmd/iaviewer/main.go @@ -49,7 +49,7 @@ func main() { fmt.Fprintf(os.Stderr, "Error hashing tree: %s\n", err) os.Exit(1) } - fmt.Printf("Tree hash is %X, tree size is %X\n", treeHash, tree.Size()) + fmt.Printf("Tree hash is %X, tree size is %X\n", treeHash, tree.ImmutableTree().Size()) switch args[0] { case "data": @@ -60,7 +60,7 @@ func main() { os.Exit(1) } fmt.Printf("Hash: %X\n", hash) - fmt.Printf("Size: %X\n", tree.Size()) + fmt.Printf("Size: %X\n", tree.ImmutableTree().Size()) case "shape": PrintShape(tree) case "versions": @@ -181,7 +181,7 @@ func encodeID(id []byte) string { func PrintShape(tree *iavl.MutableTree) { // shape := tree.RenderShape(" ", nil) //TODO: handle this error - shape, _ := tree.RenderShape(" ", nodeEncoder) + shape, _ := tree.ImmutableTree().RenderShape(" ", nodeEncoder) fmt.Println(strings.Join(shape, "\n")) } diff --git a/sei-iavl/export_test.go b/sei-iavl/export_test.go index 8b7051f2d2..f75effc51e 100644 --- a/sei-iavl/export_test.go +++ b/sei-iavl/export_test.go @@ -102,7 +102,7 @@ func setupExportTreeRandom(t *testing.T) *ImmutableTree { } require.EqualValues(t, versions, tree.Version()) - require.GreaterOrEqual(t, tree.Size(), int64(math.Trunc(versions*versionOps*(1-updateRatio-deleteRatio))/2)) + require.GreaterOrEqual(t, tree.ImmutableTree().Size(), int64(math.Trunc(versions*versionOps*(1-updateRatio-deleteRatio))/2)) itree, err := tree.GetImmutable(version) require.NoError(t, err) @@ -216,13 +216,13 @@ func TestExporter_Import(t *testing.T) { require.NoError(t, err) require.Equal(t, treeHash, newTreeHash, "Tree hash mismatch") - require.Equal(t, tree.Size(), newTree.Size(), "Tree size mismatch") + require.Equal(t, tree.Size(), newTree.ImmutableTree().Size(), "Tree size mismatch") require.Equal(t, tree.Version(), newTree.Version(), "Tree version mismatch") tree.Iterate(func(key, value []byte) bool { index, _, err := tree.GetWithIndex(key) require.NoError(t, err) - newIndex, newValue, err := newTree.GetWithIndex(key) + newIndex, newValue, err := newTree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) require.Equal(t, index, newIndex, "Index mismatch for key %v", key) require.Equal(t, value, newValue, "Value mismatch for key %v", key) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 293090bbb6..26754419ff 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -28,7 +28,7 @@ var ErrVersionDoesNotExist = errors.New("version does not exist") // // The inner ImmutableTree should not be used directly by callers. type MutableTree struct { - *ImmutableTree // The current, working tree. + immutableTree *ImmutableTree // The current, working tree. lastSaved *ImmutableTree // The most recently saved tree. orphans map[string]int64 // Nodes removed by changes to working tree. versions map[int64]bool // The previous, saved versions of the tree. @@ -40,7 +40,7 @@ type MutableTree struct { separateOrphanStorage bool separateOrphanVersionsToKeep int64 orphandb *orphanDB - mtx *sync.Mutex + mtx *sync.RWMutex } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -62,7 +62,7 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto } return &MutableTree{ - ImmutableTree: head, + immutableTree: head, lastSaved: head.clone(), orphans: map[string]int64{}, versions: map[int64]bool{}, @@ -74,16 +74,30 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto separateOrphanStorage: opts.SeparateOrphanStorage, separateOrphanVersionsToKeep: opts.SeparateOphanVersionsToKeep, orphandb: orphandb, - mtx: &sync.Mutex{}, + mtx: &sync.RWMutex{}, }, nil } +func (tree *MutableTree) ImmutableTree() *ImmutableTree { + tree.mtx.RLock() + defer tree.mtx.RUnlock() + return tree.immutableTree +} + +func (tree *MutableTree) LastSaved() *ImmutableTree { + tree.mtx.RLock() + defer tree.mtx.RUnlock() + return tree.lastSaved +} + +func (tree *MutableTree) Has(key []byte) (bool, error) { + return tree.ImmutableTree().Has(key) +} + // IsEmpty returns whether or not the tree has any keys. Only trees that are // not empty can be saved. func (tree *MutableTree) IsEmpty() bool { - tree.mtx.Lock() - defer tree.mtx.Unlock() - return tree.ImmutableTree.Size() == 0 + return tree.ImmutableTree().Size() == 0 } // VersionExists returns whether or not a version exists. @@ -122,12 +136,12 @@ func (tree *MutableTree) AvailableVersions() []int { // Hash returns the hash of the latest saved version of the tree, as returned // by SaveVersion. If no versions have been saved, Hash returns nil. func (tree *MutableTree) Hash() ([]byte, error) { - return tree.lastSaved.Hash() + return tree.LastSaved().Hash() } // WorkingHash returns the hash of the current working tree. func (tree *MutableTree) WorkingHash() ([]byte, error) { - return tree.ImmutableTree.Hash() + return tree.ImmutableTree().Hash() } // String returns a string representation of the tree. @@ -138,7 +152,7 @@ func (tree *MutableTree) String() (string, error) { // Set/Remove will orphan at most tree.Height nodes, // balancing the tree after a Set/Remove will orphan at most 3 nodes. func (tree *MutableTree) prepareOrphansSlice() []*Node { - return make([]*Node, 0, tree.Height()+3) + return make([]*Node, 0, tree.immutableTree.Height()+3) } // Set sets a key in the working tree. Nil values are invalid. The given @@ -163,12 +177,12 @@ func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { // Get returns the value of the specified key if it exists, or nil otherwise. // The returned value must not be modified, since it may point to data stored within IAVL. func (tree *MutableTree) Get(key []byte) ([]byte, error) { - tree.mtx.Lock() - defer tree.mtx.Unlock() - if tree.root == nil { + if tree.ImmutableTree().root == nil { return nil, nil } + tree.mtx.RLock() + defer tree.mtx.RUnlock() if !tree.skipFastStorageUpgrade { if fastNode, ok := tree.unsavedFastNodeAdditions[unsafeToStr(key)]; ok { return fastNode.value, nil @@ -179,7 +193,8 @@ func (tree *MutableTree) Get(key []byte) ([]byte, error) { } } - return tree.ImmutableTree.Get(key) + // mtx is already acquired + return tree.immutableTree.Get(key) } // Import returns an importer for tree nodes previously exported by ImmutableTree.Export(), @@ -197,20 +212,20 @@ func (tree *MutableTree) Import(version int64) (*Importer, error) { // Iterate iterates over all keys of the tree. The keys and values must not be modified, // since they may point to data stored within IAVL. Returns true if stopped by callnack, false otherwise func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { - if tree.root == nil { + if tree.ImmutableTree().root == nil { return false, nil } if tree.skipFastStorageUpgrade { - return tree.ImmutableTree.Iterate(fn) + return tree.ImmutableTree().Iterate(fn) } - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() if err != nil { return false, err } if !isFastCacheEnabled { - return tree.ImmutableTree.Iterate(fn) + return tree.ImmutableTree().Iterate(fn) } itr := NewUnsavedFastIterator(nil, nil, true, tree.ndb, tree.unsavedFastNodeAdditions, tree.unsavedFastNodeRemovals) @@ -227,7 +242,7 @@ func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stoppe // CONTRACT: no updates are made to the tree while an iterator is active. func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { if !tree.skipFastStorageUpgrade { - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() if err != nil { return nil, err } @@ -237,31 +252,33 @@ func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterat } } - return tree.ImmutableTree.Iterator(start, end, ascending) + return tree.ImmutableTree().Iterator(start, end, ascending) } +// no need to acquire mtx since it's only called by `Set` which already holds the mtx func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated bool, err error) { if value == nil { return nil, updated, fmt.Errorf("attempt to store nil value at key '%s'", key) } - if tree.ImmutableTree.root == nil { + if tree.immutableTree.root == nil { if !tree.skipFastStorageUpgrade { - tree.addUnsavedAddition(key, NewFastNode(key, value, tree.version+1)) + tree.addUnsavedAddition(key, NewFastNode(key, value, tree.immutableTree.version+1)) } - tree.ImmutableTree.root = NewNode(key, value, tree.version+1) + tree.immutableTree.root = NewNode(key, value, tree.immutableTree.version+1) return nil, updated, nil } orphans = tree.prepareOrphansSlice() - tree.ImmutableTree.root, updated, err = tree.recursiveSet(tree.ImmutableTree.root, key, value, &orphans) + tree.immutableTree.root, updated, err = tree.recursiveSet(tree.immutableTree.root, key, value, &orphans) return orphans, updated, err } +// no need to acquire mtx since it's only called by `set` which already holds the mtx func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orphans *[]*Node) ( newSelf *Node, updated bool, err error, ) { - version := tree.version + 1 + version := tree.immutableTree.version + 1 if node.isLeaf() { if !tree.skipFastStorageUpgrade { @@ -299,7 +316,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph } if bytes.Compare(key, node.GetNodeKey()) < 0 { - leftNode, err := node.getLeftNode(tree.ImmutableTree) + leftNode, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, false, err } @@ -311,7 +328,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph node.SetLeftNode(lNode) node.SetLeftHash(nil) // leftHash is yet unknown } else { - rightNode, err := node.getRightNode(tree.ImmutableTree) + rightNode, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, false, err } @@ -327,7 +344,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph if updated { return node, updated, nil } - err = node.calcHeightAndSize(tree.ImmutableTree) + err = node.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, false, err } @@ -359,12 +376,13 @@ func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { // remove tries to remove a key from the tree and if removed, returns its // value, nodes orphaned and 'true'. +// no need to acquire mtx since it's only called by `Remove` which already holds the mtx. func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, removed bool, err error) { - if tree.root == nil { + if tree.immutableTree.root == nil { return nil, nil, false, nil } orphaned = tree.prepareOrphansSlice() - newRootHash, newRoot, _, value, err := tree.recursiveRemove(tree.root, key, &orphaned) + newRootHash, newRoot, _, value, err := tree.recursiveRemove(tree.immutableTree.root, key, &orphaned) if err != nil { return nil, nil, false, err } @@ -377,12 +395,12 @@ func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, rem } if newRoot == nil && newRootHash != nil { - tree.root, err = tree.ndb.GetNode(newRootHash) + tree.immutableTree.root, err = tree.ndb.GetNode(newRootHash) if err != nil { return nil, nil, false, err } } else { - tree.root = newRoot + tree.immutableTree.root = newRoot } return value, orphaned, true, nil } @@ -394,8 +412,9 @@ func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, rem // - new leftmost leaf key for tree after successfully removing 'key' if changed. // - the removed value // - the orphaned nodes. +// no need to acquire mtx since it's only called by `remove` which already holds the mtx func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Node) (newHash []byte, newSelf *Node, newKey []byte, newValue []byte, err error) { - version := tree.version + 1 + version := tree.immutableTree.version + 1 if node.isLeaf() { if bytes.Equal(key, node.GetNodeKey()) { @@ -407,7 +426,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod // node.key < key; we go to the left to find the key: if bytes.Compare(key, node.GetNodeKey()) < 0 { - leftNode, err := node.getLeftNode(tree.ImmutableTree) + leftNode, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, nil, nil, nil, err } @@ -431,7 +450,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod newNode.SetLeftHash(newLeftHash) newNode.SetLeftNode(newLeftNode) - err = newNode.calcHeightAndSize(tree.ImmutableTree) + err = newNode.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, nil, nil, err } @@ -443,7 +462,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod return newNode.GetHash(), newNode, newKey, value, nil } // node.key >= key; either found or look to the right: - rightNode, err := node.getRightNode(tree.ImmutableTree) + rightNode, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, nil, nil, nil, err } @@ -469,7 +488,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod if newKey != nil { newNode.SetKey(newKey) } - err = newNode.calcHeightAndSize(tree.ImmutableTree) + err = newNode.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, nil, nil, err } @@ -507,8 +526,6 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t if latestVersion <= 0 { if targetVersion <= 0 { if !tree.skipFastStorageUpgrade { - tree.mtx.Lock() - defer tree.mtx.Unlock() _, err := tree.enableFastStorageAndCommitIfNotEnabled() return 0, err } @@ -559,7 +576,7 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t } tree.orphans = map[string]int64{} - tree.ImmutableTree = iTree + tree.immutableTree = iTree // mtx is already held tree.lastSaved = iTree.clone() return targetVersion, nil @@ -634,7 +651,7 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr } tree.orphans = map[string]int64{} - tree.ImmutableTree = t + tree.immutableTree = t // mtx is already held tree.lastSaved = t.clone() tree.allRootLoaded = true @@ -732,12 +749,13 @@ func (tree *MutableTree) enableFastStorageAndCommitIfNotEnabled() (bool, error) func (tree *MutableTree) enableFastStorageAndCommit() error { var err error - itr := NewIteratorUnlocked(nil, nil, true, tree.ImmutableTree) + itr := NewIteratorUnlocked(nil, nil, true, tree.ImmutableTree()) defer itr.Close() + version := tree.ImmutableTree().version var upgradedFastNodes uint64 for ; itr.Valid(); itr.Next() { upgradedFastNodes++ - if err = tree.ndb.SaveFastNodeNoCache(NewFastNode(itr.Key(), itr.Value(), tree.version)); err != nil { + if err = tree.ndb.SaveFastNodeNoCache(NewFastNode(itr.Key(), itr.Value(), version)); err != nil { return err } if upgradedFastNodes%commitGap == 0 { @@ -794,10 +812,12 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { // Rollback resets the working tree to the latest saved version, discarding // any unsaved modifications. func (tree *MutableTree) Rollback() { - if tree.version > 0 { - tree.ImmutableTree = tree.lastSaved.clone() + tree.mtx.Lock() + defer tree.mtx.Unlock() + if tree.immutableTree.version > 0 { + tree.immutableTree = tree.lastSaved.clone() } else { - tree.ImmutableTree = &ImmutableTree{ + tree.immutableTree = &ImmutableTree{ ndb: tree.ndb, version: 0, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, @@ -815,7 +835,7 @@ func (tree *MutableTree) Rollback() { func (tree *MutableTree) GetVersioned(key []byte, version int64) ([]byte, error) { if tree.VersionExists(version) { if !tree.skipFastStorageUpgrade { - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() if err != nil { return nil, err } @@ -849,7 +869,7 @@ func (tree *MutableTree) GetVersioned(key []byte, version int64) ([]byte, error) // the hash being saved is different. In // other words, only SaveVersion can insert new node into the tree. func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { - version := tree.version + version := tree.ImmutableTree().version if version == 1 && tree.ndb.opts.InitialVersion > 0 { version = int64(tree.ndb.opts.InitialVersion) } @@ -875,12 +895,15 @@ func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { } if bytes.Equal(existingHash, newHash) { + tree.mtx.Lock() + defer tree.mtx.Unlock() if v, err := tree.commitVersion(version, true); err != nil { return nil, v, err } - tree.version = version - tree.ImmutableTree = tree.ImmutableTree.clone() - tree.lastSaved = tree.ImmutableTree.clone() + clone := tree.immutableTree.clone() + clone.version = version + tree.immutableTree = clone + tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} return existingHash, version, nil } @@ -891,14 +914,12 @@ func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { // SaveVersion saves a new tree version to disk, based on the current state of // the tree. Returns the hash and new version number. func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { - version := tree.version + 1 + version := tree.ImmutableTree().version + 1 if version == 1 && tree.ndb.opts.InitialVersion > 0 { version = int64(tree.ndb.opts.InitialVersion) } if tree.VersionExists(version) { - tree.mtx.Lock() - defer tree.mtx.Unlock() // If the version already exists, return an error as we're attempting to overwrite. // However, the same hash means idempotent (i.e. no-op). existingHash, err := tree.ndb.getRoot(version) @@ -918,9 +939,12 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { } if bytes.Equal(existingHash, newHash) { - tree.version = version - tree.ImmutableTree = tree.ImmutableTree.clone() - tree.lastSaved = tree.ImmutableTree.clone() + tree.mtx.Lock() + defer tree.mtx.Unlock() + clone := tree.immutableTree.clone() + clone.version = version + tree.immutableTree = clone + tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} return existingHash, version, nil } @@ -935,19 +959,21 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { return nil, v, err } - tree.version = version + // mtx is already held at this point + clone := tree.immutableTree.clone() + clone.version = version tree.versions[version] = true // set new working tree - tree.ImmutableTree = tree.ImmutableTree.clone() - tree.lastSaved = tree.ImmutableTree.clone() + tree.immutableTree = clone + tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} if !tree.skipFastStorageUpgrade { tree.unsavedFastNodeAdditions = make(map[string]*FastNode) tree.unsavedFastNodeRemovals = make(map[string]interface{}) } - hash, err := tree.Hash() + hash, err := tree.lastSaved.Hash() if err != nil { return nil, version, err } @@ -998,7 +1024,7 @@ func (tree *MutableTree) handleOrphans(version int64) error { } func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) (int64, error) { - if tree.root == nil { + if tree.immutableTree.root == nil { // There can still be orphans, for example if the root is the node being // removed. logger.Debug("SAVE EMPTY TREE %v\n", version) @@ -1010,13 +1036,13 @@ func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) } } else { logger.Debug("SAVE TREE %v\n", version) - if _, err := tree.ndb.SaveBranch(tree.root); err != nil { + if _, err := tree.ndb.SaveBranch(tree.immutableTree.root); err != nil { return 0, err } if err := tree.handleOrphans(version); err != nil { return 0, err } - if err := tree.ndb.SaveRoot(tree.root, version); !silentSaveRootError && err != nil { + if err := tree.ndb.SaveRoot(tree.immutableTree.root, version); !silentSaveRootError && err != nil { return 0, err } } @@ -1087,11 +1113,12 @@ func (tree *MutableTree) saveFastNodeRemovals() error { return nil } +// unlocked func (tree *MutableTree) deleteVersion(version int64) error { if version <= 0 { return errors.New("version must be greater than 0") } - if version == tree.version { + if version == tree.ImmutableTree().version { return errors.Errorf("cannot delete latest saved version (%d)", version) } if !tree.VersionExists(version) { @@ -1108,6 +1135,8 @@ func (tree *MutableTree) deleteVersion(version int64) error { // It is only used during the initial SaveVersion() call for a tree with no other versions, // and is otherwise ignored. func (tree *MutableTree) SetInitialVersion(version uint64) { + tree.mtx.Lock() + defer tree.mtx.Unlock() tree.ndb.opts.InitialVersion = version } @@ -1191,8 +1220,9 @@ func (tree *MutableTree) DeleteVersion(version int64) error { } // Rotate right and return the new node and orphan. +// mtx already held func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { - version := tree.version + 1 + version := tree.immutableTree.version + 1 var err error // TODO: optimize balance & rotate. @@ -1201,7 +1231,7 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { return nil, nil, err } - orphaned, err := node.getLeftNode(tree.ImmutableTree) + orphaned, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, nil, err } @@ -1216,12 +1246,12 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { node.SetLeftHash(newNoderHash) node.SetLeftNode(newNoderCached) - err = node.calcHeightAndSize(tree.ImmutableTree) + err = node.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, err } - err = newNode.calcHeightAndSize(tree.ImmutableTree) + err = newNode.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, err } @@ -1231,7 +1261,7 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { // Rotate left and return the new node and orphan. func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { - version := tree.version + 1 + version := tree.immutableTree.version + 1 var err error // TODO: optimize balance & rotate. @@ -1240,7 +1270,7 @@ func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { return nil, nil, err } - orphaned, err := node.getRightNode(tree.ImmutableTree) + orphaned, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, nil, err } @@ -1255,12 +1285,12 @@ func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { node.SetRightHash(newNodelHash) node.SetRightNode(newNodelCached) - err = node.calcHeightAndSize(tree.ImmutableTree) + err = node.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, err } - err = newNode.calcHeightAndSize(tree.ImmutableTree) + err = newNode.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, err } @@ -1274,18 +1304,18 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e if node.GetPersisted() { return nil, fmt.Errorf("unexpected balance() call on persisted node") } - balance, err := node.calcBalance(tree.ImmutableTree) + balance, err := node.calcBalance(tree.immutableTree) if err != nil { return nil, err } if balance > 1 { - leftNode, err := node.getLeftNode(tree.ImmutableTree) + leftNode, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, err } - lftBalance, err := leftNode.calcBalance(tree.ImmutableTree) + lftBalance, err := leftNode.calcBalance(tree.immutableTree) if err != nil { return nil, err } @@ -1302,7 +1332,7 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e // Left Right Case var leftOrphaned *Node - left, err := node.getLeftNode(tree.ImmutableTree) + left, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, err } @@ -1322,12 +1352,12 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e return newNode, nil } if balance < -1 { - rightNode, err := node.getRightNode(tree.ImmutableTree) + rightNode, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, err } - rightBalance, err := rightNode.calcBalance(tree.ImmutableTree) + rightBalance, err := rightNode.calcBalance(tree.immutableTree) if err != nil { return nil, err } @@ -1343,7 +1373,7 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e // Right Left Case var rightOrphaned *Node - right, err := node.getRightNode(tree.ImmutableTree) + right, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, err } @@ -1379,3 +1409,7 @@ func (tree *MutableTree) addOrphans(orphans []*Node) error { } return nil } + +func (tree *MutableTree) Version() int64 { + return tree.ImmutableTree().Version() +} diff --git a/sei-iavl/mutable_tree_test.go b/sei-iavl/mutable_tree_test.go index bd26463987..6eeaedbe0f 100644 --- a/sei-iavl/mutable_tree_test.go +++ b/sei-iavl/mutable_tree_test.go @@ -105,7 +105,7 @@ func TestTraverse(t *testing.T) { tree.set([]byte(fmt.Sprintf("k%d", i)), []byte(fmt.Sprintf("v%d", i))) } - require.Equal(t, 11, tree.nodeSize(), "Size of tree unexpected") + require.Equal(t, 11, tree.ImmutableTree().nodeSize(), "Size of tree unexpected") } func TestMutableTree_DeleteVersions(t *testing.T) { @@ -435,7 +435,7 @@ func TestMutableTree_LazyLoadVersionWithEmptyTree(t *testing.T) { require.NoError(t, err) require.True(t, v1 == v2) - require.True(t, newTree1.root == newTree2.root) + require.True(t, newTree1.ImmutableTree().root == newTree2.ImmutableTree().root) } func TestMutableTree_SetSimple(t *testing.T) { @@ -452,7 +452,7 @@ func TestMutableTree_SetSimple(t *testing.T) { fastValue, err := tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Equal(t, []byte(testVal1), fastValue) @@ -486,14 +486,14 @@ func TestMutableTree_SetTwoKeys(t *testing.T) { fastValue, err := tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Equal(t, []byte(testVal1), fastValue) require.Equal(t, []byte(testVal1), regularValue) fastValue2, err := tree.Get([]byte(testKey2)) require.NoError(t, err) - _, regularValue2, err := tree.GetWithIndex([]byte(testKey2)) + _, regularValue2, err := tree.ImmutableTree().GetWithIndex([]byte(testKey2)) require.NoError(t, err) require.Equal(t, []byte(testVal2), fastValue2) require.Equal(t, []byte(testVal2), regularValue2) @@ -528,7 +528,7 @@ func TestMutableTree_SetOverwrite(t *testing.T) { fastValue, err := tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Equal(t, []byte(testVal2), fastValue) require.Equal(t, []byte(testVal2), regularValue) @@ -554,7 +554,7 @@ func TestMutableTree_SetRemoveSet(t *testing.T) { fastValue, err := tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.Equal(t, []byte(testVal1), fastValue) require.Equal(t, []byte(testVal1), regularValue) @@ -580,7 +580,7 @@ func TestMutableTree_SetRemoveSet(t *testing.T) { fastValue, err = tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err = tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err = tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Nil(t, fastValue) require.Nil(t, regularValue) @@ -592,7 +592,7 @@ func TestMutableTree_SetRemoveSet(t *testing.T) { fastValue, err = tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err = tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err = tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Equal(t, []byte(testVal1), fastValue) require.Equal(t, []byte(testVal1), regularValue) @@ -685,21 +685,21 @@ func TestMutableTree_FastNodeIntegration(t *testing.T) { // Get and GetFast fastValue, err := t2.Get([]byte(key1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(key1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(key1)) require.NoError(t, err) require.Equal(t, []byte(testVal1), fastValue) require.Equal(t, []byte(testVal1), regularValue) fastValue, err = t2.Get([]byte(key2)) require.NoError(t, err) - _, regularValue, err = t2.GetWithIndex([]byte(key2)) + _, regularValue, err = t2.ImmutableTree().GetWithIndex([]byte(key2)) require.NoError(t, err) require.Nil(t, fastValue) require.Nil(t, regularValue) fastValue, err = t2.Get([]byte(key3)) require.NoError(t, err) - _, regularValue, err = tree.GetWithIndex([]byte(key3)) + _, regularValue, err = tree.ImmutableTree().GetWithIndex([]byte(key3)) require.NoError(t, err) require.Equal(t, []byte(testVal2), fastValue) require.Equal(t, []byte(testVal2), regularValue) @@ -749,7 +749,7 @@ func TestUpgradeStorageToFast_LatestVersion_Success(t *testing.T) { require.NoError(t, err) // Default version when storage key does not exist in the db - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -768,7 +768,7 @@ func TestUpgradeStorageToFast_LatestVersion_Success(t *testing.T) { require.False(t, isUpgradeable) require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) } @@ -780,7 +780,7 @@ func TestUpgradeStorageToFast_AlreadyUpgraded_Success(t *testing.T) { require.NoError(t, err) // Default version when storage key does not exist in the db - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -795,7 +795,7 @@ func TestUpgradeStorageToFast_AlreadyUpgraded_Success(t *testing.T) { enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() require.NoError(t, err) require.True(t, enabled) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -806,7 +806,7 @@ func TestUpgradeStorageToFast_AlreadyUpgraded_Success(t *testing.T) { enabled, err = tree.enableFastStorageAndCommitIfNotEnabled() require.NoError(t, err) require.False(t, enabled) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) @@ -832,7 +832,7 @@ func TestUpgradeStorageToFast_DbErrorConstructor_Failure(t *testing.T) { require.Nil(t, err) require.NotNil(t, tree) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) } @@ -867,7 +867,7 @@ func TestUpgradeStorageToFast_DbErrorEnableFastStorage_Failure(t *testing.T) { require.Nil(t, err) require.NotNil(t, tree) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -875,7 +875,7 @@ func TestUpgradeStorageToFast_DbErrorEnableFastStorage_Failure(t *testing.T) { require.ErrorIs(t, err, expectedError) require.False(t, enabled) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) } @@ -909,13 +909,13 @@ func TestFastStorageReUpgradeProtection_NoForceUpgrade_Success(t *testing.T) { require.NotNil(t, tree) // Pretend that we called Load and have the latest state in the tree - tree.version = latestTreeVersion + tree.ImmutableTree().version = latestTreeVersion latestVersion, err := tree.ndb.getLatestVersion() require.NoError(t, err) require.Equal(t, latestVersion, int64(latestTreeVersion)) // Ensure that the right branch of enableFastStorageAndCommitIfNotEnabled will be triggered - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) shouldForce, err := tree.ndb.shouldForceFastStorageUpgrade() @@ -1002,13 +1002,13 @@ func TestFastStorageReUpgradeProtection_ForceUpgradeFirstTime_NoForceSecondTime_ require.NotNil(t, tree) // Pretend that we called Load and have the latest state in the tree - tree.version = latestTreeVersion + tree.ImmutableTree().version = latestTreeVersion latestVersion, err := tree.ndb.getLatestVersion() require.NoError(t, err) require.Equal(t, latestVersion, int64(latestTreeVersion)) // Ensure that the right branch of enableFastStorageAndCommitIfNotEnabled will be triggered - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) shouldForce, err := tree.ndb.shouldForceFastStorageUpgrade() @@ -1030,7 +1030,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi // Setup tree, mirror := setupTreeAndMirror(t, 100, false) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err := tree.IsUpgradeable() @@ -1041,7 +1041,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -1050,7 +1050,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi sut, _ := NewMutableTree(tree.ndb.db, 1000, false) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = sut.IsUpgradeable() @@ -1061,7 +1061,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi version, err := sut.Load() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) @@ -1080,7 +1080,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi // Test that upgraded immutable tree iterates as expected t.Run("Immutable tree", func(t *testing.T) { - immutableTree, err := sut.GetImmutable(sut.version) + immutableTree, err := sut.GetImmutable(sut.ImmutableTree().version) require.NoError(t, err) i := 0 @@ -1097,7 +1097,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) // Setup tree, mirror := setupTreeAndMirror(t, 100, false) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err := tree.IsUpgradeable() @@ -1108,7 +1108,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -1117,7 +1117,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) sut, _ := NewMutableTree(tree.ndb.db, 1000, false) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = sut.IsUpgradeable() @@ -1128,7 +1128,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) version, err := sut.LazyLoadVersion(1) require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) @@ -1143,7 +1143,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) }) t.Run("Immutable tree", func(t *testing.T) { - immutableTree, err := sut.GetImmutable(sut.version) + immutableTree, err := sut.GetImmutable(sut.ImmutableTree().version) require.NoError(t, err) for _, kv := range mirror { @@ -1284,7 +1284,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin // Setup tree, mirror := setupTreeAndMirror(t, 100, true) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err := tree.IsUpgradeable() @@ -1295,7 +1295,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -1304,7 +1304,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin sut, _ := NewMutableTree(tree.ndb.db, 1000, true) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = sut.IsUpgradeable() @@ -1316,7 +1316,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1325,7 +1325,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1334,7 +1334,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1343,7 +1343,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1356,7 +1356,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin }) t.Run("Immutable tree", func(t *testing.T) { - immutableTree, err := sut.GetImmutable(sut.version) + immutableTree, err := sut.GetImmutable(sut.ImmutableTree().version) require.NoError(t, err) for _, kv := range mirror { @@ -1371,7 +1371,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te // Setup tree, mirror := setupTreeAndMirror(t, 100, true) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err := tree.IsUpgradeable() @@ -1382,7 +1382,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -1391,7 +1391,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te sut, _ := NewMutableTree(tree.ndb.db, 1000, true) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = sut.IsUpgradeable() @@ -1403,7 +1403,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1412,7 +1412,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1429,7 +1429,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te // Test that the immutable tree iterates as expected t.Run("Immutable tree", func(t *testing.T) { - immutableTree, err := sut.GetImmutable(sut.version) + immutableTree, err := sut.GetImmutable(sut.ImmutableTree().version) require.NoError(t, err) i := 0 @@ -1463,7 +1463,7 @@ func TestSaveCurrentVersion_BadVersion(t *testing.T) { _, version, err := tree.SaveVersion() require.NoError(t, err) assert.EqualValues(t, 9, version) - tree.version = 10 + tree.ImmutableTree().version = 10 _, version, err = tree.SaveCurrentVersion() require.Error(t, err) assert.EqualValues(t, 10, version) diff --git a/sei-iavl/proof_forgery_test.go b/sei-iavl/proof_forgery_test.go index 241db1cd77..82ab3e5ac0 100644 --- a/sei-iavl/proof_forgery_test.go +++ b/sei-iavl/proof_forgery_test.go @@ -37,7 +37,7 @@ func TestProofFogery(t *testing.T) { k := []byte{keys[1]} v := values[1] - val, proof, err := tree.GetWithProof(k) + val, proof, err := tree.ImmutableTree().GetWithProof(k) require.NoError(t, err) err = proof.Verify(root) @@ -53,7 +53,7 @@ func TestProofFogery(t *testing.T) { // - a new leaf node to the right // - an empty inner node // - a right entry in the path - _, proof2, _ := tree.GetWithProof(k) + _, proof2, _ := tree.ImmutableTree().GetWithProof(k) forgedNode := proof2.Leaves[0] forgedNode.Key = []byte{0xFF} forgedNode.ValueHash = forgedValueHash diff --git a/sei-iavl/proof_iavl_test.go b/sei-iavl/proof_iavl_test.go index 7047309cc0..1581ecfc98 100644 --- a/sei-iavl/proof_iavl_test.go +++ b/sei-iavl/proof_iavl_test.go @@ -44,7 +44,7 @@ func TestProofOp(t *testing.T) { tc := tc t.Run(fmt.Sprintf("%02x", tc.key), func(t *testing.T) { key := []byte{tc.key} - value, proof, err := tree.GetWithProof(key) + value, proof, err := tree.ImmutableTree().GetWithProof(key) require.NoError(t, err) // Verify that proof is valid. diff --git a/sei-iavl/proof_ics23_test.go b/sei-iavl/proof_ics23_test.go index fd0a6d1967..c375ab41c5 100644 --- a/sei-iavl/proof_ics23_test.go +++ b/sei-iavl/proof_ics23_test.go @@ -48,7 +48,7 @@ func TestGetMembership(t *testing.T) { key := GetKey(allkeys, tc.loc) val, err := tree.Get(key) require.NoError(t, err) - proof, err := tree.GetMembershipProof(key) + proof, err := tree.ImmutableTree().GetMembershipProof(key) require.NoError(t, err, "Creating Proof: %+v", err) root, err := tree.Hash() @@ -77,7 +77,7 @@ func TestGetNonMembership(t *testing.T) { performTest := func(tree *MutableTree, allKeys [][]byte, loc Where) { key := GetNonKey(allKeys, loc) - proof, err := tree.GetNonMembershipProof(key) + proof, err := tree.ImmutableTree().GetNonMembershipProof(key) require.NoError(t, err, "Creating Proof: %+v", err) root, err := tree.Hash() @@ -97,7 +97,7 @@ func TestGetNonMembership(t *testing.T) { _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) @@ -107,7 +107,7 @@ func TestGetNonMembership(t *testing.T) { t.Run("regular-"+name, func(t *testing.T) { tree, allkeys, err := BuildTree(tc.size, 0) require.NoError(t, err, "Creating tree: %+v", err) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -132,7 +132,7 @@ func BenchmarkGetNonMembership(b *testing.B) { performTest := func(tree *MutableTree, allKeys [][]byte, loc Where) { key := GetNonKey(allKeys, loc) - proof, err := tree.GetNonMembershipProof(key) + proof, err := tree.ImmutableTree().GetNonMembershipProof(key) require.NoError(b, err, "Creating Proof: %+v", err) b.StopTimer() @@ -157,7 +157,7 @@ func BenchmarkGetNonMembership(b *testing.B) { _, _, err = tree.SaveVersion() require.NoError(b, err) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) b.StartTimer() @@ -173,7 +173,7 @@ func BenchmarkGetNonMembership(b *testing.B) { tree, allkeys, err := BuildTree(tc.size, 100000) require.NoError(b, err, "Creating tree: %+v", err) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.False(b, isFastCacheEnabled) @@ -207,7 +207,7 @@ func GenerateResult(size int, loc Where) (*Result, error) { } key := GetKey(allkeys, loc) - value, proof, err := tree.GetWithProof(key) + value, proof, err := tree.ImmutableTree().GetWithProof(key) if err != nil { return nil, err } diff --git a/sei-iavl/proof_test.go b/sei-iavl/proof_test.go index 5e1c0ce488..c52ea79632 100644 --- a/sei-iavl/proof_test.go +++ b/sei-iavl/proof_test.go @@ -26,7 +26,7 @@ func TestTreeGetWithProof(t *testing.T) { require.NoError(err) key := []byte{0x32} - val, proof, err := tree.GetWithProof(key) + val, proof, err := tree.ImmutableTree().GetWithProof(key) require.NoError(err) require.NotEmpty(val) require.NotNil(proof) @@ -41,7 +41,7 @@ func TestTreeGetWithProof(t *testing.T) { require.NoError(err, "%+v", err) key = []byte{0x1} - val, proof, err = tree.GetWithProof(key) + val, proof, err = tree.ImmutableTree().GetWithProof(key) require.NoError(err) require.Empty(val) require.NotNil(proof) @@ -63,7 +63,7 @@ func TestTreeKeyExistsProof(t *testing.T) { require.NoError(t, err) // should get false for proof with nil root - proof, keys, values, err := tree.getRangeProof([]byte("foo"), nil, 1) + proof, keys, values, err := tree.ImmutableTree().getRangeProof([]byte("foo"), nil, 1) assert.Nil(t, proof) assert.Error(t, proof.Verify(root)) assert.Nil(t, keys) @@ -83,13 +83,13 @@ func TestTreeKeyExistsProof(t *testing.T) { require.NoError(t, err) // query random key fails - proof, _, _, err = tree.getRangeProof([]byte("foo"), nil, 2) + proof, _, _, err = tree.ImmutableTree().getRangeProof([]byte("foo"), nil, 2) assert.Nil(t, err) assert.Nil(t, proof.Verify(root)) assert.Nil(t, proof.VerifyAbsence([]byte("foo")), proof.String()) // query min key fails - proof, _, _, err = tree.getRangeProof([]byte{0x00}, []byte{0x01}, 2) + proof, _, _, err = tree.ImmutableTree().getRangeProof([]byte{0x00}, []byte{0x01}, 2) assert.Nil(t, err) assert.Nil(t, proof.Verify(root)) assert.Nil(t, proof.VerifyAbsence([]byte{0x00})) @@ -97,7 +97,7 @@ func TestTreeKeyExistsProof(t *testing.T) { // valid proof for real keys for i, key := range allkeys { var keys, values [][]byte - proof, keys, values, err = tree.getRangeProof(key, nil, 2) + proof, keys, values, err = tree.ImmutableTree().getRangeProof(key, nil, 2) require.Nil(t, err) require.Equal(t, @@ -186,7 +186,7 @@ func TestTreeKeyInRangeProofs(t *testing.T) { end := []byte{c.end} // Compute range proof. - keys, values, proof, err := tree.GetRangeWithProof(start, end, 0) + keys, values, proof, err := tree.ImmutableTree().GetRangeWithProof(start, end, 0) if c.err { require.Error(err, "%+v", err) diff --git a/sei-iavl/repair_test.go b/sei-iavl/repair_test.go index 8d17355e0a..a9aaa17ce6 100644 --- a/sei-iavl/repair_test.go +++ b/sei-iavl/repair_test.go @@ -84,7 +84,7 @@ func TestRepair013Orphans(t *testing.T) { // assertVersion checks the given version (or current if 0) against the expected values. func assertVersion(t *testing.T, tree *MutableTree, version int64) { var err error - itree := tree.ImmutableTree + itree := tree.ImmutableTree() if version > 0 { itree, err = tree.GetImmutable(version) require.NoError(t, err) diff --git a/sei-iavl/testutils_test.go b/sei-iavl/testutils_test.go index 85b0f1eeba..f6d8ca58cc 100644 --- a/sei-iavl/testutils_test.go +++ b/sei-iavl/testutils_test.go @@ -78,7 +78,7 @@ func T(n *Node) (*MutableTree, error) { if err != nil { return nil, err } - t.root = n + t.ImmutableTree().root = n return t, nil } diff --git a/sei-iavl/tree_dotgraph_test.go b/sei-iavl/tree_dotgraph_test.go index 017bcaebd8..a4bad9cdf7 100644 --- a/sei-iavl/tree_dotgraph_test.go +++ b/sei-iavl/tree_dotgraph_test.go @@ -16,5 +16,5 @@ func TestWriteDOTGraph(t *testing.T) { key := []byte{ikey} tree.Set(key, key) } - WriteDOTGraph(ioutil.Discard, tree.ImmutableTree, []PathToLeaf{}) + WriteDOTGraph(ioutil.Discard, tree.ImmutableTree(), []PathToLeaf{}) } diff --git a/sei-iavl/tree_random_test.go b/sei-iavl/tree_random_test.go index f9aa3f6987..ad8d1e2de0 100644 --- a/sei-iavl/tree_random_test.go +++ b/sei-iavl/tree_random_test.go @@ -152,7 +152,7 @@ func testRandomOperations(t *testing.T, randSeed int64) { require.NoError(t, err) t.Logf("Saved tree at version %v with %v keys and %v versions", - version, tree.Size(), len(tree.AvailableVersions())) + version, tree.ImmutableTree().Size(), len(tree.AvailableVersions())) // Verify that the version matches the mirror. assertMirror(t, tree, mirror, 0) @@ -391,7 +391,7 @@ func assertMaxVersion(t *testing.T, tree *MutableTree, version int64, mirrors ma // Checks that a mirror, optionally for a given version, matches the tree contents. func assertMirror(t *testing.T, tree *MutableTree, mirror map[string]string, version int64) { var err error - itree := tree.ImmutableTree + itree := tree.ImmutableTree() if version > 0 { itree, err = tree.GetImmutable(version) require.NoError(t, err, "loading version %v", version) diff --git a/sei-iavl/tree_test.go b/sei-iavl/tree_test.go index c02b0de1a9..0a09a5d367 100644 --- a/sei-iavl/tree_test.go +++ b/sei-iavl/tree_test.go @@ -77,7 +77,7 @@ func TestVersionedRandomTree(t *testing.T) { // db than in the current tree version. nodes, err := tree.ndb.nodes() require.Nil(err) - require.True(len(nodes) >= tree.nodeSize()) + require.True(len(nodes) >= tree.ImmutableTree().nodeSize()) // Ensure it returns all versions in sorted order available := tree.AvailableVersions() @@ -92,7 +92,7 @@ func TestVersionedRandomTree(t *testing.T) { require.Len(tree.versions, 1, "tree must have one version left") tr, err := tree.GetImmutable(int64(versions)) require.NoError(err, "GetImmutable should not error for version %d", versions) - require.Equal(tr.root, tree.root) + require.Equal(tr.root, tree.ImmutableTree().root) // we should only have one available version now available = tree.AvailableVersions() @@ -103,11 +103,11 @@ func TestVersionedRandomTree(t *testing.T) { // in the db as in the current tree version. leafNodes, err = tree.ndb.leafNodes() require.Nil(err) - require.Len(leafNodes, int(tree.Size())) + require.Len(leafNodes, int(tree.ImmutableTree().Size())) nodes, err = tree.ndb.nodes() require.Nil(err) - require.Equal(tree.nodeSize(), len(nodes)) + require.Equal(tree.ImmutableTree().nodeSize(), len(nodes)) } // nolint: dupl @@ -216,9 +216,9 @@ func TestVersionedRandomTreeSmallKeys(t *testing.T) { nodes, err := tree.ndb.nodes() require.Nil(err) - require.Len(leafNodes, int(tree.Size())) - require.Len(nodes, tree.nodeSize()) - require.Len(nodes, singleVersionTree.nodeSize()) + require.Len(leafNodes, int(tree.ImmutableTree().Size())) + require.Len(nodes, tree.ImmutableTree().nodeSize()) + require.Len(nodes, singleVersionTree.ImmutableTree().nodeSize()) // Try getting random keys. for i := 0; i < keysPerVersion; i++ { @@ -266,9 +266,9 @@ func TestVersionedRandomTreeSmallKeysRandomDeletes(t *testing.T) { nodes, err := tree.ndb.nodes() require.Nil(err) - require.Len(leafNodes, int(tree.Size())) - require.Len(nodes, tree.nodeSize()) - require.Len(nodes, singleVersionTree.nodeSize()) + require.Len(leafNodes, int(tree.ImmutableTree().Size())) + require.Len(nodes, tree.ImmutableTree().nodeSize()) + require.Len(nodes, singleVersionTree.ImmutableTree().nodeSize()) // Try getting random keys. for i := 0; i < keysPerVersion; i++ { @@ -301,7 +301,7 @@ func TestVersionedTreeSpecial1(t *testing.T) { nodes, err := tree.ndb.nodes() require.Nil(t, err) - require.Equal(t, tree.nodeSize(), len(nodes)) + require.Equal(t, tree.ImmutableTree().nodeSize(), len(nodes)) } func TestVersionedRandomTreeSpecial2(t *testing.T) { @@ -321,7 +321,7 @@ func TestVersionedRandomTreeSpecial2(t *testing.T) { nodes, err := tree.ndb.nodes() require.NoError(err) - require.Len(nodes, tree.nodeSize()) + require.Len(nodes, tree.ImmutableTree().nodeSize()) } func TestVersionedEmptyTree(t *testing.T) { @@ -364,7 +364,7 @@ func TestVersionedEmptyTree(t *testing.T) { require.False(tree.VersionExists(3)) tree.Set([]byte("k"), []byte("v")) - require.EqualValues(5, tree.root.version) + require.EqualValues(5, tree.ImmutableTree().root.version) // Now reload the tree. @@ -393,7 +393,7 @@ func TestVersionedTree(t *testing.T) { // We start with empty database. require.Equal(0, tree.ndb.size()) require.True(tree.IsEmpty()) - require.False(tree.IsFastCacheEnabled()) + require.False(tree.ImmutableTree().IsFastCacheEnabled()) // version 0 @@ -656,7 +656,7 @@ func TestVersionedTreeVersionDeletingEfficiency(t *testing.T) { tree2.Set([]byte("key3"), []byte("val1")) tree2.SaveVersion() - require.Equal(t, tree2.nodeSize(), tree.nodeSize()) + require.Equal(t, tree2.ImmutableTree().nodeSize(), tree.ImmutableTree().nodeSize()) } func TestVersionedTreeOrphanDeleting(t *testing.T) { @@ -787,7 +787,7 @@ func TestVersionedTreeSpecialCase3(t *testing.T) { nodes, err := tree.ndb.nodes() require.NoError(err) - require.Equal(tree.nodeSize(), len(nodes)) + require.Equal(tree.ImmutableTree().nodeSize(), len(nodes)) } func TestVersionedTreeSaveAndLoad(t *testing.T) { @@ -841,10 +841,10 @@ func TestVersionedTreeSaveAndLoad(t *testing.T) { ntree.DeleteVersion(3) require.False(ntree.IsEmpty()) - require.Equal(int64(4), ntree.Size()) + require.Equal(int64(4), ntree.ImmutableTree().Size()) nodes, err := tree.ndb.nodes() require.NoError(err) - require.Len(nodes, ntree.nodeSize()) + require.Len(nodes, ntree.ImmutableTree().nodeSize()) } func TestVersionedTreeErrors(t *testing.T) { @@ -1172,7 +1172,7 @@ func TestVersionedTreeEfficiency(t *testing.T) { require.InDelta(change, keysAddedPerVersion[i], float64(keysPerVersion)/5) } } - require.Equal(keysAdded-tree.nodeSize(), keysDeleted) + require.Equal(keysAdded-tree.ImmutableTree().nodeSize(), keysDeleted) } func TestVersionedTreeProofs(t *testing.T) { @@ -1360,7 +1360,7 @@ func TestRollback(t *testing.T) { tree.SaveVersion() - require.Equal(int64(2), tree.Size()) + require.Equal(int64(2), tree.ImmutableTree().Size()) val, err := tree.Get([]byte("r")) require.Nil(val) @@ -1904,13 +1904,13 @@ func Benchmark_GetWithIndex(b *testing.B) { runtime.GC() b.Run("fast", func(sub *testing.B) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) b.ResetTimer() for i := 0; i < sub.N; i++ { randKey := rand.Intn(numKeyVals) - t.GetWithIndex(keys[randKey]) + t.ImmutableTree().GetWithIndex(keys[randKey]) } }) @@ -1953,13 +1953,13 @@ func Benchmark_GetByIndex(b *testing.B) { runtime.GC() b.Run("fast", func(sub *testing.B) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) b.ResetTimer() for i := 0; i < sub.N; i++ { randIdx := rand.Intn(numKeyVals) - t.GetByIndex(int64(randIdx)) + t.ImmutableTree().GetByIndex(int64(randIdx)) } }) From e1a95291ccb21dc1ea7b1a8830857cc188993d36 Mon Sep 17 00:00:00 2001 From: Philip Su Date: Thu, 22 Jun 2023 09:20:18 -0700 Subject: [PATCH 44/69] Fix ITree field --- sei-iavl/mutable_tree.go | 102 +++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 26754419ff..b1a920a353 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -28,7 +28,7 @@ var ErrVersionDoesNotExist = errors.New("version does not exist") // // The inner ImmutableTree should not be used directly by callers. type MutableTree struct { - immutableTree *ImmutableTree // The current, working tree. + ITree *ImmutableTree // The current, working tree. lastSaved *ImmutableTree // The most recently saved tree. orphans map[string]int64 // Nodes removed by changes to working tree. versions map[int64]bool // The previous, saved versions of the tree. @@ -62,7 +62,7 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto } return &MutableTree{ - immutableTree: head, + ITree: head, lastSaved: head.clone(), orphans: map[string]int64{}, versions: map[int64]bool{}, @@ -81,7 +81,7 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto func (tree *MutableTree) ImmutableTree() *ImmutableTree { tree.mtx.RLock() defer tree.mtx.RUnlock() - return tree.immutableTree + return tree.ITree } func (tree *MutableTree) LastSaved() *ImmutableTree { @@ -152,7 +152,7 @@ func (tree *MutableTree) String() (string, error) { // Set/Remove will orphan at most tree.Height nodes, // balancing the tree after a Set/Remove will orphan at most 3 nodes. func (tree *MutableTree) prepareOrphansSlice() []*Node { - return make([]*Node, 0, tree.immutableTree.Height()+3) + return make([]*Node, 0, tree.ITree.Height()+3) } // Set sets a key in the working tree. Nil values are invalid. The given @@ -194,7 +194,7 @@ func (tree *MutableTree) Get(key []byte) ([]byte, error) { } // mtx is already acquired - return tree.immutableTree.Get(key) + return tree.ITree.Get(key) } // Import returns an importer for tree nodes previously exported by ImmutableTree.Export(), @@ -261,16 +261,16 @@ func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated return nil, updated, fmt.Errorf("attempt to store nil value at key '%s'", key) } - if tree.immutableTree.root == nil { + if tree.ITree.root == nil { if !tree.skipFastStorageUpgrade { - tree.addUnsavedAddition(key, NewFastNode(key, value, tree.immutableTree.version+1)) + tree.addUnsavedAddition(key, NewFastNode(key, value, tree.ITree.version+1)) } - tree.immutableTree.root = NewNode(key, value, tree.immutableTree.version+1) + tree.ITree.root = NewNode(key, value, tree.ITree.version+1) return nil, updated, nil } orphans = tree.prepareOrphansSlice() - tree.immutableTree.root, updated, err = tree.recursiveSet(tree.immutableTree.root, key, value, &orphans) + tree.ITree.root, updated, err = tree.recursiveSet(tree.ITree.root, key, value, &orphans) return orphans, updated, err } @@ -278,7 +278,7 @@ func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orphans *[]*Node) ( newSelf *Node, updated bool, err error, ) { - version := tree.immutableTree.version + 1 + version := tree.ITree.version + 1 if node.isLeaf() { if !tree.skipFastStorageUpgrade { @@ -316,7 +316,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph } if bytes.Compare(key, node.GetNodeKey()) < 0 { - leftNode, err := node.getLeftNode(tree.immutableTree) + leftNode, err := node.getLeftNode(tree.ITree) if err != nil { return nil, false, err } @@ -328,7 +328,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph node.SetLeftNode(lNode) node.SetLeftHash(nil) // leftHash is yet unknown } else { - rightNode, err := node.getRightNode(tree.immutableTree) + rightNode, err := node.getRightNode(tree.ITree) if err != nil { return nil, false, err } @@ -344,7 +344,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph if updated { return node, updated, nil } - err = node.calcHeightAndSize(tree.immutableTree) + err = node.calcHeightAndSize(tree.ITree) if err != nil { return nil, false, err } @@ -378,11 +378,11 @@ func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { // value, nodes orphaned and 'true'. // no need to acquire mtx since it's only called by `Remove` which already holds the mtx. func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, removed bool, err error) { - if tree.immutableTree.root == nil { + if tree.ITree.root == nil { return nil, nil, false, nil } orphaned = tree.prepareOrphansSlice() - newRootHash, newRoot, _, value, err := tree.recursiveRemove(tree.immutableTree.root, key, &orphaned) + newRootHash, newRoot, _, value, err := tree.recursiveRemove(tree.ITree.root, key, &orphaned) if err != nil { return nil, nil, false, err } @@ -395,12 +395,12 @@ func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, rem } if newRoot == nil && newRootHash != nil { - tree.immutableTree.root, err = tree.ndb.GetNode(newRootHash) + tree.ITree.root, err = tree.ndb.GetNode(newRootHash) if err != nil { return nil, nil, false, err } } else { - tree.immutableTree.root = newRoot + tree.ITree.root = newRoot } return value, orphaned, true, nil } @@ -414,7 +414,7 @@ func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, rem // - the orphaned nodes. // no need to acquire mtx since it's only called by `remove` which already holds the mtx func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Node) (newHash []byte, newSelf *Node, newKey []byte, newValue []byte, err error) { - version := tree.immutableTree.version + 1 + version := tree.ITree.version + 1 if node.isLeaf() { if bytes.Equal(key, node.GetNodeKey()) { @@ -426,7 +426,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod // node.key < key; we go to the left to find the key: if bytes.Compare(key, node.GetNodeKey()) < 0 { - leftNode, err := node.getLeftNode(tree.immutableTree) + leftNode, err := node.getLeftNode(tree.ITree) if err != nil { return nil, nil, nil, nil, err } @@ -450,7 +450,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod newNode.SetLeftHash(newLeftHash) newNode.SetLeftNode(newLeftNode) - err = newNode.calcHeightAndSize(tree.immutableTree) + err = newNode.calcHeightAndSize(tree.ITree) if err != nil { return nil, nil, nil, nil, err } @@ -462,7 +462,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod return newNode.GetHash(), newNode, newKey, value, nil } // node.key >= key; either found or look to the right: - rightNode, err := node.getRightNode(tree.immutableTree) + rightNode, err := node.getRightNode(tree.ITree) if err != nil { return nil, nil, nil, nil, err } @@ -488,7 +488,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod if newKey != nil { newNode.SetKey(newKey) } - err = newNode.calcHeightAndSize(tree.immutableTree) + err = newNode.calcHeightAndSize(tree.ITree) if err != nil { return nil, nil, nil, nil, err } @@ -576,7 +576,7 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t } tree.orphans = map[string]int64{} - tree.immutableTree = iTree // mtx is already held + tree.ITree = iTree // mtx is already held tree.lastSaved = iTree.clone() return targetVersion, nil @@ -651,7 +651,7 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr } tree.orphans = map[string]int64{} - tree.immutableTree = t // mtx is already held + tree.ITree = t // mtx is already held tree.lastSaved = t.clone() tree.allRootLoaded = true @@ -814,10 +814,10 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { func (tree *MutableTree) Rollback() { tree.mtx.Lock() defer tree.mtx.Unlock() - if tree.immutableTree.version > 0 { - tree.immutableTree = tree.lastSaved.clone() + if tree.ITree.version > 0 { + tree.ITree = tree.lastSaved.clone() } else { - tree.immutableTree = &ImmutableTree{ + tree.ITree = &ImmutableTree{ ndb: tree.ndb, version: 0, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, @@ -900,9 +900,9 @@ func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { if v, err := tree.commitVersion(version, true); err != nil { return nil, v, err } - clone := tree.immutableTree.clone() + clone := tree.ITree.clone() clone.version = version - tree.immutableTree = clone + tree.ITree = clone tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} return existingHash, version, nil @@ -941,9 +941,9 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { if bytes.Equal(existingHash, newHash) { tree.mtx.Lock() defer tree.mtx.Unlock() - clone := tree.immutableTree.clone() + clone := tree.ITree.clone() clone.version = version - tree.immutableTree = clone + tree.ITree = clone tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} return existingHash, version, nil @@ -960,12 +960,12 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { } // mtx is already held at this point - clone := tree.immutableTree.clone() + clone := tree.ITree.clone() clone.version = version tree.versions[version] = true // set new working tree - tree.immutableTree = clone + tree.ITree = clone tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} if !tree.skipFastStorageUpgrade { @@ -1024,7 +1024,7 @@ func (tree *MutableTree) handleOrphans(version int64) error { } func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) (int64, error) { - if tree.immutableTree.root == nil { + if tree.ITree.root == nil { // There can still be orphans, for example if the root is the node being // removed. logger.Debug("SAVE EMPTY TREE %v\n", version) @@ -1036,13 +1036,13 @@ func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) } } else { logger.Debug("SAVE TREE %v\n", version) - if _, err := tree.ndb.SaveBranch(tree.immutableTree.root); err != nil { + if _, err := tree.ndb.SaveBranch(tree.ITree.root); err != nil { return 0, err } if err := tree.handleOrphans(version); err != nil { return 0, err } - if err := tree.ndb.SaveRoot(tree.immutableTree.root, version); !silentSaveRootError && err != nil { + if err := tree.ndb.SaveRoot(tree.ITree.root, version); !silentSaveRootError && err != nil { return 0, err } } @@ -1222,7 +1222,7 @@ func (tree *MutableTree) DeleteVersion(version int64) error { // Rotate right and return the new node and orphan. // mtx already held func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { - version := tree.immutableTree.version + 1 + version := tree.ITree.version + 1 var err error // TODO: optimize balance & rotate. @@ -1231,7 +1231,7 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { return nil, nil, err } - orphaned, err := node.getLeftNode(tree.immutableTree) + orphaned, err := node.getLeftNode(tree.ITree) if err != nil { return nil, nil, err } @@ -1246,12 +1246,12 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { node.SetLeftHash(newNoderHash) node.SetLeftNode(newNoderCached) - err = node.calcHeightAndSize(tree.immutableTree) + err = node.calcHeightAndSize(tree.ITree) if err != nil { return nil, nil, err } - err = newNode.calcHeightAndSize(tree.immutableTree) + err = newNode.calcHeightAndSize(tree.ITree) if err != nil { return nil, nil, err } @@ -1261,7 +1261,7 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { // Rotate left and return the new node and orphan. func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { - version := tree.immutableTree.version + 1 + version := tree.ITree.version + 1 var err error // TODO: optimize balance & rotate. @@ -1270,7 +1270,7 @@ func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { return nil, nil, err } - orphaned, err := node.getRightNode(tree.immutableTree) + orphaned, err := node.getRightNode(tree.ITree) if err != nil { return nil, nil, err } @@ -1285,12 +1285,12 @@ func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { node.SetRightHash(newNodelHash) node.SetRightNode(newNodelCached) - err = node.calcHeightAndSize(tree.immutableTree) + err = node.calcHeightAndSize(tree.ITree) if err != nil { return nil, nil, err } - err = newNode.calcHeightAndSize(tree.immutableTree) + err = newNode.calcHeightAndSize(tree.ITree) if err != nil { return nil, nil, err } @@ -1304,18 +1304,18 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e if node.GetPersisted() { return nil, fmt.Errorf("unexpected balance() call on persisted node") } - balance, err := node.calcBalance(tree.immutableTree) + balance, err := node.calcBalance(tree.ITree) if err != nil { return nil, err } if balance > 1 { - leftNode, err := node.getLeftNode(tree.immutableTree) + leftNode, err := node.getLeftNode(tree.ITree) if err != nil { return nil, err } - lftBalance, err := leftNode.calcBalance(tree.immutableTree) + lftBalance, err := leftNode.calcBalance(tree.ITree) if err != nil { return nil, err } @@ -1332,7 +1332,7 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e // Left Right Case var leftOrphaned *Node - left, err := node.getLeftNode(tree.immutableTree) + left, err := node.getLeftNode(tree.ITree) if err != nil { return nil, err } @@ -1352,12 +1352,12 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e return newNode, nil } if balance < -1 { - rightNode, err := node.getRightNode(tree.immutableTree) + rightNode, err := node.getRightNode(tree.ITree) if err != nil { return nil, err } - rightBalance, err := rightNode.calcBalance(tree.immutableTree) + rightBalance, err := rightNode.calcBalance(tree.ITree) if err != nil { return nil, err } @@ -1373,7 +1373,7 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e // Right Left Case var rightOrphaned *Node - right, err := node.getRightNode(tree.immutableTree) + right, err := node.getRightNode(tree.ITree) if err != nil { return nil, err } From 482033cf5b5048cdc27fee428b251e5be1332e0a Mon Sep 17 00:00:00 2001 From: Philip Su Date: Thu, 22 Jun 2023 10:35:32 -0700 Subject: [PATCH 45/69] Export mtx in mutable tree --- sei-iavl/mutable_tree.go | 96 ++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index b1a920a353..269bb04d80 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -28,7 +28,8 @@ var ErrVersionDoesNotExist = errors.New("version does not exist") // // The inner ImmutableTree should not be used directly by callers. type MutableTree struct { - ITree *ImmutableTree // The current, working tree. + ITree *ImmutableTree // The current, working tree. + Mtx *sync.RWMutex lastSaved *ImmutableTree // The most recently saved tree. orphans map[string]int64 // Nodes removed by changes to working tree. versions map[int64]bool // The previous, saved versions of the tree. @@ -40,7 +41,6 @@ type MutableTree struct { separateOrphanStorage bool separateOrphanVersionsToKeep int64 orphandb *orphanDB - mtx *sync.RWMutex } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -74,19 +74,19 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto separateOrphanStorage: opts.SeparateOrphanStorage, separateOrphanVersionsToKeep: opts.SeparateOphanVersionsToKeep, orphandb: orphandb, - mtx: &sync.RWMutex{}, + Mtx: &sync.RWMutex{}, }, nil } func (tree *MutableTree) ImmutableTree() *ImmutableTree { - tree.mtx.RLock() - defer tree.mtx.RUnlock() + tree.Mtx.RLock() + defer tree.Mtx.RUnlock() return tree.ITree } func (tree *MutableTree) LastSaved() *ImmutableTree { - tree.mtx.RLock() - defer tree.mtx.RUnlock() + tree.Mtx.RLock() + defer tree.Mtx.RUnlock() return tree.lastSaved } @@ -102,8 +102,8 @@ func (tree *MutableTree) IsEmpty() bool { // VersionExists returns whether or not a version exists. func (tree *MutableTree) VersionExists(version int64) bool { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() if tree.allRootLoaded { return tree.versions[version] @@ -120,8 +120,8 @@ func (tree *MutableTree) VersionExists(version int64) bool { // AvailableVersions returns all available versions in ascending order func (tree *MutableTree) AvailableVersions() []int { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() res := make([]int, 0, len(tree.versions)) for i, v := range tree.versions { @@ -160,8 +160,8 @@ func (tree *MutableTree) prepareOrphansSlice() []*Node { // to slices stored within IAVL. It returns true when an existing value was // updated, while false means it was a new key. func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() var orphaned []*Node orphaned, updated, err = tree.set(key, value) if err != nil { @@ -181,8 +181,8 @@ func (tree *MutableTree) Get(key []byte) ([]byte, error) { return nil, nil } - tree.mtx.RLock() - defer tree.mtx.RUnlock() + tree.Mtx.RLock() + defer tree.Mtx.RUnlock() if !tree.skipFastStorageUpgrade { if fastNode, ok := tree.unsavedFastNodeAdditions[unsafeToStr(key)]; ok { return fastNode.value, nil @@ -193,7 +193,7 @@ func (tree *MutableTree) Get(key []byte) ([]byte, error) { } } - // mtx is already acquired + // Mtx is already acquired return tree.ITree.Get(key) } @@ -255,7 +255,7 @@ func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterat return tree.ImmutableTree().Iterator(start, end, ascending) } -// no need to acquire mtx since it's only called by `Set` which already holds the mtx +// no need to acquire Mtx since it's only called by `Set` which already holds the Mtx func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated bool, err error) { if value == nil { return nil, updated, fmt.Errorf("attempt to store nil value at key '%s'", key) @@ -274,7 +274,7 @@ func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated return orphans, updated, err } -// no need to acquire mtx since it's only called by `set` which already holds the mtx +// no need to acquire Mtx since it's only called by `set` which already holds the Mtx func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orphans *[]*Node) ( newSelf *Node, updated bool, err error, ) { @@ -360,8 +360,8 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph // Remove removes a key from the working tree. The given key byte slice should not be modified // after this call, since it may point to data stored inside IAVL. func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() val, orphaned, removed, err := tree.remove(key) if err != nil { return nil, false, err @@ -376,7 +376,7 @@ func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { // remove tries to remove a key from the tree and if removed, returns its // value, nodes orphaned and 'true'. -// no need to acquire mtx since it's only called by `Remove` which already holds the mtx. +// no need to acquire Mtx since it's only called by `Remove` which already holds the Mtx. func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, removed bool, err error) { if tree.ITree.root == nil { return nil, nil, false, nil @@ -412,7 +412,7 @@ func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, rem // - new leftmost leaf key for tree after successfully removing 'key' if changed. // - the removed value // - the orphaned nodes. -// no need to acquire mtx since it's only called by `remove` which already holds the mtx +// no need to acquire Mtx since it's only called by `remove` which already holds the Mtx func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Node) (newHash []byte, newSelf *Node, newKey []byte, newValue []byte, err error) { version := tree.ITree.version + 1 @@ -547,9 +547,9 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t return latestVersion, ErrVersionDoesNotExist } - tree.mtx.Lock() + tree.Mtx.Lock() defer func() { - tree.mtx.Unlock() + tree.Mtx.Unlock() if !tree.skipFastStorageUpgrade { // Attempt to upgrade if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { @@ -576,7 +576,7 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t } tree.orphans = map[string]int64{} - tree.ITree = iTree // mtx is already held + tree.ITree = iTree // Mtx is already held tree.lastSaved = iTree.clone() return targetVersion, nil @@ -603,9 +603,9 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr firstVersion := int64(0) latestVersion := int64(0) - tree.mtx.Lock() + tree.Mtx.Lock() defer func() { - tree.mtx.Unlock() + tree.Mtx.Unlock() if !tree.skipFastStorageUpgrade { // Attempt to upgrade if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { @@ -651,7 +651,7 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr } tree.orphans = map[string]int64{} - tree.ITree = t // mtx is already held + tree.ITree = t // Mtx is already held tree.lastSaved = t.clone() tree.allRootLoaded = true @@ -678,8 +678,8 @@ func (tree *MutableTree) LoadVersionForOverwriting(targetVersion int64) (int64, tree.ndb.resetLatestVersion(latestVersion) - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() for v := range tree.versions { if v > targetVersion { @@ -785,8 +785,8 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { return nil, ErrVersionDoesNotExist } - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() if len(rootHash) == 0 { tree.versions[version] = true return &ImmutableTree{ @@ -812,8 +812,8 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { // Rollback resets the working tree to the latest saved version, discarding // any unsaved modifications. func (tree *MutableTree) Rollback() { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() if tree.ITree.version > 0 { tree.ITree = tree.lastSaved.clone() } else { @@ -895,8 +895,8 @@ func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { } if bytes.Equal(existingHash, newHash) { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() if v, err := tree.commitVersion(version, true); err != nil { return nil, v, err } @@ -939,8 +939,8 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { } if bytes.Equal(existingHash, newHash) { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() clone := tree.ITree.clone() clone.version = version tree.ITree = clone @@ -952,14 +952,14 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { return nil, version, fmt.Errorf("version %d was already saved to different hash %X (existing hash %X)", version, newHash, existingHash) } - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() if v, err := tree.commitVersion(version, false); err != nil { return nil, v, err } - // mtx is already held at this point + // Mtx is already held at this point clone := tree.ITree.clone() clone.version = version tree.versions[version] = true @@ -1135,8 +1135,8 @@ func (tree *MutableTree) deleteVersion(version int64) error { // It is only used during the initial SaveVersion() call for a tree with no other versions, // and is otherwise ignored. func (tree *MutableTree) SetInitialVersion(version uint64) { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() tree.ndb.opts.InitialVersion = version } @@ -1181,8 +1181,8 @@ func (tree *MutableTree) DeleteVersions(versions ...int64) error { // An error is returned if any single version has active readers. // All writes happen in a single batch with a single commit. func (tree *MutableTree) DeleteVersionsRange(fromVersion, toVersion int64) error { - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() if err := tree.ndb.DeleteVersionsRange(fromVersion, toVersion); err != nil { return err @@ -1208,8 +1208,8 @@ func (tree *MutableTree) DeleteVersion(version int64) error { return err } - tree.mtx.Lock() - defer tree.mtx.Unlock() + tree.Mtx.Lock() + defer tree.Mtx.Unlock() if err := tree.ndb.Commit(); err != nil { return err @@ -1220,7 +1220,7 @@ func (tree *MutableTree) DeleteVersion(version int64) error { } // Rotate right and return the new node and orphan. -// mtx already held +// Mtx already held func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { version := tree.ITree.version + 1 From d68f4a15fb6d7604875bd40b0976a3b28865bf64 Mon Sep 17 00:00:00 2001 From: Yiming Zang Date: Wed, 26 Jul 2023 14:38:26 -0700 Subject: [PATCH 46/69] Changes for memiavl --- sei-iavl/diff.go | 13 + sei-iavl/proto/changeset.pb.go | 599 ++++++++++++++++++++++++++++ sei-iavl/proto/iavl/changeset.proto | 14 + 3 files changed, 626 insertions(+) create mode 100644 sei-iavl/diff.go create mode 100644 sei-iavl/proto/changeset.pb.go create mode 100644 sei-iavl/proto/iavl/changeset.proto diff --git a/sei-iavl/diff.go b/sei-iavl/diff.go new file mode 100644 index 0000000000..8af0d85533 --- /dev/null +++ b/sei-iavl/diff.go @@ -0,0 +1,13 @@ +package iavl + +import ( + "github.com/cosmos/iavl/proto" +) + +type ( + KVPair = proto.KVPair + ChangeSet = proto.ChangeSet +) + +// KVPairReceiver is callback parameter of method `extractStateChanges` to receive stream of `KVPair`s. +type KVPairReceiver func(pair *KVPair) error diff --git a/sei-iavl/proto/changeset.pb.go b/sei-iavl/proto/changeset.pb.go new file mode 100644 index 0000000000..359b34e7cc --- /dev/null +++ b/sei-iavl/proto/changeset.pb.go @@ -0,0 +1,599 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: iavl/changeset.proto + +package proto + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type KVPair struct { + Delete bool `protobuf:"varint,1,opt,name=delete,proto3" json:"delete,omitempty"` + Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *KVPair) Reset() { *m = KVPair{} } +func (m *KVPair) String() string { return proto.CompactTextString(m) } +func (*KVPair) ProtoMessage() {} +func (*KVPair) Descriptor() ([]byte, []int) { + return fileDescriptor_21609c3776972f61, []int{0} +} +func (m *KVPair) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KVPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_KVPair.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *KVPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_KVPair.Merge(m, src) +} +func (m *KVPair) XXX_Size() int { + return m.Size() +} +func (m *KVPair) XXX_DiscardUnknown() { + xxx_messageInfo_KVPair.DiscardUnknown(m) +} + +var xxx_messageInfo_KVPair proto.InternalMessageInfo + +func (m *KVPair) GetDelete() bool { + if m != nil { + return m.Delete + } + return false +} + +func (m *KVPair) GetKey() []byte { + if m != nil { + return m.Key + } + return nil +} + +func (m *KVPair) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +type ChangeSet struct { + Pairs []*KVPair `protobuf:"bytes,1,rep,name=pairs,proto3" json:"pairs,omitempty"` +} + +func (m *ChangeSet) Reset() { *m = ChangeSet{} } +func (m *ChangeSet) String() string { return proto.CompactTextString(m) } +func (*ChangeSet) ProtoMessage() {} +func (*ChangeSet) Descriptor() ([]byte, []int) { + return fileDescriptor_21609c3776972f61, []int{1} +} +func (m *ChangeSet) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChangeSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ChangeSet.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ChangeSet) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChangeSet.Merge(m, src) +} +func (m *ChangeSet) XXX_Size() int { + return m.Size() +} +func (m *ChangeSet) XXX_DiscardUnknown() { + xxx_messageInfo_ChangeSet.DiscardUnknown(m) +} + +var xxx_messageInfo_ChangeSet proto.InternalMessageInfo + +func (m *ChangeSet) GetPairs() []*KVPair { + if m != nil { + return m.Pairs + } + return nil +} + +func init() { + proto.RegisterType((*KVPair)(nil), "iavl.KVPair") + proto.RegisterType((*ChangeSet)(nil), "iavl.ChangeSet") +} + +func init() { proto.RegisterFile("iavl/changeset.proto", fileDescriptor_21609c3776972f61) } + +var fileDescriptor_21609c3776972f61 = []byte{ + // 182 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc9, 0x4c, 0x2c, 0xcb, + 0xd1, 0x4f, 0xce, 0x48, 0xcc, 0x4b, 0x4f, 0x2d, 0x4e, 0x2d, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, + 0x17, 0x62, 0x01, 0x89, 0x2a, 0x79, 0x70, 0xb1, 0x79, 0x87, 0x05, 0x24, 0x66, 0x16, 0x09, 0x89, + 0x71, 0xb1, 0xa5, 0xa4, 0xe6, 0xa4, 0x96, 0xa4, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x04, 0x41, + 0x79, 0x42, 0x02, 0x5c, 0xcc, 0xd9, 0xa9, 0x95, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0x20, + 0xa6, 0x90, 0x08, 0x17, 0x6b, 0x59, 0x62, 0x4e, 0x69, 0xaa, 0x04, 0x33, 0x58, 0x0c, 0xc2, 0x51, + 0xd2, 0xe7, 0xe2, 0x74, 0x06, 0x5b, 0x11, 0x9c, 0x5a, 0x22, 0xa4, 0xc4, 0xc5, 0x5a, 0x90, 0x98, + 0x59, 0x54, 0x2c, 0xc1, 0xa8, 0xc0, 0xac, 0xc1, 0x6d, 0xc4, 0xa3, 0x07, 0xb2, 0x4c, 0x0f, 0x62, + 0x53, 0x10, 0x44, 0xca, 0x49, 0xfe, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, + 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, + 0x58, 0xc1, 0x2e, 0x4c, 0x62, 0x03, 0x53, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x26, 0xfc, + 0xaa, 0xbd, 0xc0, 0x00, 0x00, 0x00, +} + +func (m *KVPair) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *KVPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KVPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintChangeset(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x1a + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintChangeset(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x12 + } + if m.Delete { + i-- + if m.Delete { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ChangeSet) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ChangeSet) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChangeSet) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Pairs) > 0 { + for iNdEx := len(m.Pairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Pairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintChangeset(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintChangeset(dAtA []byte, offset int, v uint64) int { + offset -= sovChangeset(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *KVPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Delete { + n += 2 + } + l = len(m.Key) + if l > 0 { + n += 1 + l + sovChangeset(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovChangeset(uint64(l)) + } + return n +} + +func (m *ChangeSet) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Pairs) > 0 { + for _, e := range m.Pairs { + l = e.Size() + n += 1 + l + sovChangeset(uint64(l)) + } + } + return n +} + +func sovChangeset(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozChangeset(x uint64) (n int) { + return sovChangeset(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *KVPair) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChangeset + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: KVPair: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: KVPair: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Delete", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChangeset + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Delete = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChangeset + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthChangeset + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthChangeset + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChangeset + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthChangeset + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthChangeset + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipChangeset(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthChangeset + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthChangeset + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ChangeSet) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChangeset + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ChangeSet: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChangeSet: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pairs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChangeset + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthChangeset + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthChangeset + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pairs = append(m.Pairs, &KVPair{}) + if err := m.Pairs[len(m.Pairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipChangeset(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthChangeset + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthChangeset + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipChangeset(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowChangeset + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowChangeset + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowChangeset + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthChangeset + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupChangeset + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthChangeset + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthChangeset = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowChangeset = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupChangeset = fmt.Errorf("proto: unexpected end of group") +) diff --git a/sei-iavl/proto/iavl/changeset.proto b/sei-iavl/proto/iavl/changeset.proto new file mode 100644 index 0000000000..efef05e0fc --- /dev/null +++ b/sei-iavl/proto/iavl/changeset.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; +package iavl; + +option go_package = "proto"; + +message KVPair { + bool delete = 1; + bytes key = 2; + bytes value = 3; +} + +message ChangeSet { + repeated KVPair pairs = 1; +} From b7d451d0766cadd0cc6b4b0fa3bb5776daf9d930 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Fri, 25 Aug 2023 04:59:37 -0700 Subject: [PATCH 47/69] Add keys only command --- sei-iavl/cmd/iaviewer/main.go | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go index 471fd85429..6759bfa67e 100644 --- a/sei-iavl/cmd/iaviewer/main.go +++ b/sei-iavl/cmd/iaviewer/main.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "crypto/sha256" "encoding/hex" "fmt" @@ -22,7 +21,7 @@ const ( func main() { args := os.Args[1:] - if len(args) < 3 || (args[0] != "data" && args[0] != "shape" && args[0] != "versions" && args[0] != "size") { + if len(args) < 3 || (args[0] != "data" && args[0] != "keys" && args[0] != "shape" && args[0] != "versions" && args[0] != "size") { fmt.Fprintln(os.Stderr, "Usage: iaviewer [version number]") fmt.Fprintln(os.Stderr, " is the prefix of db, and the iavl tree of different modules in cosmos-sdk uses ") fmt.Fprintln(os.Stderr, "different to identify, just like \"s/k:gov/\" represents the prefix of gov module") @@ -49,18 +48,13 @@ func main() { fmt.Fprintf(os.Stderr, "Error hashing tree: %s\n", err) os.Exit(1) } - fmt.Printf("Tree hash is %X, tree size is %X\n", treeHash, tree.ImmutableTree().Size()) + fmt.Printf("Tree hash is %X, tree size is %d\n", treeHash, tree.ImmutableTree().Size()) switch args[0] { case "data": - PrintKeys(tree) - hash, err := tree.Hash() - if err != nil { - fmt.Fprintf(os.Stderr, "Error hashing tree: %s\n", err) - os.Exit(1) - } - fmt.Printf("Hash: %X\n", hash) - fmt.Printf("Size: %X\n", tree.ImmutableTree().Size()) + PrintTreeData(tree, false) + case "keys": + PrintTreeData(tree, true) case "shape": PrintShape(tree) case "versions": @@ -137,7 +131,7 @@ func ReadTree(dir string, version int, prefix []byte) (*iavl.MutableTree, error) return tree, err } -func PrintKeys(tree *iavl.MutableTree) { +func PrintTreeData(tree *iavl.MutableTree, keysOnly bool) { fmt.Println("Printing all keys with hashed values (to detect diff)") totalKeySize := 0 totalValSize := 0 @@ -145,8 +139,12 @@ func PrintKeys(tree *iavl.MutableTree) { keyPrefixMap := map[string]int{} tree.Iterate(func(key []byte, value []byte) bool { printKey := parseWeaveKey(key) - digest := sha256.Sum256(value) - fmt.Printf(" %s\n %X\n", printKey, digest) + if keysOnly { + fmt.Printf("%s\n", printKey) + } else { + digest := sha256.Sum256(value) + fmt.Printf("%s\n %X\n", printKey, digest) + } totalKeySize += len(key) totalValSize += len(value) totalNumKeys++ @@ -159,13 +157,7 @@ func PrintKeys(tree *iavl.MutableTree) { // parseWeaveKey assumes a separating : where all in front should be ascii, // and all afterwards may be ascii or binary func parseWeaveKey(key []byte) string { - cut := bytes.IndexRune(key, ':') - if cut == -1 { - return encodeID(key) - } - prefix := key[:cut] - id := key[cut+1:] - return fmt.Sprintf("%s:%s", encodeID(prefix), encodeID(id)) + return encodeID(key) } // casts to a string if it is printable ascii, hex-encodes otherwise From 65614afd89dfba4ebe6cc8c006362c0ec8d53b81 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Fri, 25 Aug 2023 05:56:42 -0700 Subject: [PATCH 48/69] Add script to dump top N contracts --- sei-iavl/cmd/iaviewer/main.go | 2 +- sei-iavl/scripts/dump_top_contracts.sh | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 sei-iavl/scripts/dump_top_contracts.sh diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go index 6759bfa67e..dafecd66af 100644 --- a/sei-iavl/cmd/iaviewer/main.go +++ b/sei-iavl/cmd/iaviewer/main.go @@ -22,7 +22,7 @@ const ( func main() { args := os.Args[1:] if len(args) < 3 || (args[0] != "data" && args[0] != "keys" && args[0] != "shape" && args[0] != "versions" && args[0] != "size") { - fmt.Fprintln(os.Stderr, "Usage: iaviewer [version number]") + fmt.Fprintln(os.Stderr, "Usage: iaviewer [version number]") fmt.Fprintln(os.Stderr, " is the prefix of db, and the iavl tree of different modules in cosmos-sdk uses ") fmt.Fprintln(os.Stderr, "different to identify, just like \"s/k:gov/\" represents the prefix of gov module") os.Exit(1) diff --git a/sei-iavl/scripts/dump_top_contracts.sh b/sei-iavl/scripts/dump_top_contracts.sh new file mode 100644 index 0000000000..caabf97f96 --- /dev/null +++ b/sei-iavl/scripts/dump_top_contracts.sh @@ -0,0 +1,20 @@ +#/bin/bash + +TOP_N=$1 +TOP_N=${TOP_N:-10} + +systemctl stop seid +echo "Dumping all wasm keys to ~/wasm_keys_dump.txt..." +iaviewer keys ~/.sei/data/application.db "s/k:wasm/" > ~/wasm_keys_dump.txt + +systemctl start seid +echo "Generating top contracts to ~/top_contracts.txt..." +cat ~/wasm_keys_dump.txt |grep "^03" |cut -c 3-66 |sort |uniq -c |sort -nr |head -n "$TOP_N" > ~/top_contracts.txt + +while IFS= read -r line; do + count=$(echo "$line" | awk '{print $1}') + contract_hex=$(echo "$line" | awk '{print $2}') + contract_address=$(seid keys parse "$contract_hex" --output json |jq -r .formats[0]) + contract_label=$(seid query wasm contract "$contract_address" --output json |jq -r .contract_info.label) + echo "$contract_address - $contract_label: $count" +done < ~/top_contracts.txt From 5e9e53c130e265670957ba0e9d10ee31c72a81e6 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Tue, 2 Jan 2024 13:10:50 -0800 Subject: [PATCH 49/69] Fix nil interface conversion error --- sei-iavl/cache/cache.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sei-iavl/cache/cache.go b/sei-iavl/cache/cache.go index 29ce3bd35d..01cc38723c 100644 --- a/sei-iavl/cache/cache.go +++ b/sei-iavl/cache/cache.go @@ -104,7 +104,11 @@ func (c *lruCache) Remove(key []byte) Node { } func (c *lruCache) remove(e *list.Element) Node { - removed := c.ll.Remove(e).(Node) - delete(c.dict, ibytes.UnsafeBytesToStr(removed.GetCacheKey())) - return removed + element := c.ll.Remove(e) + if element != nil { + node := element.(Node) + delete(c.dict, ibytes.UnsafeBytesToStr(node.GetCacheKey())) + return node + } + return nil } From a403095106e7cdc90bd48c7751024009a491b7e2 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Wed, 11 Sep 2024 16:00:10 -0700 Subject: [PATCH 50/69] Fix tree versions causing slow restart and OOM --- sei-iavl/go.mod | 51 ++++---- sei-iavl/go.sum | 201 +++++++++++-------------------- sei-iavl/internal/bytes/bytes.go | 30 +++++ sei-iavl/mutable_tree.go | 112 +++++++---------- sei-iavl/nodedb.go | 76 +++++++++++- 5 files changed, 246 insertions(+), 224 deletions(-) diff --git a/sei-iavl/go.mod b/sei-iavl/go.mod index 9068f6edc6..242f5ecab3 100644 --- a/sei-iavl/go.mod +++ b/sei-iavl/go.mod @@ -3,49 +3,56 @@ module github.com/cosmos/iavl go 1.18 require ( + cosmossdk.io/core v0.12.0 github.com/confio/ics23/go v0.7.0 - github.com/cosmos/cosmos-db v1.0.0-rc.1 github.com/gogo/protobuf v1.3.2 github.com/golang/mock v1.6.0 github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.4 github.com/tendermint/tendermint v0.34.20 github.com/tendermint/tm-db v0.6.6 - golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e + golang.org/x/crypto v0.13.0 ) require ( - github.com/DataDog/zstd v1.4.5 // indirect - github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect + github.com/DataDog/zstd v1.5.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cockroachdb/errors v1.8.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect - github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 // indirect - github.com/cockroachdb/redact v1.0.8 // indirect - github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/cosmos/cosmos-db v1.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/getsentry/sentry-go v0.23.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/klauspost/compress v1.15.9 // indirect - github.com/kr/pretty v0.3.0 // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/linxGnu/grocksdb v1.7.14 // indirect + github.com/linxGnu/grocksdb v1.7.16 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.8.1 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/spf13/cast v1.5.1 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect - golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 // indirect - google.golang.org/protobuf v1.28.0 // indirect + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sei-iavl/go.sum b/sei-iavl/go.sum index ce146be116..a46880b0e5 100644 --- a/sei-iavl/go.sum +++ b/sei-iavl/go.sum @@ -60,8 +60,9 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= +cosmossdk.io/core v0.12.0 h1:aFuvkG6eDv0IQC+UDjx86wxNWVAxdCFk7OABJ1Vh4RU= +cosmossdk.io/core v0.12.0/go.mod h1:LaTtayWBSoacF5xNzoF8tmLhehqlA9z1SWiPuNC6X1w= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Antonboom/errname v0.1.6/go.mod h1:7lz79JAnuoMNDAWE9MeeIr1/c/VpSUWatBv2FH9NYpI= github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= @@ -74,20 +75,15 @@ github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v2 v2.1.0/go.mod h1:LGOGuvEgCfCQsy3JF2tRmpGDpzA53iZfyGEWSPwQ6/4= github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= @@ -99,7 +95,6 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -107,7 +102,6 @@ github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -136,11 +130,11 @@ github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= @@ -172,8 +166,9 @@ github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4/go.mod h1:W8EnPSQ8Nv4fUjc/v1/8tHFqhuOJXnRub0dTfuAQktU= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= @@ -196,19 +191,15 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= -github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= -github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= -github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 h1:qbb/AE938DFhOajUYh9+OXELpSF9KZw2ZivtmW6eX1Q= -github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677/go.mod h1:890yq1fUb9b6dGNwssgeUO5vQV9qfXnCPxAJhBQfXw0= -github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= -github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= +github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b h1:LCs8gDhg6vt8A3dN7AEJxmCoETZ4qkySoVJVm3rcSJk= +github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b/go.mod h1:TkdVsGYRqtULUppt2RbC+YaKtTHnHoWa2apfFrSKABw= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8= github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= @@ -223,8 +214,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/cosmos-db v1.0.0-rc.1 h1:SjnT8B6WKMW9WEIX32qMhnEEKcI7ZP0+G1Sa9HD3nmY= -github.com/cosmos/cosmos-db v1.0.0-rc.1/go.mod h1:Dnmk3flSf5lkwCqvvjNpoxjpXzhxnCAFzKHlbaForso= +github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0E= +github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -244,7 +235,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= @@ -266,7 +256,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -281,7 +270,6 @@ github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -289,24 +277,21 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/firefart/nonamedreturns v1.0.1/go.mod h1:D3dpIBojGGNh5UfElmwPu73SwDCm+VKhHYqwlNOk2uQ= -github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= @@ -314,15 +299,11 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= +github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE= +github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -336,7 +317,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -356,22 +336,16 @@ github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2 github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= @@ -409,8 +383,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -426,7 +401,6 @@ github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZ github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= @@ -446,9 +420,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -497,7 +470,6 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= @@ -547,10 +519,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -568,7 +538,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= -github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -576,13 +545,8 @@ github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -616,35 +580,24 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= -github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -654,8 +607,9 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -664,8 +618,6 @@ github.com/kulti/thelper v0.6.2/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dq github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= @@ -677,8 +629,8 @@ github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/linxGnu/grocksdb v1.7.14 h1:8lMZzyWeNP5lI0BIppX05DzmQzXj/Tgu82bgWYtowLY= -github.com/linxGnu/grocksdb v1.7.14/go.mod h1:pY55D0o+r8yUYLq70QmhdudxYvoDb9F+9puf4m3/W+U= +github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= +github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= @@ -689,7 +641,6 @@ github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpAp github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -697,9 +648,7 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -710,14 +659,12 @@ github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= -github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= -github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= github.com/mgechev/revive v1.2.1/go.mod h1:+Ro3wqY4vakcYNtkBWdZC7dBg1xSB6sp054wWwmeFm0= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= @@ -752,7 +699,6 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= @@ -764,14 +710,11 @@ github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4N github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= -github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= -github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/exhaustive v0.7.11/go.mod h1:gX+MP7DWMKJmNa1HfMozK+u04hQd3na9i0hyqf3/dOI= github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= @@ -788,11 +731,11 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -801,8 +744,9 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -838,7 +782,6 @@ github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7 github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -865,10 +808,14 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= @@ -876,12 +823,16 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9 github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= @@ -903,8 +854,10 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -915,14 +868,12 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= @@ -956,8 +907,9 @@ github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= @@ -980,7 +932,6 @@ github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -992,15 +943,16 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= @@ -1023,20 +975,15 @@ github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoi github.com/tommy-muehle/go-mnd/v2 v2.5.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vektra/mockery/v2 v2.14.0/go.mod h1:bnD1T8tExSgPD1ripLkDbr60JA9VtQeu12P3wgLZd7M= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= @@ -1050,7 +997,6 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= @@ -1140,8 +1086,9 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1156,9 +1103,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -1200,7 +1146,6 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1210,7 +1155,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1257,9 +1201,10 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1292,8 +1237,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1315,7 +1260,6 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1385,7 +1329,6 @@ golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1413,8 +1356,8 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 h1:fqTvyMIIj+HRzMmnzr9NtpHP6uVpvB5fkHcgPDC4nu8= -golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1428,8 +1371,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1440,7 +1384,6 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1452,7 +1395,6 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1550,7 +1492,6 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= @@ -1604,7 +1545,6 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1692,7 +1632,6 @@ google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1743,26 +1682,24 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/sei-iavl/internal/bytes/bytes.go b/sei-iavl/internal/bytes/bytes.go index ac3197d8af..23c0421962 100644 --- a/sei-iavl/internal/bytes/bytes.go +++ b/sei-iavl/internal/bytes/bytes.go @@ -62,3 +62,33 @@ func (bz HexBytes) Format(s fmt.State, verb rune) { s.Write([]byte(fmt.Sprintf("%X", []byte(bz)))) } } + +// Returns a copy of the given byte slice. +func Cp(bz []byte) (ret []byte) { + ret = make([]byte, len(bz)) + copy(ret, bz) + return ret +} + +// Returns a slice of the same length (big endian) +// except incremented by one. +// Returns nil on overflow (e.g. if bz bytes are all 0xFF) +// CONTRACT: len(bz) > 0 +func CpIncr(bz []byte) (ret []byte) { + if len(bz) == 0 { + panic("cpIncr expects non-zero bz length") + } + ret = Cp(bz) + for i := len(bz) - 1; i >= 0; i-- { + if ret[i] < byte(0xFF) { + ret[i]++ + return + } + ret[i] = byte(0x00) + if i == 0 { + // Overflow + return nil + } + } + return nil +} diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 269bb04d80..37f9bdca43 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -32,8 +32,6 @@ type MutableTree struct { Mtx *sync.RWMutex lastSaved *ImmutableTree // The most recently saved tree. orphans map[string]int64 // Nodes removed by changes to working tree. - versions map[int64]bool // The previous, saved versions of the tree. - allRootLoaded bool // Whether all roots are loaded or not(by LazyLoadVersion) unsavedFastNodeAdditions map[string]*FastNode // FastNodes that have not yet been saved to disk unsavedFastNodeRemovals map[string]interface{} // FastNodes that have not yet been removed from disk ndb *nodeDB @@ -65,8 +63,6 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto ITree: head, lastSaved: head.clone(), orphans: map[string]int64{}, - versions: map[int64]bool{}, - allRootLoaded: false, unsavedFastNodeAdditions: make(map[string]*FastNode), unsavedFastNodeRemovals: make(map[string]interface{}), ndb: ndb, @@ -104,32 +100,33 @@ func (tree *MutableTree) IsEmpty() bool { func (tree *MutableTree) VersionExists(version int64) bool { tree.Mtx.Lock() defer tree.Mtx.Unlock() - - if tree.allRootLoaded { - return tree.versions[version] + latestVersion, err := tree.ndb.getLatestVersion() + if err != nil { + return false } - - has, ok := tree.versions[version] - if ok { - return has + if version <= latestVersion { + has, err := tree.ndb.hasVersion(version) + return err == nil && has } - has, _ = tree.ndb.HasRoot(version) - tree.versions[version] = has - return has + return false } // AvailableVersions returns all available versions in ascending order func (tree *MutableTree) AvailableVersions() []int { tree.Mtx.Lock() defer tree.Mtx.Unlock() - - res := make([]int, 0, len(tree.versions)) - for i, v := range tree.versions { - if v { - res = append(res, int(i)) - } + firstVersion, err := tree.ndb.getFirstVersion() + if err != nil { + return nil + } + latestVersion, err := tree.ndb.getLatestVersion() + if err != nil { + return nil + } + res := make([]int, 0) + for version := firstVersion; version <= latestVersion; version++ { + res = append(res, int(version)) } - sort.Ints(res) return res } @@ -584,14 +581,29 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t // Returns the version number of the latest version found func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr error) { - roots, err := tree.ndb.getRoots() + firstVersion, err := tree.ndb.getFirstVersion() + if err != nil { + return 0, err + } + if firstVersion > 0 && firstVersion < int64(tree.ndb.opts.InitialVersion) { + return firstVersion, fmt.Errorf("initial version set to %v, but found earlier version %v", + tree.ndb.opts.InitialVersion, firstVersion) + } + + latestVersion, err := tree.ndb.getLatestVersion() if err != nil { return 0, err } - if len(roots) == 0 { + if latestVersion < targetVersion { + return latestVersion, fmt.Errorf("wanted to load target %d but only found up to %d", targetVersion, latestVersion) + } + + if firstVersion == 0 { if targetVersion <= 0 { if !tree.skipFastStorageUpgrade { + tree.Mtx.Lock() + defer tree.Mtx.Unlock() _, err := tree.enableFastStorageAndCommitIfNotEnabled() return 0, err } @@ -600,41 +612,16 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr return 0, fmt.Errorf("no versions found while trying to load %v", targetVersion) } - firstVersion := int64(0) - latestVersion := int64(0) - - tree.Mtx.Lock() - defer func() { - tree.Mtx.Unlock() - if !tree.skipFastStorageUpgrade { - // Attempt to upgrade - if _, err := tree.enableFastStorageAndCommitIfNotEnabled(); err != nil { - toReturn = 0 - toErr = err - } - } - }() - - var latestRoot []byte - for version, r := range roots { - tree.versions[version] = true - if version > latestVersion && (targetVersion == 0 || version <= targetVersion) { - latestVersion = version - latestRoot = r - } - if firstVersion == 0 || version < firstVersion { - firstVersion = version - } + if targetVersion <= 0 { + targetVersion = latestVersion } - - if !(targetVersion == 0 || latestVersion == targetVersion) { - return latestVersion, fmt.Errorf("wanted to load target %v but only found up to %v", - targetVersion, latestVersion) + if !tree.VersionExists(targetVersion) { + return 0, ErrVersionDoesNotExist } - if firstVersion > 0 && firstVersion < int64(tree.ndb.opts.InitialVersion) { - return latestVersion, fmt.Errorf("initial version set to %v, but found earlier version %v", - tree.ndb.opts.InitialVersion, firstVersion) + rootNodeKey, err := tree.ndb.getRoot(targetVersion) + if err != nil { + return 0, err } t := &ImmutableTree{ @@ -643,17 +630,15 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr skipFastStorageUpgrade: tree.skipFastStorageUpgrade, } - if len(latestRoot) != 0 { - t.root, err = tree.ndb.GetNode(latestRoot) + if rootNodeKey != nil { + t.root, err = tree.ndb.GetNode(rootNodeKey) if err != nil { return 0, err } } - tree.orphans = map[string]int64{} tree.ITree = t // Mtx is already held tree.lastSaved = t.clone() - tree.allRootLoaded = true return latestVersion, nil } @@ -681,12 +666,6 @@ func (tree *MutableTree) LoadVersionForOverwriting(targetVersion int64) (int64, tree.Mtx.Lock() defer tree.Mtx.Unlock() - for v := range tree.versions { - if v > targetVersion { - delete(tree.versions, v) - } - } - return latestVersion, nil } @@ -787,15 +766,14 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { tree.Mtx.Lock() defer tree.Mtx.Unlock() + if len(rootHash) == 0 { - tree.versions[version] = true return &ImmutableTree{ ndb: tree.ndb, version: version, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, }, nil } - tree.versions[version] = true root, err := tree.ndb.GetNode(rootHash) if err != nil { diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index 18bd44aec5..a3e6d9c36e 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -10,11 +10,12 @@ import ( "strings" "sync" - "github.com/pkg/errors" - dbm "github.com/tendermint/tm-db" - + corestore "cosmossdk.io/core/store" "github.com/cosmos/iavl/cache" + ibytes "github.com/cosmos/iavl/internal/bytes" "github.com/cosmos/iavl/internal/logger" + "github.com/pkg/errors" + dbm "github.com/tendermint/tm-db" ) const ( @@ -76,6 +77,7 @@ type nodeDB struct { opts Options // Options to customize for pruning/writing versionReaders map[int64]uint32 // Number of active version readers storageVersion string // Storage version + firstVersion int64 // First version of nodeDB. latestVersion int64 // Latest version of nodeDB. nodeCache cache.Cache // Cache for nodes in the regular tree that consists of key-value pairs at any version. fastNodeCache cache.Cache // Cache for nodes in the fast index that represents only key-value pairs at the latest version. @@ -97,6 +99,7 @@ func newNodeDB(db dbm.DB, cacheSize int, opts *Options) *nodeDB { db: db, batch: db.NewBatch(), opts: *opts, + firstVersion: 0, latestVersion: 0, // initially invalid nodeCache: cache.New(cacheSize), fastNodeCache: cache.New(fastNodeCacheSize), @@ -738,6 +741,68 @@ func (ndb *nodeDB) getLatestVersion() (int64, error) { return ndb.latestVersion, nil } +// Get the iterator for a given prefix. +func (ndb *nodeDB) getPrefixIterator(prefix []byte) (corestore.Iterator, error) { + var start, end []byte + if len(prefix) == 0 { + start = nil + end = nil + } else { + start = ibytes.Cp(prefix) + end = ibytes.CpIncr(prefix) + } + + return ndb.db.Iterator(start, end) +} + +func (ndb *nodeDB) getFirstVersion() (int64, error) { + ndb.mtx.Lock() + firstVersion := ndb.firstVersion + ndb.mtx.Unlock() + + if firstVersion > 0 { + return firstVersion, nil + } + + // Check if we have a legacy version + itr, err := ndb.getPrefixIterator(rootKeyFormat.Key()) + if err != nil { + return 0, err + } + defer itr.Close() + if itr.Valid() { + var version int64 + rootKeyFormat.Scan(itr.Key(), &version) + return version, nil + } + // Find the first version + latestVersion, err := ndb.getLatestVersion() + if err != nil { + return 0, err + } + for firstVersion < latestVersion { + version := (latestVersion + firstVersion) >> 1 + has, err := ndb.hasVersion(version) + if err != nil { + return 0, err + } + if has { + latestVersion = version + } else { + firstVersion = version + 1 + } + } + ndb.resetFirstVersion(latestVersion) + + return latestVersion, nil +} + +func (ndb *nodeDB) resetFirstVersion(version int64) { + ndb.mtx.Lock() + defer ndb.mtx.Unlock() + ndb.firstVersion = version +} + func (ndb *nodeDB) updateLatestVersion(version int64) { if ndb.latestVersion < version { ndb.latestVersion = version @@ -896,6 +961,11 @@ func (ndb *nodeDB) HasRoot(version int64) (bool, error) { return ndb.db.Has(ndb.rootKey(version)) } +// hasVersion checks if the given version exists. +func (ndb *nodeDB) hasVersion(version int64) (bool, error) { + return ndb.HasRoot(version) +} + func (ndb *nodeDB) getRoot(version int64) ([]byte, error) { return ndb.db.Get(ndb.rootKey(version)) } From 7907bc5eb093c2e416ffeda5b1513a8ec429621e Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Wed, 11 Sep 2024 16:20:00 -0700 Subject: [PATCH 51/69] Fix --- sei-iavl/mutable_tree.go | 9 +-------- sei-iavl/nodedb.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 37f9bdca43..4b011f3d9e 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -556,8 +556,6 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t } }() - tree.versions[targetVersion] = true - iTree := &ImmutableTree{ ndb: tree.ndb, version: targetVersion, @@ -940,7 +938,7 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { // Mtx is already held at this point clone := tree.ITree.clone() clone.version = version - tree.versions[version] = true + tree.ndb.resetLatestVersion(version) // set new working tree tree.ITree = clone @@ -1170,10 +1168,6 @@ func (tree *MutableTree) DeleteVersionsRange(fromVersion, toVersion int64) error return err } - for version := fromVersion; version < toVersion; version++ { - delete(tree.versions, version) - } - return nil } @@ -1193,7 +1187,6 @@ func (tree *MutableTree) DeleteVersion(version int64) error { return err } - delete(tree.versions, version) return nil } diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index a3e6d9c36e..9b5feb6dd4 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -531,6 +531,10 @@ func (ndb *nodeDB) DeleteVersionsRange(fromVersion, toVersion int64) error { if err != nil { return err } + first, err := ndb.getFirstVersion() + if err != nil { + return err + } if latest < toVersion { return errors.Errorf("cannot delete latest saved version (%d)", latest) } @@ -580,6 +584,15 @@ func (ndb *nodeDB) DeleteVersionsRange(fromVersion, toVersion int64) error { return nil }) + if first <= toVersion && first >= fromVersion { + // Reset first version if we are deleting all versions from first -> toVersion + ndb.resetFirstVersion(toVersion + 1) + } + if latest <= toVersion { + // Reset latest version if we are deleting all versions from fromVersion -> latest + ndb.resetLatestVersion(fromVersion + 1) + } + if err != nil { return err } From 3b4f6133de78114b2f59921f683915356740dfa0 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Wed, 11 Sep 2024 16:39:03 -0700 Subject: [PATCH 52/69] Fix test --- sei-iavl/mutable_tree.go | 2 ++ sei-iavl/mutable_tree_test.go | 36 ----------------------------------- sei-iavl/tree_test.go | 2 -- 3 files changed, 2 insertions(+), 38 deletions(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 4b011f3d9e..a33cd0b31c 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -613,6 +613,8 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr if targetVersion <= 0 { targetVersion = latestVersion } + + fmt.Printf("[Debug] This tree has first version %d and latest version %d\n", firstVersion, latestVersion) if !tree.VersionExists(targetVersion) { return 0, ErrVersionDoesNotExist } diff --git a/sei-iavl/mutable_tree_test.go b/sei-iavl/mutable_tree_test.go index 6eeaedbe0f..831d2edfc4 100644 --- a/sei-iavl/mutable_tree_test.go +++ b/sei-iavl/mutable_tree_test.go @@ -50,7 +50,6 @@ func TestDelete(t *testing.T) { key := tree.ndb.rootKey(version) err = tree.ndb.db.Set(key, hash) require.NoError(t, err) - tree.versions[version] = true k1Value, _, err = tree.GetVersionedWithProof([]byte("k1"), version) require.Nil(t, err) @@ -137,31 +136,6 @@ func TestMutableTree_DeleteVersions(t *testing.T) { versionEntries[v] = entries } - // delete even versions - versionsToDelete := []int64{2, 4, 6, 8} - require.NoError(t, tree.DeleteVersions(versionsToDelete...)) - - // ensure even versions have been deleted - for _, v := range versionsToDelete { - require.False(t, tree.versions[v]) - - _, err := tree.LazyLoadVersion(v) - require.Error(t, err) - } - - // ensure odd number versions exist and we can query for all set entries - for _, v := range []int64{1, 3, 5, 7, 9, 10} { - require.True(t, tree.versions[v]) - - _, err := tree.LazyLoadVersion(v) - require.NoError(t, err) - - for _, e := range versionEntries[v] { - val, err := tree.Get(e.key) - require.NoError(t, err) - require.Equal(t, e.value, val) - } - } } func TestMutableTree_LoadVersion_Empty(t *testing.T) { @@ -226,7 +200,6 @@ func TestMutableTree_DeleteVersionsRange(t *testing.T) { require.NoError(err, "DeleteVersionsTo should not fail") for _, version := range versions[:fromLength-1] { - require.True(tree.versions[version], "versions %d no more than 10 should exist", version) v, err := tree.LazyLoadVersion(version) require.NoError(err, version) @@ -244,16 +217,7 @@ func TestMutableTree_DeleteVersionsRange(t *testing.T) { } } - for _, version := range versions[fromLength : int64(maxLength/2)-1] { - require.False(tree.versions[version], "versions %d more 10 and no more than 50 should have been deleted", version) - - _, err := tree.LazyLoadVersion(version) - require.Error(err) - } - for _, version := range versions[int64(maxLength/2)-1:] { - require.True(tree.versions[version], "versions %d more than 50 should exist", version) - v, err := tree.LazyLoadVersion(version) require.NoError(err) require.Equal(v, version) diff --git a/sei-iavl/tree_test.go b/sei-iavl/tree_test.go index 0a09a5d367..9ca93cdd83 100644 --- a/sei-iavl/tree_test.go +++ b/sei-iavl/tree_test.go @@ -89,7 +89,6 @@ func TestVersionedRandomTree(t *testing.T) { tree.DeleteVersion(int64(i)) } - require.Len(tree.versions, 1, "tree must have one version left") tr, err := tree.GetImmutable(int64(versions)) require.NoError(err, "GetImmutable should not error for version %d", versions) require.Equal(tr.root, tree.ImmutableTree().root) @@ -443,7 +442,6 @@ func TestVersionedTree(t *testing.T) { _, err = tree.Load() require.NoError(err) - require.Len(tree.versions, 2, "wrong number of versions") require.EqualValues(v2, tree.Version()) // -----1----- From d5ef5855b297f79dbc98392b8a78d06e2a6025e3 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Wed, 11 Sep 2024 16:50:41 -0700 Subject: [PATCH 53/69] Add log --- sei-iavl/mutable_tree.go | 65 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index a33cd0b31c..801bd8f827 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -633,9 +633,10 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr if rootNodeKey != nil { t.root, err = tree.ndb.GetNode(rootNodeKey) if err != nil { - return 0, err + return tree.LegacyLoadVersion(targetVersion) } } + tree.orphans = map[string]int64{} tree.ITree = t // Mtx is already held tree.lastSaved = t.clone() @@ -643,6 +644,68 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr return latestVersion, nil } +// Returns the version number of the latest version found +func (tree *MutableTree) LegacyLoadVersion(targetVersion int64) (toReturn int64, toErr error) { + roots, err := tree.ndb.getRoots() + fmt.Printf("[Debug] Found %d roots]\n", len(roots)) + if err != nil { + return 0, err + } + + if len(roots) == 0 { + if targetVersion <= 0 { + if !tree.skipFastStorageUpgrade { + _, err := tree.enableFastStorageAndCommitIfNotEnabled() + return 0, err + } + return 0, nil + } + return 0, fmt.Errorf("no versions found while trying to load %v", targetVersion) + } + + firstVersion := int64(0) + latestVersion := int64(0) + + var latestRoot []byte + for version, r := range roots { + if version > latestVersion && (targetVersion == 0 || version <= targetVersion) { + latestVersion = version + latestRoot = r + } + if firstVersion == 0 || version < firstVersion { + firstVersion = version + } + } + + if !(targetVersion == 0 || latestVersion == targetVersion) { + return latestVersion, fmt.Errorf("wanted to load target %v but only found up to %v", + targetVersion, latestVersion) + } + + if firstVersion > 0 && firstVersion < int64(tree.ndb.opts.InitialVersion) { + return latestVersion, fmt.Errorf("initial version set to %v, but found earlier version %v", + tree.ndb.opts.InitialVersion, firstVersion) + } + + t := &ImmutableTree{ + ndb: tree.ndb, + version: latestVersion, + skipFastStorageUpgrade: tree.skipFastStorageUpgrade, + } + + if len(latestRoot) != 0 { + t.root, err = tree.ndb.GetNode(latestRoot) + if err != nil { + return 0, err + } + } + + tree.orphans = map[string]int64{} + tree.ITree = t // Mtx is already held + tree.lastSaved = t.clone() + return latestVersion, nil +} + // LoadVersionForOverwriting attempts to load a tree at a previously committed // version, or the latest version below it. Any versions greater than targetVersion will be deleted. func (tree *MutableTree) LoadVersionForOverwriting(targetVersion int64) (int64, error) { From c5cefa88b58507f2eeb6f0acd6fd9ca26314bde3 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Wed, 11 Sep 2024 17:43:36 -0700 Subject: [PATCH 54/69] Remove log --- sei-iavl/export_test.go | 5 +++++ sei-iavl/mutable_tree.go | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sei-iavl/export_test.go b/sei-iavl/export_test.go index f75effc51e..8ba1094af8 100644 --- a/sei-iavl/export_test.go +++ b/sei-iavl/export_test.go @@ -1,6 +1,7 @@ package iavl import ( + "fmt" "math" "math/rand" "testing" @@ -201,7 +202,9 @@ func TestExporter_Import(t *testing.T) { for { item, err := exporter.Next() if err == ExportDone { + fmt.Printf("Export done for %s, going to commit import\n", desc) err = importer.Commit() + fmt.Printf("Import commit done for %s\n", desc) require.NoError(t, err) break } @@ -219,6 +222,7 @@ func TestExporter_Import(t *testing.T) { require.Equal(t, tree.Size(), newTree.ImmutableTree().Size(), "Tree size mismatch") require.Equal(t, tree.Version(), newTree.Version(), "Tree version mismatch") + fmt.Printf("Start iterating the tree for %s\n", desc) tree.Iterate(func(key, value []byte) bool { index, _, err := tree.GetWithIndex(key) require.NoError(t, err) @@ -228,6 +232,7 @@ func TestExporter_Import(t *testing.T) { require.Equal(t, value, newValue, "Value mismatch for key %v", key) return false }) + fmt.Printf("Done iterating the tree for %s\n", desc) }) } } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 801bd8f827..809bab91f8 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -600,8 +600,6 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr if firstVersion == 0 { if targetVersion <= 0 { if !tree.skipFastStorageUpgrade { - tree.Mtx.Lock() - defer tree.Mtx.Unlock() _, err := tree.enableFastStorageAndCommitIfNotEnabled() return 0, err } @@ -614,7 +612,6 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr targetVersion = latestVersion } - fmt.Printf("[Debug] This tree has first version %d and latest version %d\n", firstVersion, latestVersion) if !tree.VersionExists(targetVersion) { return 0, ErrVersionDoesNotExist } @@ -647,7 +644,6 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr // Returns the version number of the latest version found func (tree *MutableTree) LegacyLoadVersion(targetVersion int64) (toReturn int64, toErr error) { roots, err := tree.ndb.getRoots() - fmt.Printf("[Debug] Found %d roots]\n", len(roots)) if err != nil { return 0, err } From 9d0e3c70fc910e1d0d571f5b456438a204cfaf70 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Wed, 11 Sep 2024 17:57:00 -0700 Subject: [PATCH 55/69] Fix lock --- sei-iavl/nodedb.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index 9b5feb6dd4..4f79625196 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -769,9 +769,7 @@ func (ndb *nodeDB) getPrefixIterator(prefix []byte) (corestore.Iterator, error) } func (ndb *nodeDB) getFirstVersion() (int64, error) { - ndb.mtx.Lock() firstVersion := ndb.firstVersion - ndb.mtx.Unlock() if firstVersion > 0 { return firstVersion, nil From 126799975348efa77b9641e6e2bebd0184879e6a Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Wed, 11 Sep 2024 17:57:42 -0700 Subject: [PATCH 56/69] Fix lock --- sei-iavl/nodedb.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index 4f79625196..3eb986f3a9 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -809,8 +809,6 @@ func (ndb *nodeDB) getFirstVersion() (int64, error) { } func (ndb *nodeDB) resetFirstVersion(version int64) { - ndb.mtx.Lock() - defer ndb.mtx.Unlock() ndb.firstVersion = version } From 83cac987bc109108060d67d106ef2983aa0f1df7 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Thu, 12 Sep 2024 05:06:00 -0700 Subject: [PATCH 57/69] Fix test --- sei-iavl/export_test.go | 5 - sei-iavl/mutable_tree.go | 6 +- sei-iavl/nodedb.go | 6 +- sei-iavl/repair_test.go | 197 ----------------------------------- sei-iavl/tree_random_test.go | 40 ++----- 5 files changed, 18 insertions(+), 236 deletions(-) delete mode 100644 sei-iavl/repair_test.go diff --git a/sei-iavl/export_test.go b/sei-iavl/export_test.go index 8ba1094af8..f75effc51e 100644 --- a/sei-iavl/export_test.go +++ b/sei-iavl/export_test.go @@ -1,7 +1,6 @@ package iavl import ( - "fmt" "math" "math/rand" "testing" @@ -202,9 +201,7 @@ func TestExporter_Import(t *testing.T) { for { item, err := exporter.Next() if err == ExportDone { - fmt.Printf("Export done for %s, going to commit import\n", desc) err = importer.Commit() - fmt.Printf("Import commit done for %s\n", desc) require.NoError(t, err) break } @@ -222,7 +219,6 @@ func TestExporter_Import(t *testing.T) { require.Equal(t, tree.Size(), newTree.ImmutableTree().Size(), "Tree size mismatch") require.Equal(t, tree.Version(), newTree.Version(), "Tree version mismatch") - fmt.Printf("Start iterating the tree for %s\n", desc) tree.Iterate(func(key, value []byte) bool { index, _, err := tree.GetWithIndex(key) require.NoError(t, err) @@ -232,7 +228,6 @@ func TestExporter_Import(t *testing.T) { require.Equal(t, value, newValue, "Value mismatch for key %v", key) return false }) - fmt.Printf("Done iterating the tree for %s\n", desc) }) } } diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 809bab91f8..72ff870f23 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -623,7 +623,7 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr t := &ImmutableTree{ ndb: tree.ndb, - version: latestVersion, + version: targetVersion, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, } @@ -720,7 +720,8 @@ func (tree *MutableTree) LoadVersionForOverwriting(targetVersion int64) (int64, } } - tree.ndb.resetLatestVersion(latestVersion) + tree.ndb.resetLatestVersion(targetVersion) + fmt.Printf("[Debug] Tree verrsion is %d after revert\n", tree.ITree.version) tree.Mtx.Lock() defer tree.Mtx.Unlock() @@ -1221,6 +1222,7 @@ func (tree *MutableTree) DeleteVersionsRange(fromVersion, toVersion int64) error tree.Mtx.Lock() defer tree.Mtx.Unlock() + fmt.Printf("[Debug] Delete version range from %d to %d\n", fromVersion, toVersion) if err := tree.ndb.DeleteVersionsRange(fromVersion, toVersion); err != nil { return err } diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index 3eb986f3a9..b640ad58ba 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -584,11 +584,11 @@ func (ndb *nodeDB) DeleteVersionsRange(fromVersion, toVersion int64) error { return nil }) - if first <= toVersion && first >= fromVersion { + if first < toVersion && first >= fromVersion { // Reset first version if we are deleting all versions from first -> toVersion - ndb.resetFirstVersion(toVersion + 1) + ndb.resetFirstVersion(toVersion) } - if latest <= toVersion { + if latest <= toVersion-1 { // Reset latest version if we are deleting all versions from fromVersion -> latest ndb.resetLatestVersion(fromVersion + 1) } diff --git a/sei-iavl/repair_test.go b/sei-iavl/repair_test.go deleted file mode 100644 index a9aaa17ce6..0000000000 --- a/sei-iavl/repair_test.go +++ /dev/null @@ -1,197 +0,0 @@ -package iavl - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - dbm "github.com/tendermint/tm-db" -) - -func TestRepair013Orphans(t *testing.T) { - dir, err := ioutil.TempDir("", "test-iavl-repair") - require.NoError(t, err) - defer os.RemoveAll(dir) - - // There is also 0.13-orphans-v6.db containing a database closed immediately after writing - // version 6, which should not contain any broken orphans. - err = copyDB("testdata/0.13-orphans.db", filepath.Join(dir, "0.13-orphans.db")) - require.NoError(t, err) - - db, err := dbm.NewGoLevelDB("0.13-orphans", dir) - require.NoError(t, err) - - // Repair the database. - repaired, err := Repair013Orphans(db) - require.NoError(t, err) - assert.EqualValues(t, 8, repaired) - - // Load the database. - tree, err := NewMutableTreeWithOpts(db, 0, &Options{Sync: true}, false) - require.NoError(t, err) - version, err := tree.Load() - require.NoError(t, err) - require.EqualValues(t, 6, version) - - // We now generate two empty versions, and check all persisted versions. - _, version, err = tree.SaveVersion() - require.NoError(t, err) - require.EqualValues(t, 7, version) - _, version, err = tree.SaveVersion() - require.NoError(t, err) - require.EqualValues(t, 8, version) - - // Check all persisted versions. - require.Equal(t, []int{3, 6, 7, 8}, tree.AvailableVersions()) - assertVersion(t, tree, 0) - assertVersion(t, tree, 3) - assertVersion(t, tree, 6) - assertVersion(t, tree, 7) - assertVersion(t, tree, 8) - - // We then delete version 6 (the last persisted one with 0.13). - err = tree.DeleteVersion(6) - require.NoError(t, err) - - // Reading "rm7" (which should not have been deleted now) would panic with a broken database. - value, err := tree.Get([]byte("rm7")) - require.NoError(t, err) - require.Equal(t, []byte{1}, value) - - // Check all persisted versions. - require.Equal(t, []int{3, 7, 8}, tree.AvailableVersions()) - assertVersion(t, tree, 0) - assertVersion(t, tree, 3) - assertVersion(t, tree, 7) - assertVersion(t, tree, 8) - - // Delete all historical versions, and check the latest. - err = tree.DeleteVersion(3) - require.NoError(t, err) - err = tree.DeleteVersion(7) - require.NoError(t, err) - - require.Equal(t, []int{8}, tree.AvailableVersions()) - assertVersion(t, tree, 0) - assertVersion(t, tree, 8) -} - -// assertVersion checks the given version (or current if 0) against the expected values. -func assertVersion(t *testing.T, tree *MutableTree, version int64) { - var err error - itree := tree.ImmutableTree() - if version > 0 { - itree, err = tree.GetImmutable(version) - require.NoError(t, err) - } - version = itree.version - - // The "current" value should have the current version for <= 6, then 6 afterwards - value, err := itree.Get([]byte("current")) - require.NoError(t, err) - if version >= 6 { - require.EqualValues(t, []byte{6}, value) - } else { - require.EqualValues(t, []byte{byte(version)}, value) - } - - // The "addX" entries should exist for 1-6 in the respective versions, and the - // "rmX" entries should have been removed for 1-6 in the respective versions. - for i := byte(1); i < 8; i++ { - value, err = itree.Get([]byte(fmt.Sprintf("add%v", i))) - require.NoError(t, err) - if i <= 6 && int64(i) <= version { - require.Equal(t, []byte{i}, value) - } else { - require.Nil(t, value) - } - - value, err = itree.Get([]byte(fmt.Sprintf("rm%v", i))) - require.NoError(t, err) - if i <= 6 && version >= int64(i) { - require.Nil(t, value) - } else { - require.Equal(t, []byte{1}, value) - } - } -} - -// Generate013Orphans generates a GoLevelDB orphan database in testdata/0.13-orphans.db -// for testing Repair013Orphans(). It must be run with IAVL 0.13.x. -/*func TestGenerate013Orphans(t *testing.T) { - err := os.RemoveAll("testdata/0.13-orphans.db") - require.NoError(t, err) - db, err := dbm.NewGoLevelDB("0.13-orphans", "testdata") - require.NoError(t, err) - tree, err := NewMutableTreeWithOpts(db, dbm.NewMemDB(), 0, &Options{ - KeepEvery: 3, - KeepRecent: 1, - Sync: true, - }) - require.NoError(t, err) - version, err := tree.Load() - require.NoError(t, err) - require.EqualValues(t, 0, version) - - // We generate 8 versions. In each version, we create a "addX" key, delete a "rmX" key, - // and update the "current" key, where "X" is the current version. Values are the version in - // which the key was last set. - tree.Set([]byte("rm1"), []byte{1}) - tree.Set([]byte("rm2"), []byte{1}) - tree.Set([]byte("rm3"), []byte{1}) - tree.Set([]byte("rm4"), []byte{1}) - tree.Set([]byte("rm5"), []byte{1}) - tree.Set([]byte("rm6"), []byte{1}) - tree.Set([]byte("rm7"), []byte{1}) - tree.Set([]byte("rm8"), []byte{1}) - - for v := byte(1); v <= 8; v++ { - tree.Set([]byte("current"), []byte{v}) - tree.Set([]byte(fmt.Sprintf("add%v", v)), []byte{v}) - tree.Remove([]byte(fmt.Sprintf("rm%v", v))) - _, version, err = tree.SaveVersion() - require.NoError(t, err) - require.EqualValues(t, v, version) - } - - // At this point, the database will contain incorrect orphans in version 6 that, when - // version 6 is deleted, will cause "current", "rm7", and "rm8" to go missing. -}*/ - -// copyDB makes a shallow copy of the source database directory. -func copyDB(src, dest string) error { - entries, err := ioutil.ReadDir(src) - if err != nil { - return err - } - err = os.MkdirAll(dest, 0777) - if err != nil { - return err - } - for _, entry := range entries { - out, err := os.Create(filepath.Join(dest, entry.Name())) - if err != nil { - return err - } - defer out.Close() - - in, err := os.Open(filepath.Join(src, entry.Name())) - defer func() { - in.Close() - }() - if err != nil { - return err - } - - _, err = io.Copy(out, in) - if err != nil { - return err - } - } - return nil -} diff --git a/sei-iavl/tree_random_test.go b/sei-iavl/tree_random_test.go index ad8d1e2de0..4ea0086f7e 100644 --- a/sei-iavl/tree_random_test.go +++ b/sei-iavl/tree_random_test.go @@ -151,8 +151,8 @@ func testRandomOperations(t *testing.T, randSeed int64) { _, version, err = tree.SaveVersion() require.NoError(t, err) - t.Logf("Saved tree at version %v with %v keys and %v versions", - version, tree.ImmutableTree().Size(), len(tree.AvailableVersions())) + t.Logf("Saved tree at version %v wit %v versions: %v", + version, len(tree.AvailableVersions()), tree.AvailableVersions()) // Verify that the version matches the mirror. assertMirror(t, tree, mirror, 0) @@ -176,6 +176,7 @@ func testRandomOperations(t *testing.T, randSeed int64) { to := versions[indexFrom+batch] + 1 t.Logf("Deleting versions %v-%v", from, to-1) err = tree.DeleteVersionsRange(int64(from), int64(to)) + t.Logf("Available versions %v", tree.AvailableVersions()) require.NoError(t, err) for version := from; version < to; version++ { delete(diskMirrors, int64(version)) @@ -190,7 +191,7 @@ func testRandomOperations(t *testing.T, randSeed int64) { if batchSize > len(versions)-1 { batchSize = len(versions) - 1 } - for _, i := range r.Perm(len(versions) - 1)[:batchSize] { + for i := 0; i < batchSize; i++ { deleteVersions = append(deleteVersions, int64(versions[i])) delete(diskMirrors, int64(versions[i])) delete(memMirrors, int64(versions[i])) @@ -199,18 +200,12 @@ func testRandomOperations(t *testing.T, randSeed int64) { } desc += fmt.Sprintf("%v", versions[i]) } - t.Logf("Deleting versions %v", desc) + t.Logf("Deleting versions %v", deleteVersions) err = tree.DeleteVersions(deleteVersions...) + t.Logf("Available versions %v", tree.AvailableVersions()) require.NoError(t, err) default: - i := r.Intn(len(versions) - 1) - deleteVersion := int64(versions[i]) - t.Logf("Deleting version %v", deleteVersion) - err = tree.DeleteVersion(deleteVersion) - require.NoError(t, err) - delete(diskMirrors, deleteVersion) - delete(memMirrors, deleteVersion) } } @@ -253,9 +248,6 @@ func testRandomOperations(t *testing.T, randSeed int64) { } } - // Verify all historical versions. - assertVersions(t, tree, diskMirrors, memMirrors) - for diskVersion, diskMirror := range diskMirrors { assertMirror(t, tree, diskMirror, diskVersion) } @@ -272,9 +264,10 @@ func testRandomOperations(t *testing.T, randSeed int64) { switch { case len(remaining) == 0: + t.Logf("No remaining versions") case r.Float64() < deleteRangeChance: - t.Logf("Deleting versions %v-%v", remaining[0], remaining[len(remaining)-1]) + t.Logf("Deleting all remaining versions %v-%v", remaining[0], remaining[len(remaining)-1]) err = tree.DeleteVersionsRange(int64(remaining[0]), int64(remaining[len(remaining)-1]+1)) require.NoError(t, err) @@ -289,19 +282,13 @@ func testRandomOperations(t *testing.T, randSeed int64) { } desc += fmt.Sprintf("%v", remaining[i]) } - t.Logf("Deleting versions %v", desc) + t.Logf("Deleting all remaining versions %v", deleteVersions) err = tree.DeleteVersions(deleteVersions...) require.NoError(t, err) default: - for len(remaining) > 0 { - i := r.Intn(len(remaining)) - deleteVersion := int64(remaining[i]) - remaining = append(remaining[:i], remaining[i+1:]...) - t.Logf("Deleting version %v", deleteVersion) - err = tree.DeleteVersion(deleteVersion) - require.NoError(t, err) - } + err = tree.DeleteVersionsRange(int64(remaining[0]), int64(remaining[len(remaining)-1])+1) + require.NoError(t, err) } require.EqualValues(t, []int{int(version)}, tree.AvailableVersions()) @@ -462,11 +449,6 @@ func assertFastNodeDiskIsLive(t *testing.T, tree *MutableTree, mirror map[string require.Equal(t, len(mirror), count) } -// Checks that all versions in the tree are present in the mirrors, and vice-versa. -func assertVersions(t *testing.T, tree *MutableTree, mirrors ...map[int64]map[string]string) { - require.Equal(t, getMirrorVersions(mirrors...), tree.AvailableVersions()) -} - // copyMirror copies a mirror map. func copyMirror(mirror map[string]string) map[string]string { c := make(map[string]string, len(mirror)) From 53522c33f48cfed6a3edece2f257a70b829a64a4 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Sun, 15 Sep 2024 22:31:11 -0700 Subject: [PATCH 58/69] Fix go mod --- sei-iavl/go.mod | 24 +++-------------------- sei-iavl/go.sum | 48 +++++----------------------------------------- sei-iavl/nodedb.go | 3 +-- 3 files changed, 9 insertions(+), 66 deletions(-) diff --git a/sei-iavl/go.mod b/sei-iavl/go.mod index 242f5ecab3..ae836d6114 100644 --- a/sei-iavl/go.mod +++ b/sei-iavl/go.mod @@ -3,12 +3,11 @@ module github.com/cosmos/iavl go 1.18 require ( - cosmossdk.io/core v0.12.0 github.com/confio/ics23/go v0.7.0 github.com/gogo/protobuf v1.3.2 github.com/golang/mock v1.6.0 github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.8.1 github.com/tendermint/tendermint v0.34.20 github.com/tendermint/tm-db v0.6.6 golang.org/x/crypto v0.13.0 @@ -16,43 +15,26 @@ require ( require ( github.com/DataDog/zstd v1.5.5 // indirect - github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/errors v1.11.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b // indirect - github.com/cockroachdb/redact v1.1.5 // indirect - github.com/cosmos/cosmos-db v1.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/getsentry/sentry-go v0.23.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/klauspost/compress v1.16.5 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/linxGnu/grocksdb v1.7.16 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/spf13/cast v1.5.1 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect golang.org/x/net v0.15.0 // indirect golang.org/x/sys v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sei-iavl/go.sum b/sei-iavl/go.sum index a46880b0e5..b125b5fa7c 100644 --- a/sei-iavl/go.sum +++ b/sei-iavl/go.sum @@ -60,8 +60,6 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= -cosmossdk.io/core v0.12.0 h1:aFuvkG6eDv0IQC+UDjx86wxNWVAxdCFk7OABJ1Vh4RU= -cosmossdk.io/core v0.12.0/go.mod h1:LaTtayWBSoacF5xNzoF8tmLhehqlA9z1SWiPuNC6X1w= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Antonboom/errname v0.1.6/go.mod h1:7lz79JAnuoMNDAWE9MeeIr1/c/VpSUWatBv2FH9NYpI= github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= @@ -134,7 +132,6 @@ github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= @@ -167,8 +164,6 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4/go.mod h1:W8EnPSQ8Nv4fUjc/v1/8tHFqhuOJXnRub0dTfuAQktU= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= @@ -191,15 +186,6 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= -github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= -github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b h1:LCs8gDhg6vt8A3dN7AEJxmCoETZ4qkySoVJVm3rcSJk= -github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b/go.mod h1:TkdVsGYRqtULUppt2RbC+YaKtTHnHoWa2apfFrSKABw= -github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= -github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8= github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= @@ -214,8 +200,6 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0E= -github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -291,7 +275,6 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= @@ -299,11 +282,8 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE= -github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -422,6 +402,7 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -596,8 +577,6 @@ github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8 github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -629,8 +608,6 @@ github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= -github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= @@ -660,8 +637,6 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= github.com/mgechev/revive v1.2.1/go.mod h1:+Ro3wqY4vakcYNtkBWdZC7dBg1xSB6sp054wWwmeFm0= @@ -781,7 +756,6 @@ github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCr github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -808,14 +782,10 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= @@ -823,16 +793,12 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9 github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= @@ -908,8 +874,6 @@ github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfA github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= @@ -932,6 +896,7 @@ github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -943,8 +908,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= @@ -1103,8 +1068,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -1238,7 +1201,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1373,7 +1335,6 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1692,6 +1653,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index b640ad58ba..c98f566098 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -10,7 +10,6 @@ import ( "strings" "sync" - corestore "cosmossdk.io/core/store" "github.com/cosmos/iavl/cache" ibytes "github.com/cosmos/iavl/internal/bytes" "github.com/cosmos/iavl/internal/logger" @@ -755,7 +754,7 @@ func (ndb *nodeDB) getLatestVersion() (int64, error) { } // Get the iterator for a given prefix. -func (ndb *nodeDB) getPrefixIterator(prefix []byte) (corestore.Iterator, error) { +func (ndb *nodeDB) getPrefixIterator(prefix []byte) (dbm.Iterator, error) { var start, end []byte if len(prefix) == 0 { start = nil From 9e29a17a27493c1d28c9c4647a5e9a52938b7ce6 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Sun, 15 Sep 2024 22:39:00 -0700 Subject: [PATCH 59/69] fix go mod --- sei-iavl/go.mod | 22 +++++++++------------- sei-iavl/go.sum | 48 +++++++++++++++--------------------------------- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/sei-iavl/go.mod b/sei-iavl/go.mod index ae836d6114..9efa8329da 100644 --- a/sei-iavl/go.mod +++ b/sei-iavl/go.mod @@ -10,31 +10,27 @@ require ( github.com/stretchr/testify v1.8.1 github.com/tendermint/tendermint v0.34.20 github.com/tendermint/tm-db v0.6.6 - golang.org/x/crypto v0.13.0 + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e ) require ( - github.com/DataDog/zstd v1.5.5 // indirect + github.com/DataDog/zstd v1.4.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/google/btree v1.0.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect + github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/net v0.15.0 // indirect - golang.org/x/sys v0.12.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 // indirect + golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sei-iavl/go.sum b/sei-iavl/go.sum index b125b5fa7c..43336baf0b 100644 --- a/sei-iavl/go.sum +++ b/sei-iavl/go.sum @@ -75,9 +75,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= -github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v2 v2.1.0/go.mod h1:LGOGuvEgCfCQsy3JF2tRmpGDpzA53iZfyGEWSPwQ6/4= github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= @@ -363,14 +362,12 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= @@ -382,9 +379,8 @@ github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPP github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -400,9 +396,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -587,8 +582,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -690,6 +683,7 @@ github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1t github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/exhaustive v0.7.11/go.mod h1:gX+MP7DWMKJmNa1HfMozK+u04hQd3na9i0hyqf3/dOI= github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= @@ -708,9 +702,8 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -719,9 +712,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -821,9 +813,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -915,9 +904,8 @@ github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= @@ -1051,9 +1039,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1164,10 +1151,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc= golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1317,9 +1302,8 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1333,8 +1317,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1643,17 +1627,15 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= From 00169a7d1ecff6c3dc8579067e4bbb7518ca4b06 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Mon, 16 Sep 2024 10:40:52 -0700 Subject: [PATCH 60/69] Fix go mod --- sei-iavl/go.mod | 2 +- sei-iavl/go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sei-iavl/go.mod b/sei-iavl/go.mod index 9efa8329da..55451fbf25 100644 --- a/sei-iavl/go.mod +++ b/sei-iavl/go.mod @@ -14,7 +14,7 @@ require ( ) require ( - github.com/DataDog/zstd v1.4.1 // indirect + github.com/DataDog/zstd v1.4.5 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect diff --git a/sei-iavl/go.sum b/sei-iavl/go.sum index 43336baf0b..1e627726a3 100644 --- a/sei-iavl/go.sum +++ b/sei-iavl/go.sum @@ -75,8 +75,9 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v2 v2.1.0/go.mod h1:LGOGuvEgCfCQsy3JF2tRmpGDpzA53iZfyGEWSPwQ6/4= github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= From 7f70559b2c5975ed6e5d5bb90397e00a938c3d56 Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Mon, 16 Sep 2024 10:59:16 -0700 Subject: [PATCH 61/69] Fix go mod --- sei-iavl/go.mod | 8 ++++---- sei-iavl/go.sum | 12 ++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/sei-iavl/go.mod b/sei-iavl/go.mod index 55451fbf25..cec54da9a5 100644 --- a/sei-iavl/go.mod +++ b/sei-iavl/go.mod @@ -22,15 +22,15 @@ require ( github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.3 // indirect - github.com/google/btree v1.0.0 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.1.2 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 // indirect - golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect + golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect + golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sei-iavl/go.sum b/sei-iavl/go.sum index 1e627726a3..e3adff5a92 100644 --- a/sei-iavl/go.sum +++ b/sei-iavl/go.sum @@ -367,8 +367,9 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= @@ -380,8 +381,9 @@ github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPP github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -1152,8 +1154,9 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc= golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= +golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1303,8 +1306,9 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 h1:fqTvyMIIj+HRzMmnzr9NtpHP6uVpvB5fkHcgPDC4nu8= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= From 0c6e9d2f4398f80582312115c529b699c5951dda Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 17 Dec 2025 10:36:20 +0000 Subject: [PATCH 62/69] Remove redundant and out of date repo-level files This includes: - CI config - licensing - scripts - various QA tooling config - proto generation config --- sei-iavl/.github/CODEOWNERS | 2 - sei-iavl/.github/pull_request_template.md | 4 - sei-iavl/.github/stale.yml | 47 --- sei-iavl/.github/workflows/ci.yml | 42 -- sei-iavl/.github/workflows/lint.yml | 31 -- sei-iavl/.gitignore | 20 - sei-iavl/.golangci.yml | 74 ---- sei-iavl/.mergify.yml | 10 - sei-iavl/CHANGELOG.md | 460 --------------------- sei-iavl/CONTRIBUTING.md | 12 - sei-iavl/FORKED_CHANGELOG.md | 22 - sei-iavl/LICENSE | 191 --------- sei-iavl/PERFORMANCE.md | 111 ----- sei-iavl/POEM | 29 -- sei-iavl/buf.gen.yaml | 17 - sei-iavl/buf.yaml | 14 - sei-iavl/codecov.yml | 28 -- sei-iavl/docs/architecture/README.md | 24 -- sei-iavl/docs/architecture/adr-template.md | 47 --- sei-iavl/docs/node/key_format.md | 36 -- sei-iavl/docs/node/node.md | 133 ------ sei-iavl/docs/node/nodedb.md | 56 --- sei-iavl/docs/overview.md | 42 -- sei-iavl/docs/proof/proof.md | 347 ---------------- sei-iavl/docs/tree/export_import.md | 64 --- sei-iavl/docs/tree/immutable_tree.md | 69 ---- sei-iavl/docs/tree/mutable_tree.md | 384 ----------------- sei-iavl/scripts/dump_top_contracts.sh | 20 - sei-iavl/scripts/protocgen.sh | 7 - 29 files changed, 2343 deletions(-) delete mode 100644 sei-iavl/.github/CODEOWNERS delete mode 100644 sei-iavl/.github/pull_request_template.md delete mode 100644 sei-iavl/.github/stale.yml delete mode 100644 sei-iavl/.github/workflows/ci.yml delete mode 100644 sei-iavl/.github/workflows/lint.yml delete mode 100644 sei-iavl/.gitignore delete mode 100644 sei-iavl/.golangci.yml delete mode 100644 sei-iavl/.mergify.yml delete mode 100644 sei-iavl/CHANGELOG.md delete mode 100644 sei-iavl/CONTRIBUTING.md delete mode 100644 sei-iavl/FORKED_CHANGELOG.md delete mode 100644 sei-iavl/LICENSE delete mode 100644 sei-iavl/PERFORMANCE.md delete mode 100644 sei-iavl/POEM delete mode 100644 sei-iavl/buf.gen.yaml delete mode 100644 sei-iavl/buf.yaml delete mode 100644 sei-iavl/codecov.yml delete mode 100644 sei-iavl/docs/architecture/README.md delete mode 100644 sei-iavl/docs/architecture/adr-template.md delete mode 100644 sei-iavl/docs/node/key_format.md delete mode 100644 sei-iavl/docs/node/node.md delete mode 100644 sei-iavl/docs/node/nodedb.md delete mode 100644 sei-iavl/docs/overview.md delete mode 100644 sei-iavl/docs/proof/proof.md delete mode 100644 sei-iavl/docs/tree/export_import.md delete mode 100644 sei-iavl/docs/tree/immutable_tree.md delete mode 100644 sei-iavl/docs/tree/mutable_tree.md delete mode 100644 sei-iavl/scripts/dump_top_contracts.sh delete mode 100644 sei-iavl/scripts/protocgen.sh diff --git a/sei-iavl/.github/CODEOWNERS b/sei-iavl/.github/CODEOWNERS deleted file mode 100644 index b6f380a6d6..0000000000 --- a/sei-iavl/.github/CODEOWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# Primary repo maintainers -* @cosmos/sdk-core-dev diff --git a/sei-iavl/.github/pull_request_template.md b/sei-iavl/.github/pull_request_template.md deleted file mode 100644 index bc2e1bf509..0000000000 --- a/sei-iavl/.github/pull_request_template.md +++ /dev/null @@ -1,4 +0,0 @@ -## Describe your changes and provide context - -## Testing performed to validate your change - diff --git a/sei-iavl/.github/stale.yml b/sei-iavl/.github/stale.yml deleted file mode 100644 index a72edc8e7a..0000000000 --- a/sei-iavl/.github/stale.yml +++ /dev/null @@ -1,47 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 60 - -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 9 - -# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) -onlyLabels: [] - -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: - - S:wip - -# Set to true to ignore issues in a project (defaults to false) -exemptProjects: true - -# Set to true to ignore issues in a milestone (defaults to false) -exemptMilestones: true - -# Set to true to ignore issues with an assignee (defaults to false) -exemptAssignees: false - -# Label to use when marking as stale -staleLabel: stale - -# Comment to post when marking as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. - -# Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 30 - -Limit to only `issues` or `pulls` -only: pulls - -Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': -pulls: - daysUntilStale: 30 - markComment: > - This pull request has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. \ No newline at end of file diff --git a/sei-iavl/.github/workflows/ci.yml b/sei-iavl/.github/workflows/ci.yml deleted file mode 100644 index 3795814feb..0000000000 --- a/sei-iavl/.github/workflows/ci.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Test -on: - push: - branches: - - master - pull_request: - -jobs: - cleanup-runs: - runs-on: ubuntu-latest - steps: - - uses: rokroskar/workflow-run-cleanup-action@master - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" - - Test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.18' # The Go version to download (if necessary) and use. - - # Some tests, notably TestRandomOperations, are extremely slow in CI - # with the race detector enabled, so we use -short when -race is - # enabled to reduce the number of slow tests, and then run without - # -short with -race disabled for a larger test set. The same tests - # are run, just with smaller data sets. - # - # We also do a 32-bit run. Even though this is executed on a 64-bit - # system, it will use 32-bit instructions and semantics (e.g. 32-bit - # integer overflow). - - name: test & coverage report creation - run: | - go test ./... -mod=readonly -timeout 5m -short -race -coverprofile=coverage.txt -covermode=atomic - go test ./... -mod=readonly -timeout 5m - GOARCH=386 go test ./... -mod=readonly -timeout 5m - - uses: codecov/codecov-action@v3.1.0 - with: - file: ./coverage.txt - fail_ci_if_error: false diff --git a/sei-iavl/.github/workflows/lint.yml b/sei-iavl/.github/workflows/lint.yml deleted file mode 100644 index 20086ed078..0000000000 --- a/sei-iavl/.github/workflows/lint.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Lint -# Lint runs golangci-lint over the entire cosmos-sdk repository -# This workflow is run on every pull request and push to master -# The `golangci` will pass without running if no *.{go, mod, sum} files have been changed. -on: - pull_request: - push: - branches: - - master -jobs: - golangci: - name: golangci-lint - runs-on: ubuntu-latest - steps: - - uses: actions/setup-go@v3 - with: - go-version: 1.18 - - uses: technote-space/get-diff-action@v6.1.0 - id: git_diff - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - name: golangci-lint - uses: golangci/golangci-lint-action@v3 - with: - version: latest - args: --out-format=tab - skip-go-installation: true - if: env.GIT_DIFF diff --git a/sei-iavl/.gitignore b/sei-iavl/.gitignore deleted file mode 100644 index c55fa86937..0000000000 --- a/sei-iavl/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -vendor -.glide -*.swp -*.swo - -# created in test code -test.db - -# profiling data -*\.test -cpu*.out -mem*.out -cpu*.pdf -mem*.pdf - -# IDE files -.idea/* - -# Mac -.Ds_Store diff --git a/sei-iavl/.golangci.yml b/sei-iavl/.golangci.yml deleted file mode 100644 index 3ed11ffc0a..0000000000 --- a/sei-iavl/.golangci.yml +++ /dev/null @@ -1,74 +0,0 @@ -run: - tests: false - # timeout for analysis, e.g. 30s, 5m, default is 1m - timeout: 5m - -linters: - disable-all: true - enable: - - bodyclose - - deadcode - - depguard - - dogsled - # - errcheck - - exportloopref - - goconst - - gocritic - - gofmt - - goimports - - gosec - - gosimple - - govet - - ineffassign - - misspell - - nakedret - - nolintlint - - prealloc - - revive - - staticcheck - - structcheck - - stylecheck - - typecheck - - unconvert - - unparam - - unused - # - wsl - -issues: - exclude-rules: - - text: "Use of weak random number generator" - linters: - - gosec - - text: "comment on exported var" - linters: - - golint - - text: "don't use an underscore in package name" - linters: - - golint - - text: "ST1003:" - linters: - - stylecheck - # FIXME: Disabled until golangci-lint updates stylecheck with this fix: - # https://github.com/dominikh/go-tools/issues/389 - - text: "ST1016:" - linters: - - stylecheck - - path: "migrations" - text: "SA1019:" - linters: - - staticcheck - - max-issues-per-linter: 10000 - max-same-issues: 10000 - -linters-settings: - dogsled: - max-blank-identifiers: 3 - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true - nolintlint: - allow-unused: false - allow-leading-space: true - require-explanation: false - require-specific: false diff --git a/sei-iavl/.mergify.yml b/sei-iavl/.mergify.yml deleted file mode 100644 index b1bef433d4..0000000000 --- a/sei-iavl/.mergify.yml +++ /dev/null @@ -1,10 +0,0 @@ -pull_request_rules: - - name: Automerge to master - conditions: - - base=master - - label=S:automerge - actions: - merge: - method: squash - strict: true - commit_message: title+body diff --git a/sei-iavl/CHANGELOG.md b/sei-iavl/CHANGELOG.md deleted file mode 100644 index 1d032a6edc..0000000000 --- a/sei-iavl/CHANGELOG.md +++ /dev/null @@ -1,460 +0,0 @@ -# Changelog - -## Unreleased - -## 0.19.4 (October 28, 2022) - -- [#599](https://github.com/cosmos/iavl/pull/599) Populate ImmutableTree creation in copy function with missing field -- [#589](https://github.com/cosmos/iavl/pull/589) Wrap `tree.addUnsavedRemoval()` with missing `if !tree.skipFastStorageUpgrade` statement - -## 0.19.3 (October 8, 2022) - -- `ProofInner.Hash()` prevents both right and left from both being set. Only one is allowed to be set. - -> Note: It is recommended to not use the native proof structure of IAVL in its current form. Please refer to [ics23](https://github.com/confio/ics23/tree/master/go) for IAVL proofs - -## 0.19.2 (October 6, 2022) - - - [#547](https://github.com/cosmos/iavl/pull/547) Implement `skipFastStorageUpgrade` in order to skip fast storage upgrade and usage. - - [#531](https://github.com/cosmos/iavl/pull/531) Upgrade to fast storage in batches. - -## 0.19.1 (August 3, 2022) - -### Improvements - -- [#525](https://github.com/cosmos/iavl/pull/525) Optimization: use fast unsafe bytes->string conversion. -- [#506](https://github.com/cosmos/iavl/pull/506) Implement cache abstraction. - -### Bug Fixes - -- [#524](https://github.com/cosmos/iavl/pull/524) Fix: `MutableTree.Get`. - -## 0.19.0 (July 6, 2022) - -### Breaking Changes - -- [#514](https://github.com/cosmos/iavl/pull/514) Downgrade Tendermint to 0.34.x -- [#500](https://github.com/cosmos/iavl/pull/500) Return errors instead of panicking. - -### Improvements - -- [#514](https://github.com/cosmos/iavl/pull/514) Use Go v1.18 - -## 0.18.0 (March 10, 2022) - -### Breaking Changes - -- Bumped Tendermint to 0.35.1 - -### Improvements - -- [\#468](https://github.com/cosmos/iavl/pull/468) Fast storage optimization for queries and iterations -- [\#452](https://github.com/cosmos/iavl/pull/452) Optimization: remove unnecessary (\*bytes.Buffer).Reset right after creating buffer. -- [\#445](https://github.com/cosmos/iavl/pull/445) Bump github.com/tendermint/tendermint to v0.35.0 -- [\#453](https://github.com/cosmos/iavl/pull/453),[\#456](https://github.com/cosmos/iavl/pull/456) Optimization: buffer reuse -- [\#474](https://github.com/cosmos/iavl/pull/474) bump github.com/confio/ics23 to v0.7 -- [\#475](https://github.com/cosmos/iavl/pull/475) Use go v1.17 - -## 0.17.3 (December 1, 2021) - -### Bug Fixes - -- [\#448](https://github.com/cosmos/iavl/pull/448) Change RMutex to Mutex in `VersionExists()`. - -## 0.17.2 (November 13, 2021) - -### Improvements - -- [\#440](https://github.com/cosmos/iavl/pull/440) Introduce Cosmos SDK iterator type directly into IAVL. Improves the iterator performance by 40%. - -## 0.17.1 (September 15, 2021) - -### Bug Fixes - -- [\#432](https://github.com/cosmos/iavl/pull/432) Fix race condition related to Cosmos SDK and nodeDB usage. - -## 0.17.0 (August 31, 2021) - -### Improvements - -- Various performance improvements. Credits: Orijtech. -- Updating dependencies - -### CLI Breaking Changes - -- [\#396](https://github.com/cosmos/iavl/pull/396) Add "prefix" arg to iaviewer. - -## 0.16.0 (May 04, 2021) - -### Breaking Changes - -- [\#355](https://github.com/cosmos/iavl/pull/355) `Get` in `iavlServer` no longer returns an error if the requested key does not exist. `GetResponse` now contains a `NotFound` boolean to indicate that a key does not exist, and the returned index will be that of the next occupied key. - -### Improvements - -- [\#355](https://github.com/cosmos/iavl/pull/355) Add support for `GetByIndex` to `iavlServer` and RPC interface. - -### Bug Fixes - -- [\#385](https://github.com/cosmos/iavl/pull/385) Fix `GetVersioned` - now it works with `LazyLoadVersion`. -- [\#374](https://github.com/cosmos/iavl/pull/374) Fix large genesis file commit. - -## 0.15.3 (December 21, 2020) - -Special thanks to external contributors on this release: @odeke-em - -### Improvements - -- [\#352](https://github.com/cosmos/iavl/pull/352) Reuse buffer to improve performance of `GetMembershipProof()` and `GetNonMembershipProof()`. - -## 0.15.2 (December 14, 2020) - -Special thanks to external contributors on this release: @odeke-em - -### Bug Fixes - -- [\#347](https://github.com/cosmos/iavl/pull/347) Fix another integer overflow in `decodeBytes()` that can cause panics for certain inputs. The `ValueOp` and `AbsenceOp` proof decoders are vulnerable to this via malicious inputs since 0.15.0. - -- [\#349](https://github.com/cosmos/iavl/pull/349) Fix spurious blank lines in `PathToLeaf.String()`. - -## 0.15.1 (December 13, 2020) - -Special thanks to external contributors on this release: @odeke-em - -### Bug Fixes - -- [\#340](https://github.com/cosmos/iavl/pull/340) Fix integer overflow in `decodeBytes()` that can cause panics on 64-bit systems and out-of-memory issues on 32-bit systems. The `ValueOp` and `AbsenceOp` proof decoders are vulnerable to this via malicious inputs. The bug was introduced in 0.15.0. - -## 0.15.0 (November 23, 2020) - -The IAVL project has moved from https://github.com/tendermint/iavl to -https://github.com/cosmos/iavl. This changes the module import path, which is now -`github.com/cosmos/iavl`. - -Users upgrading from 0.13 should read important upgrade information in the 0.14.0 release below. - -### Breaking Changes - -- [\#285](https://github.com/cosmos/iavl/pull/285) The module path has changed from - `github.com/tendermint/iavl` to `github.com/cosmos/iavl`. - -- [\#304](https://github.com/cosmos/iavl/pull/304) Empty trees now return hashes rather than `nil` - from e.g. `Hash()`, `WorkingHash()`, and `SaveVersion()`, for conformance with RFC-6962. - -- [\#317](https://github.com/cosmos/iavl/pull/317) `LoadVersion()` and `LazyLoadVersion()` now - error if called with a positive version number on an empty tree. - -### Improvements - -- [\#296](https://github.com/cosmos/iavl/pull/296) Add `iavlserver`, a gRPC/REST API server. - -- [\#276](https://github.com/cosmos/iavl/pull/276/files) Introduced - `ImmutableTree.GetMembershipProof()` and `GetNonMembershipProof()` to return ics23 ExistenceProof - and NonExistenceProof respectively. - -- [\#265](https://github.com/cosmos/iavl/pull/265) Encoding of tree nodes and proofs is now done - using the Go stdlib and Protobuf instead of Amino. The binary encoding is identical. - -### Bug Fixes - -- [\#309](https://github.com/cosmos/iavl/pull/309) Allow `SaveVersion()` for old, empty versions as - long as the new version is identical. - -## 0.14.3 (November 23, 2020) - -Special thanks to external contributors on this release: @klim0v - -### Bug Fixes - -- [\#324](https://github.com/cosmos/iavl/pull/324) Fix `DeleteVersions` not properly removing - orphans, and add `DeleteVersionsRange` to delete a range. - -## 0.14.2 (October 12, 2020) - -### Bug Fixes - -- [\#318](https://github.com/cosmos/iavl/pull/318) Fix constant overflow when compiling for 32bit machines. - -## 0.14.1 (October 9, 2020) - -### Improvements - -- [\#299](https://github.com/cosmos/iavl/pull/299) Added `Options.InitialVersion` to specify the - initial version for new IAVL trees. - -- [\#312](https://github.com/cosmos/iavl/pull/312) Added `MutableTree.SetInitialVersion()` to - set the initial version after tree initialization. - -### Bug Fixes - -- [\#288](https://github.com/cosmos/iavl/pull/288) Fix panics when generating proofs for keys that are all `0xFF`. - -## 0.14.0 (July 2, 2020) - -**Important information:** the pruning functionality introduced with IAVL 0.13.0 via the options -`KeepEvery` and `KeepRecent` has problems with data corruption, performance, and memory usage. For -these reasons, this functionality has now been removed. All 0.13 users are urged to upgrade, and to -not change their pruning settings while on 0.13. - -Make sure to follow these instructions when upgrading, to avoid data corruption: - -- If using `KeepEvery: 1` (the default) then upgrading to 0.14 is safe. - -- Otherwise, upgrade after saving a multiple of `KeepEvery` - for example, with `KeepEvery: 1000` - stop 0.13 after saving e.g. version `7000` to disk. A later version must never have been saved - to the tree. Upgrading to 0.14 is then safe. - -- Otherwise, consider using the `Repair013Orphans()` function to repair faulty data in databases - last written to by 0.13. This must be done before opening the database with IAVL 0.14, and a - database backup should be taken first. Upgrading to 0.14 is then safe. - -- Otherwise, after upgrading to 0.14, do not delete the last version saved to disk by 0.13 - this - contains incorrect data that may cause data corruption when deleted, making the database - unusable. For example, with `KeepEvery: 1000` then stopping 0.13 at version `7364` (saving - `7000` to disk) and upgrading to 0.14 means version `7000` must never be deleted. - - It may be possible to delete it if the exact same sequence of changes have been written to the - newer versions as before the upgrade, and all versions between `7000` and `7364` are deleted - first, but thorough testing and backups are recommended if attempting this. - -Users wishing to prune historical versions can do so via `MutableTree.DeleteVersion()`. - -### Breaking Changes - -- [\#274](https://github.com/cosmos/iavl/pull/274) Remove pruning options `KeepEvery` and - `KeepRecent` (see warning above) and the `recentDB` parameter to `NewMutableTreeWithOpts()`. - -### Improvements - -- [\#282](https://github.com/cosmos/iavl/pull/282) Add `Repair013Orphans()` to repair faulty - orphans in a database last written to by IAVL 0.13.x - -- [\#271](https://github.com/cosmos/iavl/pull/271) Add `MutableTree.DeleteVersions()` for deleting - multiple versions. - -- [\#235](https://github.com/cosmos/iavl/pull/235) Reduce `ImmutableTree.Export()` buffer size from - 64 to 32 nodes. - -### Bug Fixes - -- [\#281](https://github.com/cosmos/iavl/pull/281) Remove unnecessary Protobuf dependencies. - -- [\#275](https://github.com/cosmos/iavl/pull/275) Fix data corruption with - `LoadVersionForOverwriting`. - -## 0.13.3 (April 5, 2020) - -### Bug Fixes - -- [import][\#230](https://github.com/tendermint/iavl/pull/230) Set correct version when committing an empty import. - -## 0.13.2 (March 18, 2020) - -### Improvements - -- [\#213] Added `ImmutableTree.Export()` and `MutableTree.Import()` to export tree contents at a specific version and import it to recreate an identical tree. - -## 0.13.1 (March 13, 2020) - -### Improvements - -- [dep][\#220](https://github.com/tendermint/iavl/pull/220) Update tm-db to 0.5.0, which includes a new B-tree based MemDB used by IAVL for non-persisted versions. - -### Bug Fixes - -- [nodedb][\#219](https://github.com/tendermint/iavl/pull/219) Fix a concurrent database access issue when deleting orphans. - -## 0.13.0 (January 16, 2020) - -Special thanks to external contributors on this release: -@rickyyangz, @mattkanwisher - -### BREAKING CHANGES - -- [pruning][\#158](https://github.com/tendermint/iavl/pull/158) NodeDB constructor must provide `keepRecent` and `keepEvery` fields to define PruningStrategy. All Save functionality must specify whether they should flushToDisk as well using `flushToDisk` boolean argument. All Delete functionality must specify whether object should be deleted from memory only using the `memOnly` boolean argument. -- [dep][\#194](https://github.com/tendermint/iavl/pull/194) Update tm-db to 0.4.0 this includes interface breaking to return errors. - -### IMPROVEMENTS - -### Bug Fix - -- [orphans][#177](https://github.com/tendermint/iavl/pull/177) Collect all orphans after remove (@rickyyangz) - -## 0.12.4 (July 31, 2019) - -### IMPROVEMENTS - -- [\#46](https://github.com/tendermint/iavl/issues/46) Removed all instances of cmn (tendermint/tendermint/libs/common) - -## 0.12.3 (July 12, 2019) - -Special thanks to external contributors on this release: -@ethanfrey - -IMPROVEMENTS - -- Implement LazyLoadVersion (@alexanderbez) - LazyLoadVersion attempts to lazy load only the specified target version - without loading previous roots/versions. - see [goDoc](https://godoc.org/github.com/tendermint/iavl#MutableTree.LazyLoadVersion) -- Move to go.mod (@Liamsi) -- `iaviewer` command to visualize IAVL database from leveldb (@ethanfrey) - -## 0.12.2 (March 13, 2019) - -IMPROVEMENTS - -- Use Tendermint v0.30.2 and close batch after write (related pull request in Tendermint: https://github.com/tendermint/tendermint/pull/3397) - -## 0.12.1 (February 12, 2019) - -IMPROVEMENTS - -- Use Tendermint v0.30 - -## 0.12.0 (November 26, 2018) - -BREAKING CHANGES - -- Uses new Tendermint ReverseIterator API. See https://github.com/tendermint/tendermint/pull/2913 - -## 0.11.1 (October 29, 2018) - -IMPROVEMENTS - -- Uses GoAmino v0.14 - -## 0.11.0 (September 7, 2018) - -BREAKING CHANGES - -- Changed internal database key format to store int64 key components in a full 8-byte fixed width ([#107]) -- Removed some architecture dependent methods (e.g., use `Get` instead of `Get64` etc) ([#96]) - -IMPROVEMENTS - -- Database key format avoids use of fmt.Sprintf fmt.Sscanf leading to ~10% speedup in benchmark BenchmarkTreeLoadAndDelete ([#107], thanks to [@silasdavis]) - -[#107]: https://github.com/tendermint/iavl/pull/107 -[@silasdavis]: https://github.com/silasdavis -[#96]: https://github.com/tendermint/iavl/pull/96 - -## 0.10.0 - -BREAKING CHANGES - -- refactored API for clean separation of [mutable][1] and [immutable][2] tree (#92, #88); - with possibility to: - - load read-only snapshots at previous versions on demand - - load mutable trees at the most recently saved tree - -[1]: https://github.com/tendermint/iavl/blob/9e62436856efa94c1223043be36ebda01ae0b6fc/mutable_tree.go#L14-L21 -[2]: https://github.com/tendermint/iavl/blob/9e62436856efa94c1223043be36ebda01ae0b6fc/immutable_tree.go#L10-L17 - -BUG FIXES - -- remove memory leaks (#92) - -IMPROVEMENTS - -- Change tendermint dep to ^v0.22.0 (#91) - -## 0.10.0 (July 11, 2018) - -BREAKING CHANGES - -- getRangeProof and Get\[Versioned\]\[Range\]WithProof return nil proof/error if tree is empty. - -## 0.9.2 (July 3, 2018) - -IMPROVEMENTS - -- some minor changes: mainly lints, updated parts of documentation, unexported some helpers (#80) - -## 0.9.1 (July 1, 2018) - -IMPROVEMENTS - -- RangeProof.ComputeRootHash() to compute root rather than provide as in Verify(hash) -- RangeProof.Verify\*() first require .Verify(root), which memoizes - -## 0.9.0 (July 1, 2018) - -BREAKING CHANGES - -- RangeProof.VerifyItem doesn't require an index. -- Only return values in range when getting proof. -- Return keys as well. - -BUG FIXES - -- traversal bugs in traverseRange. - -## 0.8.2 - -- Swap `tmlibs` for `tendermint/libs` -- Remove `sha256truncated` in favour of `tendermint/crypto/tmhash` - same hash - function but technically a breaking change to the API, though unlikely to effect anyone. - -NOTE this means IAVL is now dependent on Tendermint Core for the libs (since it -makes heavy use of the `db` package). Ideally, that dependency would be -abstracted away, and/or this repo will be merged into the Cosmos-SDK, which is -currently is primary consumer. Once it achieves greater stability, we could -consider breaking it out into it's own repo again. - -## 0.8.1 - -_July 1st, 2018_ - -BUG FIXES - -- fix bug in iterator going outside its range - -## 0.8.0 (June 24, 2018) - -BREAKING CHANGES - -- Nodes are encoded using proto3/amino style integers and byte slices (ie. varints and - varint prefixed byte slices) -- Unified RangeProof -- Proofs are encoded using Amino -- Hash function changed from RIPEMD160 to the first 20 bytes of SHA256 output - -## 0.7.0 (March 21, 2018) - -BREAKING CHANGES - -- LoadVersion and Load return the loaded version number - - NOTE: this behaviour was lost previously and we failed to document in changelog, - but now it's back :) - -## 0.6.1 (March 2, 2018) - -IMPROVEMENT - -- Remove spurious print statement from LoadVersion - -## 0.6.0 (March 2, 2018) - -BREAKING CHANGES - -- NewTree order of arguments swapped -- int -> int64, uint64 -> int64 -- NewNode takes a version -- Node serialization format changed so version is written right after size -- SaveVersion takes no args (auto increments) -- tree.Get -> tree.Get64 -- nodeDB.SaveBranch does not take a callback -- orphaningTree.SaveVersion -> SaveAs -- proofInnerNode includes Version -- ReadKeyXxxProof consolidated into ReadKeyProof -- KeyAbsentProof doesn't include Version -- KeyRangeProof.Version -> Versions - -FEATURES - -- Implement chunking algorithm to serialize entire tree - -## 0.5.0 (October 27, 2017) - -First versioned release! -(Originally accidentally released as v0.2.0) diff --git a/sei-iavl/CONTRIBUTING.md b/sei-iavl/CONTRIBUTING.md deleted file mode 100644 index f63efe6f6a..0000000000 --- a/sei-iavl/CONTRIBUTING.md +++ /dev/null @@ -1,12 +0,0 @@ -# Contributing - -Thank you for considering making contributions to IAVL+! -This repository follows the [contribution guidelines] of tendermint and the corresponding [coding repo]. -Please take a look if you are not already familiar with those. - -[contribution guidelines]: https://github.com/tendermint/tendermint/blob/master/CONTRIBUTING.md -[coding repo]: https://github.com/tendermint/coding - -## Protobuf - -Iavl utilizes [Protocol Buffers](https://developers.google.com/protocol-buffers) if used as a gRPC server. To generate the protobuf stubs have docker running locally and run `make proto-gen` diff --git a/sei-iavl/FORKED_CHANGELOG.md b/sei-iavl/FORKED_CHANGELOG.md deleted file mode 100644 index 3d5cae4cd6..0000000000 --- a/sei-iavl/FORKED_CHANGELOG.md +++ /dev/null @@ -1,22 +0,0 @@ -Forked from https://github.com/cosmos/iavl/tree/v0.19.4 -Last commit: -``` -commit f4499a9daed0a190a4df8d55950fb5d51c835bc9 (HEAD, tag: v0.19.4) -Author: Marko -Date: Fri Oct 28 00:37:21 2022 +0200 - - chore: changelog for 0.19.4 (#600) -``` - -# Changelog - - -## Current - 2023-01-26 - -### Bug Fixes - - -### Improvements - - -### Features diff --git a/sei-iavl/LICENSE b/sei-iavl/LICENSE deleted file mode 100644 index 084d3f719f..0000000000 --- a/sei-iavl/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright Cosmos-IAVL Authors - Copyright 2015 Tendermint - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/sei-iavl/PERFORMANCE.md b/sei-iavl/PERFORMANCE.md deleted file mode 100644 index b1acdd932b..0000000000 --- a/sei-iavl/PERFORMANCE.md +++ /dev/null @@ -1,111 +0,0 @@ -# Performance - -After some discussion with Jae on the usability, it seems performance is a big concern. If every write takes around 1ms, that puts a serious upper limit on the speed of the consensus engine (especially since with the check/tx dichotomy, we need at least two writes (to cache, only one to disk) and likely two or more queries to handle any transaction). - -As Jae notes: for CheckTx, a copy of IAVLTree doesn't need to be saved. During CheckTx it'll load inner nodes into the cache. The cache is shared w/ the AppendTx state IAVLTree, so during AppendTx we should save some time. There would only be 1 set of writes. Also, there's quite a bit of free time in between blocks as provided by Tendermint, during which CheckTx can run priming the cache, so hopefully this helps as well. - -Jae: That said, I'm not sure exactly what the tx throughput would be during normal running times. I'm hoping that we can have e.g. 3 second blocks w/ say over a hundred txs per sec per block w/ 1 million items. That will get us through for some time, but that time is limited. - -Ethan: I agree, and think this works now with goleveldb backing on most host machines. For public chains, maybe it is desired to push 1000 tx every 3 sec to a block, with a db size of 1 billion items. 10x the throughput with 1000x the data. That could be a long-term goal, and would scale to the cosmos and beyond. - -## Plan - -For any goal, we need some clear steps. - -1) Cleanup code, and write some more benchmark cases to capture "realistic" usage -2) Run tests on various hardware to see the best performing backing stores -3) Do profiling on the best performance to see if there are any easy performance gains -4) (Possibly) Write another implementation of merkle.Tree to improve all the memory overhead, consider CPU cache, etc.... -5) (Possibly) Write another backend datastore to persist the tree in a more efficient way - -The rest of this document is the planned or completed actions for the above-listed steps. - -## Cleanup - -Done in branch `cleanup_deps`: - * Fixed up dependeny management (tmlibs/db etc in glide/vendor) - * Updated Makefile (test, bench, get_deps) - * Fixed broken code - `looper.go` and one benchmark didn't run - -Benchmarks should be parameterized on: - 1) storage implementation - 2) initial data size - 3) length of keys - 4) length of data - 5) block size (frequency of copy/hash...) -Thus, we would see the same benchmark run against memdb with 100K items, goleveldb with 100K, leveldb with 100K, memdb with 10K, goleveldb with 10K... - -Scenarios to run after db is set up. - * Pure query time (known/hits, vs. random/misses) - * Write timing (known/updates, vs. random/inserts) - * Delete timing (existing keys only) - * TMSP Usage: - * For each block size: - * 2x copy "last commit" -> check and real - * repeat for each tx: - * (50% update + 50% insert?) - * query + insert/update in check - * query + insert/update in real - * get hash - * save real - * real -> "last commit" - - -## Benchmarks - -After writing the benchmarks, we can run them under various environments and store the results under benchmarks directory. Some useful environments to test: - - * Dev machines - * Digital ocean small/large machine - * Various AWS setups - -Please run the benchmark on more machines and add the result. Just type: `make record` in the directory and wait a (long) while (with little other load on the machine). - -This will require also a quick setup script to install go and run tests in these environments. Maybe some scripts even. Also, this will produce a lot of files and we may have to graph them to see something useful... - -But for starting, my laptop, and one digital ocean and one aws server should be sufficient. At least to find the winner, before profiling. - - -## Profiling - -Once we figure out which current implementation looks fastest, let's profile it to make it even faster. It is great to optimize the memdb code to really speed up the hashing and tree-building logic. And then focus on the backend implementation to optimize the disk storage, which will be the next major pain point. - -Some guides: - - * [Profiling benchmarks locally](https://medium.com/@hackintoshrao/daily-code-optimization-using-benchmarks-and-profiling-in-golang-gophercon-india-2016-talk-874c8b4dc3c5#.jmnd8w2qr) - * [On optimizing memory](https://signalfx.com/blog/a-pattern-for-optimizing-go-2/) - * [Profiling running programs](http://blog.ralch.com/tutorial/golang-performance-and-memory-analysis/) - * [Dave Chenny's profiler pkg](https://github.com/pkg/profile) - -Some ideas for speedups: - - * [Speedup SHA256 100x on ARM](https://blog.minio.io/accelerating-sha256-by-100x-in-golang-on-arm-1517225f5ff4#.pybt7bb3w) - * [Faster SHA256 golang implementation](https://github.com/minio/sha256-simd) - * [Data structure alignment](http://stackoverflow.com/questions/39063530/optimising-datastructure-word-alignment-padding-in-golang) - * [Slice alignment](http://blog.chewxy.com/2016/07/25/on-the-memory-alignment-of-go-slice-values/) - * [Tool to analyze your structs](https://github.com/dominikh/go-structlayout) - -## Tree Re-implementation - -If we want to copy lots of objects, it becomes better to think of using memcpy on large (eg. 4-16KB) buffers than copying individual structs. We also could allocate arrays of structs and align them to remove a lot of memory management and gc overhead. That means going down to some C-level coding... - -Some links for thought: - - * [Array representation of a binary tree](http://www.cse.hut.fi/en/research/SVG/TRAKLA2/tutorials/heap_tutorial/taulukkona.html) - * [Memcpy buffer size timing](http://stackoverflow.com/questions/21038965/why-does-the-speed-of-memcpy-drop-dramatically-every-4kb) - * [Calling memcpy from go](https://github.com/jsgilmore/shm/blob/master/memcpy.go) - * [Unsafe docs](https://godoc.org/unsafe) - * [...and how to use it](https://copyninja.info/blog/workaround-gotypesystems.html) - * [Or maybe just plain copy...](https://godoc.org/builtin#copy) - -## Backend implementation - -Storing each link in the tree in leveldb treats each node as an isolated item. Since we know some usage patterns (when a parent is hit, very likely one child will be hit), we could try to organize the memory and disk location of the nodes ourselves to make it more efficient. Or course, this could be a long, slippery slope. - -Inspired by the [Array representation](http://www.cse.hut.fi/en/research/SVG/TRAKLA2/tutorials/heap_tutorial/taulukkona.html) link above, we could consider other layouts for the nodes. For example, rather than store them alone, or the entire tree in one big array, the nodes could be placed in groups of 15 based on the parent (parent and 3 generations of children). Then we have 4 levels before jumping to another location. Maybe we just store this larger chunk as one leveldb location, or really try to do the mmap ourselves... - -In any case, assuming around 100 bytes for one non-leaf node (3 sha hashes, plus prefix, plus other data), 15 nodes would be a little less than 2K, maybe even go one more level to 31 nodes and 3-4KB, where we could take best advantage of the memory/disk page size. - -Some links for thought: - - * [Memory mapped files](https://github.com/edsrzf/mmap-go) diff --git a/sei-iavl/POEM b/sei-iavl/POEM deleted file mode 100644 index f361067a4d..0000000000 --- a/sei-iavl/POEM +++ /dev/null @@ -1,29 +0,0 @@ -writing down, my checksum -waiting for the, data to come -no need to pray for integrity -thats cuz I use, a merkle tree - -grab the root, with a quick hash run -if the hash works out, -it must have been done - -theres no need, for trust to arise -thanks to the crypto -now that I can merkleyes - -take that data, merklize -ye, I merklize ... - -then the truth, begins to shine -the inverse of a hash, you will never find -and as I watch, the dataset grow -producing a proof, is never slow - -Where do I find, the will to hash -How do I teach it? -It doesn't pay in cash -Bitcoin, here, I've realized -Thats what I need now, -cuz real currencies merklize - --EB diff --git a/sei-iavl/buf.gen.yaml b/sei-iavl/buf.gen.yaml deleted file mode 100644 index f47275752f..0000000000 --- a/sei-iavl/buf.gen.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# The version of the generation template. -# Required. -# The only currently-valid value is v1beta1. -version: v1beta1 - -# The plugins to run. -plugins: - # The name of the plugin. - - name: gogofaster - # The the relative output directory. - out: proto - # Any options to provide to the plugin. - opt: plugins=grpc,paths=source_relative - - - name: grpc-gateway - out: proto - opt: logtostderr=true,paths=source_relative diff --git a/sei-iavl/buf.yaml b/sei-iavl/buf.yaml deleted file mode 100644 index 11558c5e7a..0000000000 --- a/sei-iavl/buf.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: v1beta1 - -build: - roots: - - proto - - third_party -lint: - use: - - MINIMAL - - FILE_LOWER_SNAKE_CASE - - FILE_LAYOUT -breaking: - use: - - FILE diff --git a/sei-iavl/codecov.yml b/sei-iavl/codecov.yml deleted file mode 100644 index 9bf12242fb..0000000000 --- a/sei-iavl/codecov.yml +++ /dev/null @@ -1,28 +0,0 @@ -# -# This codecov.yml is the default configuration for -# all repositories on Codecov. You may adjust the settings -# below in your own codecov.yml in your repository. -# -codecov: - require_ci_to_pass: yes - -coverage: - precision: 2 - round: down - range: 70...100 - - status: - # Learn more at https://docs.codecov.io/docs/commit-status - project: - default: - threshold: 1% # allow this much decrease on project - -comment: - layout: "reach, diff, files, tree" - behavior: default # update if exists else create new - require_changes: true - -ignore: - - "docs" - - "benchmarks/" - - "**.pb.go" diff --git a/sei-iavl/docs/architecture/README.md b/sei-iavl/docs/architecture/README.md deleted file mode 100644 index ea59d1670f..0000000000 --- a/sei-iavl/docs/architecture/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Architecture Decision Records (ADR) - -This is a location to record all high-level architecture decisions for the Golang IAVL library. - -You can read more about the ADR concept in this [blog post](https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t). - -An ADR should provide: - -- Context on the relevant goals and the current state -- Proposed changes to achieve the goals -- Summary of pros and cons -- References -- Changelog - -Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and -justification for a change in architecture, or for the architecture of something new. The spec is -much more compressed and streamlined summary of everything as it stands today. - -If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, -and then modify the code to match. - -## ADR Table of Contents - -- [ADR 001: Flush Version](./adr-001-flush-version.md) diff --git a/sei-iavl/docs/architecture/adr-template.md b/sei-iavl/docs/architecture/adr-template.md deleted file mode 100644 index 657f85605a..0000000000 --- a/sei-iavl/docs/architecture/adr-template.md +++ /dev/null @@ -1,47 +0,0 @@ -# ADR {ADR-NUMBER}: {TITLE} - -## Changelog - -- {date}: {changelog} - -## Status - -> A decision may be "proposed" if the project stakeholders haven't agreed with it yet, or "accepted" -> once it is agreed. If a later ADR changes or reverses a decision, it may be marked as "deprecated" -> or "superseded" with a reference to its replacement. -> {Deprecated|Proposed|Accepted} - -## Context - -> This section describes the forces at play, including technological, political, social, and project -> local. These forces are probably in tension, and should be called out as such. The language in this -> section is value-neutral. It is simply describing facts. -> {context body} - -## Decision - -> This section describes our response to these forces. It is stated in full sentences, with active -> voice. "We will ...". -> {decision body} - -## Consequences - -> This section describes the resulting context, after applying the decision. All consequences should -> be listed here, not just the "positive" ones. A particular decision may have positive, negative, -> and neutral consequences, but all of them affect the team and project in the future. - -### Positive - -{positive consequences} - -### Negative - -{negative consequences} - -### Neutral - -{neutral consequences} - -## References - -- {reference link} diff --git a/sei-iavl/docs/node/key_format.md b/sei-iavl/docs/node/key_format.md deleted file mode 100644 index f180ce66eb..0000000000 --- a/sei-iavl/docs/node/key_format.md +++ /dev/null @@ -1,36 +0,0 @@ -# Key Format - -Nodes, orphans, and roots are stored under the database with different key formats to ensure there are no key collisions and a structured key from which we can extract useful information. - -### Nodes - -Node KeyFormat: `n|` - -Nodes are marshalled and stored under nodekey with prefix `n` to prevent collisions and then appended with the node's hash. - -### Orphans - -Orphan KeyFormat: `o|toVersion|fromVersion|hash` - -Orphans are marshalled nodes stored with prefix `o` to prevent collisions. You can extract the toVersion, fromVersion and hash from the orphan key by using: - -```golang -// orphanKey: o|50|30|0xABCD -var toVersion, fromVersion int64 -var hash []byte -orphanKeyFormat.Scan(orphanKey, &toVersion, &fromVersion, hash) - -/* -toVersion = 50 -fromVersion = 30 -hash = 0xABCD -*/ -``` - -The order of the orphan KeyFormat matters. Since deleting a version `v` will delete all orphans whose `toVersion = v`, we can easily retrieve all orphans from nodeDb by iterating over the key prefix: `o|v`. - -### Roots - -Root KeyFormat: `r|` - -Root hash of the IAVL tree at version `v` is stored under the key `r|v` (prefixed with `r` to avoid collision). diff --git a/sei-iavl/docs/node/node.md b/sei-iavl/docs/node/node.md deleted file mode 100644 index 24647fe1bf..0000000000 --- a/sei-iavl/docs/node/node.md +++ /dev/null @@ -1,133 +0,0 @@ -# Node - -The Node struct stores a node in the IAVL tree. - -### Structure - -```golang -// Node represents a node in a Tree. -type Node struct { - key []byte // key for the node. - value []byte // value of leaf node. If inner node, value = nil - version int64 // The version of the IAVL that this node was first added in. - height int8 // The height of the node. Leaf nodes have height 0 - size int64 // The number of leaves that are under the current node. Leaf nodes have size = 1 - hash []byte // hash of above field and leftHash, rightHash - leftHash []byte // hash of left child - leftNode *Node // pointer to left child - rightHash []byte // hash of right child - rightNode *Node // pointer to right child - persisted bool // persisted to disk -} -``` - -Inner nodes have keys equal to the highest key on their left branch and have values set to nil. - -The version of a node is the first version of the IAVL tree that the node gets added in. Future versions of the IAVL may point to this node if they also contain the node, however the node's version itself does not change. - -Size is the number of leaves under a given node. With a full subtree, `node.size = 2^(node.height)`. - -### Marshaling - -Every node is persisted by encoding the key, version, height, size and hash. If the node is a leaf node, then the value is persisted as well. If the node is not a leaf node, then the leftHash and rightHash are persisted as well. - -```golang -// Writes the node as a serialized byte slice to the supplied io.Writer. -func (node *Node) writeBytes(w io.Writer) error { - cause := encodeVarint(w, node.height) - if cause != nil { - return errors.Wrap(cause, "writing height") - } - cause = encodeVarint(w, node.size) - if cause != nil { - return errors.Wrap(cause, "writing size") - } - cause = encodeVarint(w, node.version) - if cause != nil { - return errors.Wrap(cause, "writing version") - } - - // Unlike writeHashBytes, key is written for inner nodes. - cause = encodeBytes(w, node.key) - if cause != nil { - return errors.Wrap(cause, "writing key") - } - - if node.isLeaf() { - cause = encodeBytes(w, node.value) - if cause != nil { - return errors.Wrap(cause, "writing value") - } - } else { - if node.leftHash == nil { - panic("node.leftHash was nil in writeBytes") - } - cause = encodeBytes(w, node.leftHash) - if cause != nil { - return errors.Wrap(cause, "writing left hash") - } - - if node.rightHash == nil { - panic("node.rightHash was nil in writeBytes") - } - cause = encodeBytes(w, node.rightHash) - if cause != nil { - return errors.Wrap(cause, "writing right hash") - } - } - return nil -} -``` - -### Hashes - -A node's hash is calculated by hashing the height, size, and version of the node. If the node is a leaf node, then the key and value are also hashed. If the node is an inner node, the leftHash and rightHash are included in hash but the key is not. - -```golang -// Writes the node's hash to the given io.Writer. This function expects -// child hashes to be already set. -func (node *Node) writeHashBytes(w io.Writer) error { - err := encodeVarint(w, node.height) - if err != nil { - return errors.Wrap(err, "writing height") - } - err = encodeVarint(w, node.size) - if err != nil { - return errors.Wrap(err, "writing size") - } - err = encodeVarint(w, node.version) - if err != nil { - return errors.Wrap(err, "writing version") - } - - // Key is not written for inner nodes, unlike writeBytes. - - if node.isLeaf() { - err = encodeBytes(w, node.key) - if err != nil { - return errors.Wrap(err, "writing key") - } - // Indirection needed to provide proofs without values. - // (e.g. proofLeafNode.ValueHash) - valueHash := tmhash.Sum(node.value) - err = encodeBytes(w, valueHash) - if err != nil { - return errors.Wrap(err, "writing value") - } - } else { - if node.leftHash == nil || node.rightHash == nil { - panic("Found an empty child hash") - } - err = encodeBytes(w, node.leftHash) - if err != nil { - return errors.Wrap(err, "writing left hash") - } - err = encodeBytes(w, node.rightHash) - if err != nil { - return errors.Wrap(err, "writing right hash") - } - } - - return nil -} -``` diff --git a/sei-iavl/docs/node/nodedb.md b/sei-iavl/docs/node/nodedb.md deleted file mode 100644 index 2224d35cb6..0000000000 --- a/sei-iavl/docs/node/nodedb.md +++ /dev/null @@ -1,56 +0,0 @@ -# NodeDB - -### Structure - -The nodeDB is responsible for persisting nodes, orphans, and roots correctly in persistent storage. - -### Saving Versions - -The nodeDB saves the roothash of the IAVL tree under the key: `r|`. - -It marshals and saves any new node that has been created under: `n|`. For more details on how the node gets marshaled, see [node documentation](./node.md). Any old node that is still part of the latest IAVL tree will not get rewritten. Instead its parent will simply have a hash pointer with which the nodeDB can retrieve the old node if necessary. - -Any old nodes that were part of the previous version IAVL but are no longer part of this one have been saved in an orphan map `orphan.hash => orphan.version`. This map will get passed into the nodeDB's `SaveVersion` function. The map maps from the orphan's hash to the version that it was added to the IAVL tree. The nodeDB iterates through this map and stores each marshalled orphan node under the key: `o|toVersion|fromVersion`. Since the toVersion is always the previous version (if we are saving version `v`, toVersion of all new orphans is `v-1`), we can save the orphans by iterating over the map and saving: `o|(latestVersion-1)|orphan.fromVersion => orphan.hash`. - -(For more details on key formats see the [keyformat docs](./key_format.md)) - -### Deleting Versions - -When a version `v` is deleted, the roothash corresponding to version `v` is deleted from nodeDB. All orphans whose `toVersion = v`, will get the `toVersion` pushed back to the highest predecessor of `v` that still exists in nodeDB. If the `toVersion <= fromVersion` then this implies that there does not exist a version of the IAVL tree in the nodeDB that still contains this node. Thus, it can be safely deleted and uncached. - -##### Deleting Orphans - -The deleteOrphans algorithm is shown below: - -```golang -// deleteOrphans deletes orphaned nodes from disk, and the associated orphan -// entries. -func (ndb *nodeDB) deleteOrphans(version int64) { - // Will be zero if there is no previous version. - predecessor := ndb.getPreviousVersion(version) - - // Traverse orphans with a lifetime ending at the version specified. - ndb.traverseOrphansVersion(version, func(key, hash []byte) { - var fromVersion, toVersion int64 - - // See comment on `orphanKeyFmt`. Note that here, `version` and - // `toVersion` are always equal. - orphanKeyFormat.Scan(key, &toVersion, &fromVersion) - - // Delete orphan key and reverse-lookup key. - ndb.batch.Delete(key) - - // If there is no predecessor, or the predecessor is earlier than the - // beginning of the lifetime (ie: negative lifetime), or the lifetime - // spans a single version and that version is the one being deleted, we - // can delete the orphan. Otherwise, we shorten its lifetime, by - // moving its endpoint to the previous version. - if predecessor < fromVersion || fromVersion == toVersion { - ndb.batch.Delete(ndb.nodeKey(hash)) - ndb.uncacheNode(hash) - } else { - ndb.saveOrphan(hash, fromVersion, predecessor) - } - }) -} -``` diff --git a/sei-iavl/docs/overview.md b/sei-iavl/docs/overview.md deleted file mode 100644 index 02f32fc406..0000000000 --- a/sei-iavl/docs/overview.md +++ /dev/null @@ -1,42 +0,0 @@ -# IAVL Spec - -The IAVL tree is a versioned, snapshottable (immutable) AVL+ tree for persistent data. - -The purpose of this data structure is to provide persistent storage for key-value pairs (say to store account balances) such that a deterministic merkle root hash can be computed. The tree is balanced using a variant of the [AVL algorithm](http://en.wikipedia.org/wiki/AVL_tree) so all operations are O(log(n)). - -Nodes of this tree are immutable and indexed by their hash. Thus any node serves as an immutable snapshot which lets us stage uncommitted transactions from the mempool cheaply, and we can instantly roll back to the last committed state to process transactions of a newly committed block (which may not be the same set of transactions as those from the mempool). - -In an AVL tree, the heights of the two child subtrees of any node differ by at most one. Whenever this condition is violated upon an update, the tree is rebalanced by creating O(log(n)) new nodes that point to unmodified nodes of the old tree. In the original AVL algorithm, inner nodes can also hold key-value pairs. The AVL+ algorithm (note the plus) modifies the AVL algorithm to keep all values on leaf nodes, while only using branch-nodes to store keys. This simplifies the algorithm while keeping the merkle hash trail short. - -The IAVL tree will typically be wrapped by a `MutableTree` to enable updates to the tree. Any changes between versions get persisted to disk while nodes that exist in both the old version and new version are simply pointed to by the respective tree without duplicated the node data. - -When a node is no longer part of the latest IAVL tree, it is called an orphan. The orphaned node will exist in the nodeDB so long as there are versioned IAVL trees that are persisted in nodeDB that contain the orphaned node. Once all trees that referred to orphaned node have been deleted from database, the orphaned node will also get deleted. - -In Ethereum, the analog is [Patricia tries](http://en.wikipedia.org/wiki/Radix_tree). There are tradeoffs. Keys do not need to be hashed prior to insertion in IAVL+ trees, so this provides faster iteration in the key space which may benefit some applications. The logic is simpler to implement, requiring only two types of nodes -- inner nodes and leaf nodes. On the other hand, while IAVL+ trees provide a deterministic merkle root hash, it depends on the order of transactions. In practice this shouldn't be a problem, since you can efficiently encode the tree structure when serializing the tree contents. - -### Suggested Order for Understanding IAVL - -1. [Node docs](./node/node.md) - - Explains node structure - - Explains how node gets marshalled and hashed -2. [KeyFormat docs](./node/key_format.md) - - Explains keyformats for how nodes, orphans, and roots are stored under formatted keys in database -3. [NodeDB docs](./node/nodedb.md): - - Explains how nodes, orphans, roots get saved in database - - Explains saving and deleting tree logic. -4. [ImmutableTree docs](./tree/immutable_tree.md) - - Explains ImmutableTree structure - - Explains ImmutableTree Iteration functions -5. [MutableTree docs](./tree/mutable_tree.md) - - Explains MutableTree structure - - Explains how to make updates (set/delete) to current working tree of IAVL - - Explains how automatic rebalancing of IAVL works - - Explains how Saving and Deleting versions of IAVL works -6. [Proof docs](./proof/proof.md) - - Explains what Merkle proofs are - - Explains how IAVL supports presence, absence, and range proofs - - Explains the IAVL proof data structures -7. [Export/import docs](./tree/export_import.md) - - Explains the overall export/import functionality - - Explains the `ExportNode` format for exported nodes - - Explains the algorithms for exporting and importing nodes \ No newline at end of file diff --git a/sei-iavl/docs/proof/proof.md b/sei-iavl/docs/proof/proof.md deleted file mode 100644 index ad4617ddd2..0000000000 --- a/sei-iavl/docs/proof/proof.md +++ /dev/null @@ -1,347 +0,0 @@ -# Proofs - -What sets IAVL apart from most other key/value stores is the ability to return -[Merkle proofs](https://en.wikipedia.org/wiki/Merkle_tree) along with values. These proofs can -be used to verify that a returned value is, in fact, the value contained within a given IAVL tree. -This verification is done by comparing the proof's root hash with the tree's root hash. - -Somewhat simplified, an IAVL tree is a variant of a -[binary search tree](https://en.wikipedia.org/wiki/Binary_search_tree) where inner nodes contain -keys used for binary search, and leaf nodes contain the actual key/value pairs ordered by key. -Consider the following example, containing five key/value pairs (such as key `a` with value `1`): - -``` - d - / \ - c e - / \ / \ - b c=3 d=4 e=5 - / \ -a=1 b=2 -``` - -In reality, IAVL nodes contain more data than shown here - for details please refer to the -[node documentation](../node/node.md). However, this simplified version is sufficient for an -overview. - -A cryptographically secure hash is generated for each node in the tree by hashing the node's key -and value (if leaf node), version, and height, as well as the hashes of each direct child (if -any). This implies that the hash of any given node also depends on the hashes of all descendants -of the node. In turn, this implies that the hash of the root node depends on the hashes of all -nodes (and therefore all data) in the tree. - -If we fetch the value `a=1` from the tree and want to verify that this is the correct value, we -need the following information: - -``` - d - / \ - c hash=d6f56d - / \ - b hash=ec6088 - / \ -a,hash(1) hash=92fd030 -``` - -Note that we take the hash of the value of `a=1` instead of simply using the value `1` itself; -both would work, but the value can be arbitrarily large while the hash has a constant size. - -With this data, we are able to compute the hashes for all nodes up to and including the root, -and can compare this root hash with the root hash of the IAVL tree - if they match, we can be -reasonably certain that the provided value is the same as the value in the tree. This data is -therefore considered a _proof_ for the value. Notice how we don't need to include any data from -e.g. the `e`-branch of the tree at all, only the hash - as the tree grows in size, these savings -become very significant, requiring only `logâ‚‚(n)` hashes for a tree of `n` keys. - -However, this still introduces quite a bit of overhead. Since we usually want to fetch several -values from the tree and verify them, it is often useful to generate a _range proof_, which can -prove any and all key/value pairs within a contiguous, ordered key range. For example, the -following proof can verify both `a=1`, `b=2`, and `c=3`: - -``` - d - / \ - c hash=d6f56d - / \ - b c,hash(3) - / \ -a,hash(1) b,hash(2) -``` - -Range proofs can also prove the _absence_ of any keys within the range. For example, the above -proof can prove that the key `ab` is not in the tree, because if it was it would have to be -ordered between `a` and `b` - it is clear from the proof that there is no such node, and if -there was it would cause the parent hashes to be different from what we see. - -Range proofs can be generated for non-existant endpoints by including the nearest neighboring -keys, which allows them to cover any arbitrary key range. This can also be used to generate an -absence proof for a _single_ non-existant key, by returning a range proof between the two nearest -neighbors. The range proof is therefore a complete proof for all existing and all absent key/value -pairs ordered between two arbitrary endpoints. - -Note that the IAVL terminology for range proofs may differ from that used in other systems, where -it refers to proofs that a value lies within some interval without revealing the exact value. IAVL -range proofs are used to prove which key/value pairs exist (or not) in some key range, and may be -known as range queries elsewhere. - -## API Overview - -The following is a general overview of the API - for details, see the -[API reference](https://pkg.go.dev/github.com/cosmos/iavl). - -As an example, we will be using the same IAVL tree as described in the introduction: - -``` - d - / \ - c e - / \ / \ - b c=3 d=4 e=5 - / \ -a=1 b=2 -``` - -This tree can be generated as follows: - -```go -package main - -import ( - "fmt" - "log" - - "github.com/cosmos/iavl" - db "github.com/tendermint/tm-db" -) - -func main() { - tree, err := iavl.NewMutableTree(db.NewMemDB(), 0) - if err != nil { - log.Fatal(err) - } - - tree.Set([]byte("e"), []byte{5}) - tree.Set([]byte("d"), []byte{4}) - tree.Set([]byte("c"), []byte{3}) - tree.Set([]byte("b"), []byte{2}) - tree.Set([]byte("a"), []byte{1}) - - rootHash, version, err := tree.SaveVersion() - if err != nil { - log.Fatal(err) - } - fmt.Printf("Saved version %v with root hash %x\n", version, rootHash) - - // Output tree structure, including all node hashes (prefixed with 'n') - fmt.Println(tree.String()) -} -``` - -### Tree Root Hash - -Proofs are verified against the root hash of an IAVL tree. This root hash is retrived via -`MutableTree.Hash()` or `ImmutableTree.Hash()`, returning a `[]byte` hash. It is also returned by -`MutableTree.SaveVersion()`, as shown above. - -```go -fmt.Printf("%x\n", tree.Hash()) -// Outputs: dd21329c026b0141e76096b5df395395ae3fc3293bd46706b97c034218fe2468 -``` - -### Generating Proofs - -The following methods are used to generate proofs, all of which are of type `RangeProof`: - -* `ImmutableTree.GetWithProof(key []byte)`: fetches the key's value (if it exists) along with a - proof of existence or proof of absence. - -* `ImmutableTree.GetRangeWithProof(start, end []byte, limit int)`: fetches the keys, values, and - proofs for the given key range, optionally with a limit (end key is excluded). - -* `MutableTree.GetVersionedWithProof(key []byte, version int64)`: like `GetWithProof()`, but for a - specific version of the tree. - -* `MutableTree.GetVersionedRangeWithProof(key []byte, version int64)`: like `GetRangeWithProof()`, - but for a specific version of the tree. - -### Verifying Proofs - -The following `RangeProof` methods are used to verify proofs: - -* `Verify(rootHash []byte)`: verify that the proof root hash matches the given tree root hash. - -* `VerifyItem(key, value []byte)`: verify that the given key exists with the given value, according - to the proof. - -* `VerifyAbsent(key []byte)`: verify that the given key is absent, according to the proof. - -To verify that a `RangeProof` is valid for a given IAVL tree (i.e. that the proof root hash matches -the tree root hash), run `RangeProof.Verify()` with the tree's root hash: - -```go -// Generate a proof for a=1 -value, proof, err := tree.GetWithProof([]byte("a")) -if err != nil { - log.Fatal(err) -} - -// Verify that the proof's root hash matches the tree's -err = proof.Verify(tree.Hash()) -if err != nil { - log.Fatalf("Invalid proof: %v", err) -} -``` - -The proof must always be verified against the root hash with `Verify()` before attempting other -operations. The proof can also be verified manually with `RangeProof.ComputeRootHash()`: - -```go -if !bytes.Equal(proof.ComputeRootHash(), tree.Hash()) { - log.Fatal("Proof hash mismatch") -} -``` - -To verify that a key has a given value according to the proof, use `VerifyItem()` on a proof -generated for this key (or key range): - -```go -// The proof was generated for the item a=1, so this is successful -err = proof.VerifyItem([]byte("a"), []byte{1}) -fmt.Printf("prove a=1: %v\n", err) -// outputs nil - -// If we instead claim that a=2, the proof will error -err = proof.VerifyItem([]byte("a"), []byte{2}) -fmt.Printf("prove a=2: %v\n", err) -// outputs "leaf value hash not same: invalid proof" - -// Also, verifying b=2 errors even though it is correct, since the proof is for a=1 -err = proof.VerifyItem([]byte("b"), []byte{2}) -fmt.Printf("prove b=2: %v\n", err) -// outputs "leaf key not found in proof: invalid proof" -``` - -If we generate a proof for a range of keys, we can use this both to prove the value of any of the -keys in the range as well as the absence of any keys that would have been within it: - -```go -// Note that the end key is not inclusive, so c is not in the proof. 0 means -// no key limit (all keys). -keys, values, proof, err := tree.GetRangeWithProof([]byte("a"), []byte("c"), 0) -if err != nil { - log.Fatal(err) -} - -err = proof.Verify(tree.Hash()) -if err != nil { - log.Fatal(err) -} - -// Prove that a=1 is in the range -err = proof.VerifyItem([]byte("a"), []byte{1}) -fmt.Printf("prove a=1: %v\n", err) -// outputs nil - -// Prove that b=2 is also in the range -err = proof.VerifyItem([]byte("b"), []byte{2}) -fmt.Printf("prove b=2: %v\n", err) -// outputs nil - -// Since "ab" is ordered after "a" but before "b", we can prove that it -// is not in the range and therefore not in the tree at all -err = proof.VerifyAbsence([]byte("ab")) -fmt.Printf("prove no ab: %v\n", err) -// outputs nil - -// If we try to prove ab, we get an error: -err = proof.VerifyItem([]byte("ab"), []byte{0}) -fmt.Printf("prove ab=0: %v\n", err) -// outputs "leaf key not found in proof: invalid proof" -``` - -### Proof Structure - -The overall proof structure was described in the introduction. Here, we will have a look at the -actual data structure. Knowledge of this is not necessary to use proofs. It may also be useful -to have a look at the [`Node` data structure](../node/node.md). - -Recall our example tree: - -``` - d - / \ - c e - / \ / \ - b c=3 d=4 e=5 - / \ -a=1 b=2 -``` - -A `RangeProof` contains the following data, as well as JSON tags for serialization: - -```go -type RangeProof struct { - LeftPath PathToLeaf `json:"left_path"` - InnerNodes []PathToLeaf `json:"inner_nodes"` - Leaves []ProofLeafNode `json:"leaves"` -} -``` - -* `LeftPath` contains the path to the leftmost node in the proof. For a proof of the range `a` to - `e` (excluding `e=5`), it contains information about the inner nodes `d`, `c`, and `b` in that - order. - -* `InnerNodes` contains paths with any additional inner nodes not already in `LeftPath`, with `nil` - paths for nodes already traversed. For a proof of the range `a` to `e` (excluding `e=5`), this - contains the paths `nil`, `nil`, `[e]` where the `nil` paths refer to the paths to `b=2` and - `c=3` already traversed in `LeftPath`, and `[e]` contains data about the `e` inner node needed - to prove `d=4`. - -* `Leaves` contains data about the leaf nodes in the range. For the range `a` to `e` (exluding - `e=5`) this contains info about `a=1`, `b=2`, `c=3`, and `d=4` in left-to-right order. - -Note that `Leaves` may contain additional leaf nodes outside the requested range, for example to -satisfy absence proofs if a given key does not exist. This may require additional inner nodes -to be included as well. - -`PathToLeaf` is simply a slice of `ProofInnerNode`: - -```go -type PathToLeaf []ProofInnerNode -``` - -Where `ProofInnerNode` contains the following data (a subset of the [node data](../node/node.md)): - -```go -type ProofInnerNode struct { - Height int8 `json:"height"` - Size int64 `json:"size"` - Version int64 `json:"version"` - Left []byte `json:"left"` - Right []byte `json:"right"` -} -``` - -Unlike in our diagrams, the key of the inner nodes are not actually part of the proof. This is -because they are only used to guide binary searches and do not necessarily correspond to actual keys -in the data set, and are thus not included in any hashes. - -Similarly, `ProofLeafNode` contains a subset of leaf node data: - -```go -type ProofLeafNode struct { - Key cmn.HexBytes `json:"key"` - ValueHash cmn.HexBytes `json:"value"` - Version int64 `json:"version"` -} -``` - -Notice how the proof contains a hash of the node's value rather than the value itself. This is -because values can be arbitrarily large while the hash has a constant size. The Merkle hashes of -the tree are computed in the same way, by hashing the value before including it in the node -hash. - -The information in these proofs is sufficient to reasonably prove that a given value exists (or -does not exist) in a given version of an IAVL dataset without fetching the entire dataset, requiring -only `logâ‚‚(n)` hashes for a dataset of `n` items. For more information, please see the -[API reference](https://pkg.go.dev/github.com/cosmos/iavl). \ No newline at end of file diff --git a/sei-iavl/docs/tree/export_import.md b/sei-iavl/docs/tree/export_import.md deleted file mode 100644 index 0bbd22486a..0000000000 --- a/sei-iavl/docs/tree/export_import.md +++ /dev/null @@ -1,64 +0,0 @@ -# Export/Import - -A single `ImmutableTree` (i.e. a single version) can be exported via `ImmutableTree.Export()`, returning an iterator over `ExportNode` items. These nodes can be imported into an empty `MutableTree` with `MutableTree.Import()` to recreate an identical tree. The structure of `ExportNode` is: - -```go -type ExportNode struct { - Key []byte - Value []byte - Version int64 - Height int8 -} -``` - -This is the minimum amount of data about nodes that can be exported, see the [node documentation](../node/node.md) for comparison. The other node attributes, such as `hash` and `size`, can be derived from this data. Both leaf nodes and inner nodes are exported, since `Version` is part of the hash and inner nodes have different versions than the leaf nodes with the same key. - -The order of exported nodes is significant. Nodes are exported by depth-first post-order (LRN) tree traversal. Consider the following tree (with nodes in `key@version=value` format): - -``` - d@3 - / \ - c@3 e@3 - / \ / \ - b@3 c@3=3 d@2=4 e@3=5 - / \ -a@1=1 b@3=2 - -``` - -This would produce the following export: - -```go -[]*ExportNode{ - {Key: []byte("a"), Value: []byte{1}, Version: 1, Height: 0}, - {Key: []byte("b"), Value: []byte{2}, Version: 3, Height: 0}, - {Key: []byte("b"), Value: nil, Version: 3, Height: 1}, - {Key: []byte("c"), Value: []byte{3}, Version: 3, Height: 0}, - {Key: []byte("c"), Value: nil, Version: 3, Height: 2}, - {Key: []byte("d"), Value: []byte{4}, Version: 2, Height: 0}, - {Key: []byte("e"), Value: []byte{5}, Version: 3, Height: 0}, - {Key: []byte("e"), Value: nil, Version: 3, Height: 1}, - {Key: []byte("d"), Value: nil, Version: 3, Height: 3}, -} -``` - -When importing, the tree must be rebuilt in the same order, such that the missing attributes (e.g. `hash` and `size`) can be generated. This is possible because children are always given before their parents. We can therefore first generate the hash and size of the left and right leaf nodes, and then use these to recursively generate the hash and size of the parent. - -One way to do this is to keep a stack of orphaned children, and then pop those children once we build their parent, which then becomes a new child on the stack. We know that we encounter a parent because its height is higher than the child or children on top of the stack. We need a stack because we may need to recursively build a right branch while holding an orphaned left child. For the above export this would look like the following (in `key:height=value` format): - -``` -| Stack | Import node | -|-----------------|-------------------------------------------------------------| -| | {Key: []byte("a"), Value: []byte{1}, Version: 1, Height: 0} | -| a:0=1 | {Key: []byte("b"), Value: []byte{2}, Version: 3, Height: 0} | -| a:0=1,b:0=2 | {Key: []byte("b"), Value: nil, Version: 3, Height: 1} | -| b:1 | {Key: []byte("c"), Value: []byte{3}, Version: 3, Height: 0} | -| b:1,c:0=3 | {Key: []byte("c"), Value: nil, Version: 3, Height: 2} | -| c:2 | {Key: []byte("d"), Value: []byte{4}, Version: 2, Height: 0} | -| c:2,d:0=4 | {Key: []byte("e"), Value: []byte{5}, Version: 3, Height: 0} | -| c:2,d:0=4,e:0=5 | {Key: []byte("e"), Value: nil, Version: 3, Height: 1} | -| c:2,e:1 | {Key: []byte("d"), Value: nil, Version: 3, Height: 3} | -| d:3 | | -``` - -At the end, there will be a single node left on the stack, which is the root node of the tree. \ No newline at end of file diff --git a/sei-iavl/docs/tree/immutable_tree.md b/sei-iavl/docs/tree/immutable_tree.md deleted file mode 100644 index 0f7154100b..0000000000 --- a/sei-iavl/docs/tree/immutable_tree.md +++ /dev/null @@ -1,69 +0,0 @@ -# Immutable Tree - -### Structure - -The Immutable tree struct contains an IAVL version. - -```golang -type ImmutableTree struct { - root *Node - ndb *nodeDB - version int64 -} -``` - -Using the root and the nodeDB, the ImmutableTree can retrieve any node that is a part of the IAVL tree at this version. - -Users can get information about the IAVL tree by calling getter functions such as `Size()` and `Height()` which will return the tree's size and height by querying the root node's size and height. - -### Get - -Users can get values by specifying the key or the index of the leaf node they want to get value for. - -Get by key will return both the index and the value. - -```golang -// Get returns the index and value of the specified key if it exists, or nil -// and the next index, if it doesn't. -func (t *ImmutableTree) Get(key []byte) (index int64, value []byte) { - if t.root == nil { - return 0, nil - } - return t.root.get(t, key) -} -``` - -Get by index will return both the key and the value. The index is the index in the list of leaf nodes sorted lexicographically by key. The leftmost leaf has index 0. It's neighbor has index 1 and so on. - -```golang -// GetByIndex gets the key and value at the specified index. -func (t *ImmutableTree) GetByIndex(index int64) (key []byte, value []byte) { - if t.root == nil { - return nil, nil - } - return t.root.getByIndex(t, index) -} -``` - -### Iterating - -Iteration works by traversing from the root node. All iteration functions are provided a callback function `func(key, value []byte) (stop bool`). This callback is called on every leaf node's key and value in order of the iteration. If the callback returns true, then the iteration stops. Otherwise it continues. - -Thus the callback is useful both as a way to run some logic on every key-value pair stored in the IAVL and as a way to dynamically stop the iteration. - -The `IterateRange` functions allow users to iterate over a specific range and specify if the iteration should be in ascending or descending order. - -The API's for Iteration functions are shown below. - -```golang -// Iterate iterates over all keys of the tree, in order. -func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool) - -// IterateRange makes a callback for all nodes with key between start and end non-inclusive. -// If either are nil, then it is open on that side (nil, nil is the same as Iterate) -func (t *ImmutableTree) IterateRange(start, end []byte, ascending bool, fn func(key []byte, value []byte) bool) (stopped bool) - -// IterateRangeInclusive makes a callback for all nodes with key between start and end inclusive. -// If either are nil, then it is open on that side (nil, nil is the same as Iterate) -func (t *ImmutableTree) IterateRangeInclusive(start, end []byte, ascending bool, fn func(key, value []byte, version int64) bool) (stopped bool) -``` diff --git a/sei-iavl/docs/tree/mutable_tree.md b/sei-iavl/docs/tree/mutable_tree.md deleted file mode 100644 index 86080a1d09..0000000000 --- a/sei-iavl/docs/tree/mutable_tree.md +++ /dev/null @@ -1,384 +0,0 @@ -# Mutable Tree - -### Structure - -The MutableTree struct is a wrapper around ImmutableTree to allow for updates that get stored in successive versions. - -The MutableTree stores the last saved ImmutableTree and the current working tree in its struct while all other saved, available versions are accessible from the nodeDB. - -```golang -// MutableTree is a persistent tree which keeps track of versions. -type MutableTree struct { - *ImmutableTree // The current, working tree. - lastSaved *ImmutableTree // The most recently saved tree. - orphans map[string]int64 // Nodes removed by changes to working tree. - versions map[int64]bool // The previous, saved versions of the tree. - ndb *nodeDB -} -``` - -The versions map stores which versions of the IAVL are stored in nodeDB. Anytime a version `v` gets persisted, `versions[v]` is set to `true`. Anytime a version gets deleted, `versions[v]` is set to false. - -### Set - -Set can be used to add a new key-value pair to the IAVL tree, or to update an existing key with a new value. - -Set starts at the root of the IAVL tree, if the key is less than or equal to the root key, it recursively calls set on root's left child. Else, it recursively calls set on root's right child. It continues to recurse down the IAVL tree based on comparing the set key and the node key until it reaches a leaf node. - -If the leaf node has the same key as the set key, then the set is just updating an existing key with a new value. The value is updated, and the old version of the node is orphaned. - -If the leaf node does not have the same key as the set key, then the set is trying to add a new key to the IAVL tree. The leaf node is replaced by an inner node that has the original leaf node and the new node from the set call as its children. - -If the `setKey` < `leafKey`: - -```golang -// new leaf node that gets created by Set -// since this is a new update since latest saved version, -// this node has version=latestVersion+1 -newVersion := latestVersion+1 -newNode := NewNode(key, value, newVersion) -// original leaf node: originalLeaf gets replaced by inner node below -Node{ - key: setKey, // inner node key is equal to left child's key - height: 1, // height=1 since node is parent of leaves - size: 2, // 2 leaf nodes under this node - leftNode: newNode, // left Node is the new added leaf node - rightNode: originalLeaf, // right Node is the original leaf node - version: newVersion, // inner node is new since lastVersion, so it has an incremented version -} -``` - -If `setKey` > `leafKey`: - -```golang -// new leaf node that gets created by Set -// since this is a new update since latest saved version, -// this node has version=latestVersion+1 -newVersion := latestVersion+1 -newNode := NewNode(key, value, latestVersion+1) -// original leaf node: originalLeaf gets replaced by inner node below -Node{ - key: leafKey, // inner node key is equal to left child's key - height: 1, // height=1 since node is parent of leaves - size: 2, // 2 leaf nodes under this node - leftNode: originalLeaf, // left Node is the original leaf node - rightNode: newNode, // right Node is the new added leaf node - version: newVersion, // inner node is new since lastVersion, so it has an incremented version -} -``` - -Any node that gets recursed upon during a Set call is necessarily orphaned since it will either have a new value (in the case of an update) or it will have a new descendant. The recursive calls accumulate a list of orphans as it descends down the IAVL tree. This list of orphans is ultimately added to the mutable tree's orphan list at the end of the Set call. - -After each set, the current working tree has its height and size recalculated. If the height of the left branch and right branch of the working tree differs by more than one, then the mutable tree has to be balanced before the Set call can return. - -### Remove - -Remove is another recursive function to remove a key-value pair from the IAVL pair. If the key that is trying to be removed does not exist, Remove is a no-op. - -Remove recurses down the IAVL tree in the same way that Set does until it reaches a leaf node. If the leaf node's key is equal to the remove key, the node is removed, and all of its parents are recursively updated. If not, the remove call does nothing. - -#### Recursive Remove - -Remove works by calling an inner function `recursiveRemove` that returns the following values after a recursive call `recursiveRemove(recurseNode, removeKey)`: - -##### NewHash - -If a node in recurseNode's subtree gets removed, then the hash of the recurseNode will change. Thus during the recursive calls down the subtree, all of recurseNode's children will return their new hashes after the remove (if they have changed). Using this information, recurseNode can calculate its own updated hash and return that value. - -If recurseNode is the node getting removed itself, NewHash is `nil`. - -##### ReplaceNode - -Just like with recursiveSet, any node that gets recursed upon (in a successful remove) will get orphaned since its hash must be updated and the nodes are immutable. Thus, ReplaceNode is the new node that replaces `recurseNode`. - -If recurseNode is the leaf that gets removed, then ReplaceNode is `nil`. - -If recurseNode is the direct parent of the leaf that got removed, then it can simply be replaced by the other child. Since the parent of recurseNode can directly refer to recurseNode's remaining child. For example if recurseNode's left child gets removed, the following happens: - - -Before LeftLeaf removed: -``` - |---RightLeaf -IAVLTREE---recurseNode--| - |---LeftLeaf -``` - -After LeftLeaf removed: -``` -IAVLTREE---RightLeaf - -ReplaceNode = RightLeaf -orphaned = [LeftLeaf, recurseNode] -``` - -If recurseNode is an inner node that got called in the recursiveRemove, but is not a direct parent of the removed leaf. Then an updated version of the node will exist in the tree. Notably, it will have an incremented version, a new hash (as explained in the `NewHash` section), and recalculated height and size. - -The ReplaceNode will be a cloned version of `recurseNode` with an incremented version. The hash will be updated given the NewHash of recurseNode's left child or right child (depending on which branch got recurse upon). - -The height and size of the ReplaceNode will have to be calculated since these values can change after the `remove`. - -It's possible that the subtree for `ReplaceNode` will have to be rebalanced (see `Balance` section). If this is the case, this will also update `ReplaceNode`'s hash since the structure of `ReplaceNode`'s subtree will change. - -##### LeftmostLeafKey - -The LeftmostLeafKey is the key of the leftmost leaf of `recurseNode`'s subtree. This is only used if `recurseNode` is the right child of its parent. Since inner nodes should have their key equal to the leftmost key of their right branch (if leftmostkey is not `nil`). If recurseNode is the right child of its parent `parentNode`, `parentNode` will set its key to `parentNode.key = leftMostKeyOfRecurseNodeSubTree`. - -If `recurseNode` is a leaf, it will return `nil`. - -If `recurseNode` is a parent of the leaf that got removed, it will return its own key if the left child was removed. If the right child is removed, it will return `nil`. - -If `recurseNode` is a generic inner node that isn't a direct parent of the removed node, it will return the leftmost key of its child's recursive call if `node.key < removeKey`. It will return `nil` otherwise. - -If `removeKey` does not exist in the IAVL tree, leftMostKey is `nil` for entire recursive stack. - -##### RemovedValue - -RemovedValue is the value that was at the node that was removed. It does not get changed as it travels up the recursive stack. - -If `removeKey` does not exist in the IAVL tree, RemovedValue is `nil`. - -##### Orphans - -Just like `recursiveSet`, any node that gets recursed upon by `recursiveRemove` in a successful `Remove` call will have to be orphaned. The Orphans list in `recursiveRemove` accumulates the list of orphans so that it can return them to `Remove`. `Remove` will then iterate through this list and add all the orphans to the mutable tree's `orphans` map. - -If the `removeKey` does not exist in the IAVL tree, then the orphans list is `nil`. - -### Balance - -Anytime a node is unbalanced such that the height of its left branch and the height of its right branch differs by more than 1, the IAVL tree will rebalance itself. - -This is acheived by rotating the subtrees until there is no more than one height difference between two branches of any subtree in the IAVL. - -Since Balance is mutating the structure of the tree, any displaced nodes will be orphaned. - -#### RotateRight - -To rotate right on a node `rotatedNode`, we first orphan its left child. We clone the left child to create a new node `newNode`. We set `newNode`'s right hash and child to the `rotatedNode`. We now set `rotatedNode`'s left child to be the old right child of `newNode`. - -Visualization (Nodes are numbered to show correct key order is still preserved): - -Before `RotateRight(node8)`: -``` - |---9 -8---| - | |---7 - | |---6 - | | |---5 - |---4 - | |---3 - |---2 - |---1 -``` - -After `RotateRight(node8)`: -``` - |---9 - |---8 - | | |---7 - | |---6 - | |---5 -4'---| - | |---1 - |---2 - |---3 - -Orphaned: 4 -``` - -Note that the key order for subtrees is still preserved. - -#### RotateLeft - -Similarly, to rotate left on a node `rotatedNode` we first orphan its right child. We clone the right child to create a new node `newNode`. We set the `newNode`'s left hash and child to the `rotatedNode`. We then set the `rotatedNode`'s right child to be the old left child of the node. - -Before `RotateLeft(node2)`: -``` - |---9 - |---8 - | |---7 - |---6 - | | |---5 - | |---4 - | |---3 -2---| - |---1 -``` - -After `RotateLeft(node2)`: -``` - |---9 - |---8 - | |---7 -6'---| - | |---5 - | |---4 - | | |---3 - |---2 - |---1 - -Orphaned: 6 -``` - -The IAVL detects whenever a subtree has become unbalanced by 2 (after any set/remove). If this does happen, then the tree is immediately rebalanced. Thus, any unbalanced subtree can only exist in 4 states: - -#### Left Left Case - -1. `RotateRight(node8)` - -**Before: Left Left Unbalanced** -``` - |---9 -8---| - | |---6 - |---4 - | |---3 - |---2 -``` - -**After 1: Balanced** -``` - |---9 - |---8 - | |---6 -4'---| - | |---3 - |---2 - -Orphaned: 4 -``` - -#### Left Right Case - -Make tree left left unbalanced, and then balance. - -1. `RotateLeft(node4)` -2. `RotateRight(node8)` - -**Before: Left Right Unbalanced** -``` - |---9 -8---| - | |---6 - | | |---5 - |---4 - |---2 -``` - -**After 1: Left Left Unbalanced** -``` - |---9 -8---| - |---6' - | |---5 - |---4 - |---2 - -Orphaned: 6 -``` - -**After 2: Balanced** -``` - |---9 - |---8 -6'---| - | |---5 - |---4 - |---2 - -Orphaned: 6 -``` - -Note: 6 got orphaned again, so omit list repitition - -#### Right Right Case - -1. `RotateLeft(node2)` - -**Before: Right Right Unbalanced** -``` - |---9 - |---8 - |---6 - | |---4 -2---| - |---1 -``` - -**After: Balanced** -``` - |---9 - |---8 -6'---| - | |---4 - |---2 - |---1 - -Orphaned: 6 -``` - -#### Right Left Case - -Make tree right right unbalanced, then balance. - -1. `RotateRight(6)` -2. `RotateLeft(2)` - -**Before: Right Left Unbalanced** -``` - |---8 - |---6 - | |---4 - | |---3 -2---| - |---1 -``` - -**After 1: Right Right Unbalanced** -``` - |---8 - |---6 - |---4' - | |---3 -2---| - |---1 - -Orphaned: 4 -``` - -**After 2: Balanced** -``` - |---8 - |---6 -4'---| - | |---3 - |---2 - |---1 - -Orphaned: 4 -``` - -### SaveVersion - -SaveVersion saves the current working tree as the latest version, `tree.version+1`. - -If the tree's root is empty, then there are no nodes to save. The `nodeDB` must still save any orphans since the root itself could be the node that has been removed since the last version. Then the `nodeDB` also saves the empty root for this version. - -If the root is not empty. Then SaveVersion will ensure that the `nodeDB` saves the orphans, roots and any new nodes that have been created since the last version was saved. - -SaveVersion also calls `nodeDB.Commit`, this ensures that any batched writes from the last save gets committed to the appropriate databases. - -`tree.version` gets incremented and the versions map has `versions[tree.version] = true`. - -It will set the lastSaved `ImmutableTree` to the current working tree, and clone the tree to allow for future updates on the next working tree. It also resets orphans to the empty map. - -Lastly, it returns the tree's hash, the latest version, and nil for error. - -SaveVersion will error if a tree at the version trying to be saved already exists. - -### DeleteVersion - -DeleteVersion will simply call nodeDB's `DeleteVersion` function which is documented in the [nodeDB docs](./nodedb.md) and then call `nodeDB.Commit` to flush all batched updates. - -It will also delete the version from the versions map. - -DeleteVersion will return an error if the version is invalid, or nonexistent. DeleteVersion will also return an error if the version trying to be deleted is the latest version of the IAVL tree since that is unallowed. diff --git a/sei-iavl/scripts/dump_top_contracts.sh b/sei-iavl/scripts/dump_top_contracts.sh deleted file mode 100644 index caabf97f96..0000000000 --- a/sei-iavl/scripts/dump_top_contracts.sh +++ /dev/null @@ -1,20 +0,0 @@ -#/bin/bash - -TOP_N=$1 -TOP_N=${TOP_N:-10} - -systemctl stop seid -echo "Dumping all wasm keys to ~/wasm_keys_dump.txt..." -iaviewer keys ~/.sei/data/application.db "s/k:wasm/" > ~/wasm_keys_dump.txt - -systemctl start seid -echo "Generating top contracts to ~/top_contracts.txt..." -cat ~/wasm_keys_dump.txt |grep "^03" |cut -c 3-66 |sort |uniq -c |sort -nr |head -n "$TOP_N" > ~/top_contracts.txt - -while IFS= read -r line; do - count=$(echo "$line" | awk '{print $1}') - contract_hex=$(echo "$line" | awk '{print $2}') - contract_address=$(seid keys parse "$contract_hex" --output json |jq -r .formats[0]) - contract_label=$(seid query wasm contract "$contract_address" --output json |jq -r .contract_info.label) - echo "$contract_address - $contract_label: $count" -done < ~/top_contracts.txt diff --git a/sei-iavl/scripts/protocgen.sh b/sei-iavl/scripts/protocgen.sh deleted file mode 100644 index 4bf62a2f2e..0000000000 --- a/sei-iavl/scripts/protocgen.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -eo pipefail - -buf generate --path proto/iavl - -mv ./proto/iavl/*.go ./proto From 60082ec017bdbe3baa8e7fe9f4dbfc92655ee952 Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 17 Dec 2025 10:38:31 +0000 Subject: [PATCH 63/69] Flatten `sei-iavl` into `sei-chain` We need to do this in order to get rid of the transient dependency to tendermint in `sei-iavl`. Otherwise, it blocks the upcoming flattening of `sei-tendermint` into `sei-chain`. --- cmd/seid/cmd/debug.go | 2 +- go.mod | 2 - sei-cosmos/go.mod | 2 - sei-cosmos/store/cache/cache_test.go | 2 +- sei-cosmos/store/iavl/store.go | 2 +- sei-cosmos/store/iavl/store_test.go | 2 +- sei-cosmos/store/iavl/tree.go | 2 +- sei-cosmos/store/iavl/tree_test.go | 2 +- sei-cosmos/store/prefix/store_test.go | 2 +- sei-cosmos/store/rootmulti/proof_test.go | 2 +- sei-cosmos/store/rootmulti/store.go | 2 +- sei-cosmos/store/types/iterator_test.go | 2 +- sei-cosmos/storev2/commitment/store.go | 2 +- sei-db/proto/changelog.pb.go | 2 +- sei-db/sc/memiavl/benchmark_test.go | 2 +- sei-db/sc/memiavl/db.go | 2 +- sei-db/sc/memiavl/db_test.go | 2 +- sei-db/sc/memiavl/multitree.go | 2 +- sei-db/sc/memiavl/proof.go | 2 +- sei-db/sc/memiavl/snapshot_catchup_test.go | 2 +- sei-db/sc/memiavl/snapshot_pipeline_test.go | 2 +- sei-db/sc/memiavl/snapshot_write_test.go | 2 +- sei-db/sc/memiavl/tree.go | 2 +- sei-db/sc/memiavl/tree_test.go | 2 +- sei-db/ss/pebbledb/hash_test.go | 2 +- sei-db/ss/store_test.go | 2 +- sei-db/ss/test/storage_bench_suite.go | 2 +- sei-db/ss/test/storage_test_suite.go | 2 +- sei-db/ss/test/utils.go | 2 +- sei-db/stream/changelog/changelog_test.go | 2 +- sei-db/stream/changelog/utils.go | 2 +- sei-db/tools/bench/benchmark.go | 2 +- sei-db/tools/utils/utils.go | 2 +- sei-iavl/benchmarks/bench_test.go | 2 +- sei-iavl/benchmarks/cosmos-exim/main.go | 2 +- sei-iavl/benchmarks/hash_test.go | 2 +- sei-iavl/cache/cache.go | 2 +- sei-iavl/cache/cache_bench_test.go | 2 +- sei-iavl/cache/cache_test.go | 2 +- sei-iavl/cmd/iaviewer/main.go | 4 +- sei-iavl/diff.go | 2 +- sei-iavl/doc.go | 48 +- sei-iavl/fast_node.go | 4 +- sei-iavl/go.mod | 36 - sei-iavl/go.sum | 1692 ------------------- sei-iavl/mutable_tree.go | 2 +- sei-iavl/mutable_tree_test.go | 4 +- sei-iavl/node.go | 4 +- sei-iavl/nodedb.go | 6 +- sei-iavl/nodedb_test.go | 2 +- sei-iavl/proof.go | 6 +- sei-iavl/proof_forgery_test.go | 2 +- sei-iavl/proof_iavl_absence.go | 4 +- sei-iavl/proof_iavl_value.go | 4 +- sei-iavl/proof_range.go | 2 +- sei-iavl/proof_test.go | 4 +- sei-iavl/testutils_test.go | 4 +- sei-iavl/tree_fuzz_test.go | 2 +- sei-iavl/tree_test.go | 2 +- sei-iavl/unsafe.go | 2 +- sei-wasmd/x/wasm/types/iavl_range_test.go | 2 +- tools/hash_verification/iavl/scanner.go | 2 +- tools/migration/cmd/cmd.go | 2 +- tools/migration/ss/migrator.go | 2 +- x/evm/keeper/receipt.go | 2 +- 65 files changed, 95 insertions(+), 1829 deletions(-) delete mode 100644 sei-iavl/go.mod delete mode 100644 sei-iavl/go.sum diff --git a/cmd/seid/cmd/debug.go b/cmd/seid/cmd/debug.go index 6ff647f99d..fe48041573 100644 --- a/cmd/seid/cmd/debug.go +++ b/cmd/seid/cmd/debug.go @@ -13,7 +13,7 @@ import ( "strings" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/spf13/cobra" dbm "github.com/tendermint/tm-db" ) diff --git a/go.mod b/go.mod index aa10488ec0..1b4ce2d350 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/confio/ics23/go v0.9.0 github.com/cosmos/cosmos-sdk v0.45.10 github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/iavl v0.21.0-alpha.1.0.20230904092046-df3db2d96583 github.com/dvsekhvalnov/jose2go v1.5.0 github.com/ethereum/go-ethereum v1.16.1 github.com/go-playground/validator/v10 v10.11.1 @@ -343,7 +342,6 @@ replace ( github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.23.2 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 github.com/cosmos/cosmos-sdk => ./sei-cosmos - github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.2.0 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.15.7-sei-7.0.20250929182230-93350978bb7c github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 // Latest goleveldb is broken, we have to stick to this version diff --git a/sei-cosmos/go.mod b/sei-cosmos/go.mod index 5fc05eb49e..cb253ede39 100644 --- a/sei-cosmos/go.mod +++ b/sei-cosmos/go.mod @@ -12,7 +12,6 @@ require ( github.com/confio/ics23/go v0.9.0 github.com/cosmos/btcutil v1.0.5 github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/iavl v0.21.0-alpha.1.0.20230904092046-df3db2d96583 github.com/cosmos/ledger-cosmos-go v0.12.2 github.com/ethereum/go-ethereum v1.13.2 github.com/gogo/gateway v1.1.0 @@ -175,7 +174,6 @@ replace ( github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76 github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.23.2 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.2.0 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.15.7-sei-7.0.20250929182230-93350978bb7c // Fix upstream GHSA-h395-qcrw-5vmq vulnerability. // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 diff --git a/sei-cosmos/store/cache/cache_test.go b/sei-cosmos/store/cache/cache_test.go index 635f098c2e..4c753aee8a 100644 --- a/sei-cosmos/store/cache/cache_test.go +++ b/sei-cosmos/store/cache/cache_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" diff --git a/sei-cosmos/store/iavl/store.go b/sei-cosmos/store/iavl/store.go index 727466158b..bbf99f964f 100644 --- a/sei-cosmos/store/iavl/store.go +++ b/sei-cosmos/store/iavl/store.go @@ -8,7 +8,7 @@ import ( "time" ics23 "github.com/confio/ics23/go" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" diff --git a/sei-cosmos/store/iavl/store_test.go b/sei-cosmos/store/iavl/store_test.go index 434a827a53..427a5d10dc 100644 --- a/sei-cosmos/store/iavl/store_test.go +++ b/sei-cosmos/store/iavl/store_test.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/cachekv" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" diff --git a/sei-cosmos/store/iavl/tree.go b/sei-cosmos/store/iavl/tree.go index efc62713f4..67aec3e391 100644 --- a/sei-cosmos/store/iavl/tree.go +++ b/sei-cosmos/store/iavl/tree.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/store/types" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" ) var ( diff --git a/sei-cosmos/store/iavl/tree_test.go b/sei-cosmos/store/iavl/tree_test.go index 02d19a97bf..2990cec753 100644 --- a/sei-cosmos/store/iavl/tree_test.go +++ b/sei-cosmos/store/iavl/tree_test.go @@ -3,7 +3,7 @@ package iavl import ( "testing" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" ) diff --git a/sei-cosmos/store/prefix/store_test.go b/sei-cosmos/store/prefix/store_test.go index 2a78a48132..301fc903e7 100644 --- a/sei-cosmos/store/prefix/store_test.go +++ b/sei-cosmos/store/prefix/store_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" - tiavl "github.com/cosmos/iavl" + tiavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/gaskv" diff --git a/sei-cosmos/store/rootmulti/proof_test.go b/sei-cosmos/store/rootmulti/proof_test.go index 746e9e963b..98e7281c30 100644 --- a/sei-cosmos/store/rootmulti/proof_test.go +++ b/sei-cosmos/store/rootmulti/proof_test.go @@ -3,7 +3,7 @@ package rootmulti import ( "testing" - iavltree "github.com/cosmos/iavl" + iavltree "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" diff --git a/sei-cosmos/store/rootmulti/store.go b/sei-cosmos/store/rootmulti/store.go index 21d8dfb774..ec8722ce38 100644 --- a/sei-cosmos/store/rootmulti/store.go +++ b/sei-cosmos/store/rootmulti/store.go @@ -11,10 +11,10 @@ import ( "github.com/armon/go-metrics" "github.com/cosmos/cosmos-sdk/telemetry" - iavltree "github.com/cosmos/iavl" protoio "github.com/gogo/protobuf/io" gogotypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" + iavltree "github.com/sei-protocol/sei-chain/sei-iavl" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/proto/tendermint/crypto" diff --git a/sei-cosmos/store/types/iterator_test.go b/sei-cosmos/store/types/iterator_test.go index 9512296325..5483b6a9aa 100644 --- a/sei-cosmos/store/types/iterator_test.go +++ b/sei-cosmos/store/types/iterator_test.go @@ -3,7 +3,7 @@ package types_test import ( "testing" - iavltree "github.com/cosmos/iavl" + iavltree "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" diff --git a/sei-cosmos/storev2/commitment/store.go b/sei-cosmos/storev2/commitment/store.go index bde5968e70..60041900ec 100644 --- a/sei-cosmos/storev2/commitment/store.go +++ b/sei-cosmos/storev2/commitment/store.go @@ -11,8 +11,8 @@ import ( "github.com/cosmos/cosmos-sdk/store/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/iavl" sctypes "github.com/sei-protocol/sei-chain/sei-db/sc/types" + "github.com/sei-protocol/sei-chain/sei-iavl" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/proto/tendermint/crypto" diff --git a/sei-db/proto/changelog.pb.go b/sei-db/proto/changelog.pb.go index 2193b17254..abdd548b22 100644 --- a/sei-db/proto/changelog.pb.go +++ b/sei-db/proto/changelog.pb.go @@ -9,7 +9,7 @@ import ( math "math" math_bits "math/bits" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" ) diff --git a/sei-db/sc/memiavl/benchmark_test.go b/sei-db/sc/memiavl/benchmark_test.go index 8141d63ce5..25fae1aa04 100644 --- a/sei-db/sc/memiavl/benchmark_test.go +++ b/sei-db/sc/memiavl/benchmark_test.go @@ -8,7 +8,7 @@ import ( "sort" "testing" - iavlcache "github.com/cosmos/iavl/cache" + iavlcache "github.com/sei-protocol/sei-chain/sei-iavl/cache" "github.com/stretchr/testify/require" "github.com/tidwall/btree" ) diff --git a/sei-db/sc/memiavl/db.go b/sei-db/sc/memiavl/db.go index a11a2b32d1..dc22bea0a3 100644 --- a/sei-db/sc/memiavl/db.go +++ b/sei-db/sc/memiavl/db.go @@ -18,13 +18,13 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" - "github.com/cosmos/iavl" errorutils "github.com/sei-protocol/sei-chain/sei-db/common/errors" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/common/utils" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/stream/changelog" "github.com/sei-protocol/sei-chain/sei-db/stream/types" + "github.com/sei-protocol/sei-chain/sei-iavl" ) const LockFileName = "LOCK" diff --git a/sei-db/sc/memiavl/db_test.go b/sei-db/sc/memiavl/db_test.go index d917655e1b..2a70252d20 100644 --- a/sei-db/sc/memiavl/db_test.go +++ b/sei-db/sc/memiavl/db_test.go @@ -11,11 +11,11 @@ import ( "testing" "time" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/common/errors" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/common/utils" "github.com/sei-protocol/sei-chain/sei-db/proto" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/sc/memiavl/multitree.go b/sei-db/sc/memiavl/multitree.go index fa91a10078..b13957ad40 100644 --- a/sei-db/sc/memiavl/multitree.go +++ b/sei-db/sc/memiavl/multitree.go @@ -14,12 +14,12 @@ import ( "github.com/alitto/pond" "golang.org/x/exp/slices" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/common/errors" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/common/utils" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/stream/types" + "github.com/sei-protocol/sei-chain/sei-iavl" ) const ( diff --git a/sei-db/sc/memiavl/proof.go b/sei-db/sc/memiavl/proof.go index 575225042d..7853f3a35c 100644 --- a/sei-db/sc/memiavl/proof.go +++ b/sei-db/sc/memiavl/proof.go @@ -8,7 +8,7 @@ import ( "math" ics23 "github.com/confio/ics23/go" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" ) /* diff --git a/sei-db/sc/memiavl/snapshot_catchup_test.go b/sei-db/sc/memiavl/snapshot_catchup_test.go index d4c45be537..356c625f9c 100644 --- a/sei-db/sc/memiavl/snapshot_catchup_test.go +++ b/sei-db/sc/memiavl/snapshot_catchup_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/proto" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/sc/memiavl/snapshot_pipeline_test.go b/sei-db/sc/memiavl/snapshot_pipeline_test.go index 8c1b84e82b..4677dc0ef4 100644 --- a/sei-db/sc/memiavl/snapshot_pipeline_test.go +++ b/sei-db/sc/memiavl/snapshot_pipeline_test.go @@ -4,9 +4,9 @@ import ( "context" "testing" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/sc/types" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/sc/memiavl/snapshot_write_test.go b/sei-db/sc/memiavl/snapshot_write_test.go index 474e84d783..ada645415f 100644 --- a/sei-db/sc/memiavl/snapshot_write_test.go +++ b/sei-db/sc/memiavl/snapshot_write_test.go @@ -6,9 +6,9 @@ import ( "path/filepath" "testing" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/proto" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/sc/memiavl/tree.go b/sei-db/sc/memiavl/tree.go index 2d110f4ced..ad7e3e6f32 100644 --- a/sei-db/sc/memiavl/tree.go +++ b/sei-db/sc/memiavl/tree.go @@ -8,10 +8,10 @@ import ( "sync" ics23 "github.com/confio/ics23/go" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/common/utils" "github.com/sei-protocol/sei-chain/sei-db/sc/types" + "github.com/sei-protocol/sei-chain/sei-iavl" dbm "github.com/tendermint/tm-db" ) diff --git a/sei-db/sc/memiavl/tree_test.go b/sei-db/sc/memiavl/tree_test.go index 17675f59a9..7b98ac11f7 100644 --- a/sei-db/sc/memiavl/tree_test.go +++ b/sei-db/sc/memiavl/tree_test.go @@ -6,7 +6,7 @@ import ( "strconv" "testing" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" db "github.com/tendermint/tm-db" ) diff --git a/sei-db/ss/pebbledb/hash_test.go b/sei-db/ss/pebbledb/hash_test.go index f9061c9e3b..0c29d6e15f 100644 --- a/sei-db/ss/pebbledb/hash_test.go +++ b/sei-db/ss/pebbledb/hash_test.go @@ -8,10 +8,10 @@ import ( "time" "github.com/cockroachdb/pebble" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/config" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/util" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/sei-db/ss/store_test.go b/sei-db/ss/store_test.go index a28889aaf4..91eb654652 100644 --- a/sei-db/ss/store_test.go +++ b/sei-db/ss/store_test.go @@ -6,10 +6,10 @@ import ( "path/filepath" "testing" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/config" "github.com/sei-protocol/sei-chain/sei-db/proto" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/ss/test/storage_bench_suite.go b/sei-db/ss/test/storage_bench_suite.go index 64ebeb90d6..448cdeda07 100644 --- a/sei-db/ss/test/storage_bench_suite.go +++ b/sei-db/ss/test/storage_bench_suite.go @@ -8,9 +8,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/types" + "github.com/sei-protocol/sei-chain/sei-iavl" ) // StorageBenchSuite defines a reusable benchmark suite for all storage backends. diff --git a/sei-db/ss/test/storage_test_suite.go b/sei-db/ss/test/storage_test_suite.go index 80a9b4d270..341de93bf1 100644 --- a/sei-db/ss/test/storage_test_suite.go +++ b/sei-db/ss/test/storage_test_suite.go @@ -4,10 +4,10 @@ import ( "fmt" "sync" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/config" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/types" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/suite" "golang.org/x/exp/slices" ) diff --git a/sei-db/ss/test/utils.go b/sei-db/ss/test/utils.go index bc60e016f2..70ff45de41 100644 --- a/sei-db/ss/test/utils.go +++ b/sei-db/ss/test/utils.go @@ -3,9 +3,9 @@ package sstest import ( "fmt" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/types" + "github.com/sei-protocol/sei-chain/sei-iavl" ) // Fills the db with multiple keys each with different versions diff --git a/sei-db/stream/changelog/changelog_test.go b/sei-db/stream/changelog/changelog_test.go index e15b1e076f..36e2c55a9f 100644 --- a/sei-db/stream/changelog/changelog_test.go +++ b/sei-db/stream/changelog/changelog_test.go @@ -6,9 +6,9 @@ import ( "path/filepath" "testing" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/proto" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" "github.com/tidwall/wal" ) diff --git a/sei-db/stream/changelog/utils.go b/sei-db/stream/changelog/utils.go index e3e11f3a02..6193fb1527 100644 --- a/sei-db/stream/changelog/utils.go +++ b/sei-db/stream/changelog/utils.go @@ -8,7 +8,7 @@ import ( "path/filepath" "unsafe" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/tidwall/gjson" "github.com/tidwall/wal" ) diff --git a/sei-db/tools/bench/benchmark.go b/sei-db/tools/bench/benchmark.go index 89a3c3006b..d821406ceb 100644 --- a/sei-db/tools/bench/benchmark.go +++ b/sei-db/tools/bench/benchmark.go @@ -9,10 +9,10 @@ import ( "sync/atomic" "time" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/types" "github.com/sei-protocol/sei-chain/sei-db/tools/utils" + "github.com/sei-protocol/sei-chain/sei-iavl" ) // writeToDBConcurrently generates random write load against the db diff --git a/sei-db/tools/utils/utils.go b/sei-db/tools/utils/utils.go index 6df14bfffe..6d25f5495a 100644 --- a/sei-db/tools/utils/utils.go +++ b/sei-db/tools/utils/utils.go @@ -13,7 +13,7 @@ import ( "sync" "time" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" dbm "github.com/tendermint/tm-db" ) diff --git a/sei-iavl/benchmarks/bench_test.go b/sei-iavl/benchmarks/bench_test.go index a38828170f..6b937eb1e4 100644 --- a/sei-iavl/benchmarks/bench_test.go +++ b/sei-iavl/benchmarks/bench_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" db "github.com/tendermint/tm-db" ) diff --git a/sei-iavl/benchmarks/cosmos-exim/main.go b/sei-iavl/benchmarks/cosmos-exim/main.go index 4b7ee35807..2d71686055 100644 --- a/sei-iavl/benchmarks/cosmos-exim/main.go +++ b/sei-iavl/benchmarks/cosmos-exim/main.go @@ -6,7 +6,7 @@ import ( "os" "time" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" tmdb "github.com/tendermint/tm-db" ) diff --git a/sei-iavl/benchmarks/hash_test.go b/sei-iavl/benchmarks/hash_test.go index 4ed6c527de..9fd55d3f97 100644 --- a/sei-iavl/benchmarks/hash_test.go +++ b/sei-iavl/benchmarks/hash_test.go @@ -6,7 +6,7 @@ import ( "hash" "testing" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" _ "crypto/sha256" diff --git a/sei-iavl/cache/cache.go b/sei-iavl/cache/cache.go index 01cc38723c..a5d34332aa 100644 --- a/sei-iavl/cache/cache.go +++ b/sei-iavl/cache/cache.go @@ -3,7 +3,7 @@ package cache import ( "container/list" - ibytes "github.com/cosmos/iavl/internal/bytes" + ibytes "github.com/sei-protocol/sei-chain/sei-iavl/internal/bytes" ) // Node represents a node eligible for caching. diff --git a/sei-iavl/cache/cache_bench_test.go b/sei-iavl/cache/cache_bench_test.go index 7332b68697..815e97bffe 100644 --- a/sei-iavl/cache/cache_bench_test.go +++ b/sei-iavl/cache/cache_bench_test.go @@ -4,7 +4,7 @@ import ( "math/rand" "testing" - "github.com/cosmos/iavl/cache" + "github.com/sei-protocol/sei-chain/sei-iavl/cache" ) func BenchmarkAdd(b *testing.B) { diff --git a/sei-iavl/cache/cache_test.go b/sei-iavl/cache/cache_test.go index a29a2815d8..4dbdd7e0de 100644 --- a/sei-iavl/cache/cache_test.go +++ b/sei-iavl/cache/cache_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/cosmos/iavl/cache" + "github.com/sei-protocol/sei-chain/sei-iavl/cache" "github.com/stretchr/testify/require" ) diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go index dafecd66af..622deb8c6f 100644 --- a/sei-iavl/cmd/iaviewer/main.go +++ b/sei-iavl/cmd/iaviewer/main.go @@ -10,8 +10,8 @@ import ( dbm "github.com/tendermint/tm-db" - "github.com/cosmos/iavl" - ibytes "github.com/cosmos/iavl/internal/bytes" + "github.com/sei-protocol/sei-chain/sei-iavl" + ibytes "github.com/sei-protocol/sei-chain/sei-iavl/internal/bytes" ) // TODO: make this configurable? diff --git a/sei-iavl/diff.go b/sei-iavl/diff.go index 8af0d85533..9d3ec3edd2 100644 --- a/sei-iavl/diff.go +++ b/sei-iavl/diff.go @@ -1,7 +1,7 @@ package iavl import ( - "github.com/cosmos/iavl/proto" + "github.com/sei-protocol/sei-chain/sei-iavl/proto" ) type ( diff --git a/sei-iavl/doc.go b/sei-iavl/doc.go index 97ae918aff..493f5bf286 100644 --- a/sei-iavl/doc.go +++ b/sei-iavl/doc.go @@ -6,49 +6,47 @@ // MutableTree.GetImmutable() which are safe for concurrent use as long as // the version is not deleted via DeleteVersion(). // -// // Basic usage of MutableTree: // -// import "github.com/cosmos/iavl" -// import "github.com/tendermint/tm-db" -// ... +// import "github.com/sei-protocol/sei-chain/sei-iavl" +// import "github.com/tendermint/tm-db" +// ... // -// tree := iavl.NewMutableTree(db.NewMemDB(), 128) +// tree := iavl.NewMutableTree(db.NewMemDB(), 128) // -// tree.IsEmpty() // true +// tree.IsEmpty() // true // -// tree.Set([]byte("alice"), []byte("abc")) -// tree.SaveVersion(1) +// tree.Set([]byte("alice"), []byte("abc")) +// tree.SaveVersion(1) // -// tree.Set([]byte("alice"), []byte("xyz")) -// tree.Set([]byte("bob"), []byte("xyz")) -// tree.SaveVersion(2) +// tree.Set([]byte("alice"), []byte("xyz")) +// tree.Set([]byte("bob"), []byte("xyz")) +// tree.SaveVersion(2) // -// tree.LatestVersion() // 2 +// tree.LatestVersion() // 2 // -// tree.GetVersioned([]byte("alice"), 1) // "abc" -// tree.GetVersioned([]byte("alice"), 2) // "xyz" +// tree.GetVersioned([]byte("alice"), 1) // "abc" +// tree.GetVersioned([]byte("alice"), 2) // "xyz" // // Proof of existence: // -// root := tree.Hash() -// val, proof, err := tree.GetVersionedWithProof([]byte("bob"), 2) // "xyz", RangeProof, nil -// proof.Verify([]byte("bob"), val, root) // nil +// root := tree.Hash() +// val, proof, err := tree.GetVersionedWithProof([]byte("bob"), 2) // "xyz", RangeProof, nil +// proof.Verify([]byte("bob"), val, root) // nil // // Proof of absence: // -// _, proof, err = tree.GetVersionedWithProof([]byte("tom"), 2) // nil, RangeProof, nil -// proof.Verify([]byte("tom"), nil, root) // nil +// _, proof, err = tree.GetVersionedWithProof([]byte("tom"), 2) // nil, RangeProof, nil +// proof.Verify([]byte("tom"), nil, root) // nil // // Now we delete an old version: // -// tree.DeleteVersion(1) -// tree.VersionExists(1) // false -// tree.Get([]byte("alice")) // "xyz" -// tree.GetVersioned([]byte("alice"), 1) // nil +// tree.DeleteVersion(1) +// tree.VersionExists(1) // false +// tree.Get([]byte("alice")) // "xyz" +// tree.GetVersioned([]byte("alice"), 1) // nil // // Can't create a proof of absence for a version we no longer have: // -// _, proof, err = tree.GetVersionedWithProof([]byte("tom"), 1) // nil, nil, error -// +// _, proof, err = tree.GetVersionedWithProof([]byte("tom"), 1) // nil, nil, error package iavl diff --git a/sei-iavl/fast_node.go b/sei-iavl/fast_node.go index b32924551c..8fb93ba39e 100644 --- a/sei-iavl/fast_node.go +++ b/sei-iavl/fast_node.go @@ -3,9 +3,9 @@ package iavl import ( "io" - "github.com/cosmos/iavl/cache" - "github.com/cosmos/iavl/internal/encoding" "github.com/pkg/errors" + "github.com/sei-protocol/sei-chain/sei-iavl/cache" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/encoding" ) // NOTE: This file favors int64 as opposed to int for size/counts. diff --git a/sei-iavl/go.mod b/sei-iavl/go.mod deleted file mode 100644 index cec54da9a5..0000000000 --- a/sei-iavl/go.mod +++ /dev/null @@ -1,36 +0,0 @@ -module github.com/cosmos/iavl - -go 1.18 - -require ( - github.com/confio/ics23/go v0.7.0 - github.com/gogo/protobuf v1.3.2 - github.com/golang/mock v1.6.0 - github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.8.1 - github.com/tendermint/tendermint v0.34.20 - github.com/tendermint/tm-db v0.6.6 - golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e -) - -require ( - github.com/DataDog/zstd v1.4.5 // indirect - github.com/cespare/xxhash v1.1.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgraph-io/badger/v2 v2.2007.2 // indirect - github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect - github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/jmhodges/levigo v1.0.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect - github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect - go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect - golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 // indirect - google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/sei-iavl/go.sum b/sei-iavl/go.sum deleted file mode 100644 index e3adff5a92..0000000000 --- a/sei-iavl/go.sum +++ /dev/null @@ -1,1692 +0,0 @@ -4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= -bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= -cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Antonboom/errname v0.1.6/go.mod h1:7lz79JAnuoMNDAWE9MeeIr1/c/VpSUWatBv2FH9NYpI= -github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= -github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GaijinEntertainment/go-exhaustruct/v2 v2.1.0/go.mod h1:LGOGuvEgCfCQsy3JF2tRmpGDpzA53iZfyGEWSPwQ6/4= -github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= -github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI= -github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= -github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= -github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= -github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= -github.com/breml/bidichk v0.2.3/go.mod h1:8u2C6DnAy0g2cEq+k/A2+tr9O1s+vHGxWn0LTc70T2A= -github.com/breml/errchkjson v0.3.0/go.mod h1:9Cogkyv9gcT8HREpzi3TiqBxCqDzo8awa92zSDFcofU= -github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= -github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/bufbuild/buf v1.4.0/go.mod h1:mwHG7klTHnX+rM/ym8LXGl7vYpVmnwT96xWoRB4H5QI= -github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= -github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= -github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4/go.mod h1:W8EnPSQ8Nv4fUjc/v1/8tHFqhuOJXnRub0dTfuAQktU= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8= -github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/daixiang0/gci v0.3.3/go.mod h1:1Xr2bxnQbDxCqqulUOv8qpGqkgRw9RSCGGjEC2LjF8o= -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= -github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= -github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= -github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/cli v20.10.14+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= -github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= -github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= -github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= -github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= -github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= -github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= -github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= -github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/firefart/nonamedreturns v1.0.1/go.mod h1:D3dpIBojGGNh5UfElmwPu73SwDCm+VKhHYqwlNOk2uQ= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= -github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= -github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= -github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw= -github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= -github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= -github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= -github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= -github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= -github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.46.2/go.mod h1:3DkdHnxn9eoTTrpT2gB0TEv8KSziuoqe9FitgQLHvAY= -github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= -github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= -github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= -github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= -github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= -github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= -github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= -github.com/gostaticanalysis/analysisutil v0.4.1/go.mod h1:18U/DLpRgIUd459wGxVHE0fRgmo1UgHDcbw7F5idXu0= -github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= -github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= -github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= -github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= -github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= -github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= -github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= -github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= -github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= -github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= -github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= -github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= -github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= -github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= -github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= -github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f/go.mod h1:qr2b5kx4HbFS7/g4uYO5qv9ei8303JMsC7ESbYiqr2Q= -github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= -github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= -github.com/jhump/protoreflect v1.12.1-0.20220417024638-438db461d753/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= -github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= -github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= -github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/josharian/txtarfs v0.0.0-20210218200122-0702f000015a/go.mod h1:izVPOvVRsHiKkeGCT6tYBNWyDVuzj9wAaBb5R9qamfw= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kulti/thelper v0.6.2/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= -github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= -github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= -github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= -github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= -github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= -github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= -github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= -github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= -github.com/mgechev/revive v1.2.1/go.mod h1:+Ro3wqY4vakcYNtkBWdZC7dBg1xSB6sp054wWwmeFm0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= -github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= -github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= -github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= -github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= -github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= -github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= -github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= -github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= -github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= -github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nishanths/exhaustive v0.7.11/go.mod h1:gX+MP7DWMKJmNa1HfMozK+u04hQd3na9i0hyqf3/dOI= -github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= -github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= -github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= -github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.0/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= -github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.0.0/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= -github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= -github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= -github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a/go.mod h1:VMX+OnnSw4LicdiEGtRSD/1X8kW7GuEscjYNr4cOIT4= -github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/dsl v0.3.16/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/dsl v0.3.19/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= -github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= -github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= -github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/remyoudompheng/go-dbus v0.0.0-20121104212943-b7232d34b1d5/go.mod h1:+u151txRmLpwxBmpYn9z3d1sdJdjRPQpsXuYeY9jNls= -github.com/remyoudompheng/go-liblzma v0.0.0-20190506200333-81bf2d431b96/go.mod h1:90HvCY7+oHHUKkbeMCiHt1WuFR2/hPJ9QrljDG+v6ls= -github.com/remyoudompheng/go-misc v0.0.0-20190427085024-2d6ac652a50e/go.mod h1:80FQABjoFzZ2M5uEa6FUaJYEmqU2UOKojlFVak1UAwI= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= -github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= -github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= -github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= -github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= -github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= -github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/securego/gosec/v2 v2.11.0/go.mod h1:SX8bptShuG8reGC0XS09+a4H2BoWSJi+fscA+Pulbpo= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= -github.com/shirou/gopsutil/v3 v3.22.4/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H4ifUguaQzHM= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw= -github.com/sivchari/tenv v1.5.0/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= -github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= -github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= -github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= -github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= -github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= -github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= -github.com/tendermint/tendermint v0.34.20 h1:/pmvJhO3IqOxhbi8iRXudTjA2YKpaMqrLwFNkyxDSzw= -github.com/tendermint/tendermint v0.34.20/go.mod h1:KtOwCLYJcsS1ymtAfnjjAtXfXClbqcqjdqzFt2Em1Ac= -github.com/tendermint/tm-db v0.6.6 h1:EzhaOfR0bdKyATqcd5PNeyeq8r+V4bRPHBfyFdD9kGM= -github.com/tendermint/tm-db v0.6.6/go.mod h1:wP8d49A85B7/erz/r4YbKssKw6ylsO/hKtFk7E1aWZI= -github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= -github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= -github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= -github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= -github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= -github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomarrell/wrapcheck/v2 v2.6.1/go.mod h1:Eo+Opt6pyMW1b6cNllOcDSSoHO0aTJ+iF6BfCUbHltA= -github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= -github.com/tommy-muehle/go-mnd/v2 v2.5.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= -github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vektra/mockery/v2 v2.14.0/go.mod h1:bnD1T8tExSgPD1ripLkDbr60JA9VtQeu12P3wgLZd7M= -github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= -github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -gitlab.com/bosi/decorder v0.2.1/go.mod h1:6C/nhLSbF6qZbYD8bRmISBwc6vcWdNsiIBkRvjJFrH0= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= -go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.etcd.io/etcd/client/v2 v2.305.2/go.mod h1:2D7ZejHVMIfog1221iLSYlQRzrtECw3kz4I4VAQm3qI= -go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220403020550-483a9cbc67c0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 h1:fqTvyMIIj+HRzMmnzr9NtpHP6uVpvB5fkHcgPDC4nu8= -golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190228203856-589c23e65e65/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201028025901-8cd080b735b3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= -golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.6/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.3.1/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= -mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE= -mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= -mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5/go.mod h1:b8RRCBm0eeiWR8cfN88xeq2G5SG3VKGO+5UPWi5FSOY= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 72ff870f23..623642ee67 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -10,7 +10,7 @@ import ( "github.com/pkg/errors" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/iavl/internal/logger" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/logger" ) // commitGap after upgrade/delete commitGap FastNodes when commit the batch diff --git a/sei-iavl/mutable_tree_test.go b/sei-iavl/mutable_tree_test.go index 831d2edfc4..f65f54f4ea 100644 --- a/sei-iavl/mutable_tree_test.go +++ b/sei-iavl/mutable_tree_test.go @@ -9,9 +9,9 @@ import ( "strconv" "testing" - "github.com/cosmos/iavl/internal/encoding" - "github.com/cosmos/iavl/mock" "github.com/golang/mock/gomock" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/encoding" + "github.com/sei-protocol/sei-chain/sei-iavl/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/sei-iavl/node.go b/sei-iavl/node.go index 898602ea22..96b3cc0a8b 100644 --- a/sei-iavl/node.go +++ b/sei-iavl/node.go @@ -11,10 +11,10 @@ import ( "math" "sync" - "github.com/cosmos/iavl/cache" "github.com/pkg/errors" + "github.com/sei-protocol/sei-chain/sei-iavl/cache" - "github.com/cosmos/iavl/internal/encoding" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/encoding" ) // Node represents a node in a Tree. diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index c98f566098..d06642fb77 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -10,10 +10,10 @@ import ( "strings" "sync" - "github.com/cosmos/iavl/cache" - ibytes "github.com/cosmos/iavl/internal/bytes" - "github.com/cosmos/iavl/internal/logger" "github.com/pkg/errors" + "github.com/sei-protocol/sei-chain/sei-iavl/cache" + ibytes "github.com/sei-protocol/sei-chain/sei-iavl/internal/bytes" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/logger" dbm "github.com/tendermint/tm-db" ) diff --git a/sei-iavl/nodedb_test.go b/sei-iavl/nodedb_test.go index d889d6b1af..1bca7f2b61 100644 --- a/sei-iavl/nodedb_test.go +++ b/sei-iavl/nodedb_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" db "github.com/tendermint/tm-db" - "github.com/cosmos/iavl/mock" + "github.com/sei-protocol/sei-chain/sei-iavl/mock" ) func BenchmarkNodeKey(b *testing.B) { diff --git a/sei-iavl/proof.go b/sei-iavl/proof.go index a379e444f9..63ad0a420f 100644 --- a/sei-iavl/proof.go +++ b/sei-iavl/proof.go @@ -9,9 +9,9 @@ import ( "github.com/pkg/errors" - hexbytes "github.com/cosmos/iavl/internal/bytes" - "github.com/cosmos/iavl/internal/encoding" - iavlproto "github.com/cosmos/iavl/proto" + hexbytes "github.com/sei-protocol/sei-chain/sei-iavl/internal/bytes" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/encoding" + iavlproto "github.com/sei-protocol/sei-chain/sei-iavl/proto" ) var bufPool = &sync.Pool{ diff --git a/sei-iavl/proof_forgery_test.go b/sei-iavl/proof_forgery_test.go index 82ab3e5ac0..8833f40bc4 100644 --- a/sei-iavl/proof_forgery_test.go +++ b/sei-iavl/proof_forgery_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/tmhash" db "github.com/tendermint/tm-db" diff --git a/sei-iavl/proof_iavl_absence.go b/sei-iavl/proof_iavl_absence.go index e18dbe3f40..ff71ffba0c 100644 --- a/sei-iavl/proof_iavl_absence.go +++ b/sei-iavl/proof_iavl_absence.go @@ -8,8 +8,8 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" tmmerkle "github.com/tendermint/tendermint/proto/tendermint/crypto" - "github.com/cosmos/iavl/internal/encoding" - iavlproto "github.com/cosmos/iavl/proto" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/encoding" + iavlproto "github.com/sei-protocol/sei-chain/sei-iavl/proto" ) const ProofOpIAVLAbsence = "iavl:a" diff --git a/sei-iavl/proof_iavl_value.go b/sei-iavl/proof_iavl_value.go index 68dada259d..46136fd3cd 100644 --- a/sei-iavl/proof_iavl_value.go +++ b/sei-iavl/proof_iavl_value.go @@ -8,8 +8,8 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" tmmerkle "github.com/tendermint/tendermint/proto/tendermint/crypto" - "github.com/cosmos/iavl/internal/encoding" - iavlproto "github.com/cosmos/iavl/proto" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/encoding" + iavlproto "github.com/sei-protocol/sei-chain/sei-iavl/proto" ) const ProofOpIAVLValue = "iavl:v" diff --git a/sei-iavl/proof_range.go b/sei-iavl/proof_range.go index 866e913da4..c920848fcf 100644 --- a/sei-iavl/proof_range.go +++ b/sei-iavl/proof_range.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" - iavlproto "github.com/cosmos/iavl/proto" + iavlproto "github.com/sei-protocol/sei-chain/sei-iavl/proto" ) type RangeProof struct { diff --git a/sei-iavl/proof_test.go b/sei-iavl/proof_test.go index c52ea79632..7af16b39fe 100644 --- a/sei-iavl/proof_test.go +++ b/sei-iavl/proof_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - iavlrand "github.com/cosmos/iavl/internal/rand" - iavlproto "github.com/cosmos/iavl/proto" + iavlrand "github.com/sei-protocol/sei-chain/sei-iavl/internal/rand" + iavlproto "github.com/sei-protocol/sei-chain/sei-iavl/proto" ) func TestTreeGetWithProof(t *testing.T) { diff --git a/sei-iavl/testutils_test.go b/sei-iavl/testutils_test.go index f6d8ca58cc..7f7484fffd 100644 --- a/sei-iavl/testutils_test.go +++ b/sei-iavl/testutils_test.go @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/require" db "github.com/tendermint/tm-db" - "github.com/cosmos/iavl/internal/encoding" - iavlrand "github.com/cosmos/iavl/internal/rand" + "github.com/sei-protocol/sei-chain/sei-iavl/internal/encoding" + iavlrand "github.com/sei-protocol/sei-chain/sei-iavl/internal/rand" ) type iteratorTestConfig struct { diff --git a/sei-iavl/tree_fuzz_test.go b/sei-iavl/tree_fuzz_test.go index 6f760290b3..b3219a8f78 100644 --- a/sei-iavl/tree_fuzz_test.go +++ b/sei-iavl/tree_fuzz_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" - iavlrand "github.com/cosmos/iavl/internal/rand" + iavlrand "github.com/sei-protocol/sei-chain/sei-iavl/internal/rand" ) // This file implement fuzz testing by generating programs and then running diff --git a/sei-iavl/tree_test.go b/sei-iavl/tree_test.go index 9ca93cdd83..dfbe481c2b 100644 --- a/sei-iavl/tree_test.go +++ b/sei-iavl/tree_test.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/require" db "github.com/tendermint/tm-db" - iavlrand "github.com/cosmos/iavl/internal/rand" + iavlrand "github.com/sei-protocol/sei-chain/sei-iavl/internal/rand" ) var testLevelDB bool diff --git a/sei-iavl/unsafe.go b/sei-iavl/unsafe.go index 2d00540d76..a5fbbe8b79 100644 --- a/sei-iavl/unsafe.go +++ b/sei-iavl/unsafe.go @@ -1,6 +1,6 @@ package iavl -import ibytes "github.com/cosmos/iavl/internal/bytes" +import ibytes "github.com/sei-protocol/sei-chain/sei-iavl/internal/bytes" var ( unsafeToStr = ibytes.UnsafeBytesToStr diff --git a/sei-wasmd/x/wasm/types/iavl_range_test.go b/sei-wasmd/x/wasm/types/iavl_range_test.go index a361525e10..bdd2135e83 100644 --- a/sei-wasmd/x/wasm/types/iavl_range_test.go +++ b/sei-wasmd/x/wasm/types/iavl_range_test.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/store/iavl" - iavl2 "github.com/cosmos/iavl" + iavl2 "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" ) diff --git a/tools/hash_verification/iavl/scanner.go b/tools/hash_verification/iavl/scanner.go index 492896f83e..1d5b808c26 100644 --- a/tools/hash_verification/iavl/scanner.go +++ b/tools/hash_verification/iavl/scanner.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/store/rootmulti" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/ss/types" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/sei-protocol/sei-chain/tools/hash_verification/hasher" "github.com/sei-protocol/sei-chain/tools/utils" dbm "github.com/tendermint/tm-db" diff --git a/tools/migration/cmd/cmd.go b/tools/migration/cmd/cmd.go index 2589ffa69d..ca9ac76dc6 100644 --- a/tools/migration/cmd/cmd.go +++ b/tools/migration/cmd/cmd.go @@ -7,9 +7,9 @@ import ( "time" "github.com/cosmos/cosmos-sdk/store/rootmulti" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/config" sstypes "github.com/sei-protocol/sei-chain/sei-db/ss" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/sei-protocol/sei-chain/tools/migration/sc" "github.com/sei-protocol/sei-chain/tools/migration/ss" "github.com/sei-protocol/sei-chain/tools/utils" diff --git a/tools/migration/ss/migrator.go b/tools/migration/ss/migrator.go index e58438776e..a2b44a9bc2 100644 --- a/tools/migration/ss/migrator.go +++ b/tools/migration/ss/migrator.go @@ -6,8 +6,8 @@ import ( "time" "github.com/armon/go-metrics" - "github.com/cosmos/iavl" "github.com/sei-protocol/sei-chain/sei-db/ss/types" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/sei-protocol/sei-chain/tools/utils" seimetrics "github.com/sei-protocol/sei-chain/utils/metrics" dbm "github.com/tendermint/tm-db" diff --git a/x/evm/keeper/receipt.go b/x/evm/keeper/receipt.go index 689094e900..c81549bfc1 100644 --- a/x/evm/keeper/receipt.go +++ b/x/evm/keeper/receipt.go @@ -8,9 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/iavl" "github.com/ethereum/go-ethereum/common" "github.com/sei-protocol/sei-chain/sei-db/proto" + "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" From 06532de70181a054a7c5ac31cf1d5a64bf2e8361 Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 17 Dec 2025 10:57:18 +0000 Subject: [PATCH 64/69] Fix `sei-iavl` buf generation to work with top level Fix the buf-based generation to integrate `sei-avl`. Update out of date pb.go files, and remove now redundant duplicate protos. --- buf.gen.yaml | 1 + buf.yaml | 1 + scripts/protoc.sh | 6 +- sei-iavl/proto/changeset.pb.go | 20 +- sei-iavl/proto/iavl/changeset.proto | 2 +- sei-iavl/proto/iavl/proof.proto | 2 +- sei-iavl/proto/proof.pb.go | 81 ++-- .../third_party/google/api/annotations.proto | 31 -- sei-iavl/third_party/google/api/http.proto | 376 ------------------ 9 files changed, 49 insertions(+), 471 deletions(-) delete mode 100644 sei-iavl/third_party/google/api/annotations.proto delete mode 100644 sei-iavl/third_party/google/api/http.proto diff --git a/buf.gen.yaml b/buf.gen.yaml index dfe4a5e848..42a48ab8f4 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -5,6 +5,7 @@ inputs: - directory: sei-ibc-go/proto - directory: sei-tendermint/proto - directory: sei-wasmd/proto + - directory: sei-iavl/proto plugins: - local: - ./build/proto/gocosmos/protoc-gen-gocosmos diff --git a/buf.yaml b/buf.yaml index 31cb3d07db..6baa572c92 100644 --- a/buf.yaml +++ b/buf.yaml @@ -9,6 +9,7 @@ modules: - path: sei-ibc-go/third_party/proto - path: sei-tendermint/proto - path: sei-wasmd/proto + - path: sei-iavl/proto lint: use: diff --git a/scripts/protoc.sh b/scripts/protoc.sh index c6fecd8a3a..bf03b03ca4 100755 --- a/scripts/protoc.sh +++ b/scripts/protoc.sh @@ -32,8 +32,12 @@ cp -rf ./build/proto/gocosmos/github.com/sei-protocol/sei-chain/* ./ cp -rf ./build/proto/gocosmos/github.com/cosmos/cosmos-sdk/* ./sei-cosmos cp -rf ./build/proto/gocosmos/github.com/sei-protocol/sei-chain/sei-wasmd/* ./sei-wasmd -# Use gogofaster for tendermint because that's the generator it is using currently. +# Use gogofaster for tendermint and iavl because that's the generator they used originally. +# See: +# * https://github.com/sei-protocol/sei-tendermint/blob/46d0a598a7f5c67cbdefea37c8da18df2c25d184/buf.gen.yaml#L3 +# * https://github.com/sei-protocol/sei-iavl/blob/ff17b3473ee2438caa1777930a0bf73d267527fa/buf.gen.yaml#L9 cp -rf ./build/proto/gogofaster/github.com/tendermint/tendermint/* ./sei-tendermint +cp -rf ./build/proto/gogofaster/github.com/sei-protocol/sei-chain/sei-iavl/* ./sei-iavl rm -rf ./build/proto diff --git a/sei-iavl/proto/changeset.pb.go b/sei-iavl/proto/changeset.pb.go index 359b34e7cc..3c65935a85 100644 --- a/sei-iavl/proto/changeset.pb.go +++ b/sei-iavl/proto/changeset.pb.go @@ -134,7 +134,7 @@ func init() { func init() { proto.RegisterFile("iavl/changeset.proto", fileDescriptor_21609c3776972f61) } var fileDescriptor_21609c3776972f61 = []byte{ - // 182 bytes of a gzipped FileDescriptorProto + // 212 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc9, 0x4c, 0x2c, 0xcb, 0xd1, 0x4f, 0xce, 0x48, 0xcc, 0x4b, 0x4f, 0x2d, 0x4e, 0x2d, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x01, 0x89, 0x2a, 0x79, 0x70, 0xb1, 0x79, 0x87, 0x05, 0x24, 0x66, 0x16, 0x09, 0x89, @@ -143,10 +143,12 @@ var fileDescriptor_21609c3776972f61 = []byte{ 0xa6, 0x90, 0x08, 0x17, 0x6b, 0x59, 0x62, 0x4e, 0x69, 0xaa, 0x04, 0x33, 0x58, 0x0c, 0xc2, 0x51, 0xd2, 0xe7, 0xe2, 0x74, 0x06, 0x5b, 0x11, 0x9c, 0x5a, 0x22, 0xa4, 0xc4, 0xc5, 0x5a, 0x90, 0x98, 0x59, 0x54, 0x2c, 0xc1, 0xa8, 0xc0, 0xac, 0xc1, 0x6d, 0xc4, 0xa3, 0x07, 0xb2, 0x4c, 0x0f, 0x62, - 0x53, 0x10, 0x44, 0xca, 0x49, 0xfe, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, + 0x53, 0x10, 0x44, 0xca, 0xc9, 0xeb, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, - 0x58, 0xc1, 0x2e, 0x4c, 0x62, 0x03, 0x53, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x26, 0xfc, - 0xaa, 0xbd, 0xc0, 0x00, 0x00, 0x00, + 0x0c, 0xd2, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x8b, 0x53, 0x33, 0x75, + 0xc1, 0x0e, 0x4e, 0xce, 0xcf, 0x01, 0x73, 0x92, 0x33, 0x12, 0x33, 0xf3, 0xc0, 0x2c, 0xb0, 0xb7, + 0xc0, 0x72, 0x49, 0x6c, 0x60, 0xca, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0xf8, 0xbd, 0x58, 0xe8, + 0xeb, 0x00, 0x00, 0x00, } func (m *KVPair) Marshal() (dAtA []byte, err error) { @@ -408,10 +410,7 @@ func (m *KVPair) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthChangeset - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthChangeset } if (iNdEx + skippy) > l { @@ -495,10 +494,7 @@ func (m *ChangeSet) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthChangeset - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthChangeset } if (iNdEx + skippy) > l { diff --git a/sei-iavl/proto/iavl/changeset.proto b/sei-iavl/proto/iavl/changeset.proto index efef05e0fc..56479c698c 100644 --- a/sei-iavl/proto/iavl/changeset.proto +++ b/sei-iavl/proto/iavl/changeset.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package iavl; -option go_package = "proto"; +option go_package = "github.com/sei-protocol/sei-chain/sei-iavl/proto"; message KVPair { bool delete = 1; diff --git a/sei-iavl/proto/iavl/proof.proto b/sei-iavl/proto/iavl/proof.proto index dc94c2d35b..79e8ab87c8 100644 --- a/sei-iavl/proto/iavl/proof.proto +++ b/sei-iavl/proto/iavl/proof.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package iavl; -option go_package = "proto"; +option go_package = "github.com/sei-protocol/sei-chain/sei-iavl/proto"; // ValueOp is a Protobuf representation of iavl.ValueOp. message ValueOp { diff --git a/sei-iavl/proto/proof.pb.go b/sei-iavl/proto/proof.pb.go index 35bbbff0ac..24c5e0164d 100644 --- a/sei-iavl/proto/proof.pb.go +++ b/sei-iavl/proto/proof.pb.go @@ -368,31 +368,32 @@ func init() { func init() { proto.RegisterFile("iavl/proof.proto", fileDescriptor_92b2514a05d2a2db) } var fileDescriptor_92b2514a05d2a2db = []byte{ - // 373 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xb1, 0x4e, 0xe3, 0x40, - 0x10, 0x86, 0xb3, 0x71, 0xec, 0x5c, 0x26, 0xb9, 0x53, 0x6e, 0x2f, 0x3a, 0x6d, 0x73, 0x3e, 0xcb, - 0x05, 0xb2, 0x04, 0x0a, 0x4a, 0xd2, 0xd1, 0x41, 0x05, 0x12, 0x82, 0x68, 0x85, 0x28, 0xd2, 0x44, - 0x1b, 0xb2, 0x89, 0x2d, 0x2c, 0xaf, 0xe5, 0x35, 0x96, 0xa0, 0xe2, 0x11, 0x78, 0x03, 0x5e, 0x87, - 0x32, 0x25, 0x25, 0x4a, 0x5e, 0x04, 0xed, 0xc4, 0x51, 0x48, 0x01, 0x12, 0x95, 0x67, 0xfe, 0xf9, - 0x66, 0xfe, 0xf1, 0xd8, 0xd0, 0x8e, 0x44, 0x11, 0x1f, 0xa6, 0x99, 0x52, 0xb3, 0x6e, 0x9a, 0xa9, - 0x5c, 0xd1, 0x9a, 0x51, 0xfc, 0x1e, 0xd4, 0xaf, 0x45, 0x7c, 0x27, 0x2f, 0x53, 0xba, 0x07, 0x36, - 0xd6, 0x19, 0xf1, 0x48, 0xd0, 0xec, 0xb7, 0xbb, 0x06, 0xe8, 0x72, 0x91, 0xcc, 0xe5, 0xd0, 0xe8, - 0x7c, 0x5d, 0xf6, 0x07, 0xd0, 0x38, 0x9e, 0x68, 0x99, 0xdc, 0x7c, 0xa7, 0xe9, 0x99, 0x00, 0x6c, - 0x55, 0xda, 0x83, 0x46, 0x2c, 0x67, 0xf9, 0x38, 0x15, 0x79, 0xc8, 0x88, 0x67, 0x05, 0xcd, 0x7e, - 0x67, 0xdd, 0x8a, 0xf5, 0xb3, 0x24, 0x91, 0xd9, 0x85, 0x9a, 0x4a, 0xfe, 0xc3, 0x60, 0x43, 0x91, - 0x87, 0xb4, 0x07, 0xcd, 0xc8, 0xc8, 0xe3, 0x44, 0x4d, 0xa5, 0x66, 0x55, 0x6c, 0x2a, 0xfd, 0x0c, - 0x70, 0xa5, 0xce, 0xa5, 0x98, 0x71, 0x88, 0x36, 0xbd, 0x9a, 0xee, 0x83, 0x13, 0x4b, 0x51, 0x48, - 0xcd, 0x2c, 0xa4, 0xff, 0x7c, 0xb0, 0x30, 0x30, 0x3a, 0x94, 0x88, 0x7f, 0x04, 0xb0, 0x1d, 0x43, - 0x0f, 0xc0, 0xc1, 0x41, 0xfa, 0xcb, 0xed, 0x4a, 0xc6, 0x7f, 0x24, 0xf0, 0x6b, 0xb7, 0x44, 0xff, - 0x82, 0x13, 0xca, 0x68, 0x1e, 0xe6, 0x78, 0x99, 0xdf, 0xbc, 0xcc, 0x28, 0x85, 0x9a, 0x8e, 0x1e, - 0x24, 0xab, 0x7a, 0x24, 0xb0, 0x38, 0xc6, 0x94, 0x41, 0xbd, 0x90, 0x99, 0x8e, 0x54, 0xc2, 0x2c, - 0x94, 0x37, 0xa9, 0xa1, 0xcd, 0x01, 0x58, 0xcd, 0x23, 0x41, 0x8b, 0x63, 0x4c, 0x3b, 0x60, 0x67, - 0x38, 0xd8, 0x46, 0x71, 0x9d, 0xf8, 0x23, 0xf8, 0xb9, 0xf3, 0x5e, 0xb4, 0x0d, 0xd6, 0xad, 0xbc, - 0x47, 0xf7, 0x16, 0x37, 0x21, 0xfd, 0x07, 0x50, 0x98, 0x6f, 0x3d, 0x0e, 0x85, 0x0e, 0x71, 0x81, - 0x16, 0x6f, 0xa0, 0x72, 0x2a, 0x74, 0xf8, 0xf9, 0x16, 0x27, 0xff, 0x5f, 0x96, 0x2e, 0x59, 0x2c, - 0x5d, 0xf2, 0xb6, 0x74, 0xc9, 0xd3, 0xca, 0xad, 0x2c, 0x56, 0x6e, 0xe5, 0x75, 0xe5, 0x56, 0x46, - 0x36, 0xfe, 0x4b, 0x13, 0x07, 0x1f, 0x83, 0xf7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x60, 0x25, - 0x89, 0x66, 0x02, 0x00, 0x00, + // 395 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0xee, 0xd2, 0x40, + 0x10, 0xc6, 0xd9, 0x7f, 0xa1, 0xc8, 0x80, 0x06, 0x57, 0x62, 0xf6, 0x62, 0xd3, 0xf4, 0x60, 0x9a, + 0xa8, 0x45, 0xe0, 0xe6, 0x4d, 0x4f, 0x6a, 0x8c, 0x92, 0x8d, 0xf1, 0xc0, 0x85, 0x2c, 0x65, 0x61, + 0x37, 0xd6, 0x6e, 0xd3, 0x2d, 0x4d, 0xf4, 0xe4, 0x23, 0xf8, 0x06, 0xbe, 0x8e, 0x47, 0x8e, 0x1e, + 0x0d, 0xbc, 0x88, 0xd9, 0xa1, 0x04, 0x39, 0x68, 0xe2, 0xa9, 0x33, 0xdf, 0xfc, 0x66, 0xbe, 0xe9, + 0xee, 0xc2, 0x50, 0x8b, 0x3a, 0x1b, 0x17, 0xa5, 0x31, 0x9b, 0xa4, 0x28, 0x4d, 0x65, 0x68, 0xdb, + 0x29, 0xd1, 0x04, 0xba, 0x1f, 0x44, 0xb6, 0x93, 0xef, 0x0a, 0xfa, 0x10, 0x3a, 0x58, 0x67, 0x24, + 0x24, 0x71, 0x7f, 0x3a, 0x4c, 0x1c, 0x90, 0x70, 0x91, 0x6f, 0xe5, 0xdc, 0xe9, 0xfc, 0x54, 0x8e, + 0x66, 0xd0, 0x7b, 0xbe, 0xb2, 0x32, 0x4f, 0xff, 0xa7, 0xe9, 0x3b, 0x01, 0xb8, 0xa8, 0x74, 0x02, + 0xbd, 0x4c, 0x6e, 0xaa, 0x65, 0x21, 0x2a, 0xc5, 0x48, 0xe8, 0xc5, 0xfd, 0xe9, 0xe8, 0xd4, 0x8a, + 0xf5, 0x57, 0x79, 0x2e, 0xcb, 0xb7, 0x66, 0x2d, 0xf9, 0x2d, 0x87, 0xcd, 0x45, 0xa5, 0xe8, 0x04, + 0xfa, 0xda, 0xc9, 0xcb, 0xdc, 0xac, 0xa5, 0x65, 0x37, 0xd8, 0xd4, 0xf8, 0x39, 0xe0, 0xbd, 0x79, + 0x23, 0xc5, 0x86, 0x83, 0x3e, 0xf7, 0x5a, 0xfa, 0x08, 0xfc, 0x4c, 0x8a, 0x5a, 0x5a, 0xe6, 0x21, + 0x7d, 0xef, 0x0f, 0x0b, 0x07, 0xa3, 0x43, 0x83, 0x44, 0xcf, 0x00, 0x2e, 0x63, 0xe8, 0x63, 0xf0, + 0x71, 0x90, 0xfd, 0xe7, 0x76, 0x0d, 0x13, 0x7d, 0x25, 0x70, 0xe7, 0xba, 0x44, 0xef, 0x83, 0xaf, + 0xa4, 0xde, 0xaa, 0x0a, 0x4f, 0xe6, 0x2e, 0x6f, 0x32, 0x4a, 0xa1, 0x6d, 0xf5, 0x17, 0xc9, 0x6e, + 0x42, 0x12, 0x7b, 0x1c, 0x63, 0xca, 0xa0, 0x5b, 0xcb, 0xd2, 0x6a, 0x93, 0x33, 0x0f, 0xe5, 0x73, + 0xea, 0x68, 0x77, 0x00, 0xac, 0x1d, 0x92, 0x78, 0xc0, 0x31, 0xa6, 0x23, 0xe8, 0x94, 0x38, 0xb8, + 0x83, 0xe2, 0x29, 0x89, 0x16, 0x70, 0xfb, 0xea, 0xbf, 0xe8, 0x10, 0xbc, 0x8f, 0xf2, 0x33, 0xba, + 0x0f, 0xb8, 0x0b, 0xe9, 0x03, 0x80, 0xda, 0xdd, 0xf5, 0x52, 0x09, 0xab, 0x70, 0x81, 0x01, 0xef, + 0xa1, 0xf2, 0x52, 0x58, 0xf5, 0xf7, 0x2d, 0x5e, 0xbc, 0xfe, 0x71, 0x08, 0xc8, 0xfe, 0x10, 0x90, + 0x5f, 0x87, 0x80, 0x7c, 0x3b, 0x06, 0xad, 0xfd, 0x31, 0x68, 0xfd, 0x3c, 0x06, 0xad, 0xc5, 0xd3, + 0xad, 0xae, 0xd4, 0x6e, 0x95, 0xa4, 0xe6, 0xd3, 0xd8, 0x4a, 0xfd, 0x04, 0x9f, 0x56, 0x6a, 0x32, + 0x4c, 0x52, 0x25, 0x74, 0x8e, 0xd1, 0xf9, 0xf1, 0x55, 0x66, 0xe5, 0xe3, 0x67, 0xf6, 0x3b, 0x00, + 0x00, 0xff, 0xff, 0x6a, 0xab, 0xb7, 0xd6, 0x91, 0x02, 0x00, 0x00, } func (m *ValueOp) Marshal() (dAtA []byte, err error) { @@ -863,10 +864,7 @@ func (m *ValueOp) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthProof } if (iNdEx + skippy) > l { @@ -952,10 +950,7 @@ func (m *AbsenceOp) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthProof } if (iNdEx + skippy) > l { @@ -1107,10 +1102,7 @@ func (m *RangeProof) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthProof } if (iNdEx + skippy) > l { @@ -1194,10 +1186,7 @@ func (m *PathToLeaf) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthProof } if (iNdEx + skippy) > l { @@ -1374,10 +1363,7 @@ func (m *ProofInnerNode) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthProof } if (iNdEx + skippy) > l { @@ -1514,10 +1500,7 @@ func (m *ProofLeafNode) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthProof } if (iNdEx + skippy) > l { diff --git a/sei-iavl/third_party/google/api/annotations.proto b/sei-iavl/third_party/google/api/annotations.proto deleted file mode 100644 index 85c361b47f..0000000000 --- a/sei-iavl/third_party/google/api/annotations.proto +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2015, Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package google.api; - -import "google/api/http.proto"; -import "google/protobuf/descriptor.proto"; - -option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; -option java_multiple_files = true; -option java_outer_classname = "AnnotationsProto"; -option java_package = "com.google.api"; -option objc_class_prefix = "GAPI"; - -extend google.protobuf.MethodOptions { - // See `HttpRule`. - HttpRule http = 72295728; -} diff --git a/sei-iavl/third_party/google/api/http.proto b/sei-iavl/third_party/google/api/http.proto deleted file mode 100644 index a43cff771f..0000000000 --- a/sei-iavl/third_party/google/api/http.proto +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -syntax = "proto3"; - -package google.api; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; -option java_multiple_files = true; -option java_outer_classname = "HttpProto"; -option java_package = "com.google.api"; -option objc_class_prefix = "GAPI"; - -// Defines the HTTP configuration for an API service. It contains a list of -// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method -// to one or more HTTP REST API methods. -message Http { - // A list of HTTP configuration rules that apply to individual API methods. - // - // **NOTE:** All service configuration rules follow "last one wins" order. - repeated HttpRule rules = 1; - - // When set to true, URL path parameters will be fully URI-decoded except in - // cases of single segment matches in reserved expansion, where "%2F" will be - // left encoded. - // - // The default behavior is to not decode RFC 6570 reserved characters in multi - // segment matches. - bool fully_decode_reserved_expansion = 2; -} - -// # gRPC Transcoding -// -// gRPC Transcoding is a feature for mapping between a gRPC method and one or -// more HTTP REST endpoints. It allows developers to build a single API service -// that supports both gRPC APIs and REST APIs. Many systems, including [Google -// APIs](https://github.com/googleapis/googleapis), -// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC -// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), -// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature -// and use it for large scale production services. -// -// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies -// how different portions of the gRPC request message are mapped to the URL -// path, URL query parameters, and HTTP request body. It also controls how the -// gRPC response message is mapped to the HTTP response body. `HttpRule` is -// typically specified as an `google.api.http` annotation on the gRPC method. -// -// Each mapping specifies a URL path template and an HTTP method. The path -// template may refer to one or more fields in the gRPC request message, as long -// as each field is a non-repeated field with a primitive (non-message) type. -// The path template controls how fields of the request message are mapped to -// the URL path. -// -// Example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/{name=messages/*}" -// }; -// } -// } -// message GetMessageRequest { -// string name = 1; // Mapped to URL path. -// } -// message Message { -// string text = 1; // The resource content. -// } -// -// This enables an HTTP REST to gRPC mapping as below: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` -// -// Any fields in the request message which are not bound by the path template -// automatically become HTTP query parameters if there is no HTTP request body. -// For example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get:"/v1/messages/{message_id}" -// }; -// } -// } -// message GetMessageRequest { -// message SubMessage { -// string subfield = 1; -// } -// string message_id = 1; // Mapped to URL path. -// int64 revision = 2; // Mapped to URL query parameter `revision`. -// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. -// } -// -// This enables a HTTP JSON to RPC mapping as below: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | -// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: -// "foo"))` -// -// Note that fields which are mapped to URL query parameters must have a -// primitive type or a repeated primitive type or a non-repeated message type. -// In the case of a repeated type, the parameter can be repeated in the URL -// as `...?param=A¶m=B`. In the case of a message type, each field of the -// message is mapped to a separate parameter, such as -// `...?foo.a=A&foo.b=B&foo.c=C`. -// -// For HTTP methods that allow a request body, the `body` field -// specifies the mapping. Consider a REST update method on the -// message resource collection: -// -// service Messaging { -// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { -// option (google.api.http) = { -// patch: "/v1/messages/{message_id}" -// body: "message" -// }; -// } -// } -// message UpdateMessageRequest { -// string message_id = 1; // mapped to the URL -// Message message = 2; // mapped to the body -// } -// -// The following HTTP JSON to RPC mapping is enabled, where the -// representation of the JSON in the request body is determined by -// protos JSON encoding: -// -// HTTP | gRPC -// -----|----- -// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: -// "123456" message { text: "Hi!" })` -// -// The special name `*` can be used in the body mapping to define that -// every field not bound by the path template should be mapped to the -// request body. This enables the following alternative definition of -// the update method: -// -// service Messaging { -// rpc UpdateMessage(Message) returns (Message) { -// option (google.api.http) = { -// patch: "/v1/messages/{message_id}" -// body: "*" -// }; -// } -// } -// message Message { -// string message_id = 1; -// string text = 2; -// } -// -// -// The following HTTP JSON to RPC mapping is enabled: -// -// HTTP | gRPC -// -----|----- -// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: -// "123456" text: "Hi!")` -// -// Note that when using `*` in the body mapping, it is not possible to -// have HTTP parameters, as all fields not bound by the path end in -// the body. This makes this option more rarely used in practice when -// defining REST APIs. The common usage of `*` is in custom methods -// which don't use the URL at all for transferring data. -// -// It is possible to define multiple HTTP methods for one RPC by using -// the `additional_bindings` option. Example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/messages/{message_id}" -// additional_bindings { -// get: "/v1/users/{user_id}/messages/{message_id}" -// } -// }; -// } -// } -// message GetMessageRequest { -// string message_id = 1; -// string user_id = 2; -// } -// -// This enables the following two alternative HTTP JSON to RPC mappings: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` -// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: -// "123456")` -// -// ## Rules for HTTP mapping -// -// 1. Leaf request fields (recursive expansion nested messages in the request -// message) are classified into three categories: -// - Fields referred by the path template. They are passed via the URL path. -// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP -// request body. -// - All other fields are passed via the URL query parameters, and the -// parameter name is the field path in the request message. A repeated -// field can be represented as multiple query parameters under the same -// name. -// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields -// are passed via URL path and HTTP request body. -// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all -// fields are passed via URL path and URL query parameters. -// -// ### Path template syntax -// -// Template = "/" Segments [ Verb ] ; -// Segments = Segment { "/" Segment } ; -// Segment = "*" | "**" | LITERAL | Variable ; -// Variable = "{" FieldPath [ "=" Segments ] "}" ; -// FieldPath = IDENT { "." IDENT } ; -// Verb = ":" LITERAL ; -// -// The syntax `*` matches a single URL path segment. The syntax `**` matches -// zero or more URL path segments, which must be the last part of the URL path -// except the `Verb`. -// -// The syntax `Variable` matches part of the URL path as specified by its -// template. A variable template must not contain other variables. If a variable -// matches a single path segment, its template may be omitted, e.g. `{var}` -// is equivalent to `{var=*}`. -// -// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` -// contains any reserved character, such characters should be percent-encoded -// before the matching. -// -// If a variable contains exactly one path segment, such as `"{var}"` or -// `"{var=*}"`, when such a variable is expanded into a URL path on the client -// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The -// server side does the reverse decoding. Such variables show up in the -// [Discovery -// Document](https://developers.google.com/discovery/v1/reference/apis) as -// `{var}`. -// -// If a variable contains multiple path segments, such as `"{var=foo/*}"` -// or `"{var=**}"`, when such a variable is expanded into a URL path on the -// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. -// The server side does the reverse decoding, except "%2F" and "%2f" are left -// unchanged. Such variables show up in the -// [Discovery -// Document](https://developers.google.com/discovery/v1/reference/apis) as -// `{+var}`. -// -// ## Using gRPC API Service Configuration -// -// gRPC API Service Configuration (service config) is a configuration language -// for configuring a gRPC service to become a user-facing product. The -// service config is simply the YAML representation of the `google.api.Service` -// proto message. -// -// As an alternative to annotating your proto file, you can configure gRPC -// transcoding in your service config YAML files. You do this by specifying a -// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same -// effect as the proto annotation. This can be particularly useful if you -// have a proto that is reused in multiple services. Note that any transcoding -// specified in the service config will override any matching transcoding -// configuration in the proto. -// -// Example: -// -// http: -// rules: -// # Selects a gRPC method and applies HttpRule to it. -// - selector: example.v1.Messaging.GetMessage -// get: /v1/messages/{message_id}/{sub.subfield} -// -// ## Special notes -// -// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the -// proto to JSON conversion must follow the [proto3 -// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). -// -// While the single segment variable follows the semantics of -// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String -// Expansion, the multi segment variable **does not** follow RFC 6570 Section -// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion -// does not expand special characters like `?` and `#`, which would lead -// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding -// for multi segment variables. -// -// The path variables **must not** refer to any repeated or mapped field, -// because client libraries are not capable of handling such variable expansion. -// -// The path variables **must not** capture the leading "/" character. The reason -// is that the most common use case "{var}" does not capture the leading "/" -// character. For consistency, all path variables must share the same behavior. -// -// Repeated message fields must not be mapped to URL query parameters, because -// no client library can support such complicated mapping. -// -// If an API needs to use a JSON array for request or response body, it can map -// the request or response body to a repeated field. However, some gRPC -// Transcoding implementations may not support this feature. -message HttpRule { - // Selects a method to which this rule applies. - // - // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. - string selector = 1; - - // Determines the URL pattern is matched by this rules. This pattern can be - // used with any of the {get|put|post|delete|patch} methods. A custom method - // can be defined using the 'custom' field. - oneof pattern { - // Maps to HTTP GET. Used for listing and getting information about - // resources. - string get = 2; - - // Maps to HTTP PUT. Used for replacing a resource. - string put = 3; - - // Maps to HTTP POST. Used for creating a resource or performing an action. - string post = 4; - - // Maps to HTTP DELETE. Used for deleting a resource. - string delete = 5; - - // Maps to HTTP PATCH. Used for updating a resource. - string patch = 6; - - // The custom pattern is used for specifying an HTTP method that is not - // included in the `pattern` field, such as HEAD, or "*" to leave the - // HTTP method unspecified for this rule. The wild-card rule is useful - // for services that provide content to Web (HTML) clients. - CustomHttpPattern custom = 8; - } - - // The name of the request field whose value is mapped to the HTTP request - // body, or `*` for mapping all request fields not captured by the path - // pattern to the HTTP body, or omitted for not having any HTTP request body. - // - // NOTE: the referred field must be present at the top-level of the request - // message type. - string body = 7; - - // Optional. The name of the response field whose value is mapped to the HTTP - // response body. When omitted, the entire response message will be used - // as the HTTP response body. - // - // NOTE: The referred field must be present at the top-level of the response - // message type. - string response_body = 12; - - // Additional HTTP bindings for the selector. Nested bindings must - // not contain an `additional_bindings` field themselves (that is, - // the nesting may only be one level deep). - repeated HttpRule additional_bindings = 11; -} - -// A custom pattern is used for defining custom HTTP verb. -message CustomHttpPattern { - // The name of this custom HTTP verb. - string kind = 1; - - // The path matched by this custom verb. - string path = 2; -} \ No newline at end of file From 7d945542f5b9b035bea17942bf2eea998633f53f Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 17 Dec 2025 11:16:47 +0000 Subject: [PATCH 65/69] Fix `buf` formatting for iavl protos --- sei-iavl/proto/iavl/proof.proto | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sei-iavl/proto/iavl/proof.proto b/sei-iavl/proto/iavl/proof.proto index 79e8ab87c8..9b5e28ba3a 100644 --- a/sei-iavl/proto/iavl/proof.proto +++ b/sei-iavl/proto/iavl/proof.proto @@ -15,9 +15,9 @@ message AbsenceOp { // RangeProof is a Protobuf representation of iavl.RangeProof. message RangeProof { - repeated ProofInnerNode left_path = 1; - repeated PathToLeaf inner_nodes = 2; - repeated ProofLeafNode leaves = 3; + repeated ProofInnerNode left_path = 1; + repeated PathToLeaf inner_nodes = 2; + repeated ProofLeafNode leaves = 3; } // PathToLeaf is a Protobuf representation of iavl.PathToLeaf. @@ -27,16 +27,16 @@ message PathToLeaf { // ProofInnerNode is a Protobuf representation of iavl.ProofInnerNode. message ProofInnerNode { - sint32 height = 1; - int64 size = 2; - int64 version = 3; - bytes left = 4; - bytes right = 5; + sint32 height = 1; + int64 size = 2; + int64 version = 3; + bytes left = 4; + bytes right = 5; } // ProofLeafNode is a Protobuf representation of iavl.ProofInnerNode. message ProofLeafNode { - bytes key = 1; + bytes key = 1; bytes value_hash = 2; - int64 version = 3; + int64 version = 3; } From bc21552e28cd97a885c92c2490f4a4e8ff52e7ed Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 17 Dec 2025 12:29:39 +0000 Subject: [PATCH 66/69] Fix golangci lint issues and bugs --- cmd/seid/cmd/debug.go | 2 +- go.mod | 4 +- go.sum | 2 - sei-cosmos/store/cache/cache_test.go | 2 +- sei-cosmos/store/iavl/store.go | 2 +- sei-cosmos/store/iavl/store_test.go | 2 +- sei-cosmos/store/iavl/tree.go | 2 +- sei-cosmos/store/iavl/tree_test.go | 2 +- sei-cosmos/storev2/commitment/store.go | 2 +- sei-db/proto/changelog.pb.go | 2 +- sei-db/sc/memiavl/db.go | 2 +- sei-db/sc/memiavl/db_test.go | 2 +- sei-db/sc/memiavl/multitree.go | 5 +-- sei-db/sc/memiavl/proof.go | 2 +- sei-db/sc/memiavl/snapshot_catchup_test.go | 2 +- sei-db/sc/memiavl/snapshot_pipeline_test.go | 2 +- sei-db/sc/memiavl/snapshot_write_test.go | 2 +- sei-db/sc/memiavl/tree.go | 2 +- sei-db/sc/memiavl/tree_test.go | 2 +- sei-db/ss/pebbledb/hash_test.go | 2 +- sei-db/ss/store_test.go | 2 +- sei-db/ss/test/storage_bench_suite.go | 5 +-- sei-db/ss/test/storage_test_suite.go | 2 +- sei-db/ss/test/utils.go | 2 +- sei-db/stream/changelog/changelog_test.go | 2 +- sei-db/stream/changelog/utils.go | 5 ++- sei-db/tools/bench/benchmark.go | 2 +- sei-db/tools/utils/utils.go | 2 +- sei-iavl/benchmarks/bench_test.go | 4 +- sei-iavl/benchmarks/cosmos-exim/main.go | 19 +++++--- sei-iavl/benchmarks/hash_test.go | 2 +- sei-iavl/cmd/iaviewer/main.go | 20 ++++++--- sei-iavl/export_test.go | 8 ++-- sei-iavl/immutable_tree.go | 4 +- sei-iavl/import.go | 2 +- sei-iavl/import_test.go | 8 ++-- sei-iavl/internal/bytes/bytes.go | 4 +- sei-iavl/internal/bytes/string.go | 14 +++--- sei-iavl/internal/rand/random.go | 10 ++++- sei-iavl/key_format.go | 23 +++++++--- sei-iavl/mutable_tree.go | 29 ++++++++++--- sei-iavl/node.go | 3 +- sei-iavl/nodedb.go | 16 ++++--- sei-iavl/orphandb.go | 35 +++++++++------ sei-iavl/proof_forgery_test.go | 2 +- sei-iavl/proof_range.go | 2 +- sei-iavl/repair.go | 2 +- sei-iavl/testutils_test.go | 2 +- sei-iavl/tree_dotgraph.go | 5 ++- sei-iavl/tree_test.go | 2 +- sei-iavl/util.go | 48 --------------------- tools/hash_verification/iavl/scanner.go | 2 +- tools/migration/cmd/cmd.go | 2 +- tools/migration/ss/migrator.go | 2 +- x/evm/keeper/receipt.go | 2 +- 55 files changed, 176 insertions(+), 163 deletions(-) diff --git a/cmd/seid/cmd/debug.go b/cmd/seid/cmd/debug.go index fe48041573..a297939a4e 100644 --- a/cmd/seid/cmd/debug.go +++ b/cmd/seid/cmd/debug.go @@ -13,7 +13,7 @@ import ( "strings" "github.com/cosmos/cosmos-sdk/version" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/spf13/cobra" dbm "github.com/tendermint/tm-db" ) diff --git a/go.mod b/go.mod index 1b4ce2d350..5b55e92f18 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/go-playground/validator/v10 v10.11.1 github.com/gogo/protobuf v1.3.3 github.com/golang-jwt/jwt/v4 v4.5.1 + github.com/golang/mock v1.7.0-rc.1 github.com/golang/protobuf v1.5.4 github.com/golangci/golangci-lint v1.46.0 github.com/google/btree v1.1.3 @@ -56,6 +57,7 @@ require ( go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 + golang.org/x/crypto v0.40.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.16.0 golang.org/x/sys v0.35.0 @@ -170,7 +172,6 @@ require ( github.com/gogo/gateway v1.1.0 // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/mock v1.7.0-rc.1 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect @@ -319,7 +320,6 @@ require ( go.opentelemetry.io/otel/exporters/jaeger v1.9.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.40.0 // indirect golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect golang.org/x/mod v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect diff --git a/go.sum b/go.sum index ca617c702a..56bcfa7c3d 100644 --- a/go.sum +++ b/go.sum @@ -2001,8 +2001,6 @@ github.com/sei-protocol/go-ethereum v1.15.7-sei-7.0.20250929182230-93350978bb7c github.com/sei-protocol/go-ethereum v1.15.7-sei-7.0.20250929182230-93350978bb7c/go.mod h1:+S9k+jFzlyVTNcYGvqFhzN/SFhI6vA+aOY4T5tLSPL0= github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA= github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= -github.com/sei-protocol/sei-iavl v0.2.0 h1:OisPjXiDT+oe+aeckzDEFgkZCYuUjHgs/PP8DPicN+I= -github.com/sei-protocol/sei-iavl v0.2.0/go.mod h1:qRf8QYUPfrAO7K6VDB2B2l/N7K5L76OorioGBcJBIbw= github.com/sei-protocol/sei-load v0.0.0-20251007135253-78fbdc141082 h1:f2sY8OcN60UL1/6POx+HDMZ4w04FTZtSScnrFSnGZHg= github.com/sei-protocol/sei-load v0.0.0-20251007135253-78fbdc141082/go.mod h1:V0fNURAjS6A8+sA1VllegjNeSobay3oRUW5VFZd04bA= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= diff --git a/sei-cosmos/store/cache/cache_test.go b/sei-cosmos/store/cache/cache_test.go index 4c753aee8a..cdbf2fce08 100644 --- a/sei-cosmos/store/cache/cache_test.go +++ b/sei-cosmos/store/cache/cache_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" diff --git a/sei-cosmos/store/iavl/store.go b/sei-cosmos/store/iavl/store.go index bbf99f964f..66bd86c128 100644 --- a/sei-cosmos/store/iavl/store.go +++ b/sei-cosmos/store/iavl/store.go @@ -8,7 +8,7 @@ import ( "time" ics23 "github.com/confio/ics23/go" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" diff --git a/sei-cosmos/store/iavl/store_test.go b/sei-cosmos/store/iavl/store_test.go index 427a5d10dc..f70fcfd2ff 100644 --- a/sei-cosmos/store/iavl/store_test.go +++ b/sei-cosmos/store/iavl/store_test.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/cachekv" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" diff --git a/sei-cosmos/store/iavl/tree.go b/sei-cosmos/store/iavl/tree.go index 67aec3e391..98253f5245 100644 --- a/sei-cosmos/store/iavl/tree.go +++ b/sei-cosmos/store/iavl/tree.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/store/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) var ( diff --git a/sei-cosmos/store/iavl/tree_test.go b/sei-cosmos/store/iavl/tree_test.go index 2990cec753..a12bdfe50e 100644 --- a/sei-cosmos/store/iavl/tree_test.go +++ b/sei-cosmos/store/iavl/tree_test.go @@ -3,7 +3,7 @@ package iavl import ( "testing" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" ) diff --git a/sei-cosmos/storev2/commitment/store.go b/sei-cosmos/storev2/commitment/store.go index 60041900ec..055a41a8e3 100644 --- a/sei-cosmos/storev2/commitment/store.go +++ b/sei-cosmos/storev2/commitment/store.go @@ -12,7 +12,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/kv" sctypes "github.com/sei-protocol/sei-chain/sei-db/sc/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/proto/tendermint/crypto" diff --git a/sei-db/proto/changelog.pb.go b/sei-db/proto/changelog.pb.go index abdd548b22..50c24aad0c 100644 --- a/sei-db/proto/changelog.pb.go +++ b/sei-db/proto/changelog.pb.go @@ -9,9 +9,9 @@ import ( math "math" math_bits "math/bits" - "github.com/sei-protocol/sei-chain/sei-iavl" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/sei-db/sc/memiavl/db.go b/sei-db/sc/memiavl/db.go index dc22bea0a3..66ace7e02f 100644 --- a/sei-db/sc/memiavl/db.go +++ b/sei-db/sc/memiavl/db.go @@ -24,7 +24,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/stream/changelog" "github.com/sei-protocol/sei-chain/sei-db/stream/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) const LockFileName = "LOCK" diff --git a/sei-db/sc/memiavl/db_test.go b/sei-db/sc/memiavl/db_test.go index 2a70252d20..07e477ff58 100644 --- a/sei-db/sc/memiavl/db_test.go +++ b/sei-db/sc/memiavl/db_test.go @@ -15,7 +15,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/common/utils" "github.com/sei-protocol/sei-chain/sei-db/proto" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/sc/memiavl/multitree.go b/sei-db/sc/memiavl/multitree.go index b13957ad40..b07c5b98f9 100644 --- a/sei-db/sc/memiavl/multitree.go +++ b/sei-db/sc/memiavl/multitree.go @@ -12,14 +12,13 @@ import ( "time" "github.com/alitto/pond" - "golang.org/x/exp/slices" - "github.com/sei-protocol/sei-chain/sei-db/common/errors" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/common/utils" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/stream/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" + "golang.org/x/exp/slices" ) const ( diff --git a/sei-db/sc/memiavl/proof.go b/sei-db/sc/memiavl/proof.go index 7853f3a35c..f7919d04ff 100644 --- a/sei-db/sc/memiavl/proof.go +++ b/sei-db/sc/memiavl/proof.go @@ -8,7 +8,7 @@ import ( "math" ics23 "github.com/confio/ics23/go" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) /* diff --git a/sei-db/sc/memiavl/snapshot_catchup_test.go b/sei-db/sc/memiavl/snapshot_catchup_test.go index 356c625f9c..13976bb1bd 100644 --- a/sei-db/sc/memiavl/snapshot_catchup_test.go +++ b/sei-db/sc/memiavl/snapshot_catchup_test.go @@ -6,7 +6,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/proto" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/sc/memiavl/snapshot_pipeline_test.go b/sei-db/sc/memiavl/snapshot_pipeline_test.go index 4677dc0ef4..6527825ba5 100644 --- a/sei-db/sc/memiavl/snapshot_pipeline_test.go +++ b/sei-db/sc/memiavl/snapshot_pipeline_test.go @@ -6,7 +6,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/sc/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/sc/memiavl/snapshot_write_test.go b/sei-db/sc/memiavl/snapshot_write_test.go index ada645415f..1a11fba240 100644 --- a/sei-db/sc/memiavl/snapshot_write_test.go +++ b/sei-db/sc/memiavl/snapshot_write_test.go @@ -8,7 +8,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/proto" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/sc/memiavl/tree.go b/sei-db/sc/memiavl/tree.go index ad7e3e6f32..bca5cec399 100644 --- a/sei-db/sc/memiavl/tree.go +++ b/sei-db/sc/memiavl/tree.go @@ -11,7 +11,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/common/utils" "github.com/sei-protocol/sei-chain/sei-db/sc/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" dbm "github.com/tendermint/tm-db" ) diff --git a/sei-db/sc/memiavl/tree_test.go b/sei-db/sc/memiavl/tree_test.go index 7b98ac11f7..04a9cd57e8 100644 --- a/sei-db/sc/memiavl/tree_test.go +++ b/sei-db/sc/memiavl/tree_test.go @@ -6,7 +6,7 @@ import ( "strconv" "testing" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" db "github.com/tendermint/tm-db" ) diff --git a/sei-db/ss/pebbledb/hash_test.go b/sei-db/ss/pebbledb/hash_test.go index 0c29d6e15f..23c45b6aba 100644 --- a/sei-db/ss/pebbledb/hash_test.go +++ b/sei-db/ss/pebbledb/hash_test.go @@ -11,7 +11,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/config" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/util" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/sei-db/ss/store_test.go b/sei-db/ss/store_test.go index 91eb654652..9db08d4c41 100644 --- a/sei-db/ss/store_test.go +++ b/sei-db/ss/store_test.go @@ -9,7 +9,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/config" "github.com/sei-protocol/sei-chain/sei-db/proto" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" ) diff --git a/sei-db/ss/test/storage_bench_suite.go b/sei-db/ss/test/storage_bench_suite.go index 448cdeda07..ee5376274e 100644 --- a/sei-db/ss/test/storage_bench_suite.go +++ b/sei-db/ss/test/storage_bench_suite.go @@ -6,11 +6,10 @@ import ( "sort" "testing" - "github.com/stretchr/testify/require" - "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" + "github.com/stretchr/testify/require" ) // StorageBenchSuite defines a reusable benchmark suite for all storage backends. diff --git a/sei-db/ss/test/storage_test_suite.go b/sei-db/ss/test/storage_test_suite.go index 341de93bf1..f8fd1e55b0 100644 --- a/sei-db/ss/test/storage_test_suite.go +++ b/sei-db/ss/test/storage_test_suite.go @@ -7,7 +7,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/config" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/suite" "golang.org/x/exp/slices" ) diff --git a/sei-db/ss/test/utils.go b/sei-db/ss/test/utils.go index 70ff45de41..3ce9c30dd7 100644 --- a/sei-db/ss/test/utils.go +++ b/sei-db/ss/test/utils.go @@ -5,7 +5,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) // Fills the db with multiple keys each with different versions diff --git a/sei-db/stream/changelog/changelog_test.go b/sei-db/stream/changelog/changelog_test.go index 36e2c55a9f..860b39f4b9 100644 --- a/sei-db/stream/changelog/changelog_test.go +++ b/sei-db/stream/changelog/changelog_test.go @@ -8,7 +8,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/proto" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" "github.com/tidwall/wal" ) diff --git a/sei-db/stream/changelog/utils.go b/sei-db/stream/changelog/utils.go index 6193fb1527..2500e57dd1 100644 --- a/sei-db/stream/changelog/utils.go +++ b/sei-db/stream/changelog/utils.go @@ -3,12 +3,13 @@ package changelog import ( "bytes" "encoding/binary" + "errors" "math" "os" "path/filepath" "unsafe" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/tidwall/gjson" "github.com/tidwall/wal" ) @@ -44,7 +45,7 @@ func truncateCorruptedTail(path string, format wal.LogFormat) error { } else { n, err = loadNextBinaryEntry(data) } - if err == wal.ErrCorrupt { + if errors.Is(err, wal.ErrCorrupt) { break } if err != nil { diff --git a/sei-db/tools/bench/benchmark.go b/sei-db/tools/bench/benchmark.go index d821406ceb..bbee44e58a 100644 --- a/sei-db/tools/bench/benchmark.go +++ b/sei-db/tools/bench/benchmark.go @@ -12,7 +12,7 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/ss/types" "github.com/sei-protocol/sei-chain/sei-db/tools/utils" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) // writeToDBConcurrently generates random write load against the db diff --git a/sei-db/tools/utils/utils.go b/sei-db/tools/utils/utils.go index 6d25f5495a..8948bf72ef 100644 --- a/sei-db/tools/utils/utils.go +++ b/sei-db/tools/utils/utils.go @@ -13,7 +13,7 @@ import ( "sync" "time" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" dbm "github.com/tendermint/tm-db" ) diff --git a/sei-iavl/benchmarks/bench_test.go b/sei-iavl/benchmarks/bench_test.go index 6b937eb1e4..2f19b879f0 100644 --- a/sei-iavl/benchmarks/bench_test.go +++ b/sei-iavl/benchmarks/bench_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" db "github.com/tendermint/tm-db" ) @@ -344,7 +344,7 @@ func runBenchmarks(b *testing.B, benchmarks []benchmark) { if bb.dbType != "nodb" { d, err = db.NewDB("test", bb.dbType, dirName) require.NoError(b, err) - defer d.Close() + defer func() { _ = d.Close() }() } b.Run(prefix, func(sub *testing.B) { runSuite(sub, d, bb.initSize, bb.blockSize, bb.keyLen, bb.dataLen) diff --git a/sei-iavl/benchmarks/cosmos-exim/main.go b/sei-iavl/benchmarks/cosmos-exim/main.go index 2d71686055..179b851f01 100644 --- a/sei-iavl/benchmarks/cosmos-exim/main.go +++ b/sei-iavl/benchmarks/cosmos-exim/main.go @@ -2,11 +2,10 @@ package main import ( "fmt" - "io/ioutil" "os" "time" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" tmdb "github.com/tendermint/tm-db" ) @@ -50,7 +49,8 @@ func (s *Stats) AddNode(node *iavl.ExportNode) { if node.Height == 0 { s.leafNodes++ } - s.size += uint64(len(node.Key) + len(node.Value) + 8 + 1) + // #nosec G115 -- len() always returns non-negative values + s.size += uint64(len(node.Key)) + uint64(len(node.Value)) + 9 } func (s *Stats) String() string { @@ -61,12 +61,12 @@ func (s *Stats) String() string { // main runs the main program func main() { if len(os.Args) != 2 { - fmt.Fprintf(os.Stderr, "Usage: %v \n", os.Args[0]) + _, _ = fmt.Fprintf(os.Stderr, "Usage: %v \n", os.Args[0]) os.Exit(1) } err := run(os.Args[1]) if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err.Error()) + _, _ = fmt.Fprintf(os.Stderr, "Error: %v\n", err.Error()) os.Exit(1) } } @@ -158,42 +158,47 @@ func runImport(version int64, exports map[string][]*iavl.ExportNode) error { totalStats := Stats{} for _, name := range stores { - tempdir, err := ioutil.TempDir("", name) + tempdir, err := os.MkdirTemp("", name) if err != nil { return err } - defer os.RemoveAll(tempdir) start := time.Now() stats := Stats{} newDB, err := tmdb.NewDB(name, tmdb.GoLevelDBBackend, tempdir) if err != nil { + _ = os.RemoveAll(tempdir) return err } newTree, err := iavl.NewMutableTree(newDB, 0, false) if err != nil { + _ = os.RemoveAll(tempdir) return err } importer, err := newTree.Import(version) if err != nil { + _ = os.RemoveAll(tempdir) return err } defer importer.Close() for _, node := range exports[name] { err = importer.Add(node) if err != nil { + _ = os.RemoveAll(tempdir) return err } stats.AddNode(node) } err = importer.Commit() if err != nil { + _ = os.RemoveAll(tempdir) return err } stats.AddDurationSince(start) fmt.Printf("%-12v: %v\n", name, stats.String()) totalStats.Add(stats) + _ = os.RemoveAll(tempdir) } fmt.Printf("\nImported %v stores with %v\n", len(stores), totalStats.String()) diff --git a/sei-iavl/benchmarks/hash_test.go b/sei-iavl/benchmarks/hash_test.go index 9fd55d3f97..62da2ca8d0 100644 --- a/sei-iavl/benchmarks/hash_test.go +++ b/sei-iavl/benchmarks/hash_test.go @@ -6,7 +6,7 @@ import ( "hash" "testing" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" _ "crypto/sha256" diff --git a/sei-iavl/cmd/iaviewer/main.go b/sei-iavl/cmd/iaviewer/main.go index 622deb8c6f..526cf20942 100644 --- a/sei-iavl/cmd/iaviewer/main.go +++ b/sei-iavl/cmd/iaviewer/main.go @@ -10,7 +10,7 @@ import ( dbm "github.com/tendermint/tm-db" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" ibytes "github.com/sei-protocol/sei-chain/sei-iavl/internal/bytes" ) @@ -95,7 +95,7 @@ func PrintDBStats(db dbm.DB) { panic(err) } - defer itr.Close() + defer func() { _ = itr.Close() }() for ; itr.Valid(); itr.Next() { key := ibytes.UnsafeBytesToStr(itr.Key()[:1]) prefix[key]++ @@ -137,7 +137,7 @@ func PrintTreeData(tree *iavl.MutableTree, keysOnly bool) { totalValSize := 0 totalNumKeys := 0 keyPrefixMap := map[string]int{} - tree.Iterate(func(key []byte, value []byte) bool { + _, err := tree.Iterate(func(key []byte, value []byte) bool { printKey := parseWeaveKey(key) if keysOnly { fmt.Printf("%s\n", printKey) @@ -151,11 +151,15 @@ func PrintTreeData(tree *iavl.MutableTree, keysOnly bool) { keyPrefixMap[fmt.Sprintf("%x", key[0])]++ return false }) - fmt.Printf("Total key count %d, total key bytes %d, total value bytes %d, prefix map %v\n", totalNumKeys, totalKeySize, totalValSize, keyPrefixMap) + if err != nil { + fmt.Printf("Failed to iterate the tree fully: %v\n", err) + } else { + fmt.Printf("Total key count %d, total key bytes %d, total value bytes %d, prefix map %v\n", totalNumKeys, totalKeySize, totalValSize, keyPrefixMap) + } } // parseWeaveKey assumes a separating : where all in front should be ascii, -// and all afterwards may be ascii or binary +// and all afterward may be ascii or binary func parseWeaveKey(key []byte) string { return encodeID(key) } @@ -199,7 +203,7 @@ func PrintVersions(tree *iavl.MutableTree) { func PrintSize(tree *iavl.MutableTree) { count, totalKeySize, totalValueSize := 0, 0, 0 keySizeByPrefix, valSizeByPrefix := map[byte]int{}, map[byte]int{} - tree.Iterate(func(key []byte, value []byte) bool { + _, err := tree.Iterate(func(key []byte, value []byte) bool { count += 1 totalKeySize += len(key) totalValueSize += len(value) @@ -211,6 +215,10 @@ func PrintSize(tree *iavl.MutableTree) { valSizeByPrefix[key[0]] += len(value) return false }) + if err != nil { + fmt.Printf("Failed to iterate the tree fully: %v\n", err) + return + } fmt.Printf("Total entry count: %d. Total key bytes: %d. Total value bytes: %d\n", count, totalKeySize, totalValueSize) for p := range keySizeByPrefix { fmt.Printf("prefix %d has key bytes %d and value bytes %d\n", p, keySizeByPrefix[p], valSizeByPrefix[p]) diff --git a/sei-iavl/export_test.go b/sei-iavl/export_test.go index f75effc51e..37b4c79d1c 100644 --- a/sei-iavl/export_test.go +++ b/sei-iavl/export_test.go @@ -161,7 +161,7 @@ func TestExporter(t *testing.T) { actual := make([]*ExportNode, 0, len(expect)) exporter := tree.Export() - defer exporter.Close() + defer func() { _ = exporter.Close() }() for { node, err := exporter.Next() if err == ExportDone { @@ -190,13 +190,13 @@ func TestExporter_Import(t *testing.T) { t.Parallel() exporter := tree.Export() - defer exporter.Close() + defer func() { _ = exporter.Close() }() newTree, err := NewMutableTree(db.NewMemDB(), 0, false) require.NoError(t, err) importer, err := newTree.Import(tree.Version()) require.NoError(t, err) - defer importer.Close() + defer func() { _ = importer.Close() }() for { item, err := exporter.Next() @@ -274,7 +274,7 @@ func TestExporter_DeleteVersionErrors(t *testing.T) { itree, err := tree.GetImmutable(2) require.NoError(t, err) exporter := itree.Export() - defer exporter.Close() + defer func() { _ = exporter.Close() }() err = tree.DeleteVersion(2) require.Error(t, err) diff --git a/sei-iavl/immutable_tree.go b/sei-iavl/immutable_tree.go index 3f6fe52a0b..c9962e657a 100644 --- a/sei-iavl/immutable_tree.go +++ b/sei-iavl/immutable_tree.go @@ -45,7 +45,7 @@ func NewImmutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastS // String returns a string representation of Tree. func (t *ImmutableTree) String() string { leaves := []string{} - t.Iterate(func(key []byte, val []byte) (stop bool) { + _, _ = t.Iterate(func(key []byte, val []byte) (stop bool) { leaves = append(leaves, fmt.Sprintf("%x: %x", key, val)) return false }) @@ -231,7 +231,7 @@ func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (bool, e } itr, err := t.Iterator(nil, nil, true) - defer itr.Close() + defer func() { _ = itr.Close() }() if err != nil { return false, err } diff --git a/sei-iavl/import.go b/sei-iavl/import.go index 9687c3d3c6..45bf8ae976 100644 --- a/sei-iavl/import.go +++ b/sei-iavl/import.go @@ -142,7 +142,7 @@ func batchWrite(i *Importer) { break } i.batchMtx.Lock() - nextBatch.Close() + _ = nextBatch.Close() i.batchMtx.Unlock() } else { break diff --git a/sei-iavl/import_test.go b/sei-iavl/import_test.go index 5fbf7d733e..0c08520aa6 100644 --- a/sei-iavl/import_test.go +++ b/sei-iavl/import_test.go @@ -28,7 +28,7 @@ func ExampleImporter() { // handle err } exporter := itree.Export() - defer exporter.Close() + defer func() { _ = exporter.Close() }() exported := []*ExportNode{} for { var node *ExportNode @@ -49,7 +49,7 @@ func ExampleImporter() { if err != nil { // handle err } - defer importer.Close() + defer func() { _ = importer.Close() }() for _, node := range exported { err = importer.Add(node) if err != nil { @@ -130,7 +130,7 @@ func TestImporter_Add(t *testing.T) { require.NoError(t, err) importer, err := tree.Import(1) require.NoError(t, err) - defer importer.Close() + defer func() { _ = importer.Close() }() err = importer.Add(tc.node) if tc.valid { @@ -207,7 +207,7 @@ func TestImporter_Commit_Empty(t *testing.T) { require.NoError(t, err) importer, err := tree.Import(3) require.NoError(t, err) - defer importer.Close() + defer func() { _ = importer.Close() }() err = importer.Commit() require.NoError(t, err) diff --git a/sei-iavl/internal/bytes/bytes.go b/sei-iavl/internal/bytes/bytes.go index 23c0421962..f99a584397 100644 --- a/sei-iavl/internal/bytes/bytes.go +++ b/sei-iavl/internal/bytes/bytes.go @@ -57,9 +57,9 @@ func (bz HexBytes) String() string { func (bz HexBytes) Format(s fmt.State, verb rune) { switch verb { case 'p': - s.Write([]byte(fmt.Sprintf("%p", bz))) + _, _ = fmt.Fprintf(s, "%p", bz) default: - s.Write([]byte(fmt.Sprintf("%X", []byte(bz)))) + _, _ = fmt.Fprintf(s, "%X", []byte(bz)) } } diff --git a/sei-iavl/internal/bytes/string.go b/sei-iavl/internal/bytes/string.go index a09422218b..0d882488a8 100644 --- a/sei-iavl/internal/bytes/string.go +++ b/sei-iavl/internal/bytes/string.go @@ -1,26 +1,24 @@ package common import ( - "reflect" "unsafe" ) // UnsafeStrToBytes uses unsafe to convert string into byte array. Returned bytes // must not be altered after this function is called as it will cause a segmentation fault. +// #nosec G103 -- unsafe usage is intentional for zero-copy string to byte conversion func UnsafeStrToBytes(s string) []byte { - var buf []byte - sHdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) - bufHdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) - bufHdr.Data = sHdr.Data - bufHdr.Cap = sHdr.Len - bufHdr.Len = sHdr.Len - return buf + if s == "" { + return nil + } + return unsafe.Slice(unsafe.StringData(s), len(s)) } // UnsafeBytesToStr is meant to make a zero allocation conversion // from []byte -> string to speed up operations, it is not meant // to be used generally, but for a specific pattern to delete keys // from a map. +// #nosec G103 -- unsafe usage is intentional for zero-copy byte slice to string conversion func UnsafeBytesToStr(b []byte) string { return *(*string)(unsafe.Pointer(&b)) } diff --git a/sei-iavl/internal/rand/random.go b/sei-iavl/internal/rand/random.go index 2b52df9dee..1bbb8609aa 100644 --- a/sei-iavl/internal/rand/random.go +++ b/sei-iavl/internal/rand/random.go @@ -2,6 +2,7 @@ package common import ( crand "crypto/rand" + "math" mrand "math/rand" "sync" "time" @@ -43,6 +44,7 @@ func (r *Rand) init() { seed |= uint64(bz[i]) seed <<= 8 } + // #nosec G115 -- seed is intentionally truncated for PRNG seeding r.reset(int64(seed)) } @@ -111,6 +113,7 @@ MAIN_LOOP: } func (r *Rand) Uint16() uint16 { + // #nosec G115 -- value is masked to 16 bits, always fits in uint16 return uint16(r.Uint32() & (1<<16 - 1)) } @@ -129,18 +132,22 @@ func (r *Rand) Uint() uint { r.Lock() i := r.rand.Int() r.Unlock() + // #nosec G115 -- rand.Int() always returns non-negative values return uint(i) } func (r *Rand) Int16() int16 { + // #nosec G115 -- value is masked to 16 bits, always fits in int16 return int16(r.Uint32() & (1<<16 - 1)) } func (r *Rand) Int32() int32 { + // #nosec G115 -- intentional conversion for random number generation return int32(r.Uint32()) } func (r *Rand) Int64() int64 { + // #nosec G115 -- intentional conversion for random number generation return int64(r.Uint64()) } @@ -194,7 +201,8 @@ func (r *Rand) Float64() float64 { } func (r *Rand) Time() time.Time { - return time.Unix(int64(r.Uint64()), 0) + // #nosec G115 -- limiting to MaxInt64 to ensure valid Unix timestamp + return time.Unix(int64(r.Uint64()&math.MaxInt64), 0) } // Bytes returns n random bytes generated from the internal diff --git a/sei-iavl/key_format.go b/sei-iavl/key_format.go index 31ff82a26f..9dc363fd2e 100644 --- a/sei-iavl/key_format.go +++ b/sei-iavl/key_format.go @@ -19,15 +19,16 @@ type KeyFormat struct { // For example, to store keys that could index some objects by a version number and their SHA256 hash using the form: // 'c' then you would define the KeyFormat with: // -// var keyFormat = NewKeyFormat('c', 8, 32) +// var keyFormat = NewKeyFormat('c', 8, 32) // // Then you can create a key with: // -// func ObjectKey(version uint64, objectBytes []byte) []byte { -// hasher := sha256.New() -// hasher.Sum(nil) -// return keyFormat.Key(version, hasher.Sum(nil)) -// } +// func ObjectKey(version uint64, objectBytes []byte) []byte { +// hasher := sha256.New() +// hasher.Sum(nil) +// return keyFormat.Key(version, hasher.Sum(nil)) +// } +// // if the last term of the layout ends in 0 func NewKeyFormat(prefix byte, layout ...int) *KeyFormat { // For prefix byte @@ -146,7 +147,7 @@ func (kf *KeyFormat) Prefix() string { func scan(a interface{}, value []byte) { switch v := a.(type) { case *int64: - // Negative values will be mapped correctly when read in as uint64 and then type converted + // #nosec G115 -- Negative values will be mapped correctly when read in as uint64 and then type converted *v = int64(binary.BigEndian.Uint64(value)) case *uint64: *v = binary.BigEndian.Uint64(value) @@ -162,11 +163,19 @@ func format(a interface{}) []byte { case uint64: return formatUint64(v) case int64: + if v < 0 { + panic(fmt.Errorf("keyFormat format() does not support negative int64 value: %d", v)) + } + // #nosec G115 -- value is checked above to be non-negative return formatUint64(uint64(v)) // Provide formatting from int,uint as a convenience to avoid casting arguments case uint: return formatUint64(uint64(v)) case int: + if v < 0 { + panic(fmt.Errorf("keyFormat format() does not support negative int value: %d", v)) + } + // #nosec G115 -- value is checked above to be non-negative return formatUint64(uint64(v)) case []byte: return v diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index 623642ee67..dd7cad7da0 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/sha256" "fmt" + "math" "sort" "sync" @@ -226,7 +227,7 @@ func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stoppe } itr := NewUnsavedFastIterator(nil, nil, true, tree.ndb, tree.unsavedFastNodeAdditions, tree.unsavedFastNodeRemovals) - defer itr.Close() + defer func() { _ = itr.Close() }() for ; itr.Valid(); itr.Next() { if fn(itr.Key(), itr.Value()) { return true, nil @@ -583,6 +584,10 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr if err != nil { return 0, err } + if tree.ndb.opts.InitialVersion > math.MaxInt64 { + return firstVersion, fmt.Errorf("initial version %d exceeds max int64", tree.ndb.opts.InitialVersion) + } + // #nosec G115 -- InitialVersion is bounds checked above if firstVersion > 0 && firstVersion < int64(tree.ndb.opts.InitialVersion) { return firstVersion, fmt.Errorf("initial version set to %v, but found earlier version %v", tree.ndb.opts.InitialVersion, firstVersion) @@ -673,11 +678,15 @@ func (tree *MutableTree) LegacyLoadVersion(targetVersion int64) (toReturn int64, } } - if !(targetVersion == 0 || latestVersion == targetVersion) { + if targetVersion != 0 || latestVersion != targetVersion { return latestVersion, fmt.Errorf("wanted to load target %v but only found up to %v", targetVersion, latestVersion) } + if tree.ndb.opts.InitialVersion > math.MaxInt64 { + return latestVersion, fmt.Errorf("initial version %d exceeds max int64", tree.ndb.opts.InitialVersion) + } + // #nosec G115 -- InitialVersion is bounds checked above if firstVersion > 0 && firstVersion < int64(tree.ndb.opts.InitialVersion) { return latestVersion, fmt.Errorf("initial version set to %v, but found earlier version %v", tree.ndb.opts.InitialVersion, firstVersion) @@ -759,7 +768,7 @@ func (tree *MutableTree) enableFastStorageAndCommitIfNotEnabled() (bool, error) // Therefore, there might exist stale fast nodes on disk. As a result, to avoid persisting the stale state, it might // be worth to delete the fast nodes from disk. fastItr := NewFastIterator(nil, nil, true, tree.ndb) - defer fastItr.Close() + defer func() { _ = fastItr.Close() }() var deletedFastNodes uint64 for ; fastItr.Valid(); fastItr.Next() { deletedFastNodes++ @@ -789,7 +798,7 @@ func (tree *MutableTree) enableFastStorageAndCommit() error { var err error itr := NewIteratorUnlocked(nil, nil, true, tree.ImmutableTree()) - defer itr.Close() + defer func() { _ = itr.Close() }() version := tree.ImmutableTree().version var upgradedFastNodes uint64 for ; itr.Valid(); itr.Next() { @@ -798,7 +807,9 @@ func (tree *MutableTree) enableFastStorageAndCommit() error { return err } if upgradedFastNodes%commitGap == 0 { - tree.ndb.Commit() + if err := tree.ndb.Commit(); err != nil { + return err + } } } @@ -909,6 +920,10 @@ func (tree *MutableTree) GetVersioned(key []byte, version int64) ([]byte, error) func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { version := tree.ImmutableTree().version if version == 1 && tree.ndb.opts.InitialVersion > 0 { + if tree.ndb.opts.InitialVersion > math.MaxInt64 { + return nil, 0, fmt.Errorf("initial version %d exceeds max int64", tree.ndb.opts.InitialVersion) + } + // #nosec G115 -- InitialVersion is bounds checked above version = int64(tree.ndb.opts.InitialVersion) } @@ -954,6 +969,10 @@ func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { version := tree.ImmutableTree().version + 1 if version == 1 && tree.ndb.opts.InitialVersion > 0 { + if tree.ndb.opts.InitialVersion > math.MaxInt64 { + return nil, 0, fmt.Errorf("initial version %d exceeds max int64", tree.ndb.opts.InitialVersion) + } + // #nosec G115 -- InitialVersion is bounds checked above version = int64(tree.ndb.opts.InitialVersion) } diff --git a/sei-iavl/node.go b/sei-iavl/node.go index 96b3cc0a8b..d2d8fb8f1b 100644 --- a/sei-iavl/node.go +++ b/sei-iavl/node.go @@ -50,7 +50,7 @@ func NewNode(key []byte, value []byte, version int64) *Node { // MakeNode constructs an *Node from an encoded byte slice. // // The new node doesn't have its hash saved or set. The caller must set it -// afterwards. +// afterward. func MakeNode(buf []byte) (*Node, error) { // Read node header (height, size, version, key). @@ -82,6 +82,7 @@ func MakeNode(buf []byte) (*Node, error) { buf = buf[n:] node := &Node{ + // #nosec G115 -- height is bounds checked above to be within int8 range height: int8(height), size: size, version: ver, diff --git a/sei-iavl/nodedb.go b/sei-iavl/nodedb.go index d06642fb77..8ec04a8aeb 100644 --- a/sei-iavl/nodedb.go +++ b/sei-iavl/nodedb.go @@ -720,7 +720,9 @@ func (ndb *nodeDB) deleteOrphans(version int64) error { ndb.nodeCache.Remove(hash) } else { logger.Debug("MOVE predecessor:%v fromVersion:%v toVersion:%v %X\n", predecessor, fromVersion, toVersion, hash) - ndb.saveOrphan(hash, fromVersion, predecessor) + if err := ndb.saveOrphan(hash, fromVersion, predecessor); err != nil { + return err + } } return nil }) @@ -779,7 +781,7 @@ func (ndb *nodeDB) getFirstVersion() (int64, error) { if err != nil { return 0, err } - defer itr.Close() + defer func() { _ = itr.Close() }() if itr.Valid() { var version int64 rootKeyFormat.Scan(itr.Key(), &version) @@ -829,7 +831,7 @@ func (ndb *nodeDB) getPreviousVersion(version int64) (int64, error) { if err != nil { return 0, err } - defer itr.Close() + defer func() { _ = itr.Close() }() pversion := int64(-1) for ; itr.Valid(); itr.Next() { @@ -888,7 +890,7 @@ func (ndb *nodeDB) traverseRange(start []byte, end []byte, fn func(k, v []byte) if err != nil { return err } - defer itr.Close() + defer func() { _ = itr.Close() }() for ; itr.Valid(); itr.Next() { if err := fn(itr.Key(), itr.Value()); err != nil { @@ -909,7 +911,7 @@ func (ndb *nodeDB) traversePrefix(prefix []byte, fn func(k, v []byte) error) err if err != nil { return err } - defer itr.Close() + defer func() { _ = itr.Close() }() for ; itr.Valid(); itr.Next() { if err := fn(itr.Key(), itr.Value()); err != nil { @@ -959,7 +961,9 @@ func (ndb *nodeDB) Commit() error { return errors.Wrap(err, "failed to write batch") } - ndb.batch.Close() + if err := ndb.batch.Close(); err != nil { + return err + } ndb.batch = ndb.db.NewBatch() return nil diff --git a/sei-iavl/orphandb.go b/sei-iavl/orphandb.go index fb714e19a7..da49926851 100644 --- a/sei-iavl/orphandb.go +++ b/sei-iavl/orphandb.go @@ -3,9 +3,8 @@ package iavl import ( "fmt" "io/fs" - "io/ioutil" "os" - "path" + "path/filepath" "strings" ) @@ -32,16 +31,28 @@ func (o *orphanDB) SaveOrphans(version int64, orphans map[string]int64) error { } chunks[len(chunks)-1] = append(chunks[len(chunks)-1], orphan) } - dir := path.Join(o.directory, fmt.Sprintf("%d", version)) - os.RemoveAll(dir) - os.MkdirAll(dir, fs.ModePerm) + dir := filepath.Clean(filepath.Join(o.directory, fmt.Sprintf("%d", version))) + if err := os.RemoveAll(dir); err != nil { + return err + } + if err := os.MkdirAll(dir, fs.ModePerm); err != nil { + return err + } for i, chunk := range chunks { - f, err := os.Create(path.Join(dir, fmt.Sprintf("%d", i))) + subPath := filepath.Clean(filepath.Join(dir, fmt.Sprintf("%d", i))) + f, err := os.Create(subPath) if err != nil { return err } - f.WriteString(strings.Join(chunk, "\n")) - f.Close() + if _, err := f.WriteString(strings.Join(chunk, "\n")); err != nil { + _ = f.Close() + _ = os.RemoveAll(subPath) + return err + } + if err := f.Close(); err != nil { + _ = os.RemoveAll(subPath) + return err + } } return nil } @@ -49,14 +60,14 @@ func (o *orphanDB) SaveOrphans(version int64, orphans map[string]int64) error { func (o *orphanDB) GetOrphans(version int64) map[string]int64 { if _, ok := o.cache[version]; !ok { o.cache[version] = map[string]int64{} - dir := path.Join(o.directory, fmt.Sprintf("%d", version)) - files, err := ioutil.ReadDir(dir) + dir := filepath.Clean(filepath.Join(o.directory, fmt.Sprintf("%d", version))) + files, err := os.ReadDir(dir) if err != nil { // no orphans found return o.cache[version] } for _, file := range files { - content, err := ioutil.ReadFile(path.Join(dir, file.Name())) + content, err := os.ReadFile(filepath.Clean(filepath.Join(dir, file.Name()))) if err != nil { return o.cache[version] } @@ -70,6 +81,6 @@ func (o *orphanDB) GetOrphans(version int64) map[string]int64 { func (o *orphanDB) DeleteOrphans(version int64) error { delete(o.cache, version) - dir := path.Join(o.directory, fmt.Sprintf("%d", version)) + dir := filepath.Clean(filepath.Join(o.directory, fmt.Sprintf("%d", version))) return os.RemoveAll(dir) } diff --git a/sei-iavl/proof_forgery_test.go b/sei-iavl/proof_forgery_test.go index 8833f40bc4..8d0d1e8cd5 100644 --- a/sei-iavl/proof_forgery_test.go +++ b/sei-iavl/proof_forgery_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/tmhash" db "github.com/tendermint/tm-db" diff --git a/sei-iavl/proof_range.go b/sei-iavl/proof_range.go index c920848fcf..1ea0798e2d 100644 --- a/sei-iavl/proof_range.go +++ b/sei-iavl/proof_range.go @@ -405,7 +405,7 @@ func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof if err != nil { // Key doesn't exist, but instead we got the prev leaf (or the // first or last leaf), which provides proof of absence). - err = nil + _ = err } startOK := keyStart == nil || bytes.Compare(keyStart, left.GetNodeKey()) <= 0 endOK := keyEnd == nil || bytes.Compare(left.GetNodeKey(), keyEnd) < 0 diff --git a/sei-iavl/repair.go b/sei-iavl/repair.go index 952e9ff9bd..c0ec6f17f4 100644 --- a/sei-iavl/repair.go +++ b/sei-iavl/repair.go @@ -40,7 +40,7 @@ func Repair013Orphans(db dbm.DB) (uint64, error) { var repaired uint64 batch := db.NewBatch() - defer batch.Close() + defer func() { _ = batch.Close() }() err = ndb.traverseRange(orphanKeyFormat.Key(version), orphanKeyFormat.Key(int64(math.MaxInt64)), func(k, v []byte) error { // Sanity check so we don't remove stuff we shouldn't var toVersion int64 diff --git a/sei-iavl/testutils_test.go b/sei-iavl/testutils_test.go index 7f7484fffd..d0354a7d3a 100644 --- a/sei-iavl/testutils_test.go +++ b/sei-iavl/testutils_test.go @@ -324,7 +324,7 @@ func BenchmarkImmutableAvlTreeMemDB(b *testing.B) { } func benchmarkImmutableAvlTreeWithDB(b *testing.B, db db.DB) { - defer db.Close() + defer func() { _ = db.Close() }() b.StopTimer() diff --git a/sei-iavl/tree_dotgraph.go b/sei-iavl/tree_dotgraph.go index 1701f9cad7..c9bd2300e2 100644 --- a/sei-iavl/tree_dotgraph.go +++ b/sei-iavl/tree_dotgraph.go @@ -44,8 +44,9 @@ var defaultGraphNodeAttrs = map[string]string{ func WriteDOTGraph(w io.Writer, tree *ImmutableTree, paths []PathToLeaf) { ctx := &graphContext{} - // TODO: handle error - tree.root.hashWithCount() + if _, _, err := tree.root.hashWithCount(); err != nil { + panic(err) + } tree.root.traverse(tree, true, func(node *Node) bool { graphNode := &graphNode{ Attrs: map[string]string{}, diff --git a/sei-iavl/tree_test.go b/sei-iavl/tree_test.go index dfbe481c2b..8ac75a0871 100644 --- a/sei-iavl/tree_test.go +++ b/sei-iavl/tree_test.go @@ -1653,7 +1653,7 @@ func BenchmarkTreeLoadAndDelete(b *testing.B) { if err != nil { panic(err) } - defer d.Close() + defer func() { _ = d.Close() }() defer os.RemoveAll("./bench.db") tree, err := NewMutableTree(d, 0, false) diff --git a/sei-iavl/util.go b/sei-iavl/util.go index ab46646a66..51590a0e1f 100644 --- a/sei-iavl/util.go +++ b/sei-iavl/util.go @@ -6,54 +6,6 @@ import ( "strings" ) -// PrintTree prints the whole tree in an indented form. -func PrintTree(tree *ImmutableTree) { - ndb, root := tree.ndb, tree.root - printNode(ndb, root, 0) -} - -func printNode(ndb *nodeDB, node *Node, indent int) error { - indentPrefix := "" - for i := 0; i < indent; i++ { - indentPrefix += " " - } - - if node == nil { - fmt.Printf("%s\n", indentPrefix) - return nil - } - if node.GetRightNode() != nil { - printNode(ndb, node.GetRightNode(), indent+1) - } else if node.GetRightHash() != nil { - rightNode, err := ndb.GetNode(node.GetRightHash()) - if err != nil { - return err - } - printNode(ndb, rightNode, indent+1) - } - - hash, err := node._hash() - if err != nil { - return err - } - - fmt.Printf("%sh:%X\n", indentPrefix, hash) - if node.isLeaf() { - fmt.Printf("%s%X:%X (%v)\n", indentPrefix, node.GetNodeKey(), node.GetValue(), node.GetHeight()) - } - - if node.GetLeftNode() != nil { - printNode(ndb, node.GetLeftNode(), indent+1) - } else if node.GetLeftHash() != nil { - leftNode, err := ndb.GetNode(node.GetLeftHash()) - if err != nil { - return err - } - printNode(ndb, leftNode, indent+1) - } - return nil -} - func maxInt8(a, b int8) int8 { if a > b { return a diff --git a/tools/hash_verification/iavl/scanner.go b/tools/hash_verification/iavl/scanner.go index 1d5b808c26..60c18db936 100644 --- a/tools/hash_verification/iavl/scanner.go +++ b/tools/hash_verification/iavl/scanner.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/rootmulti" "github.com/sei-protocol/sei-chain/sei-db/ss/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/sei-protocol/sei-chain/tools/hash_verification/hasher" "github.com/sei-protocol/sei-chain/tools/utils" dbm "github.com/tendermint/tm-db" diff --git a/tools/migration/cmd/cmd.go b/tools/migration/cmd/cmd.go index ca9ac76dc6..b6b158abb3 100644 --- a/tools/migration/cmd/cmd.go +++ b/tools/migration/cmd/cmd.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/rootmulti" "github.com/sei-protocol/sei-chain/sei-db/config" sstypes "github.com/sei-protocol/sei-chain/sei-db/ss" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/sei-protocol/sei-chain/tools/migration/sc" "github.com/sei-protocol/sei-chain/tools/migration/ss" "github.com/sei-protocol/sei-chain/tools/utils" diff --git a/tools/migration/ss/migrator.go b/tools/migration/ss/migrator.go index a2b44a9bc2..dbe7ce50d9 100644 --- a/tools/migration/ss/migrator.go +++ b/tools/migration/ss/migrator.go @@ -7,7 +7,7 @@ import ( "github.com/armon/go-metrics" "github.com/sei-protocol/sei-chain/sei-db/ss/types" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/sei-protocol/sei-chain/tools/utils" seimetrics "github.com/sei-protocol/sei-chain/utils/metrics" dbm "github.com/tendermint/tm-db" diff --git a/x/evm/keeper/receipt.go b/x/evm/keeper/receipt.go index c81549bfc1..c81209e7de 100644 --- a/x/evm/keeper/receipt.go +++ b/x/evm/keeper/receipt.go @@ -10,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/sei-protocol/sei-chain/sei-db/proto" - "github.com/sei-protocol/sei-chain/sei-iavl" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" From bb82449e94914f1dad956bff2f719f8d65f8628f Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 17 Dec 2025 12:39:21 +0000 Subject: [PATCH 67/69] Fix `go vet` issues --- sei-iavl/export_test.go | 8 ++++---- sei-iavl/import_test.go | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sei-iavl/export_test.go b/sei-iavl/export_test.go index 37b4c79d1c..f75effc51e 100644 --- a/sei-iavl/export_test.go +++ b/sei-iavl/export_test.go @@ -161,7 +161,7 @@ func TestExporter(t *testing.T) { actual := make([]*ExportNode, 0, len(expect)) exporter := tree.Export() - defer func() { _ = exporter.Close() }() + defer exporter.Close() for { node, err := exporter.Next() if err == ExportDone { @@ -190,13 +190,13 @@ func TestExporter_Import(t *testing.T) { t.Parallel() exporter := tree.Export() - defer func() { _ = exporter.Close() }() + defer exporter.Close() newTree, err := NewMutableTree(db.NewMemDB(), 0, false) require.NoError(t, err) importer, err := newTree.Import(tree.Version()) require.NoError(t, err) - defer func() { _ = importer.Close() }() + defer importer.Close() for { item, err := exporter.Next() @@ -274,7 +274,7 @@ func TestExporter_DeleteVersionErrors(t *testing.T) { itree, err := tree.GetImmutable(2) require.NoError(t, err) exporter := itree.Export() - defer func() { _ = exporter.Close() }() + defer exporter.Close() err = tree.DeleteVersion(2) require.Error(t, err) diff --git a/sei-iavl/import_test.go b/sei-iavl/import_test.go index 0c08520aa6..5fbf7d733e 100644 --- a/sei-iavl/import_test.go +++ b/sei-iavl/import_test.go @@ -28,7 +28,7 @@ func ExampleImporter() { // handle err } exporter := itree.Export() - defer func() { _ = exporter.Close() }() + defer exporter.Close() exported := []*ExportNode{} for { var node *ExportNode @@ -49,7 +49,7 @@ func ExampleImporter() { if err != nil { // handle err } - defer func() { _ = importer.Close() }() + defer importer.Close() for _, node := range exported { err = importer.Add(node) if err != nil { @@ -130,7 +130,7 @@ func TestImporter_Add(t *testing.T) { require.NoError(t, err) importer, err := tree.Import(1) require.NoError(t, err) - defer func() { _ = importer.Close() }() + defer importer.Close() err = importer.Add(tc.node) if tc.valid { @@ -207,7 +207,7 @@ func TestImporter_Commit_Empty(t *testing.T) { require.NoError(t, err) importer, err := tree.Import(3) require.NoError(t, err) - defer func() { _ = importer.Close() }() + defer importer.Close() err = importer.Commit() require.NoError(t, err) From c9bc88a3fe649a3231a5365627f968e64d04cbad Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 17 Dec 2025 13:09:36 +0000 Subject: [PATCH 68/69] Fix incorrect De Morgan's law application --- sei-iavl/mutable_tree.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sei-iavl/mutable_tree.go b/sei-iavl/mutable_tree.go index dd7cad7da0..8cbfc04719 100644 --- a/sei-iavl/mutable_tree.go +++ b/sei-iavl/mutable_tree.go @@ -678,7 +678,7 @@ func (tree *MutableTree) LegacyLoadVersion(targetVersion int64) (toReturn int64, } } - if targetVersion != 0 || latestVersion != targetVersion { + if targetVersion != 0 && latestVersion != targetVersion { return latestVersion, fmt.Errorf("wanted to load target %v but only found up to %v", targetVersion, latestVersion) } From e53b121c1d4138ded7e98c1d75919c834c8d927c Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 17 Dec 2025 13:10:05 +0000 Subject: [PATCH 69/69] Revert gosec fixes that seem to be expected by tests? --- sei-iavl/key_format.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sei-iavl/key_format.go b/sei-iavl/key_format.go index 9dc363fd2e..3c1cbecc23 100644 --- a/sei-iavl/key_format.go +++ b/sei-iavl/key_format.go @@ -163,19 +163,13 @@ func format(a interface{}) []byte { case uint64: return formatUint64(v) case int64: - if v < 0 { - panic(fmt.Errorf("keyFormat format() does not support negative int64 value: %d", v)) - } - // #nosec G115 -- value is checked above to be non-negative + // #nosec G115 -- TestNegativeKeys seems to expect negative keys? return formatUint64(uint64(v)) // Provide formatting from int,uint as a convenience to avoid casting arguments case uint: return formatUint64(uint64(v)) case int: - if v < 0 { - panic(fmt.Errorf("keyFormat format() does not support negative int value: %d", v)) - } - // #nosec G115 -- value is checked above to be non-negative + // #nosec G115 -- TestNegativeKeys seems to expect negative keys? return formatUint64(uint64(v)) case []byte: return v