From 86c00465d0462b02e6cce03151b03e932f1b2c87 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Mon, 21 Aug 2023 16:34:25 -0500 Subject: [PATCH] Fix/abci (#188) * created some basic initializations to better abstract cometBFT node creation. Still a bit more to think through. Spent some time trying to figure out the proper way to do validator keys, only to find out that it does in fact only support ED25519 and will fail at runtime if anything else implements the interface * added atomic kv store, altered atomic committer to suport atomic persistence of app-hashes, made slight bug fixes, implemented wal for 2pc * added privval to avoid using cometbfts type * aqdded register/unregister to AtomicCommitter for on-the-fly registration of Committables * got cometbft running * bug fixes for atomic committer, added garbage collection for KV store, workable dependency building * typo fix * fixed bug with closers not closing gracefully * made resource closure synchronous to prevent bugs that can occur from out of order closing * merged with snapshots, made final changes * made closers the outermost thing to close, even after server panic * removed debug_bin --- go.mod | 168 +++--- go.sum | 486 +++++++++++------- internal/app/kwild/cmd/server/root.go | 16 + internal/app/kwild/config/config_test.go | 3 +- internal/app/kwild/config/variables.go | 43 +- internal/app/kwild/server/root.go | 226 ++++---- internal/app/kwild/server/server.go | 21 +- internal/app/kwild/server/utils.go | 56 ++ internal/pkg/nodecfg/generate.go | 7 +- pkg/abci/abci.go | 381 ++++++++++---- pkg/abci/cometbft/node.go | 65 +++ pkg/abci/cometbft/privval/privvalidator.go | 348 +++++++++++++ .../cometbft/privval/privvalidator_test.go | 456 ++++++++++++++++ pkg/abci/interfaces.go | 11 +- pkg/abci/opts.go | 6 + pkg/abci/utils.go | 2 + pkg/config/config_test.go | 10 +- pkg/crypto/ed25519.go | 12 + pkg/crypto/ed25519_test.go | 9 + pkg/engine/{session.go => _session.go} | 49 +- pkg/engine/dataset.go | 11 +- pkg/engine/db/db.go | 2 +- pkg/engine/engine.go | 37 +- pkg/engine/engine_test.go | 39 +- pkg/engine/execute.go | 1 - pkg/engine/interfaces.go | 37 +- pkg/engine/testing/engine.go | 4 +- pkg/kv/atomic/committer.go | 216 ++++++++ pkg/kv/atomic/errors.go | 10 + pkg/kv/atomic/kv.go | 104 ++++ pkg/kv/atomic/kv_test.go | 197 +++++++ pkg/kv/atomic/testing/testing.go | 43 ++ pkg/kv/badger/db.go | 237 +++++++++ pkg/kv/badger/db_test.go | 27 + pkg/kv/badger/testing/db.go | 32 ++ pkg/kv/common.go | 28 + pkg/kv/testing/memory.go | 106 ++++ pkg/modules/snapshots/interfaces.go | 12 - pkg/serialize/encode.go | 88 ++++ pkg/serialize/encode_test.go | 148 +++++- pkg/sessions/errors.go | 4 + pkg/sessions/interfaces.go | 11 +- pkg/sessions/mock_test.go | 26 +- pkg/sessions/session.go | 271 +++++++--- pkg/sessions/sessions_test.go | 82 +-- pkg/sessions/sql-session/session.go | 66 +-- pkg/sessions/wal.go | 36 +- pkg/sessions/wal/wal.go | 119 +++++ pkg/sessions/wal/wal_test.go | 96 ++++ pkg/{modules => }/snapshots/snapshot_store.go | 9 +- .../snapshots/snapshot_store_test.go | 2 +- pkg/transactions/transaction.go | 3 + pkg/utils/order/order.go | 57 ++ pkg/utils/serialization/slice.go | 52 ++ 54 files changed, 3819 insertions(+), 769 deletions(-) create mode 100644 pkg/abci/cometbft/node.go create mode 100644 pkg/abci/cometbft/privval/privvalidator.go create mode 100644 pkg/abci/cometbft/privval/privvalidator_test.go rename pkg/engine/{session.go => _session.go} (89%) delete mode 100644 pkg/engine/execute.go create mode 100644 pkg/kv/atomic/committer.go create mode 100644 pkg/kv/atomic/errors.go create mode 100644 pkg/kv/atomic/kv.go create mode 100644 pkg/kv/atomic/kv_test.go create mode 100644 pkg/kv/atomic/testing/testing.go create mode 100644 pkg/kv/badger/db.go create mode 100644 pkg/kv/badger/db_test.go create mode 100644 pkg/kv/badger/testing/db.go create mode 100644 pkg/kv/common.go create mode 100644 pkg/kv/testing/memory.go delete mode 100644 pkg/modules/snapshots/interfaces.go create mode 100644 pkg/sessions/wal/wal.go create mode 100644 pkg/sessions/wal/wal_test.go rename pkg/{modules => }/snapshots/snapshot_store.go (87%) rename pkg/{modules => }/snapshots/snapshot_store_test.go (94%) create mode 100644 pkg/utils/order/order.go create mode 100644 pkg/utils/serialization/slice.go diff --git a/go.mod b/go.mod index 3fd2b1b55..608cc5eee 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,14 @@ module github.com/kwilteam/kwil-db -go 1.20 +go 1.21 require ( github.com/alexliesenfeld/health v0.6.0 github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 github.com/buger/jsonparser v1.1.1 + github.com/cosmos/gogoproto v1.4.10 github.com/cstockton/go-conv v1.0.0 + github.com/dgraph-io/badger/v3 v3.2103.5 github.com/ethereum/go-ethereum v1.12.0 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5 github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 @@ -23,66 +25,73 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.14.0 github.com/stretchr/testify v1.8.4 - github.com/testcontainers/testcontainers-go v0.20.1 - github.com/testcontainers/testcontainers-go/modules/compose v0.20.1 + github.com/testcontainers/testcontainers-go v0.23.0 + github.com/testcontainers/testcontainers-go/modules/compose v0.23.0 + github.com/tidwall/wal v1.1.7 github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 go.uber.org/zap v1.24.0 - golang.org/x/sync v0.2.0 + golang.org/x/sync v0.3.0 google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 - google.golang.org/grpc v1.56.2 + google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 ) require ( - github.com/AlecAivazis/survey/v2 v2.3.6 // indirect - github.com/aws/aws-sdk-go-v2 v1.16.3 // indirect - github.com/aws/aws-sdk-go-v2/config v1.15.5 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 // indirect - github.com/aws/smithy-go v1.11.2 // indirect + dario.cat/mergo v1.0.0 // indirect + github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect + github.com/AlecAivazis/survey/v2 v2.3.7 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.17.6 // indirect + github.com/aws/aws-sdk-go-v2/config v1.18.16 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 // indirect + github.com/aws/smithy-go v1.13.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/buger/goterm v1.0.4 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect - github.com/compose-spec/compose-go v1.13.4 // indirect + github.com/compose-spec/compose-go v1.18.1 // indirect github.com/containerd/console v1.0.3 // indirect - github.com/containerd/continuity v0.3.0 // indirect - github.com/containerd/ttrpc v1.1.0 // indirect - github.com/containerd/typeurl v1.0.2 // indirect - github.com/cosmos/gogoproto v1.4.10 // indirect + github.com/containerd/continuity v0.4.1 // indirect + github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect + github.com/cyphar/filepath-securejoin v0.2.3 // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect - github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect - github.com/distribution/distribution/v3 v3.0.0-20230327091844-0c958010ace2 // indirect - github.com/docker/buildx v0.10.4 // indirect - github.com/docker/cli v23.0.5+incompatible // indirect - github.com/docker/compose/v2 v2.17.3 // indirect + github.com/distribution/distribution/v3 v3.0.0-20230601133803-97b1d649c493 // indirect + github.com/docker/buildx v0.11.2 // indirect + github.com/docker/cli v24.0.5+incompatible // indirect + github.com/docker/compose/v2 v2.20.3 // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect - github.com/felixge/httpsnoop v1.0.2 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsevents v0.1.1 // indirect github.com/fvbommel/sortorder v1.0.2 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect + github.com/golang/glog v1.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/flatbuffers v1.12.1 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/orderedcode v0.0.1 // indirect @@ -90,12 +99,12 @@ require ( github.com/googleapis/gnostic v0.5.5 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect - github.com/imdario/mergo v0.3.15 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/in-toto/in-toto-golang v0.5.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/jonboulle/clockwork v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -109,7 +118,7 @@ require ( github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/buildkit v0.11.5 // indirect + github.com/moby/buildkit v0.12.1 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect @@ -121,66 +130,73 @@ require ( github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.39.0 // indirect + github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect + github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/theupdateframework/notary v0.7.0 // indirect + github.com/tidwall/gjson v1.16.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/tidwall/tinylru v1.2.1 // indirect github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 // indirect - github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa // indirect + github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect - github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f // indirect + github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect + github.com/weppos/publicsuffix-go v0.30.1 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - go.etcd.io/bbolt v1.3.6 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 // indirect - go.opentelemetry.io/otel v1.14.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1 // indirect - go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect - go.opentelemetry.io/otel/metric v0.27.0 // indirect - go.opentelemetry.io/otel/sdk v1.4.1 // indirect - go.opentelemetry.io/otel/trace v1.14.0 // indirect - go.opentelemetry.io/proto/otlp v0.12.0 // indirect - golang.org/x/mod v0.9.0 // indirect + go.etcd.io/bbolt v1.3.7 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.40.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 // indirect + go.opentelemetry.io/otel v1.15.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.15.0 // indirect + go.opentelemetry.io/otel/metric v0.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.15.0 // indirect + go.opentelemetry.io/otel/trace v1.15.1 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect + golang.org/x/mod v0.12.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/time v0.1.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/api v0.24.1 // indirect - k8s.io/apimachinery v0.24.1 // indirect - k8s.io/client-go v0.24.1 // indirect - k8s.io/klog/v2 v2.60.1 // indirect - k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + k8s.io/api v0.26.2 // indirect + k8s.io/apimachinery v0.26.2 // indirect + k8s.io/client-go v0.26.2 // indirect + k8s.io/klog/v2 v2.90.1 // indirect + k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect - github.com/cenkalti/backoff/v4 v4.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/chzyer/readline v1.5.0 // indirect - github.com/cometbft/cometbft v0.37.1 - github.com/containerd/containerd v1.6.19 // indirect + github.com/cometbft/cometbft v0.37.2 + github.com/containerd/containerd v1.7.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/docker v23.0.5+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker v24.0.5+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -192,7 +208,7 @@ require ( github.com/holiman/uint256 v1.2.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/klauspost/compress v1.15.15 // indirect + github.com/klauspost/compress v1.16.5 // indirect github.com/kwilteam/kuneiform-grammar-go v0.4.1-0.20230807195420-c5c1c840c665 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -200,29 +216,29 @@ require ( github.com/mattn/go-runewidth v0.0.14 // indirect github.com/moby/patternmatcher v0.5.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect - github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect + github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc2 // indirect - github.com/opencontainers/runc v1.1.5 // indirect + github.com/opencontainers/image-spec v1.1.0-rc4 // indirect + github.com/opencontainers/runc v1.1.7 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rs/cors v1.8.2 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.9.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.4.1 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230419192730-864b3d6c5c2c // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/exp v0.0.0-20230724220655-d98519c11495 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230710151506-e685fd7b542b // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index ca0a280f9..7a4304672 100644 --- a/go.sum +++ b/go.sum @@ -43,7 +43,9 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= 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/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= @@ -58,9 +60,15 @@ 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= cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw= -github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652 h1:+vTEFqeoeur6XSq06bs+roX3YiT49gUniJK7Zky7Xjg= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= @@ -73,53 +81,72 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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 h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek= +github.com/Microsoft/hcsshim v0.10.0-rc.8/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +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/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= +github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= +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/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexliesenfeld/health v0.6.0 h1:HRBTCgybNSe4lqGEk7nU82c3bjwh9W+3b46W6UvD4CQ= github.com/alexliesenfeld/health v0.6.0/go.mod h1:N4NDIeQtlWumG+6z1ne1v62eQxktz5ylEgGgH9emdMw= +github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= +github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go-v2 v1.16.3 h1:0W1TSJ7O6OzwuEvIXAtJGvOeQ0SGAhcpxPN2/NK5EhM= -github.com/aws/aws-sdk-go-v2 v1.16.3/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= -github.com/aws/aws-sdk-go-v2/config v1.15.5 h1:P+xwhr6kabhxDTXTVH9YoHkqjLJ0wVVpIUHtFNr2hjU= -github.com/aws/aws-sdk-go-v2/config v1.15.5/go.mod h1:ZijHHh0xd/A+ZY53az0qzC5tT46kt4JVCePf2NX9Lk4= -github.com/aws/aws-sdk-go-v2/credentials v1.12.0 h1:4R/NqlcRFSkR0wxOhgHi+agGpbEr5qMCjn7VqUIJY+E= -github.com/aws/aws-sdk-go-v2/credentials v1.12.0/go.mod h1:9YWk7VW+eyKsoIL6/CljkTrNVWBSK9pkqOPUuijid4A= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 h1:FP8gquGeGHHdfY6G5llaMQDF+HAf20VKc8opRwmjf04= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4/go.mod h1:u/s5/Z+ohUQOPXl00m2yJVyioWDECsbpXTQlaqSlufc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 h1:uFWgo6mGJI1n17nbcvSc6fxVuR3xLNqvXt12JCnEcT8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10/go.mod h1:F+EZtuIwjlv35kRJPyBGcsA4f7bnSoz15zOQ2lJq1Z4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 h1:cnsvEKSoHN4oAN7spMMr0zhEW2MHnhAVpmqQg8E6UcM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4/go.mod h1:8glyUqVIM4AmeenIsPo0oVh3+NUwnsQml2OFupfQW+0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 h1:6cZRymlLEIlDTEB0+5+An6Zj1CKt6rSE69tOmFeu1nk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11/go.mod h1:0MR+sS1b/yxsfAPvAESrw8NfwUoxMinDyw6EYR9BS2U= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 h1:b16QW0XWl0jWjLABFc1A+uh145Oqv+xDcObNk0iQgUk= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4/go.mod h1:uKkN7qmSIsNJVyMtxNQoCEYMvFEXbOg9fwCJPdfp2u8= -github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 h1:Uw5wBybFQ1UeA9ts0Y07gbv0ncZnIAyw858tDW0NP2o= -github.com/aws/aws-sdk-go-v2/service/sso v1.11.4/go.mod h1:cPDwJwsP4Kff9mldCXAmddjJL6JGQqtA3Mzer2zyr88= -github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 h1:+xtV90n3abQmgzk1pS++FdxZTrPEDgQng6e4/56WR2A= -github.com/aws/aws-sdk-go-v2/service/sts v1.16.4/go.mod h1:lfSYenAXtavyX2A1LsViglqlG9eEFYxNryTZS5rn3QE= -github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE= -github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= +github.com/aws/aws-sdk-go-v2 v1.17.6 h1:Y773UK7OBqhzi5VDXMi1zVGsoj+CVHs2eaC2bDsLwi0= +github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.16 h1:4r7gsCu8Ekwl5iJGE/GmspA2UifqySCCkyyyPFeWs3w= +github.com/aws/aws-sdk-go-v2/config v1.18.16/go.mod h1:XjM6lVbq7UgELp9NjXBrb1DQY/ownlWsvDhEQksemJc= +github.com/aws/aws-sdk-go-v2/credentials v1.13.16 h1:GgToSxaENX/1zXIGNFfiVk4hxryYJ5Vt4Mh8XLAL7Lc= +github.com/aws/aws-sdk-go-v2/credentials v1.13.16/go.mod h1:KP7aFJhfwPFgx9aoVYL2nYHjya5WBD98CWaadpgmnpY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 h1:5qyqXASrX2zy5cTnoHHa4N2c3Lc94GH7gjnBP3GwKdU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24/go.mod h1:neYVaeKr5eT7BzwULuG2YbLhzWZ22lpjKdCybR7AXrQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 h1:y+8n9AGDjikyXoMBTRaHHHSaFEB8267ykmvyPodJfys= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 h1:r+Kv+SEJquhAZXaJ7G4u44cIwXV3f8K+N482NNAzJZA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 h1:hf+Vhp5WtTdcSdE+yEcUz8L73sAzN0R+0jQv+Z51/mI= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31/go.mod h1:5zUjguZfG5qjhG9/wqmuyHRyUftl2B5Cp6NNxNC6kRA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 h1:c5qGfdbCHav6viBwiyDns3OXqhqAbGjfIB4uVu2ayhk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24/go.mod h1:HMA4FZG6fyib+NDo5bpIxX1EhYjrAOveZJY2YR0xrNE= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 h1:bdKIX6SVF3nc3xJFw6Nf0igzS6Ff/louGq8Z6VP/3Hs= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.5/go.mod h1:vuWiaDB30M/QTC+lI3Wj6S/zb7tpUK2MSYgy3Guh2L0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 h1:xLPZMyuZ4GuqRCIec/zWuIhRFPXh2UOJdLXBSi64ZWQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5/go.mod h1:QjxpHmCwAg0ESGtPQnLIVp7SedTOBMYy+Slr3IfMKeI= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 h1:rIFn5J3yDoeuKCE9sESXqM5POTAhOP1du3bv/qTL+tE= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.6/go.mod h1:48WJ9l3dwP0GSHWGc5sFGGlCkuA82Mc2xnw+T6Q8aDw= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -160,20 +187,22 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v1.5.0 h1:tP8hiPv1pGGW3LA6LKy5lW6WG+y9J2xWUdPd3WC452k= +github.com/bugsnag/bugsnag-go v1.5.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= +github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= -github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= -github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/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.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -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/logex v1.2.0 h1:+eqR0HfOetur4tgnC8ftU5imRnhi4te+BadWS95c5AM= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= @@ -183,10 +212,11 @@ github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86c github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23 h1:dZ0/VyGgQdVGAss6Ju0dt5P0QltE0SFY5Woh6hbIfiQ= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= -github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiKw= +github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8= +github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= 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= @@ -197,46 +227,62 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH 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-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cometbft/cometbft v0.37.1 h1:KLxkQTK2hICXYq21U2hn1W5hOVYUdQgDQ1uB+90xPIg= -github.com/cometbft/cometbft v0.37.1/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= +github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= +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-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= +github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= +github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= +github.com/cometbft/cometbft v0.37.2 h1:XB0yyHGT0lwmJlFmM4+rsRnczPlHoAKFX6K8Zgc2/Jc= +github.com/cometbft/cometbft v0.37.2/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= -github.com/compose-spec/compose-go v1.13.4 h1:O6xAsPqaY1s9KXteiO7wRCDTJLahv1XP/z/eUO9EfbI= -github.com/compose-spec/compose-go v1.13.4/go.mod h1:rsiZ8uaOHJYJemDBzTe9UBpaq5ZFVEOO4TxM2G3SJxk= -github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= +github.com/compose-spec/compose-go v1.18.1 h1:YVYYkV8fAHW/eCOgtqSe1tHrlaDVvwS8zgs6F5ukm/Y= +github.com/compose-spec/compose-go v1.18.1/go.mod h1:zR2tP1+kZHi5vJz7PjpW6oMoDji/Js3GHjP+hfjf70Q= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z/4FTUAU= -github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/containerd/fifo v1.0.0 h1:6PirWBr9/L7GDamKr+XM0IeUFXu5mf3M/BPpH9gaLBU= -github.com/containerd/nydus-snapshotter v0.3.1 h1:b8WahTrPkt3XsabjG2o/leN4fw3HWZYr+qxo/Z8Mfzk= -github.com/containerd/stargz-snapshotter v0.13.0 h1:3zr1/IkW1aEo6cMYTQeZ4L2jSuCN+F4kgGfjnuowe4U= -github.com/containerd/stargz-snapshotter/estargz v0.13.0 h1:fD7AwuVV+B40p0d9qVkH/Au1qhp8hn/HWJHIYjpEcfw= -github.com/containerd/ttrpc v1.1.0 h1:GbtyLRxb0gOLR0TYQWt3O6B0NvT8tMdorEHqIQo/lWI= -github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= -github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/containerd v1.7.3 h1:cKwYKkP1eTj54bP3wCdXXBymmKRQMrWjkLSWZZJDa8o= +github.com/containerd/containerd v1.7.3/go.mod h1:32FOM4/O0RkNg7AjQj3hDzN9cUGtu+HMvaKUNiqCZB8= +github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= +github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= +github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= +github.com/containerd/nydus-snapshotter v0.8.2 h1:7SOrMU2YmLzfbsr5J7liMZJlNi5WT6vtIOxLGv+iz7E= +github.com/containerd/nydus-snapshotter v0.8.2/go.mod h1:UJILTN5LVBRY+dt8BGJbp72Xy729hUZsOugObEI3/O8= +github.com/containerd/stargz-snapshotter v0.14.3 h1:OTUVZoPSPs8mGgmQUE1dqw3WX/3nrsmsurW7UPLWl1U= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtOs= +github.com/containerd/ttrpc v1.2.2/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= +github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= +github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= 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-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= 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.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cstockton/go-conv v1.0.0 h1:zj/q/0MpQ/97XfiC9glWiohO8lhgR4TTnHYZifLTv6I= github.com/cstockton/go-conv v1.0.0/go.mod h1:HuiHkkRgOA0IoBNPC7ysG7kNpjDYlgM7Kj62yQPxjy4= +github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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= @@ -244,6 +290,7 @@ 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/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= @@ -251,23 +298,26 @@ github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0 github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= +github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= +github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= 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/distribution/distribution/v3 v3.0.0-20230327091844-0c958010ace2 h1:KTYNpKuqtdZJOobHigxfdikPdsBwddmzeRn3UMocznM= -github.com/distribution/distribution/v3 v3.0.0-20230327091844-0c958010ace2/go.mod h1:r5XLH1cp+Wau2jxdptkYsFvvvzPPQTIe8eUuQ0vq30Q= -github.com/docker/buildx v0.10.4 h1:qsHwlUZaLu7UQkDhJDSRQ+jrvWf6mqwwtY+gWO3rzuA= -github.com/docker/buildx v0.10.4/go.mod h1:2mHDjD0QevclBGYIXDOWY/ZU71JAzx7w4CfgroYbHQw= -github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE= -github.com/docker/cli v23.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/compose/v2 v2.17.3 h1:z8Q1PYjXKHVWvrOQo5plel14mGCyGIAPagcX2FY767A= -github.com/docker/compose/v2 v2.17.3/go.mod h1:hHY3SeoI5TCY+OPJAN0adMwFH0iUKTPOfjac6xiohZc= +github.com/distribution/distribution/v3 v3.0.0-20230601133803-97b1d649c493 h1:fm5DpBD+A7o0+x9Nf+o9/4/qPGbfxLpr9qIPVuV8vQc= +github.com/distribution/distribution/v3 v3.0.0-20230601133803-97b1d649c493/go.mod h1:+fqBJ4vPYo4Uu1ZE4d+bUtTLRXfdSL3NvCZIZ9GHv58= +github.com/docker/buildx v0.11.2 h1:R3p9F0gnI4FwvQ0p40UwdX1T4ugap4UWxY3TFHoP4Ws= +github.com/docker/buildx v0.11.2/go.mod h1:CWAABt10iIuGpleypA3103mplDfcGu0A2AvT03xfpTc= +github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc= +github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/compose/v2 v2.20.3 h1:UM6EaYgpjANQBKo7r7S4yNEdOeXr9IhBOpFFhOhqyd4= +github.com/docker/compose/v2 v2.20.3/go.mod h1:xbMcMnkNJQfwh1PlMie2DfzIYAcqhtc2ipgcRGUOHfo= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v23.0.5+incompatible h1:DaxtlTJjFSnLOXVNUBU1+6kXGz2lpDoEAH6QoxaSg8k= -github.com/docker/docker v23.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= +github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= @@ -275,10 +325,10 @@ github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= @@ -290,6 +340,7 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8= +github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 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= @@ -302,20 +353,25 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/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-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= -github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= -github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsevents v0.1.1 h1:/125uxJvvoSDDBPen6yUZbil8J9ydKZnnl3TWWmvnkw= github.com/fsnotify/fsevents v0.1.1/go.mod h1:+d+hS27T6k5J8CRaPLKFgwKYcpS7GwW3Ule9+SC2ZRc= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -324,6 +380,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 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= @@ -342,27 +400,33 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +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-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= +github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= 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= @@ -407,7 +471,10 @@ github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9 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.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= +github.com/google/certificate-transparency-go v1.1.4 h1:hCyXHDbtqlr/lMXU0D4WgbalXL0Zk4dSWWMbPV8VrqY= +github.com/google/certificate-transparency-go v1.1.4/go.mod h1:D6lvbfwckhNrbM9WVl1EVeMOyzC19mpIjMOI4nxBHtQ= +github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -424,6 +491,8 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -480,13 +549,14 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaW github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5 h1:3IZOAnD058zZllQTZNBioTlrzrBG/IjpiZ133IEtusM= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5/go.mod h1:xbKERva94Pw2cPen0s79J3uXmGzbbpDYFBFDlZ4mV/w= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 h1:kr3j8iIMR4ywO/O0rvksXaJvauGGCMg2zAZIiNZ9uIQ= github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg= github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -508,9 +578,10 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO 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.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/in-toto/in-toto-golang v0.5.0 h1:hb8bgwr0M2hGdDsLjkJ3ZqJ8JFLL/tgYdAxF/XEFBbY= +github.com/in-toto/in-toto-golang v0.5.0/go.mod h1:/Rq0IZHLV7Ku5gielPT4wPHJfH1GdHMCq8+WPxw8/BE= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= @@ -518,6 +589,7 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/gorm v1.9.11 h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE= +github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= @@ -526,6 +598,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW 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.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= @@ -543,22 +617,23 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= -github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= +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/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/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.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= @@ -575,6 +650,8 @@ github.com/kwilteam/kwil-extensions v0.0.0-20230710163303-bfa03f64ff82 h1:pA0ya2 github.com/kwilteam/kwil-extensions v0.0.0-20230710163303-bfa03f64ff82/go.mod h1:+BrFrV+3qcdYIfptqjwatE5gT19azuRHJzw77wMPY8c= github.com/kwilteam/sql-grammar-go v0.0.2 h1:Tg8xo/Pzd72QsO19wwNvFrpw2muuBaERP7XTv21U4Iw= github.com/kwilteam/sql-grammar-go v0.0.2/go.mod h1:OqmGyCwHfBZvYv/sYPrQ5Ih290dhlD5AcKOHDlUSS0Y= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -618,15 +695,14 @@ github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/buildkit v0.11.5 h1:S6YrFJ0bfBT2w9e8kOxqsDV8Bw+HtfqdB6eHL17BXRI= -github.com/moby/buildkit v0.11.5/go.mod h1:P5Qi041LvCfhkfYBHry+Rwoo3Wi6H971J2ggE+PcIoo= +github.com/moby/buildkit v0.12.1 h1:vvMG7EZYCiQZpTtXQkvyeyj7HzT1JHhDWj+/aiGIzLM= +github.com/moby/buildkit v0.12.1/go.mod h1:adB4y0SxxX8trnrY+oEulb48ODLqPO6pKMF0ppGcCoI= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -635,8 +711,8 @@ github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= github.com/moby/sys/symlink v0.2.0 h1:tk1rOM+Ljp0nFmfOIBtlV3rTDlWOwFRhjEeAhZB0nZc= github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -646,7 +722,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= @@ -654,6 +729,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA 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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 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= @@ -674,18 +751,19 @@ github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= -github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= -github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= -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/opencontainers/selinux v1.10.2 h1:NFy2xCsjn7+WspbfZkUd5zyVeisV7VFbPSP96+8/ha4= +github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= +github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/runtime-spec v1.1.0-rc.2 h1:ucBtEms2tamYYW/SvGpvq9yUN0NEVL6oyLEwDcTSrk8= +github.com/opencontainers/runtime-spec v1.1.0-rc.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= -github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 h1:DiLBVp4DAcZlBVBEtJpNWZpZVq0AEeCY7Hqk8URVs4o= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -716,13 +794,12 @@ github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3d github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= -github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 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.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= @@ -737,30 +814,32 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ 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.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= 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/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= -github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE= +github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs= github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 h1:ka9QPuQg2u4LGipiZGsgkg3rJCo4iIUCy75FddM0GRQ= github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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/spdx/tools-golang v0.3.1-0.20230104082527-d6f58551be3f h1:9B623Cfs+mclYK6dsae7gLSwuIBHvlgmEup87qpqsAQ= +github.com/spdx/tools-golang v0.5.1 h1:fJg3SVOGG+eIva9ZUBm/hvyA7PIPVFjRxUKe6fdAgwE= +github.com/spdx/tools-golang v0.5.1/go.mod h1:/DRDQuBfB37HctM29YtrX1v+bXiVmT2OpQDalRmX9aU= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= @@ -792,6 +871,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify 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= @@ -800,37 +880,53 @@ 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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +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.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= 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/testcontainers/testcontainers-go v0.20.1 h1:mK15UPJ8c5P+NsQKmkqzs/jMdJt6JMs5vlw2y4j92c0= -github.com/testcontainers/testcontainers-go v0.20.1/go.mod h1:zb+NOlCQBkZ7RQp4QI+YMIHyO2CQ/qsXzNF5eLJ24SY= -github.com/testcontainers/testcontainers-go/modules/compose v0.20.1 h1:I6/IB2gzlS7zDQhScMmrmAIF7ZyDzm+lE9wQwr+QUIo= -github.com/testcontainers/testcontainers-go/modules/compose v0.20.1/go.mod h1:sCzdl1NTL1KexCVYlTNmY/ji/Y5JAZJRL6zHQlXKSkM= +github.com/testcontainers/testcontainers-go v0.23.0 h1:ERYTSikX01QczBLPZpqsETTBO7lInqEP349phDOVJVs= +github.com/testcontainers/testcontainers-go v0.23.0/go.mod h1:3gzuZfb7T9qfcH2pHpV4RLlWrPjeWNQah6XlYQ32c4I= +github.com/testcontainers/testcontainers-go/modules/compose v0.23.0 h1:Pc6m9JcfBTxUDTZq9TxtqDZkuZOmO4E9d/I2bQfZeMA= +github.com/testcontainers/testcontainers-go/modules/compose v0.23.0/go.mod h1:HOs+yV997xwe8A+3Vd8obHuHqRXi1eEqX7n0PpkakSE= github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c= github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw= +github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= +github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/tinylru v1.1.0/go.mod h1:3+bX+TJ2baOLMWTnlyNWHh4QMnFyARg2TLTQ6OFbzw8= +github.com/tidwall/tinylru v1.2.1 h1:VgBr72c2IEr+V+pCdkPZUwiQ0KJknnWIYbhxAVkYfQk= +github.com/tidwall/tinylru v1.2.1/go.mod h1:9bQnEduwB6inr2Y7AkBP7JPgCkyrhTV/ZpX0oOOpBI4= +github.com/tidwall/wal v1.1.7 h1:emc1TRjIVsdKKSnpwGBAcsAGg0767SvUk8+ygx7Bb+4= +github.com/tidwall/wal v1.1.7/go.mod h1:r6lR1j27W9EPalgHiB7zLJDYu3mzW5BQP5KrzBpYY/E= github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 h1:QB54BJwA6x8QU9nHY3xJSZR2kX9bgpZekRKGkLTmEXA= github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375/go.mod h1:xRroudyp5iVtxKqZCrA6n2TLFRBf8bmnjr1UD4x+z7g= -github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa h1:XOFp/3aBXlqmOFAg3r6e0qQjPnK5I970LilqX+Is1W8= -github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa/go.mod h1:AvLEd1LEIl64G2Jpgwo7aVV5lGH0ePcKl0ygGIHNYl8= +github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= +github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= +github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= +github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb h1:uUe8rNyVXM8moActoBol6Xf6xX2GMr7SosR2EywMvGg= +github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb/go.mod h1:SxX/oNQ/ag6Vaoli547ipFK9J7BZn5JqJG0JE8lf8bA= github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 h1:TvtdmeYsYEij78hS4oxnwikoiLdIrgav3BA+CbhaDAI= github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346/go.mod h1:xKQhd7snlzKFuUi1taTGWjpRE8iFTA06DeacYi3CVFQ= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk= -github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f h1:DLpt6B5oaaS8jyXHa9VA4rrZloBVPVXeCtrOsrFauxc= -github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc= +github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 h1:Y/M5lygoNPKwVNLMPXgVfsRT40CSFKXCxuU8LoHySjs= +github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= -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/weppos/publicsuffix-go v0.20.0 h1:59ypvSUbW3Dunc6zVm+v+MmXf2Q6cGiNDkxgRIzEnaA= +github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= +github.com/weppos/publicsuffix-go v0.30.1 h1:8q+QwBS1MY56Zjfk/50ycu33NN8aa1iCCEQwo/71Oos= +github.com/weppos/publicsuffix-go v0.30.1/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -845,55 +941,52 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de 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.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zmap/zcrypto v0.0.0-20220605182715-4dfcec6e9a8c h1:ufDm/IlBYZYLuiqvQuhpTKwrcAS2OlXEzWbDvTVGbSQ= -github.com/zmap/zlint v1.1.0 h1:Vyh2GmprXw5TLmKmkTa2BgFvvYAFBValBFesqkKsszM= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 h1:DZH5n7L3L8RxKdSyJHZt7WePgwdhHnPhQFdQSJaHF+o= +github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300/go.mod h1:mOd4yUMgn2fe2nV9KXsa9AyQBFZGzygVPovsZR+Rl5w= +github.com/zmap/zlint/v3 v3.5.0 h1:Eh2B5t6VKgVH0DFmTwOqE50POvyDhUaU9T2mJOe1vfQ= +github.com/zmap/zlint/v3 v3.5.0/go.mod h1:JkNSrsDJ8F4VRtBZcYUQSvnWFL7utcjDIn+FE64mlBI= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= 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 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3 h1:syAz40OyelLZo42+3U68Phisvrx4qh+4wpdZw7eUUdY= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3/go.mod h1:Dts42MGkzZne2yCru741+bFiTMWkIj/LLRizad7b9tw= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0 h1:Wjp9vsVSIEyvdiaECfqxY9xBqQ7JaSCGtvHgR4doXZk= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0/go.mod h1:vHItvsnJtp7ES++nFLLFBzUWny7fJQSvTlxFcqQGUr4= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 h1:SLme4Porm+UwX0DdHMxlwRt7FzPSE0sys81bet2o0pU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0/go.mod h1:tLYsuf2v8fZreBVwp9gVMhefZlLFZaUiNVSq8QxXRII= -go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk= -go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4= -go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= -go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1 h1:imIM3vRDMyZK1ypQlQlO+brE22I9lRhJsBDXpDWjlz8= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 h1:WPpPsAAs8I2rA47v5u0558meKmmwm1Dj99ZbqCV8sZ8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1/go.mod h1:o5RW5o2pKpJLD5dNTCmjF1DorYwMeFJmb/rKr5sLaa8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1 h1:AxqDiGk8CorEXStMDZF5Hz9vo9Z7ZZ+I5m8JRl/ko40= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1/go.mod h1:c6E4V3/U+miqjs/8l950wggHGL1qzlp0Ypj9xoGrPqo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1 h1:8qOago/OqoFclMUUj/184tZyRdDZFpcejSjbk5Jrl6Y= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1/go.mod h1:VwYo0Hak6Efuy0TXsZs8o1hnV3dHDPNtDbycG0hI8+M= -go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk= -go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw= -go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1sC5kIwQ= -go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g= -go.opentelemetry.io/otel/sdk v1.4.1 h1:J7EaW71E0v87qflB4cDolaqq3AcujGrtyIPGQoZOB0Y= -go.opentelemetry.io/otel/sdk v1.4.1/go.mod h1:NBwHDgDIBYjwK2WNu1OPgsIc2IJzmBXNnvIJxJc8BpE= -go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE= -go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc= -go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= -go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 h1:5jD3teb4Qh7mx/nfzq4jO2WFFpvXD0vYWFDrdvNWmXk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0/go.mod h1:UMklln0+MRhZC4e3PwmN3pCtq4DyIadWw4yikh6bNrw= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.40.0 h1:ZjF6qLnAVNq6xUh0sK2mCEqwnRrpgr0mLALQXJL34NI= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.40.0/go.mod h1:SD34NWTW0VMH2VvFVfArHPoF+L1ddT4MOQCTb2l8T5I= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 h1:lE9EJyw3/JhrjWH/hEy9FptnalDQgj7vpbgC2KCCCxE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0/go.mod h1:pcQ3MM3SWvrA71U4GDqv9UFDJ3HQsW7y5ZO3tDTlUdI= +go.opentelemetry.io/otel v1.15.1 h1:3Iwq3lfRByPaws0f6bU3naAqOR1n5IeDWd9390kWHa8= +go.opentelemetry.io/otel v1.15.1/go.mod h1:mHHGEHVDLal6YrKMmk9LqC4a3sF5g+fHfrttQIB1NTc= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.0 h1:ZSdnH1x5Gm/eUFNQquwSt4/LMCOqS6KPlI9qaTKx5Ho= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.0/go.mod h1:uOTV75+LOzV+ODmL8ahRLWkFA3eQcSC2aAsbxIu4duk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.0 h1:rk5I7PaOk5NGQHfHR2Rz6MgdA8AYQSHwsigFsOxEC1c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.0/go.mod h1:pvkFJxNUXyJ5i8u6m8NIcqkoOf/65VM2mSyBbBJfeVQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.0 h1:rHD0vfQbtki6/FnsMzTpAOgdv+Ku+T6R47MZXmgelf8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.0/go.mod h1:RPagkaZrpwD+rSwQjzos6rBLsHOvenOqufCj4/7I46E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.15.0 h1:MOeyNzoSvrn4/08FtGint7wwodzSXdXefoi6bPsBhVM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.15.0/go.mod h1:3YofWWr7LMDyBtpDC0RYvRmjcUwk99YOZl3TmwFsp8w= +go.opentelemetry.io/otel/metric v0.37.0 h1:pHDQuLQOZwYD+Km0eb657A25NaRzy0a+eLyKfDXedEs= +go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= +go.opentelemetry.io/otel/sdk v1.15.0 h1:jZTCkRRd08nxD6w7rIaZeDNGZGGQstH3SfLQ3ZsKICk= +go.opentelemetry.io/otel/sdk v1.15.0/go.mod h1:XDEMrYWzJ4YlC17i6Luih2lwDw2j6G0PkUfr1ZqE+rQ= +go.opentelemetry.io/otel/trace v1.15.1 h1:uXLo6iHJEzDfrNC0L0mNjItIp06SyaBQxu5t3xMlngY= +go.opentelemetry.io/otel/trace v1.15.1/go.mod h1:IWdQG/5N1x7f6YUlmdLeJvH9yxtuJAfc4VW5Agv9r/8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.12.0 h1:CMJ/3Wp7iOWES+CYLfnBv+DVmPbB+kmy9PJ92XvlR6c= -go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= @@ -916,8 +1009,10 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 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.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/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= @@ -928,8 +1023,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230419192730-864b3d6c5c2c h1:HDdYQYKOkvJT/Plb5HwJJywTVyUnIctjQm6XSnZ/0CY= -golang.org/x/exp v0.0.0-20230419192730-864b3d6c5c2c/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230724220655-d98519c11495 h1:zKGKw2WlGb8oPoRGqQ2PT8g2YoCN1w/YbbQjHXCdUWE= +golang.org/x/exp v0.0.0-20230724220655-d98519c11495/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= 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= @@ -956,8 +1051,9 @@ 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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= @@ -1010,8 +1106,12 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1027,8 +1127,9 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= @@ -1044,7 +1145,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w 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= @@ -1053,7 +1153,6 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w 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-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= @@ -1073,7 +1172,6 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w 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-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= @@ -1098,10 +1196,9 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc 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-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-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1111,7 +1208,6 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-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-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1120,18 +1216,25 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.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-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= 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= @@ -1142,14 +1245,18 @@ 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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1206,8 +1313,9 @@ 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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= 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= @@ -1378,14 +1486,14 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD 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.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +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.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= 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= @@ -1401,6 +1509,7 @@ 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.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/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/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= @@ -1412,6 +1521,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= @@ -1437,7 +1547,8 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C 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 h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= +gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= 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= @@ -1454,12 +1565,12 @@ k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= -k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= @@ -1473,7 +1584,8 @@ 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/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/app/kwild/cmd/server/root.go b/internal/app/kwild/cmd/server/root.go index 4b4c4f86c..33840a139 100644 --- a/internal/app/kwild/cmd/server/root.go +++ b/internal/app/kwild/cmd/server/root.go @@ -1,6 +1,11 @@ package server import ( + "context" + "os" + "os/signal" + "syscall" + "github.com/kwilteam/kwil-db/internal/app/kwild/config" // shorthand for chain client service @@ -20,12 +25,23 @@ var startCmd = &cobra.Command{ Long: "Starts node with Kwild and CometBFT services", RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() + + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) + ctx, cancel := context.WithCancel(ctx) + + go func() { + <-signalChan + cancel() + }() + svr, err := server.BuildKwildServer(ctx) if err != nil { return err } return svr.Start(ctx) + }, } diff --git a/internal/app/kwild/config/config_test.go b/internal/app/kwild/config/config_test.go index 040dcf63a..056cb8cfc 100644 --- a/internal/app/kwild/config/config_test.go +++ b/internal/app/kwild/config/config_test.go @@ -8,9 +8,8 @@ import ( ) func Test_Config(t *testing.T) { - os.Setenv("KWILD_PRIVATE_KEY", "f1aa5a7966c3863ccde3047f6a1e266cdc0c76b399e256b8fede92b1c69e4f4e") + os.Setenv("KWILD_PRIVATE_KEY", "f2d82d73ba03a7e843443f2b3179a01398144baa4a23d40d1e8a3a8e4fb217d0484d59f4de46b2174ebce66ac3afa7989b444244323c19a74b683f54cf33227c") os.Setenv("KWILD_PORT", "8081") - os.Setenv("KWILD_DEPOSITS_POOL_ADDRESS", "0xabc") os.Setenv("KWILD_EXTENSION_ENDPOINTS", "localhost:8080,localhost:8081, localhost:8082") _, err := config.LoadKwildConfig() if err != nil { diff --git a/internal/app/kwild/config/variables.go b/internal/app/kwild/config/variables.go index abe8bce21..8eb5bd8da 100644 --- a/internal/app/kwild/config/variables.go +++ b/internal/app/kwild/config/variables.go @@ -1,18 +1,17 @@ package config import ( - "crypto/ecdsa" "fmt" "os" + "path/filepath" "strings" + "github.com/kwilteam/kwil-db/pkg/crypto" "github.com/kwilteam/kwil-db/pkg/log" "github.com/kwilteam/kwil-db/pkg/config" - cmtCrypto "github.com/cometbft/cometbft/crypto" "github.com/cstockton/go-conv" - "github.com/ethereum/go-ethereum/crypto" ) const ( @@ -22,20 +21,15 @@ const ( type KwildConfig struct { GrpcListenAddress string HttpListenAddress string - PrivateKey *ecdsa.PrivateKey + PrivateKey *crypto.Ed25519PrivateKey SqliteFilePath string Log log.Config ExtensionEndpoints []string - ArweaveConfig ArweaveConfig BcRpcUrl string - BCPrivateKey cmtCrypto.PrivKey WithoutGasCosts bool WithoutNonces bool SnapshotConfig SnapshotConfig -} - -type ArweaveConfig struct { - BundlrURL string + RootDir string } type SnapshotConfig struct { @@ -54,10 +48,10 @@ var ( LogOutputPaths, HttpListenAddress, ExtensionEndpoints, - ArweaveBundlrURL, CometBftRPCUrl, WithoutGasCosts, WithoutNonces, + RootDir, } ) @@ -68,7 +62,7 @@ var ( Setter: func(val any) (any, error) { if val == nil { fmt.Println("no private key provided, generating a new one...") - return crypto.GenerateKey() + return crypto.GenerateEd25519Key() } strVal, err := conv.String(val) @@ -76,7 +70,7 @@ var ( return nil, err } - return crypto.HexToECDSA(strVal) + return crypto.Ed25519PrivateKeyFromHex(strVal) }, } @@ -160,12 +154,6 @@ var ( }, } - ArweaveBundlrURL = config.CfgVar{ - EnvName: "ARWEAVE_BUNDLR_URL", - Field: "ArweaveConfig.BundlrURL", - Default: "", - } - WithoutGasCosts = config.CfgVar{ EnvName: "WITHOUT_GAS_COSTS", Field: "WithoutGasCosts", @@ -201,4 +189,21 @@ var ( Field: "SnapshotConfig.SnapshotDir", Default: "/tmp/kwil/snapshots", } + + RootDir = config.CfgVar{ + EnvName: "ROOT_DIR", + Field: "RootDir", + Setter: func(val any) (any, error) { + if val == nil { + return filepath.Clean("~/.kwil"), nil + } + + str, err := conv.String(val) + if err != nil { + return nil, err + } + + return filepath.Clean(str), nil + }, + } ) diff --git a/internal/app/kwild/server/root.go b/internal/app/kwild/server/root.go index 431d2527b..58d9d3d53 100644 --- a/internal/app/kwild/server/root.go +++ b/internal/app/kwild/server/root.go @@ -2,9 +2,10 @@ package server import ( "context" + "errors" "fmt" "net" - "os" + "path/filepath" "time" // kwil-db @@ -15,30 +16,26 @@ import ( "github.com/kwilteam/kwil-db/internal/pkg/healthcheck" simple_checker "github.com/kwilteam/kwil-db/internal/pkg/healthcheck/simple-checker" "github.com/kwilteam/kwil-db/pkg/abci" + "github.com/kwilteam/kwil-db/pkg/abci/cometbft" "github.com/kwilteam/kwil-db/pkg/balances" "github.com/kwilteam/kwil-db/pkg/engine" "github.com/kwilteam/kwil-db/pkg/grpc/gateway" "github.com/kwilteam/kwil-db/pkg/grpc/gateway/middleware/cors" grpc "github.com/kwilteam/kwil-db/pkg/grpc/server" + "github.com/kwilteam/kwil-db/pkg/kv/atomic" + "github.com/kwilteam/kwil-db/pkg/kv/badger" "github.com/kwilteam/kwil-db/pkg/log" "github.com/kwilteam/kwil-db/pkg/modules/datasets" - "github.com/kwilteam/kwil-db/pkg/modules/snapshots" "github.com/kwilteam/kwil-db/pkg/modules/validators" - snapshotPkg "github.com/kwilteam/kwil-db/pkg/snapshots" + "github.com/kwilteam/kwil-db/pkg/sessions" + "github.com/kwilteam/kwil-db/pkg/sessions/wal" + "github.com/kwilteam/kwil-db/pkg/snapshots" "github.com/kwilteam/kwil-db/pkg/sql" vmgr "github.com/kwilteam/kwil-db/pkg/validators" - // CometBFT - cmtcfg "github.com/cometbft/cometbft/config" - cmtflags "github.com/cometbft/cometbft/libs/cli/flags" - cmtlog "github.com/cometbft/cometbft/libs/log" - nm "github.com/cometbft/cometbft/node" - "github.com/cometbft/cometbft/p2p" - "github.com/cometbft/cometbft/privval" - "github.com/cometbft/cometbft/proxy" + abciTypes "github.com/cometbft/cometbft/abci/types" cmtlocal "github.com/cometbft/cometbft/rpc/client/local" - "github.com/spf13/viper" "google.golang.org/grpc/health/grpc_health_v1" ) @@ -65,53 +62,41 @@ func BuildKwildServer(ctx context.Context) (svr *Server, err error) { opener: newSqliteOpener(cfg.SqliteFilePath), } - return buildServer(deps), nil -} - -type nodeWrapper struct { - n *nm.Node -} - -func (nw *nodeWrapper) Start() error { - return nw.n.Start() -} - -func (nw *nodeWrapper) Stop() error { - if err := nw.n.Stop(); err != nil { - return err + closers := &closeFuncs{ + closers: make([]func() error, 0), } - nw.n.Wait() - return nil + + return buildServer(deps, closers), nil } -var _ (startStopper) = (*nodeWrapper)(nil) +func buildServer(d *coreDependencies, closers *closeFuncs) *Server { + // atomic committer + ac := buildAtomicCommitter(d, closers) + closers.addCloser(ac.Close) -func buildServer(d *coreDependencies) *Server { // engine - e := buildEngine(d) + e := buildEngine(d, ac) + closers.addCloser(e.Close) // account store - accs := buildAccountRepository(d) + accs := buildAccountRepository(d, closers, ac) // datasets module datasetsModule := buildDatasetsModule(d, e, accs) // validator updater and store - vstore := buildValidatorManager(d) + vstore := buildValidatorManager(d, closers, ac) // validator module validatorModule := buildValidatorModule(d, accs, vstore) - snapshotModule := buildSnapshotModule(d) + snapshotModule := buildSnapshotter(d) - bootstrapperModule := buildBootstrapModule(d) + bootstrapperModule := buildBootstrapper(d) - abciApp := buildAbci(d, datasetsModule, validatorModule, nil, snapshotModule, bootstrapperModule) + abciApp := buildAbci(d, closers, datasetsModule, validatorModule, ac, snapshotModule, bootstrapperModule) - cometBftNode, err := newCometNode(abciApp, d.cfg) - if err != nil { - failBuild(err, "failed to create cometbft node") - } + cometBftNode := buildCometNode(d, closers, abciApp) cometBftClient := buildCometBftClient(cometBftNode) @@ -124,7 +109,10 @@ func buildServer(d *coreDependencies) *Server { return &Server{ grpcServer: grpcServer, gateway: buildGatewayServer(d), - cometBftNode: &nodeWrapper{cometBftNode}, + cometBftNode: cometBftNode, + log: *d.log.Named("kwild-server"), + closers: closers, + cfg: d.cfg, } } @@ -136,11 +124,54 @@ type coreDependencies struct { opener sql.Opener } -func buildAbci(d *coreDependencies, datasetsModule abci.DatasetsModule, validatorModule abci.ValidatorModule, - atomicCommitter abci.AtomicCommitter, snapshotter abci.SnapshotModule, bootstrapper abci.DBBootstrapModule) *abci.AbciApp { +// closeFuncs holds a list of closers +// it is used to close all resources on shutdown +type closeFuncs struct { + closers []func() error +} + +func (c *closeFuncs) addCloser(f func() error) { + c.closers = append(c.closers, f) +} + +// closeAll closeps all closers, in the order they were added +func (c *closeFuncs) closeAll() error { + errs := make([]error, 0) + for _, closer := range c.closers { + err := closer() + if err != nil { + errs = append(errs, err) + } + } + + return errors.Join(errs...) +} + +func buildAbci(d *coreDependencies, closer *closeFuncs, datasetsModule abci.DatasetsModule, validatorModule abci.ValidatorModule, + atomicCommitter *sessions.AtomicCommitter, snapshotter *snapshots.SnapshotStore, bootstrapper *snapshots.Bootstrapper) *abci.AbciApp { + badgerKv, err := badger.NewBadgerDB(d.ctx, filepath.Join(d.cfg.RootDir, "abci/info"), &badger.Options{ + GuaranteeFSync: true, + Logger: *d.log.Named("abci-kv-store"), + }) + if err != nil { + failBuild(err, "failed to open badger") + } + closer.addCloser(badgerKv.Close) + + atomicKv, err := atomic.NewAtomicKV(badgerKv) + if err != nil { + failBuild(err, "failed to open atomic kv") + } + + err = atomicCommitter.Register(d.ctx, "blockchain_kv", atomicKv) + if err != nil { + failBuild(err, "failed to register atomic kv") + } + return abci.NewAbciApp( datasetsModule, validatorModule, + atomicKv, atomicCommitter, snapshotter, bootstrapper, @@ -167,13 +198,19 @@ func buildDatasetsModule(d *coreDependencies, eng datasets.Engine, accs datasets ) } -func buildEngine(d *coreDependencies) *engine.Engine { +func buildEngine(d *coreDependencies, a *sessions.AtomicCommitter) *engine.Engine { extensions, err := connectExtensions(d.ctx, d.cfg.ExtensionEndpoints) if err != nil { failBuild(err, "failed to connect to extensions") } + sqlCommitRegister := &sqlCommittableRegister{ + committer: a, + log: *d.log.Named("sqlite-committable"), + } + e, err := engine.Open(d.ctx, d.opener, + sqlCommitRegister, engine.WithLogger(*d.log.Named("engine")), engine.WithExtensions(adaptExtensions(extensions)), ) @@ -184,11 +221,17 @@ func buildEngine(d *coreDependencies) *engine.Engine { return e } -func buildAccountRepository(d *coreDependencies) *balances.AccountStore { +func buildAccountRepository(d *coreDependencies, closer *closeFuncs, ac *sessions.AtomicCommitter) *balances.AccountStore { db, err := d.opener.Open("accounts_db", *d.log.Named("account-store")) if err != nil { failBuild(err, "failed to open accounts db") } + closer.addCloser(db.Close) + + err = registerSQL(d.ctx, ac, db, "accounts_db", d.log) + if err != nil { + failBuild(err, "failed to register accounts db") + } b, err := balances.NewAccountStore(d.ctx, db, balances.WithLogger(*d.log.Named("accountStore")), @@ -202,11 +245,17 @@ func buildAccountRepository(d *coreDependencies) *balances.AccountStore { return b } -func buildValidatorManager(d *coreDependencies) *vmgr.ValidatorMgr { +func buildValidatorManager(d *coreDependencies, closer *closeFuncs, ac *sessions.AtomicCommitter) *vmgr.ValidatorMgr { db, err := d.opener.Open("validator_db", *d.log.Named("validator-store")) if err != nil { failBuild(err, "failed to open validator db") } + closer.addCloser(db.Close) + + err = registerSQL(d.ctx, ac, db, "validator_db", d.log) + if err != nil { + failBuild(err, "failed to register validator db") + } v, err := vmgr.NewValidatorMgr(d.ctx, db, vmgr.WithLogger(*d.log.Named("validatorStore")), @@ -224,7 +273,7 @@ func buildValidatorModule(d *coreDependencies, accs datasets.AccountStore, validators.WithLogger(*d.log.Named("validator-module"))) } -func buildSnapshotModule(d *coreDependencies) *snapshots.SnapshotStore { +func buildSnapshotter(d *coreDependencies) *snapshots.SnapshotStore { if !d.cfg.SnapshotConfig.Enabled { return nil } @@ -237,8 +286,8 @@ func buildSnapshotModule(d *coreDependencies) *snapshots.SnapshotStore { ) } -func buildBootstrapModule(d *coreDependencies) *snapshotPkg.Bootstrapper { - bootstrapper, err := snapshotPkg.NewBootstrapper(d.cfg.SqliteFilePath) +func buildBootstrapper(d *coreDependencies) *snapshots.Bootstrapper { + bootstrapper, err := snapshots.NewBootstrapper(d.cfg.SqliteFilePath) if err != nil { failBuild(err, "Bootstrap module initialization failure") } @@ -285,68 +334,49 @@ func buildGatewayServer(d *coreDependencies) *gateway.GatewayServer { return gw } -func buildCometBftClient(cometBftNode *nm.Node) *cmtlocal.Local { - return cmtlocal.New(cometBftNode) +func buildCometBftClient(cometBftNode *cometbft.CometBftNode) *cmtlocal.Local { + return cmtlocal.New(cometBftNode.Node) } -// TODO: clean this up --> @jchappelow -// it seems some of this should be handled in ABCI package if we do not provide it as a package -func newCometNode(app *abci.AbciApp, cfg *config.KwildConfig) (*nm.Node, error) { - config := cmtcfg.DefaultConfig() - CometHomeDir := os.Getenv("COMET_BFT_HOME") - fmt.Printf("Home Directory: %v", CometHomeDir) - config.SetRoot(CometHomeDir) - - viper.SetConfigFile(fmt.Sprintf("%s/%s", CometHomeDir, "config/config.toml")) - if err := viper.ReadInConfig(); err != nil { - return nil, fmt.Errorf("reading config: %v", err) - } - if err := viper.Unmarshal(config); err != nil { - return nil, fmt.Errorf("decoding config: %v", err) - } - if err := config.ValidateBasic(); err != nil { - return nil, fmt.Errorf("invalid configuration data: %v", err) - } - - pv := privval.LoadFilePV( - config.PrivValidatorKeyFile(), - config.PrivValidatorStateFile(), - ) - fmt.Println("PrivateKey: ", pv.Key.PrivKey) +func buildCometNode(d *coreDependencies, closer *closeFuncs, abciApp abciTypes.Application) *cometbft.CometBftNode { + // TODO: a lot of the filepaths, as well as cometbft logging level, are hardcoded. This should be cleaned up with a config - fmt.Println("PrivateValidator: ", string(pv.Key.PrivKey.Bytes())) - nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile()) + // for now, I'm just using a KV store for my atomic commit. This probably is not ideal; a file may be better + // I'm simply using this because we know it fsyncs the data to disk + db, err := badger.NewBadgerDB(d.ctx, filepath.Join(d.cfg.RootDir, "signing"), &badger.Options{ + GuaranteeFSync: true, + Logger: *d.log.Named("private-validator-signature-store"), + }) if err != nil { - return nil, fmt.Errorf("failed to load node's key: %v", err) + failBuild(err, "failed to build comet node") + } + closer.addCloser(db.Close) + + readWriter := &atomicReadWriter{ + kv: db, + key: []byte("az"), // any key here will work } - logger := cmtlog.NewTMLogger(cmtlog.NewSyncWriter(os.Stdout)) - logger, err = cmtflags.ParseLogLevel(config.LogLevel, logger, cfg.Log.Level) + node, err := cometbft.NewCometBftNode(abciApp, d.cfg.PrivateKey.Bytes(), readWriter, filepath.Join(d.cfg.RootDir, "abci"), "debug") if err != nil { - return nil, fmt.Errorf("failed to parse log level: %v", err) + failBuild(err, "failed to build comet node") } - // TODO: Move this to Application init and maybe use some kind of kvstore to store the validators info - fmt.Println("Pre RPC Config: ", config.RPC.ListenAddress, " ", cfg.BcRpcUrl) - cfg.BcRpcUrl = config.RPC.ListenAddress - fmt.Println("Post RPC Config: ", config.RPC.ListenAddress, " ", cfg.BcRpcUrl) - - node, err := nm.NewNode( - config, - pv, - nodeKey, - proxy.NewLocalClientCreator(app), // TODO: NewUnsyncedLocalClientCreator(app) is other option which doesn't take a lock on all the connections to the app - nm.DefaultGenesisDocProviderFunc(config), - nm.DefaultDBProvider, - nm.DefaultMetricsProvider(config.Instrumentation), - logger, - ) + return node +} +func buildAtomicCommitter(d *coreDependencies, closers *closeFuncs) *sessions.AtomicCommitter { + twoPCWal, err := wal.OpenWal(filepath.Join(d.cfg.RootDir, "application/wal")) if err != nil { - return nil, fmt.Errorf("creating node: %v", err) + failBuild(err, "failed to open 2pc wal") } - return node, nil + // we are actually registering all committables ad-hoc, so we can pass nil here + s := sessions.NewAtomicCommitter(d.ctx, twoPCWal, sessions.WithLogger(*d.log.Named("atomic-committer"))) + // we need atomic committer to close before 2pc wal + closers.addCloser(s.Close) + closers.addCloser(twoPCWal.Close) + return s } func failBuild(err error, msg string) { diff --git a/internal/app/kwild/server/server.go b/internal/app/kwild/server/server.go index 280e42c17..eb3d845b1 100644 --- a/internal/app/kwild/server/server.go +++ b/internal/app/kwild/server/server.go @@ -8,6 +8,7 @@ import ( "github.com/kwilteam/kwil-db/internal/app/kwild/config" "github.com/kwilteam/kwil-db/pkg/abci" + "github.com/kwilteam/kwil-db/pkg/abci/cometbft" "github.com/kwilteam/kwil-db/pkg/grpc/gateway" grpc "github.com/kwilteam/kwil-db/pkg/grpc/server" "github.com/kwilteam/kwil-db/pkg/log" @@ -15,17 +16,12 @@ import ( "golang.org/x/sync/errgroup" ) -// comet bft node has a gross and confusing interface, so we use this to make it more clear -type startStopper interface { - Start() error - Stop() error -} - // Server controls the gRPC server and http gateway. type Server struct { grpcServer *grpc.Server gateway *gateway.GatewayServer - cometBftNode startStopper + cometBftNode *cometbft.CometBftNode + closers *closeFuncs log log.Logger cfg *config.KwildConfig @@ -34,6 +30,12 @@ type Server struct { } func (s *Server) Start(ctx context.Context) error { + defer func() { + err := s.closers.closeAll() + if err != nil { + s.log.Error("failed to close resource:", zap.Error(err)) + } + }() defer func() { if err := recover(); err != nil { switch et := err.(type) { @@ -58,9 +60,9 @@ func (s *Server) Start(ctx context.Context) error { go func() { <-groupCtx.Done() s.log.Info("stop http server") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx2, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - if err := s.gateway.Shutdown(ctx); err != nil { + if err := s.gateway.Shutdown(ctx2); err != nil { s.log.Error("http server shutdown error", zap.Error(err)) } }() @@ -94,6 +96,7 @@ func (s *Server) Start(ctx context.Context) error { s.log.Info("comet node started") err := group.Wait() + if err != nil { if errors.Is(err, context.Canceled) { s.log.Info("server context is canceled") diff --git a/internal/app/kwild/server/utils.go b/internal/app/kwild/server/utils.go index d6eb93d4a..8fbc436f4 100644 --- a/internal/app/kwild/server/utils.go +++ b/internal/app/kwild/server/utils.go @@ -7,9 +7,13 @@ import ( cmtlocal "github.com/cometbft/cometbft/rpc/client/local" cmttypes "github.com/cometbft/cometbft/types" + "github.com/kwilteam/kwil-db/pkg/abci/cometbft/privval" "github.com/kwilteam/kwil-db/pkg/engine" "github.com/kwilteam/kwil-db/pkg/extensions" + "github.com/kwilteam/kwil-db/pkg/kv" "github.com/kwilteam/kwil-db/pkg/log" + "github.com/kwilteam/kwil-db/pkg/sessions" + sqlSessions "github.com/kwilteam/kwil-db/pkg/sessions/sql-session" "github.com/kwilteam/kwil-db/pkg/sql" "github.com/kwilteam/kwil-db/pkg/sql/client" "github.com/kwilteam/kwil-db/pkg/transactions" @@ -106,3 +110,55 @@ func (wc *wrappedCometBFTClient) BroadcastTxAsync(ctx context.Context, tx *trans return err } + +// atomicReadWriter implements the CometBFt AtomicReadWriter interface. +// This should probably be done with a file instead of a KV store, +// but we already have a good implementation of an atomic KV store. +type atomicReadWriter struct { + kv kv.KVStore + key []byte +} + +var _ privval.AtomicReadWriter = (*atomicReadWriter)(nil) + +func (a *atomicReadWriter) Read() ([]byte, error) { + res, err := a.kv.Get(a.key) + if err == kv.ErrKeyNotFound { + return nil, nil + } + if err != nil { + return nil, err + } + + return res, nil +} + +func (a *atomicReadWriter) Write(val []byte) error { + return a.kv.Set(a.key, val) +} + +// sqlCommittableRegister allows dynamic registration of SQL committables +// it implements engine.CommitRegister +type sqlCommittableRegister struct { + committer *sessions.AtomicCommitter + log log.Logger +} + +var _ engine.CommitRegister = (*sqlCommittableRegister)(nil) + +func (s *sqlCommittableRegister) Register(ctx context.Context, name string, db sql.Database) error { + return registerSQL(ctx, s.committer, db, name, s.log) +} + +func (s *sqlCommittableRegister) Unregister(ctx context.Context, name string) error { + return s.committer.Unregister(ctx, name) +} + +// registerSQL is a helper function to register a SQL committable to the atomic committer. +func registerSQL(ctx context.Context, ac *sessions.AtomicCommitter, db sql.Database, name string, logger log.Logger) error { + return ac.Register(ctx, name, + sqlSessions.NewSqlCommitable(db, + sqlSessions.WithLogger(*logger.Named(name + "-committable")), + ), + ) +} diff --git a/internal/pkg/nodecfg/generate.go b/internal/pkg/nodecfg/generate.go index d8374b90e..4103a6d08 100644 --- a/internal/pkg/nodecfg/generate.go +++ b/internal/pkg/nodecfg/generate.go @@ -9,8 +9,9 @@ import ( cmtCfg "github.com/cometbft/cometbft/config" cmtos "github.com/cometbft/cometbft/libs/os" - cmtrand "github.com/cometbft/cometbft/libs/rand" "github.com/cometbft/cometbft/p2p" + + cmtrand "github.com/cometbft/cometbft/libs/rand" "github.com/cometbft/cometbft/privval" "github.com/cometbft/cometbft/types" cmttime "github.com/cometbft/cometbft/types/time" @@ -42,6 +43,8 @@ type TestnetGenerateConfig struct { P2pPort int } +// TODO: if we use our own keys for cosmos, this will not work +// privval.LoadFilePV will need to be replacew with something else func GenerateNodeConfig(genCfg *NodeGenerateConfig) error { cfg := cmtCfg.DefaultConfig() cfg.SetRoot(genCfg.HomeDir) @@ -210,6 +213,8 @@ func GenerateTestnetConfig(genCfg *TestnetGenerateConfig) error { return nil } +// TODO: we definitely want to get rid of this, or at least make it more understandable / move it +// It generates private keys, which we should not leave up to Comet func initFilesWithConfig(cfg *cmtCfg.Config) error { // private validator privValKeyFile := cfg.PrivValidatorKeyFile() diff --git a/pkg/abci/abci.go b/pkg/abci/abci.go index 9e657caf7..dc966b7a8 100644 --- a/pkg/abci/abci.go +++ b/pkg/abci/abci.go @@ -3,6 +3,7 @@ package abci import ( "context" "encoding/base64" + "encoding/binary" "encoding/hex" "errors" "fmt" @@ -10,7 +11,10 @@ import ( abciTypes "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/ed25519" + tendermintTypes "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/kwilteam/kwil-db/pkg/crypto" engineTypes "github.com/kwilteam/kwil-db/pkg/engine/types" + "github.com/kwilteam/kwil-db/pkg/kv" "github.com/kwilteam/kwil-db/pkg/log" "github.com/kwilteam/kwil-db/pkg/modules/datasets" @@ -28,12 +32,22 @@ type FatalError struct { Message string } +// appState is an in-memory representation of the state of the application. +type appState struct { + height int64 + appHash []byte +} + func (fe FatalError) String() string { return fmt.Sprintf("Application Method: %s\nError: %s\nRequest (%T): %v", fe.AppMethod, fe.Message, fe.Request, fe.Request) } func newFatalError(method string, request fmt.Stringer, message string) FatalError { + if request == nil { + request = nilStringer{} + } + return FatalError{ AppMethod: method, Request: request, @@ -41,21 +55,26 @@ func newFatalError(method string, request fmt.Stringer, message string) FatalErr } } -type appState struct { // TODO - prevBlockHeight int64 - prevAppHash []byte +type nilStringer struct{} + +func (ds nilStringer) String() string { + return "no message" } -func NewAbciApp(database DatasetsModule, validators ValidatorModule, committer AtomicCommitter, - snapshotter SnapshotModule, - bootstrapper DBBootstrapModule, - opts ...AbciOpt) *AbciApp { +func NewAbciApp(database DatasetsModule, vldtrs ValidatorModule, kv KVStore, committer AtomicCommitter, snapshotter SnapshotModule, + bootstrapper DBBootstrapModule, opts ...AbciOpt) *AbciApp { app := &AbciApp{ - database: database, - validators: validators, - committer: committer, - snapshotter: snapshotter, - bootstrapper: bootstrapper, + database: database, + validators: vldtrs, + committer: committer, + metadataStore: &metadataStore{ + kv: kv, + }, + bootstrapper: nil, + snapshotter: nil, + + valAddrToKey: make(map[string][]byte), + valUpdates: make([]*validators.Validator, 0), log: log.NewNoOp(), @@ -102,7 +121,8 @@ type AbciApp struct { snapshotter SnapshotModule // bootstrapper is the bootstrapper module that handles bootstrapping the database - bootstrapper DBBootstrapModule + bootstrapper DBBootstrapModule + metadataStore *metadataStore log log.Logger @@ -112,75 +132,14 @@ type AbciApp struct { // when a commit is finished, the commitWaiter is decremented commitWaiter sync.WaitGroup - state appState - // Expected AppState after bootstrapping the node with a given snapshot, // state gets updated with the bootupState after bootstrapping bootupState appState -} - -func (a *AbciApp) ApplySnapshotChunk(p0 abciTypes.RequestApplySnapshotChunk) abciTypes.ResponseApplySnapshotChunk { - refetchChunks, status, err := a.bootstrapper.ApplySnapshotChunk(p0.Chunk, p0.Index) - if err != nil { - return abciTypes.ResponseApplySnapshotChunk{Result: abciStatus(status), RefetchChunks: refetchChunks} - } - if a.bootstrapper.IsDBRestored() { - a.state.prevAppHash = a.bootupState.prevAppHash - a.state.prevBlockHeight = a.bootupState.prevBlockHeight - a.log.Info("Bootstrapped database successfully") - } - return abciTypes.ResponseApplySnapshotChunk{Result: abciTypes.ResponseApplySnapshotChunk_ACCEPT, RefetchChunks: nil} + applicationVersion uint64 } -func (a *AbciApp) Info(p0 abciTypes.RequestInfo) abciTypes.ResponseInfo { - // Load the current validator set from our store. - vals, err := a.validators.CurrentSet(context.Background()) - if err != nil { // TODO error return - panic(newFatalError("Info", &p0, fmt.Sprintf("failed to load current validators: %v", err))) - } - // NOTE: We can check against cometbft/rpc/core.Validators(), but that only - // works with an *in-process* node and after the node is started. - - // Prepare the validator addr=>pubkey map. - a.valAddrToKey = make(map[string][]byte, len(vals)) - for _, vi := range vals { - addr, err := pubkeyToAddr(vi.PubKey) - if err != nil { - panic(newFatalError("Info", &p0, fmt.Sprintf("invalid validator pubkey: %v", err))) - } - a.valAddrToKey[addr] = vi.PubKey - } - - return abciTypes.ResponseInfo{ - LastBlockHeight: a.state.prevBlockHeight, // otherwise comet will restart and InitChain! - LastBlockAppHash: a.state.prevAppHash, - } -} - -func (a *AbciApp) InitChain(p0 abciTypes.RequestInitChain) abciTypes.ResponseInitChain { - // Initialize the validator module with the genesis validators. - vs := make([]*validators.Validator, len(p0.Validators)) - for i := range p0.Validators { - vi := &p0.Validators[i] - // pk := vi.PubKey.GetEd25519() - // if pk == nil { panic("only ed25519 validator keys are supported") } - pk, err := vi.PubKey.Marshal() - if err != nil { - panic(fmt.Sprintf("invalid validator pubkey: %v", err)) - } - vs[i] = &validators.Validator{ - PubKey: pk, - Power: vi.Power, - } - } - - if err := a.validators.GenesisInit(context.Background(), vs); err != nil { - panic(fmt.Sprintf("GenesisInit failed: %v", err)) - } - - return abciTypes.ResponseInitChain{} // no change to validators -} +var _ abciTypes.Application = &AbciApp{} // BeginBlock begins a block. // If the previous commit is not finished, it will wait for the previous commit to finish. @@ -193,8 +152,7 @@ func (a *AbciApp) BeginBlock(req abciTypes.RequestBeginBlock) abciTypes.Response err := a.committer.Begin(context.Background()) if err != nil { - a.log.Error("failed to begin atomic commit", zap.Error(err)) - return abciTypes.ResponseBeginBlock{} + panic(newFatalError("BeginBlock", &req, err.Error())) } // Punish bad validators. @@ -209,26 +167,33 @@ func (a *AbciApp) BeginBlock(req abciTypes.RequestBeginBlock) abciTypes.Response // This is why we need the addr=>pubkey map. Why, comet, why? pubkey, ok := a.valAddrToKey[addr] if !ok { - panic(fmt.Sprintf("unknown validator address %v", addr)) + panic(newFatalError("BeginBlock", &req, fmt.Sprintf("unknown validator address %v", addr))) } const punishDelta = 1 newPower := ev.Validator.Power - punishDelta if err = a.validators.Punish(context.Background(), pubkey, newPower); err != nil { - panic(fmt.Sprintf("failed to punish validator %v: %v", addr, err)) + panic(newFatalError("BeginBlock", &req, fmt.Sprintf("failed to punish validator %v", addr))) } } return abciTypes.ResponseBeginBlock{} } -func (a *AbciApp) CheckTx(p0 abciTypes.RequestCheckTx) abciTypes.ResponseCheckTx { - panic("TODO") -} +func (a *AbciApp) CheckTx(incoming abciTypes.RequestCheckTx) abciTypes.ResponseCheckTx { + tx := &transactions.Transaction{} + err := tx.UnmarshalBinary(incoming.Tx) + if err != nil { + a.log.Error("failed to unmarshal transaction", zap.Error(err)) + return abciTypes.ResponseCheckTx{Code: 1, Log: err.Error()} + } -// pubkeys in event attributes returned to comet as strings are base64 encoded, -// apparently. -func encodeBase64(b []byte) string { - return base64.StdEncoding.EncodeToString(b) + err = tx.Verify() + if err != nil { + a.log.Error("failed to verify transaction", zap.Error(err)) + return abciTypes.ResponseCheckTx{Code: 1, Log: err.Error()} + } + + return abciTypes.ResponseCheckTx{Code: 0} } func (a *AbciApp) DeliverTx(req abciTypes.RequestDeliverTx) abciTypes.ResponseDeliverTx { @@ -377,7 +342,9 @@ func (a *AbciApp) DeliverTx(req abciTypes.RequestDeliverTx) abciTypes.ResponseDe } } -func (a *AbciApp) EndBlock(_ abciTypes.RequestEndBlock) abciTypes.ResponseEndBlock { +func (a *AbciApp) EndBlock(e abciTypes.RequestEndBlock) abciTypes.ResponseEndBlock { + a.log.Info("end block", zap.Int64("height", e.Height)) + a.valUpdates = a.validators.Finalize(context.Background()) valUpdates := make([]abciTypes.ValidatorUpdate, len(a.valUpdates)) @@ -387,24 +354,46 @@ func (a *AbciApp) EndBlock(_ abciTypes.RequestEndBlock) abciTypes.ResponseEndBlo return abciTypes.ResponseEndBlock{ ValidatorUpdates: valUpdates, - // will include AppHash in v0.38 + ConsensusParamUpdates: &tendermintTypes.ConsensusParams{ + // we can include evidence in here for malicious actors, but this is not important this release + Version: &tendermintTypes.VersionParams{ + App: a.applicationVersion, + }, + Validator: &tendermintTypes.ValidatorParams{ + PubKeyTypes: []string{"ed25519"}, + }, + }, } } -// Commit commits a block. -// It will commit all changes to a wal, and then asynchronously apply the changes to the database. func (a *AbciApp) Commit() abciTypes.ResponseCommit { ctx := context.Background() - appHash, err := a.committer.Commit(ctx, func(err error) { + + // generate the unique id for all changes occurred thus far + id, err := a.committer.ID(ctx) + if err != nil { + panic(newFatalError("Commit", nil, fmt.Sprintf("failed to get commit id: %v", err))) + } + + appHash, err := a.createNewAppHash(ctx, id) + if err != nil { + panic(newFatalError("Commit", nil, fmt.Sprintf("failed to create new app hash: %v", err))) + } + + err = a.metadataStore.IncrementBlockHeight(ctx) + if err != nil { + panic(newFatalError("Commit", nil, fmt.Sprintf("failed to increment block height: %v", err))) + } + + err = a.committer.Commit(ctx, func(err error) { if err != nil { - a.log.Error("failed to apply atomic commit", zap.Error(err)) + panic(newFatalError("Commit", nil, fmt.Sprintf("failed to commit atomic commit: %v", err))) } a.commitWaiter.Done() }) if err != nil { - a.log.Error("failed to commit atomic commit", zap.Error(err)) - return abciTypes.ResponseCommit{} + panic(newFatalError("Commit", nil, fmt.Sprintf("failed to commit atomic commit: %v", err))) } // Update the validator address=>pubkey map used by Penalize. @@ -417,13 +406,16 @@ func (a *AbciApp) Commit() abciTypes.ResponseCommit { } a.valUpdates = nil - a.state.prevBlockHeight++ - a.state.prevAppHash = appHash + // snapshotting + height, err := a.metadataStore.GetBlockHeight(ctx) + if err != nil { + a.log.Error("failed to get block height", zap.Error(err)) + return abciTypes.ResponseCommit{} + } - height := uint64(a.state.prevBlockHeight) - if a.snapshotter != nil && a.snapshotter.IsSnapshotDue(height) { + if a.snapshotter != nil && a.snapshotter.IsSnapshotDue(uint64(height)) { // TODO: Lock all DBs - err = a.snapshotter.CreateSnapshot(height) + err = a.snapshotter.CreateSnapshot(uint64(height)) if err != nil { a.log.Error("snapshot creation failed", zap.Error(err)) } @@ -431,8 +423,114 @@ func (a *AbciApp) Commit() abciTypes.ResponseCommit { } return abciTypes.ResponseCommit{ - Data: appHash, // will be in ResponseFinalizeBlock in v0.38 + Data: appHash, + } +} + +func (a *AbciApp) Info(p0 abciTypes.RequestInfo) abciTypes.ResponseInfo { + ctx := context.Background() + + err := a.committer.ClearWal(ctx) + if err != nil { + panic(newFatalError("Info", &p0, fmt.Sprintf("failed to clear WAL: %v", err))) + } + + // Load the current validator set from our store. + vals, err := a.validators.CurrentSet(ctx) + if err != nil { // TODO error return + panic(newFatalError("Info", &p0, fmt.Sprintf("failed to load current validators: %v", err))) + } + // NOTE: We can check against cometbft/rpc/core.Validators(), but that only + // works with an *in-process* node and after the node is started. + + // Prepare the validator addr=>pubkey map. + a.valAddrToKey = make(map[string][]byte, len(vals)) + for _, vi := range vals { + addr, err := pubkeyToAddr(vi.PubKey) + if err != nil { + panic(newFatalError("Info", &p0, fmt.Sprintf("invalid validator pubkey: %v", err))) + } + a.valAddrToKey[addr] = vi.PubKey + } + + height, err := a.metadataStore.GetBlockHeight(ctx) + if err != nil { + panic(newFatalError("Info", &p0, fmt.Sprintf("failed to get block height: %v", err))) + } + + appHash, err := a.metadataStore.GetAppHash(ctx) + if err != nil { + panic(newFatalError("Info", &p0, fmt.Sprintf("failed to get app hash: %v", err))) + } + + return abciTypes.ResponseInfo{ + LastBlockHeight: height, + LastBlockAppHash: appHash, + AppVersion: a.applicationVersion, + } +} + +func (a *AbciApp) InitChain(p0 abciTypes.RequestInitChain) abciTypes.ResponseInitChain { + ctx := context.Background() + + // Initialize the validator module with the genesis validators. + vldtrs := make([]*validators.Validator, len(p0.Validators)) + for i := range p0.Validators { + vi := &p0.Validators[i] + // pk := vi.PubKey.GetEd25519() + // if pk == nil { panic("only ed25519 validator keys are supported") } + pk := vi.PubKey.GetEd25519() + vldtrs[i] = &validators.Validator{ + PubKey: pk, + Power: vi.Power, + } + } + + if err := a.validators.GenesisInit(context.Background(), vldtrs); err != nil { + panic(fmt.Sprintf("GenesisInit failed: %v", err)) + } + + valUpdates := make([]abciTypes.ValidatorUpdate, len(vldtrs)) + for i, validator := range vldtrs { + valUpdates[i] = abciTypes.Ed25519ValidatorUpdate(validator.PubKey, validator.Power) + } + + apphash, err := a.metadataStore.GetAppHash(ctx) + if err != nil { + panic(fmt.Sprintf("failed to get app hash: %v", err)) + // TODO: should we initialize with a genesis hash instead if it fails + // TODO: apparently InitChain is only genesis, so yes it should only be genesis hash + // in fact, I don't think we should be getting it from this store at all + } + + return abciTypes.ResponseInitChain{ + Validators: valUpdates, + AppHash: apphash, + } +} + +func (a *AbciApp) ApplySnapshotChunk(p0 abciTypes.RequestApplySnapshotChunk) abciTypes.ResponseApplySnapshotChunk { + refetchChunks, status, err := a.bootstrapper.ApplySnapshotChunk(p0.Chunk, p0.Index) + if err != nil { + return abciTypes.ResponseApplySnapshotChunk{Result: abciStatus(status), RefetchChunks: refetchChunks} + } + + ctx := context.Background() + + if a.bootstrapper.IsDBRestored() { + err = a.metadataStore.SetAppHash(ctx, a.bootupState.appHash) + if err != nil { + return abciTypes.ResponseApplySnapshotChunk{Result: abciTypes.ResponseApplySnapshotChunk_ABORT, RefetchChunks: nil} + } + + err = a.metadataStore.SetBlockHeight(ctx, a.bootupState.height) + if err != nil { + return abciTypes.ResponseApplySnapshotChunk{Result: abciTypes.ResponseApplySnapshotChunk_ABORT, RefetchChunks: nil} + } + + a.log.Info("Bootstrapped database successfully") } + return abciTypes.ResponseApplySnapshotChunk{Result: abciTypes.ResponseApplySnapshotChunk_ACCEPT, RefetchChunks: nil} } func (a *AbciApp) ListSnapshots(p0 abciTypes.RequestListSnapshots) abciTypes.ResponseListSnapshots { @@ -467,24 +565,38 @@ func (a *AbciApp) LoadSnapshotChunk(p0 abciTypes.RequestLoadSnapshotChunk) abciT func (a *AbciApp) OfferSnapshot(p0 abciTypes.RequestOfferSnapshot) abciTypes.ResponseOfferSnapshot { snapshot := convertABCISnapshots(p0.Snapshot) - if (a.bootstrapper.OfferSnapshot(snapshot)) != nil { + if a.bootstrapper.OfferSnapshot(snapshot) != nil { return abciTypes.ResponseOfferSnapshot{Result: abciTypes.ResponseOfferSnapshot_REJECT} } - a.bootupState.prevAppHash = p0.Snapshot.Hash - a.bootupState.prevBlockHeight = int64(snapshot.Height) + a.bootupState.appHash = p0.Snapshot.Hash + a.bootupState.height = int64(snapshot.Height) return abciTypes.ResponseOfferSnapshot{Result: abciTypes.ResponseOfferSnapshot_ACCEPT} } func (a *AbciApp) PrepareProposal(p0 abciTypes.RequestPrepareProposal) abciTypes.ResponsePrepareProposal { - panic("TODO") + return abciTypes.ResponsePrepareProposal{} } func (a *AbciApp) ProcessProposal(p0 abciTypes.RequestProcessProposal) abciTypes.ResponseProcessProposal { - panic("TODO") + return abciTypes.ResponseProcessProposal{Status: abciTypes.ResponseProcessProposal_ACCEPT} } func (a *AbciApp) Query(p0 abciTypes.RequestQuery) abciTypes.ResponseQuery { - panic("TODO") + return abciTypes.ResponseQuery{} +} + +// updateAppHash updates the app hash with the given app hash. +// It persists the app hash to the metadata store. +func (a *AbciApp) createNewAppHash(ctx context.Context, addition []byte) ([]byte, error) { + oldHash, err := a.metadataStore.GetAppHash(ctx) + if err != nil { + return nil, err + } + + newHash := crypto.Sha256(append(oldHash, addition...)) + + err = a.metadataStore.SetAppHash(ctx, newHash) + return newHash, err } // convertArgs converts the string args to type any. @@ -499,3 +611,58 @@ func convertArgs(args [][]string) [][]any { return converted } + +var ( + appHashKey = []byte("a") + blockHeightKey = []byte("b") +) + +type metadataStore struct { + kv KVStore +} + +func (m *metadataStore) GetAppHash(ctx context.Context) ([]byte, error) { + res, err := m.kv.Get(appHashKey) + if err == kv.ErrKeyNotFound { + return nil, nil + } + return res, err +} + +func (m *metadataStore) SetAppHash(ctx context.Context, appHash []byte) error { + return m.kv.Set(appHashKey, appHash) +} + +func (m *metadataStore) GetBlockHeight(ctx context.Context) (int64, error) { + height, err := m.kv.Get(blockHeightKey) + if err == kv.ErrKeyNotFound { + return 0, nil + } + if err != nil { + return 0, err + } + + return int64(binary.BigEndian.Uint64(height)), nil +} + +func (m *metadataStore) SetBlockHeight(ctx context.Context, height int64) error { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, uint64(height)) + + return m.kv.Set(blockHeightKey, buf) +} + +func (m *metadataStore) IncrementBlockHeight(ctx context.Context) error { + height, err := m.GetBlockHeight(ctx) + if err != nil { + return err + } + + return m.SetBlockHeight(ctx, height+1) +} + +// pubkeys in event attributes returned to comet as strings are base64 encoded, +// apparently. +func encodeBase64(b []byte) string { + return base64.StdEncoding.EncodeToString(b) +} diff --git a/pkg/abci/cometbft/node.go b/pkg/abci/cometbft/node.go new file mode 100644 index 000000000..1a0842525 --- /dev/null +++ b/pkg/abci/cometbft/node.go @@ -0,0 +1,65 @@ +package cometbft + +import ( + "fmt" + "os" + + abciTypes "github.com/cometbft/cometbft/abci/types" + cometConfig "github.com/cometbft/cometbft/config" + cometEd25519 "github.com/cometbft/cometbft/crypto/ed25519" + cometFlags "github.com/cometbft/cometbft/libs/cli/flags" + cometLog "github.com/cometbft/cometbft/libs/log" + cometNodes "github.com/cometbft/cometbft/node" + "github.com/cometbft/cometbft/p2p" + "github.com/cometbft/cometbft/proxy" + "github.com/kwilteam/kwil-db/pkg/abci/cometbft/privval" +) + +type CometBftNode struct { + Node *cometNodes.Node +} + +// NewCometBftNode creates a new CometBFT node. +func NewCometBftNode(app abciTypes.Application, privateKey []byte, atomicStore privval.AtomicReadWriter, directory string, logLevel string) (*CometBftNode, error) { + conf := cometConfig.DefaultConfig().SetRoot(directory) + logger := cometLog.NewTMLogger(cometLog.NewSyncWriter(os.Stdout)) + logger, err := cometFlags.ParseLogLevel(conf.LogLevel, logger, logLevel) + if err != nil { + return nil, fmt.Errorf("failed to parse log level: %v", err) + } + + privateValidator, err := privval.NewValidatorSigner(privateKey, atomicStore) + if err != nil { + return nil, fmt.Errorf("failed to create private validator: %v", err) + } + + node, err := cometNodes.NewNode( + conf, + privateValidator, + &p2p.NodeKey{ + PrivKey: cometEd25519.PrivKey(privateKey), + }, + proxy.NewLocalClientCreator(app), + cometNodes.DefaultGenesisDocProviderFunc(conf), + cometNodes.DefaultDBProvider, + cometNodes.DefaultMetricsProvider(conf.Instrumentation), + logger, + ) + if err != nil { + return nil, fmt.Errorf("failed to create CometBFT node: %v", err) + } + + return &CometBftNode{ + Node: node, + }, nil +} + +// Start starts the CometBFT node. +func (n *CometBftNode) Start() error { + return n.Node.Start() +} + +// Stop stops the CometBFT node. +func (n *CometBftNode) Stop() error { + return n.Node.Stop() +} diff --git a/pkg/abci/cometbft/privval/privvalidator.go b/pkg/abci/cometbft/privval/privvalidator.go new file mode 100644 index 000000000..b7c7eb135 --- /dev/null +++ b/pkg/abci/cometbft/privval/privvalidator.go @@ -0,0 +1,348 @@ +package privval + +/* + Much of the code in this package is inspired or pulled directly from cometbft/privval, + [https://github.com/cometbft/cometbft/blob/1fb31e05d304bcbdbf01aaeb073781aa9f441e34/privval/file.go#L100] + + Licensed under the Apache License, Version 2.0 +*/ + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "time" + + cometEd25519 "github.com/cometbft/cometbft/crypto/ed25519" + cmtbytes "github.com/cometbft/cometbft/libs/bytes" + "github.com/cometbft/cometbft/libs/protoio" + tendermintTypes "github.com/cometbft/cometbft/proto/tendermint/types" + cmttime "github.com/cometbft/cometbft/types/time" + "github.com/cosmos/gogoproto/proto" + + "github.com/cometbft/cometbft/crypto" + "github.com/cometbft/cometbft/types" +) + +// NewValidatorSigner returns a new ValidatorSigner +// it takes in an ed25519 key, and a keyvalue store +// the key values store should NOT be atomically committed with other KV +// stores. Instead, it should simply fsync after every write/commit +func NewValidatorSigner(ed25519Key []byte, storer AtomicReadWriter) (*ValidatorSigner, error) { + if len(ed25519Key) != cometEd25519.PrivateKeySize { + return nil, fmt.Errorf("invalid private key size. received: %d, expected: %d", len(ed25519Key), cometEd25519.PrivateKeySize) + } + + lss := &LastSignState{ + storer: storer, + } + err := lss.loadLatest() + if err != nil { + return nil, err + } + + return &ValidatorSigner{ + privateKey: cometEd25519.PrivKey(ed25519Key), + lastSignedState: lss, + }, nil +} + +// ValidatorSigner implements CometBFT's cometTypes.PrivValidator +// It persists its most recent signature, which can be used during +// recovery to prevent double signing +type ValidatorSigner struct { + // privateKey is the ed25519 private key used to sign messages + privateKey crypto.PrivKey + + // lastSignedState is the most recent signature made by this validator + lastSignedState *LastSignState +} + +var _ types.PrivValidator = (*ValidatorSigner)(nil) + +// GetPubKey returns the public key of the validator +// It is part of the cometTypes.PrivValidator interface +func (v *ValidatorSigner) GetPubKey() (crypto.PubKey, error) { + return v.privateKey.PubKey(), nil + +} + +// SignProposal signs a proposal message +// It is part of the cometTypes.PrivValidator interface +func (v *ValidatorSigner) SignProposal(chainID string, proposal *tendermintTypes.Proposal) error { + height, round, step := proposal.Height, proposal.Round, stepPropose + + sameHRS, err := v.lastSignedState.checkHRS(height, round, step) + if err != nil { + return err + } + + signBytes := types.ProposalSignBytes(chainID, proposal) + + // We might crash before writing to the wal, + // causing us to try to re-sign for the same HRS. + // If signbytes are the same, use the last signature. + // If they only differ by timestamp, use last timestamp and signature + // Otherwise, return error + if sameHRS { + if bytes.Equal(signBytes, v.lastSignedState.SignBytes) { + proposal.Signature = v.lastSignedState.Signature + } else if timestamp, ok := checkProposalsOnlyDifferByTimestamp(v.lastSignedState.SignBytes, signBytes); ok { + proposal.Signature = v.lastSignedState.Signature + proposal.Timestamp = timestamp + } else { + err = fmt.Errorf("proposal sign bytes differ from last sign bytes") + } + return err + } + + // Sign the proposal + signature, err := v.signAndPersist(height, round, step, signBytes) + if err != nil { + return err + } + + // Set the proposal signature + proposal.Signature = signature + + return nil +} + +// SignVote signs a vote message +// It is part of the cometTypes.PrivValidator interface +func (v *ValidatorSigner) SignVote(chainID string, vote *tendermintTypes.Vote) error { + height, round, step := vote.Height, vote.Round, VoteToStep(vote) + + sameHRS, err := v.lastSignedState.checkHRS(height, round, step) + if err != nil { + return err + } + + signBytes := types.VoteSignBytes(chainID, vote) + + // We might crash before writing to the wal, + // causing us to try to re-sign for the same HRS. + // If signbytes are the same, use the last signature. + // If they only differ by timestamp, use last timestamp and signature + // Otherwise, return error + if sameHRS { + if bytes.Equal(signBytes, v.lastSignedState.SignBytes) { + vote.Signature = v.lastSignedState.Signature + } else if timestamp, ok := checkVotesOnlyDifferByTimestamp(v.lastSignedState.SignBytes, signBytes); ok { + vote.Timestamp = timestamp + vote.Signature = v.lastSignedState.Signature + } else { + err = fmt.Errorf("conflicting data") + } + return err + } + + // Sign the vote + signature, err := v.signAndPersist(height, round, step, signBytes) + if err != nil { + return err + } + + // Set the vote signature + vote.Signature = signature + + return nil +} + +// signAndPersist signs a message and persists the signature +// it returns the signature after it has been persisted +func (v *ValidatorSigner) signAndPersist(height int64, round int32, step int8, signBytes []byte) ([]byte, error) { + signature, err := v.privateKey.Sign(signBytes) + if err != nil { + return nil, err + } + + v.lastSignedState.Height = height + v.lastSignedState.Round = round + v.lastSignedState.Step = step + v.lastSignedState.SignBytes = signBytes + v.lastSignedState.Signature = signature + err = v.lastSignedState.store() + if err != nil { + return nil, err + } + + return signature, nil +} + +// LastSignState tracks the most recent signature +// made by this validator. It is atomically committed to disk +// before it is used for anything else, and can be reloaded in case +// of a crash +type LastSignState struct { + // Height is the height of the block that the message was signed for + Height int64 `json:"height"` + + // Round is the consensus round that the message was signed for + // CometBFT can have an arbitrary number of rounds per height + Round int32 `json:"round"` + + // Step is the consensus step that the message was signed for + // e.g. propose, prevote, precommit + Step int8 `json:"step"` + + // Signature is the signature generated by the validator + Signature []byte `json:"signature"` + + // SignBytes is the bytes that were signed by the validator + SignBytes cmtbytes.HexBytes `json:"sign_bytes"` + + // storer is the store that this lastSignState is persisted to + storer AtomicReadWriter +} + +// store stores the lastSignState to the given KV store +// it is atomic, and will only commit if all writes succeed +func (l *LastSignState) store() error { + bts, err := json.Marshal(l) + if err != nil { + return err + } + return l.storer.Write(bts) +} + +// loadLatest loads the latest lastSignState from the given KV store +// if none exists, it sets all fields to zero values +func (l *LastSignState) loadLatest() (err error) { + bts, err := l.storer.Read() + if err != nil { + return err + } + + if bts == nil { + l.setZero() + return nil + } + + return json.Unmarshal(bts, l) +} + +// setZero sets all fields to zero values +func (l *LastSignState) setZero() { + l.Height = 0 + l.Round = 0 + l.Step = 0 + l.Signature = nil + l.SignBytes = nil +} + +// checkHRS checks that the given height, round, and step match the lastSignState. +func (lss *LastSignState) checkHRS(height int64, round int32, step int8) (bool, error) { + + if lss.Height > height { + return false, fmt.Errorf("%w: height regression. Got %v, last height %v", ErrHeightRegression, height, lss.Height) + } + + if lss.Height == height { + if lss.Round > round { + return false, fmt.Errorf("%w: round regression at height %v. Got %v, last round %v", ErrRoundRegression, height, round, lss.Round) + } + + if lss.Round == round { + if lss.Step > step { + return false, fmt.Errorf( + "%w: step regression at height %v round %v. Got %v, last step %v", + ErrStepRegression, + height, + round, + step, + lss.Step, + ) + } else if lss.Step == step { + if lss.SignBytes != nil { + if lss.Signature == nil { + return false, fmt.Errorf("%w: Signature is nil but SignBytes is not", ErrNilSignature) + } + return true, nil + } + return false, errors.New("no SignBytes found") + } + } + } + return false, nil +} + +// Returns the timestamp from the lastSignBytes. +// Returns true if the only difference in the votes is their timestamp. +// Performs these checks on the canonical votes (excluding the vote extension +// and vote extension signatures). +func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) { + var lastVote, newVote tendermintTypes.CanonicalVote + if err := protoio.UnmarshalDelimited(lastSignBytes, &lastVote); err != nil { + panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into vote: %v", err)) + } + if err := protoio.UnmarshalDelimited(newSignBytes, &newVote); err != nil { + panic(fmt.Sprintf("signBytes cannot be unmarshalled into vote: %v", err)) + } + + lastTime := lastVote.Timestamp + // set the times to the same value and check equality + now := cmttime.Now() + lastVote.Timestamp = now + newVote.Timestamp = now + + return lastTime, proto.Equal(&newVote, &lastVote) +} + +// returns the timestamp from the lastSignBytes. +// returns true if the only difference in the proposals is their timestamp +func checkProposalsOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) { + var lastProposal, newProposal tendermintTypes.CanonicalProposal + if err := protoio.UnmarshalDelimited(lastSignBytes, &lastProposal); err != nil { + panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into proposal: %v", err)) + } + if err := protoio.UnmarshalDelimited(newSignBytes, &newProposal); err != nil { + panic(fmt.Sprintf("signBytes cannot be unmarshalled into proposal: %v", err)) + } + + lastTime := lastProposal.Timestamp + // set the times to the same value and check equality + now := cmttime.Now() + lastProposal.Timestamp = now + newProposal.Timestamp = now + + return lastTime, proto.Equal(&newProposal, &lastProposal) +} + +// this should be unexported, but is needed for testing +// A vote is either stepPrevote or stepPrecommit. +func VoteToStep(vote *tendermintTypes.Vote) int8 { + switch vote.Type { + case tendermintTypes.PrevoteType: + return stepPrevote + case tendermintTypes.PrecommitType: + return stepPrecommit + default: + panic(fmt.Sprintf("Unknown vote type: %v", vote.Type)) + } +} + +const ( + stepNone int8 = 0 // Used to distinguish the initial state + stepPropose int8 = 1 + stepPrevote int8 = 2 + stepPrecommit int8 = 3 +) + +// AtomicReadWriter is an interface for any store +// that can atomically read and write to a persistent store +type AtomicReadWriter interface { + // Write should overwrite the current value with the given value + Write([]byte) error + // Read should return the current value + // if the value is empty, it should return empty bytes and no error + Read() ([]byte, error) +} + +var ( + ErrHeightRegression = errors.New("height regression") + ErrRoundRegression = errors.New("round regression") + ErrStepRegression = errors.New("step regression") + ErrNilSignature = errors.New("signature is nil") +) diff --git a/pkg/abci/cometbft/privval/privvalidator_test.go b/pkg/abci/cometbft/privval/privvalidator_test.go new file mode 100644 index 000000000..c6072d9f3 --- /dev/null +++ b/pkg/abci/cometbft/privval/privvalidator_test.go @@ -0,0 +1,456 @@ +package privval_test + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "testing" + "time" + + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/cometbft/cometbft/types" + "github.com/kwilteam/kwil-db/pkg/abci/cometbft/privval" + "github.com/stretchr/testify/assert" +) + +const defaultChainID = "test-chain" +const defaultPrivateKey = "7c67e60fce0c403ff40193a3128e5f3d8c2139aed36d76d7b5f1e70ec19c43f00aa611bf555596912bc6f9a9f169f8785918e7bab9924001895798ff13f05842" + +func Test_PrivValidatorVote(t *testing.T) { + type testCase struct { + // name is the name of the test case. + name string + // lastSigned is the last signed vote. + // it can be nil. + lastSigned *cmtproto.Vote + // vote is the vote to sign. + vote *cmtproto.Vote + // secondVote is the second vote to sign. + // it can be nil. + secondVote *cmtproto.Vote + + // chainid is the default chain ID to use. + chainID string + + // privKey is the private key to use. + privKey string + + // err is the expected error. + // if nil, no error is expected. + err error + + // after is a function to run after the test case. + // it can be nil. + after func(t *testing.T, tc *testCase) + } + + tests := []testCase{ + // { + // name: "signing a vote with no other votes signed", + // vote: testVote(), + // chainID: defaultChainID, + // privKey: defaultPrivateKey, + // }, + // { + // name: "signing two separate votes, validly", + // vote: testVote(height(1)), + // secondVote: testVote(height(2)), + // chainID: defaultChainID, + // privKey: defaultPrivateKey, + // }, + // { + // name: "signing a vote with a different previous vote signed", + // lastSigned: testVote(height(1)), + // vote: testVote(height(2)), + // chainID: defaultChainID, + // privKey: defaultPrivateKey, + // }, + // { + // name: "signing the same vote despite it being signed already, first vote is last signed", + // lastSigned: testVote(signed("sig")), + // vote: testVote(), + // chainID: defaultChainID, + // privKey: defaultPrivateKey, + // after: func(t *testing.T, tc *testCase) { + // // it should have the same signature as the last signed vote. + // assert.Equal(t, tc.lastSigned.Signature, tc.vote.Signature) + // }, + // }, + { + name: "signing same vote twice, with different timestamps", + lastSigned: testVote(signed("sig"), timestamped(100)), + vote: testVote(timestamped(200)), + chainID: defaultChainID, + privKey: defaultPrivateKey, + after: func(t *testing.T, tc *testCase) { + // it should have the same signature as the last signed vote. + assert.Equal(t, tc.lastSigned.Signature, tc.vote.Signature) + assert.Equal(t, tc.lastSigned.Timestamp.UTC(), tc.vote.Timestamp.UTC()) + }, + }, + { + name: "test height regression", + lastSigned: testVote(height(100)), + vote: testVote(height(99)), + chainID: defaultChainID, + privKey: defaultPrivateKey, + err: privval.ErrHeightRegression, + }, + { + name: "test round regression", + lastSigned: testVote(round(100)), + vote: testVote(round(99)), + chainID: defaultChainID, + privKey: defaultPrivateKey, + err: privval.ErrRoundRegression, + }, + { + name: "test step regression", + lastSigned: testVote(step(cmtproto.PrecommitType)), + vote: testVote(step(cmtproto.PrevoteType)), + chainID: defaultChainID, + privKey: defaultPrivateKey, + err: privval.ErrStepRegression, + }, + } + + // test cases for signing a vote. + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // outer function to catch any returns errors + err := func() error { + privKeyBts, err := hex.DecodeString(tc.privKey) + if err != nil { + return err + } + + store := newMockStore() + if tc.lastSigned != nil { + if err := setKeys(store, tc.lastSigned.Height, tc.lastSigned.Round, privval.VoteToStep(tc.lastSigned), tc.lastSigned.Signature, types.VoteSignBytes(tc.chainID, tc.lastSigned)); err != nil { + return err + } + } + + privVal, err := privval.NewValidatorSigner(privKeyBts, store) + if err != nil { + return err + } + + // sign the vote + err = privVal.SignVote(tc.chainID, tc.vote) + if err != nil { + return err + } + + assert.NotNil(t, tc.vote.Signature) + + if tc.secondVote != nil { + // sign the second vote + err = privVal.SignVote(tc.chainID, tc.secondVote) + if err != nil { + return err + } + + assert.Equal(t, tc.vote.Timestamp, tc.secondVote.Timestamp) + } + + return nil + }() + if err != nil { + if tc.err == nil { + t.Fatalf("unexpected error: %v", err) + } + + assert.ErrorIs(t, err, tc.err) + return + } + if tc.err != nil { + t.Fatalf("expected error: %v", tc.err) + } + + if tc.after != nil { + tc.after(t, &tc) + } + }) + } +} + +func Test_Proposals(t *testing.T) { + type testCase struct { + // name is the name of the test case. + name string + // lastSigned is the last signed vote. + // it can be nil. + lastSigned *cmtproto.Proposal + // vote is the vote to sign. + vote *cmtproto.Proposal + // secondVote is the second vote to sign. + // it can be nil. + secondVote *cmtproto.Proposal + + // err is the expected error. + // if nil, no error is expected. + err error + + // after is a function to run after the test case. + // it can be nil. + after func(t *testing.T, tc *testCase) + } + + tests := []testCase{ + { + name: "signing a vote with no other votes signed", + vote: testProposal(), + }, + { + name: "signing two separate votes, validly", + vote: testProposal(height(1)), + secondVote: testProposal(height(2)), + }, + { + name: "signing a vote with a different previous vote signed", + lastSigned: testProposal(height(1)), + vote: testProposal(height(2)), + }, + { + name: "signing the same vote despite it being signed already, first vote is last signed", + lastSigned: testProposal(signed("sig")), + vote: testProposal(), + + after: func(t *testing.T, tc *testCase) { + // it should have the same signature as the last signed vote. + assert.Equal(t, tc.lastSigned.Signature, tc.vote.Signature) + }, + }, + { + name: "signing same vote twice, with different timestamps", + lastSigned: testProposal(signed("sig"), timestamped(100)), + vote: testProposal(timestamped(200)), + + after: func(t *testing.T, tc *testCase) { + // it should have the same signature as the last signed vote. + assert.Equal(t, tc.lastSigned.Signature, tc.vote.Signature) + assert.Equal(t, tc.lastSigned.Timestamp.UTC(), tc.vote.Timestamp.UTC()) + }, + }, + { + name: "test height regression", + lastSigned: testProposal(height(100)), + vote: testProposal(height(99)), + + err: privval.ErrHeightRegression, + }, + { + name: "test round regression", + lastSigned: testProposal(round(100)), + vote: testProposal(round(99)), + + err: privval.ErrRoundRegression, + }, + } + + // test cases for signing a vote. + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // outer function to catch any returns errors + err := func() error { + privKeyBts, err := hex.DecodeString(defaultPrivateKey) + if err != nil { + return err + } + + store := newMockStore() + if tc.lastSigned != nil { + if err := setKeys(store, tc.lastSigned.Height, tc.lastSigned.Round, 1, tc.lastSigned.Signature, types.ProposalSignBytes(defaultChainID, tc.lastSigned)); err != nil { + return err + } + } + + privVal, err := privval.NewValidatorSigner(privKeyBts, store) + if err != nil { + return err + } + + // sign the vote + err = privVal.SignProposal(defaultChainID, tc.vote) + if err != nil { + return err + } + + assert.NotNil(t, tc.vote.Signature) + + if tc.secondVote != nil { + // sign the second vote + err = privVal.SignProposal(defaultChainID, tc.secondVote) + if err != nil { + return err + } + + assert.Equal(t, tc.vote.Timestamp, tc.secondVote.Timestamp) + } + + return nil + }() + if err != nil { + if tc.err == nil { + t.Fatalf("unexpected error: %v", err) + } + + assert.ErrorIs(t, err, tc.err) + return + } + if tc.err != nil { + t.Fatalf("expected error: %v", tc.err) + } + + if tc.after != nil { + tc.after(t, &tc) + } + }) + } +} + +// setKeys from vote sets the keys in the AtomicKV from the vote. +// this is useful for testing starting up the atomic KV with an existing vote. +func setKeys(store privval.AtomicReadWriter, ht int64, rnd int32, stp int8, signature []byte, signBytes []byte) error { + latest := privval.LastSignState{ + Height: ht, + Round: rnd, + Step: stp, + Signature: signature, + SignBytes: signBytes, + } + + latestBts, err := json.Marshal(latest) + if err != nil { + return err + } + + return store.Write(latestBts) +} + +// mockStore implements AtomicReadWriter +type mockStore struct { + latest []byte +} + +func newMockStore() *mockStore { + return &mockStore{ + latest: nil, + } +} + +// testVote is a valid vote for height 1 +func testVote(opts ...testVotOpt) *cmtproto.Vote { + options := defaultOptions() + for _, opt := range opts { + opt(options) + } + + return &cmtproto.Vote{ + Type: options.step, + Height: options.height, + Round: options.round, + BlockID: cmtproto.BlockID{ + Hash: hash("hash1"), + PartSetHeader: cmtproto.PartSetHeader{ + Total: 1, + Hash: hash("hash12"), + }, + }, + Timestamp: time.Unix(options.timestamp, 0), + ValidatorAddress: []byte("validator1"), + ValidatorIndex: 1, + Signature: options.signature, + } +} + +func testProposal(opts ...testVotOpt) *cmtproto.Proposal { + options := defaultOptions() + for _, opt := range opts { + opt(options) + } + if options.step != 1 { + panic("cannot create proposal with step != 1") + } + + return &cmtproto.Proposal{ + Type: 1, + Height: options.height, + Round: options.round, + PolRound: 0, + BlockID: cmtproto.BlockID{ + Hash: hash("hash1"), + PartSetHeader: cmtproto.PartSetHeader{ + Total: 1, + Hash: hash("hash12"), + }, + }, + Timestamp: time.Unix(options.timestamp, 0), + Signature: options.signature, + } +} + +func defaultOptions() *testVoteOptions { + return &testVoteOptions{ + timestamp: 500, + height: 10, + round: 0, + step: cmtproto.PrevoteType, + } +} + +type testVoteOptions struct { + timestamp int64 + signature []byte + height int64 + round int32 + step cmtproto.SignedMsgType +} + +type testVotOpt func(*testVoteOptions) + +func timestamped(ts int64) testVotOpt { + return func(opts *testVoteOptions) { + opts.timestamp = ts + } +} + +func signed(sig string) testVotOpt { + return func(opts *testVoteOptions) { + opts.signature = []byte(sig) + } +} + +func height(h int64) testVotOpt { + return func(opts *testVoteOptions) { + opts.height = h + } +} + +func round(r int32) testVotOpt { + return func(opts *testVoteOptions) { + opts.round = r + } +} + +func step(s cmtproto.SignedMsgType) testVotOpt { + return func(opts *testVoteOptions) { + opts.step = s + } +} + +func (m *mockStore) Read() ([]byte, error) { + return m.latest, nil +} + +func (m *mockStore) Write(p0 []byte) error { + m.latest = p0 + return nil +} + +func hash(s string) []byte { + hasher := sha256.New() + hasher.Write([]byte(s)) + return hasher.Sum(nil) +} diff --git a/pkg/abci/interfaces.go b/pkg/abci/interfaces.go index 7f9865e2c..3969496e6 100644 --- a/pkg/abci/interfaces.go +++ b/pkg/abci/interfaces.go @@ -54,8 +54,17 @@ type ValidatorModule interface { // AtomicCommitter is an interface for a struct that implements atomic commits across multiple stores type AtomicCommitter interface { + ClearWal(ctx context.Context) error Begin(ctx context.Context) error - Commit(ctx context.Context, applyCallback func(error)) (commitID []byte, err error) + ID(ctx context.Context) ([]byte, error) + Commit(ctx context.Context, applyCallback func(error)) error +} + +// KVStore is an interface for a basic key-value store +type KVStore interface { + Get(key []byte) ([]byte, error) + Set(key []byte, value []byte) error + Delete(key []byte) error } // SnapshotModule is an interface for a struct that implements snapshotting diff --git a/pkg/abci/opts.go b/pkg/abci/opts.go index 074cd6e07..c27cfd6ac 100644 --- a/pkg/abci/opts.go +++ b/pkg/abci/opts.go @@ -9,3 +9,9 @@ func WithLogger(logger log.Logger) AbciOpt { a.log = logger } } + +func WithApplicationVersion(version uint64) AbciOpt { + return func(a *AbciApp) { + a.applicationVersion = version + } +} diff --git a/pkg/abci/utils.go b/pkg/abci/utils.go index 67b227186..c948a5c6f 100644 --- a/pkg/abci/utils.go +++ b/pkg/abci/utils.go @@ -86,6 +86,8 @@ func ResetState(dbDir string) error { return nil } +// TODO: we will have to get rid of this if we use our own private keys from CometBFT +// Resetting the privValStateFile is ok, however we don't persist Comet's private key func ResetFilePV(privValKeyFile, privValStateFile string) { if _, err := os.Stat(privValKeyFile); err == nil { pv := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 287d76081..834170ca2 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -1,12 +1,11 @@ package config_test import ( - "crypto/ecdsa" "os" "testing" - "github.com/ethereum/go-ethereum/crypto" "github.com/kwilteam/kwil-db/pkg/config" + "github.com/kwilteam/kwil-db/pkg/crypto" "github.com/cstockton/go-conv" ) @@ -16,7 +15,6 @@ var ( ) func Test_Config(t *testing.T) { - // TEST 1: load config with no private key, should fail testCfg := &TestConfig{ Inner: InnerTestConfig{ @@ -29,7 +27,7 @@ func Test_Config(t *testing.T) { t.Fatal("Expected error, got nil") } - os.Setenv("KWIL_TEST_PRIVATE_KEY", "f1aa5a7966c3863ccde3047f6a1e266cdc0c76b399e256b8fede92b1c69e4f4e") + os.Setenv("KWIL_TEST_PRIVATE_KEY", "f2d82d73ba03a7e843443f2b3179a01398144baa4a23d40d1e8a3a8e4fb217d0484d59f4de46b2174ebce66ac3afa7989b444244323c19a74b683f54cf33227c") // TEST 2: load config with private key, should succeed err = config.LoadConfig(RegisteredVariables, envPrefix, testCfg) @@ -105,7 +103,7 @@ func Test_Failures(t *testing.T) { } type TestConfig struct { - PrivateKey *ecdsa.PrivateKey + PrivateKey crypto.PrivateKey Inner InnerTestConfig } @@ -134,7 +132,7 @@ var ( return nil, err } - return crypto.HexToECDSA(strVal) // TODO: we should rethink this since we support ed25519 now + return crypto.Ed25519PrivateKeyFromHex(strVal) }, Required: true, } diff --git a/pkg/crypto/ed25519.go b/pkg/crypto/ed25519.go index 138a36065..a80f2e4cc 100644 --- a/pkg/crypto/ed25519.go +++ b/pkg/crypto/ed25519.go @@ -96,3 +96,15 @@ func (s Ed25519Address) String() string { // TODO: need an address format return hex.EncodeToString(s.Bytes()) } + +// GenerateEd25519Key generates a new ed25519 key pair. +func GenerateEd25519Key() (*Ed25519PrivateKey, error) { + _, priv, err := ed25519.GenerateKey(nil) + if err != nil { + return nil, err + } + + return &Ed25519PrivateKey{ + key: priv, + }, nil +} diff --git a/pkg/crypto/ed25519_test.go b/pkg/crypto/ed25519_test.go index 5483839c4..5d5322095 100644 --- a/pkg/crypto/ed25519_test.go +++ b/pkg/crypto/ed25519_test.go @@ -105,3 +105,12 @@ func TestEd25519PublicKey_Address(t *testing.T) { eq := pubKey.Address().String() == "0aa611bf555596912bc6f9a9f169f8785918e7ba" assert.True(t, eq, "mismatch address") } + +func Test_GenerateEd25518PrivateKey(t *testing.T) { + pk, err := crypto.GenerateEd25519Key() + require.NoError(t, err, "error generate key") + + if len(pk.Bytes()) != 64 { + t.Errorf("invalid private key length: %d", len(pk.Bytes())) + } +} diff --git a/pkg/engine/session.go b/pkg/engine/_session.go similarity index 89% rename from pkg/engine/session.go rename to pkg/engine/_session.go index 9431820a0..e8dced8e6 100644 --- a/pkg/engine/session.go +++ b/pkg/engine/_session.go @@ -3,13 +3,15 @@ package engine import ( "bytes" "context" + "crypto/sha256" "errors" "fmt" "io" - "github.com/kwilteam/kwil-db/pkg/crypto" "github.com/kwilteam/kwil-db/pkg/log" + "github.com/kwilteam/kwil-db/pkg/sessions" "github.com/kwilteam/kwil-db/pkg/sql" + "github.com/kwilteam/kwil-db/pkg/utils/order" "go.uber.org/zap" ) @@ -19,6 +21,8 @@ type EngineSession struct { log log.Logger } +var _ sessions.Committable = (*EngineSession)(nil) + // BeginCommit begins a session for each of the datasets that are being tracked by this engineSession. func (e *EngineSession) BeginCommit(ctx context.Context) (err error) { defer func() { @@ -52,7 +56,7 @@ func (e *EngineSession) BeginCommit(ctx context.Context) (err error) { // EndCommit commits the changes for each of the sessions that were created by this engineSession. // It will rollback all of the savepoints and delete all of the sessions. -func (e *EngineSession) EndCommit(ctx context.Context, appender func([]byte) error) (commitId []byte, err error) { +func (e *EngineSession) EndCommit(ctx context.Context, appender func([]byte) error) (err error) { defer func() { err2 := e.deleteAndRollbackAll() if err2 != nil { @@ -60,24 +64,16 @@ func (e *EngineSession) EndCommit(ctx context.Context, appender func([]byte) err } }() - var idContent []byte - for dbid, ds := range e.trackedDatasets { changeset, err := ds.session.GenerateChangeset() if err != nil { - return nil, err + return err } defer changeset.Close() - id, err := changeset.ID() - if err != nil { - return nil, err - } - idContent = append(idContent, id...) - data, err := changeset.Export() if err != nil { - return nil, err + return err } bts, err := serializeEngineChangeset(&engineChangeset{ @@ -85,16 +81,16 @@ func (e *EngineSession) EndCommit(ctx context.Context, appender func([]byte) err changeset: data, }) if err != nil { - return nil, err + return err } err = appender(bts) if err != nil { - return nil, err + return err } } - return crypto.Sha256(idContent), nil + return nil } // BeginApply begins a session for each of the datasets that are being tracked by this engineSession. @@ -157,6 +153,29 @@ func (e *EngineSession) Cancel(ctx context.Context) { } } +func (e *EngineSession) ID(ctx context.Context) ([]byte, error) { + hash := sha256.New() + for _, d := range order.OrderMapLexicographically[string, *trackedDataset](e.trackedDatasets) { + changeset, err := d.Value.session.GenerateChangeset() + if err != nil { + return nil, err + } + defer changeset.Close() + + id, err := changeset.ID() + if err != nil { + return nil, err + } + + _, err = hash.Write(id) + if err != nil { + return nil, err + } + } + + return hash.Sum(nil), nil +} + // untrackAll deletes all of the sessions and rollsback all savepoints that were created by this engineSession. // it then clears the trackedDatasets map. func (e *EngineSession) untrackAll() error { diff --git a/pkg/engine/dataset.go b/pkg/engine/dataset.go index 0d8cd67da..61b6b8f10 100644 --- a/pkg/engine/dataset.go +++ b/pkg/engine/dataset.go @@ -48,10 +48,11 @@ func (e *Engine) CreateDataset(ctx context.Context, schema *types.Schema) (dbid // buildNewDataset builds a new datastore, and puts it in a dataset func (e *Engine) buildNewDataset(ctx context.Context, name string, owner string, schema *types.Schema) (ds *dataset.Dataset, finalErr error) { dbid := GenerateDBID(name, owner) - datastore, err := e.opener.Open(dbid, e.log) + datastore, err := e.open(ctx, dbid) if err != nil { return nil, fmt.Errorf("failed to open database: %w", err) } + defer func() { if err != nil { err2 := datastore.Delete() @@ -105,7 +106,13 @@ func (e *Engine) DropDataset(ctx context.Context, sender, dbid string) error { return fmt.Errorf("%w: %s", ErrDatasetNotOwned, dbid) } - err := ds.Delete() + // we call unregister first so the session can be canceled, before the database is deleted + err := e.commitRegister.Unregister(ctx, dbid) + if err != nil { + return fmt.Errorf("failed to unregister dataset: %w", err) + } + + err = ds.Delete() if err != nil { return fmt.Errorf("failed to close dataset: %w", err) } diff --git a/pkg/engine/db/db.go b/pkg/engine/db/db.go index 55a08ef4a..7dcc6e632 100644 --- a/pkg/engine/db/db.go +++ b/pkg/engine/db/db.go @@ -40,7 +40,7 @@ func (d *DB) Prepare(ctx context.Context, query string) (*PreparedStatement, err return nil, err } - err = sqlanalyzer.ApplyRules(ast, sqlanalyzer.DeterministicAggregates, &sqlanalyzer.RuleMetadata{ + err = sqlanalyzer.ApplyRules(ast, sqlanalyzer.AllRules, &sqlanalyzer.RuleMetadata{ Tables: tables, }) if err != nil { diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index de1b2df1e..31f0f1467 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -40,17 +40,21 @@ type Engine struct { // opener is the function that is used to open sqlite databases opener sql.Opener + + // commitRegister is the commit register that is used to register commits + commitRegister CommitRegister } // Open opens a new engine with the provided options. // It will also open any stored datasets. -func Open(ctx context.Context, dbOpener sql.Opener, opts ...EngineOpt) (*Engine, error) { +func Open(ctx context.Context, dbOpener sql.Opener, commitRegister CommitRegister, opts ...EngineOpt) (*Engine, error) { e := &Engine{ - name: masterDBName, - log: log.NewNoOp(), - datasets: make(map[string]Dataset), - extensions: make(map[string]ExtensionInitializer), - opener: dbOpener, + name: masterDBName, + log: log.NewNoOp(), + datasets: make(map[string]Dataset), + extensions: make(map[string]ExtensionInitializer), + opener: dbOpener, + commitRegister: commitRegister, } for _, opt := range opts { @@ -70,9 +74,9 @@ func Open(ctx context.Context, dbOpener sql.Opener, opts ...EngineOpt) (*Engine, return e, nil } -// openMasterDB opens the master database +// openMasterDB opens the master database and registers it with the commit register func (e *Engine) openMasterDB(ctx context.Context) error { - ds, err := e.opener.Open(e.name, e.log) + ds, err := e.open(ctx, e.name) if err != nil { return err } @@ -81,6 +85,21 @@ func (e *Engine) openMasterDB(ctx context.Context) error { return err } +// open opens a database with the given DBID. It also registers the database with the commit register +func (e *Engine) open(ctx context.Context, dbid string) (sql.Database, error) { + ds, err := e.opener.Open(dbid, e.log) + if err != nil { + return nil, err + } + + err = e.commitRegister.Register(ctx, dbid, ds) + if err != nil { + return nil, err + } + + return ds, nil +} + // openStoredDatasets opens all of the datasets that are stored in the master func (e *Engine) openStoredDatasets(ctx context.Context) error { datasets, err := e.master.ListDatasets(ctx) @@ -89,7 +108,7 @@ func (e *Engine) openStoredDatasets(ctx context.Context) error { } for _, datasetInfo := range datasets { - datastore, err := e.opener.Open(datasetInfo.DBID, e.log) + datastore, err := e.open(ctx, datasetInfo.DBID) if err != nil { return err } diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index ba2fa0090..df6a5cf03 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -10,6 +10,7 @@ import ( "github.com/kwilteam/kwil-db/pkg/engine/types" "github.com/kwilteam/kwil-db/pkg/engine/types/testdata" "github.com/kwilteam/kwil-db/pkg/engine/utils" + "github.com/kwilteam/kwil-db/pkg/sql" "github.com/stretchr/testify/assert" ) @@ -39,7 +40,7 @@ var ( func Test_Open(t *testing.T) { ctx := context.Background() - e, teardown, err := engineTesting.NewTestEngine(ctx, + e, teardown, err := engineTesting.NewTestEngine(ctx, newMockRegister(), engine.WithExtensions(testExtensions), ) if err != nil { @@ -66,7 +67,7 @@ func Test_Open(t *testing.T) { t.Fatal(err) } - e2, teardown2, err := engineTesting.NewTestEngine(ctx, + e2, teardown2, err := engineTesting.NewTestEngine(ctx, newMockRegister(), engine.WithExtensions(testExtensions), ) if err != nil { @@ -155,7 +156,7 @@ func Test_CreateDataset(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() - e, teardown, err := engineTesting.NewTestEngine(ctx, + e, teardown, err := engineTesting.NewTestEngine(ctx, newMockRegister(), engine.WithExtensions(testExtensions), ) if err != nil { @@ -226,3 +227,35 @@ var testExtensions = map[string]engine.ExtensionInitializer{ }, }, } + +func newMockRegister() *mockRegister { + return &mockRegister{ + datasets: make(map[string]sql.Database), + } +} + +type mockRegister struct { + datasets map[string]sql.Database +} + +func (m *mockRegister) Register(ctx context.Context, name string, db sql.Database) error { + _, ok := m.datasets[name] + if ok { + return errors.New("dataset already registered") + } + + m.datasets[name] = db + + return nil +} + +func (m *mockRegister) Unregister(ctx context.Context, name string) error { + _, ok := m.datasets[name] + if !ok { + return errors.New("dataset not registered") + } + + delete(m.datasets, name) + + return nil +} diff --git a/pkg/engine/execute.go b/pkg/engine/execute.go deleted file mode 100644 index 00a22ef62..000000000 --- a/pkg/engine/execute.go +++ /dev/null @@ -1 +0,0 @@ -package engine diff --git a/pkg/engine/interfaces.go b/pkg/engine/interfaces.go index d7fe921e5..45fdad0cd 100644 --- a/pkg/engine/interfaces.go +++ b/pkg/engine/interfaces.go @@ -9,34 +9,6 @@ import ( "github.com/kwilteam/kwil-db/pkg/sql" ) -type Datastore interface { - Close() error - Delete() error - Execute(ctx context.Context, stmt string, args map[string]any) error - Prepare(stmt string) (sql.Statement, error) - Query(ctx context.Context, query string, args map[string]any) ([]map[string]any, error) - Savepoint() (sql.Savepoint, error) - TableExists(ctx context.Context, table string) (bool, error) - CreateSession() (sql.Session, error) - ApplyChangeset(changeset io.Reader) error -} - -type Session interface { - GenerateChangeset() ([]byte, error) - Delete() -} - -type Statement interface { - Close() error - Execute(ctx context.Context, args map[string]any) ([]map[string]any, error) -} - -type Savepoint interface { - Commit() error - Rollback() error - CommitAndCheckpoint() error -} - type Dataset interface { Close() error ListProcedures() []*types.Procedure @@ -59,3 +31,12 @@ type MasterDB interface { RegisterDataset(ctx context.Context, name, owner string) error UnregisterDataset(ctx context.Context, dbid string) error } + +// CommitRegister is an interface for registering atomically committable data stores +// Any database registered to this will be atomically synced in a 2pc transaction +type CommitRegister interface { + // Register registers a database to the commit register + Register(ctx context.Context, name string, db sql.Database) error + // Unregister unregisters a database from the commit register + Unregister(ctx context.Context, name string) error +} diff --git a/pkg/engine/testing/engine.go b/pkg/engine/testing/engine.go index e0d007464..a4d0077be 100644 --- a/pkg/engine/testing/engine.go +++ b/pkg/engine/testing/engine.go @@ -11,10 +11,10 @@ import ( sqlTesting "github.com/kwilteam/kwil-db/pkg/sql/testing" ) -func NewTestEngine(ctx context.Context, opts ...engine.EngineOpt) (*engine.Engine, func() error, error) { +func NewTestEngine(ctx context.Context, ec engine.CommitRegister, opts ...engine.EngineOpt) (*engine.Engine, func() error, error) { opener := newTestDBOpener() - e, err := engine.Open(ctx, opener, + e, err := engine.Open(ctx, opener, ec, opts..., ) if err != nil { diff --git a/pkg/kv/atomic/committer.go b/pkg/kv/atomic/committer.go new file mode 100644 index 000000000..1247500fe --- /dev/null +++ b/pkg/kv/atomic/committer.go @@ -0,0 +1,216 @@ +package atomic + +import ( + "context" + "crypto/sha256" + "fmt" + + "github.com/kwilteam/kwil-db/pkg/utils/numbers/bytes" + "github.com/kwilteam/kwil-db/pkg/utils/serialization" +) + +type kvOperation uint8 + +const ( + kvOperationSet kvOperation = iota + kvOperationDelete +) + +// keyValue is a basic struct containing keys and values +// it can be quickly serialized and deserialized, which is +// used for writing to and receiving data from the AtomicCommitter +type keyValue struct { + Operation kvOperation + // Key cannot be longer than 65535 bytes + Key []byte + Value []byte // value can be any length +} + +// MarshalBinary appends the length of the key, the key, and the value +func (k *keyValue) MarshalBinary() ([]byte, error) { + var buf []byte + + // write operation + buf = append(buf, byte(k.Operation)) + + buf = append(buf, bytes.Uint16ToBytes(uint16(len(k.Key)))...) + buf = append(buf, k.Key...) + + // write value + buf = append(buf, k.Value...) + + return buf, nil +} + +// UnmarshalBinary reads the length of the key, the key, and the value +func (k *keyValue) UnmarshalBinary(data []byte) error { + if len(data) < 3 { + return fmt.Errorf("data too short") + } + // read operation + k.Operation = kvOperation(data[0]) + + // read key length and key + keyLen := bytes.BytesToUint16(data[1:3]) + if len(data) < int(keyLen)+3 { + return fmt.Errorf("data too short") + } + k.Key = data[3 : keyLen+3] + + // read value + k.Value = data[keyLen+3:] + return nil +} + +/* + The below implements the sessions.Committable interface +*/ + +func (k *AtomicKV) BeginCommit(ctx context.Context) error { + k.mu.Lock() + defer k.mu.Unlock() + + if k.inSession { + return ErrSessionActive + } + k.inSession = true + return nil +} + +func (k *AtomicKV) EndCommit(ctx context.Context, appender func([]byte) error) (err error) { + k.mu.Lock() + defer k.mu.Unlock() + + if !k.inSession { + return ErrSessionNotActive + } + k.inSession = false + + // flush uncommitted data + bts, err := k.flushUncommittedData() + if err != nil { + return err + } + + // append the data to the appender + if err := appender(bts); err != nil { + return err + } + + // return the commit id + return nil +} + +func (k *AtomicKV) BeginApply(ctx context.Context) error { + k.mu.Lock() + defer k.mu.Unlock() + + if k.currentTx != nil { + return ErrTxnActive + } + + k.currentTx = k.db.BeginTransaction() + + return nil +} + +func (k *AtomicKV) Apply(ctx context.Context, changes []byte) error { + k.mu.Lock() + defer k.mu.Unlock() + + if k.currentTx == nil { + return ErrTxnNotActive + } + + // deserialize the changes + values, err := serialization.DeserializeSlice[*keyValue](changes, func() *keyValue { + return &keyValue{} + }) + if err != nil { + return err + } + + // apply the changes + for _, v := range values { + var err error + switch v.Operation { + case kvOperationSet: + err = k.currentTx.Set(v.Key, v.Value) + case kvOperationDelete: + err = k.currentTx.Delete(v.Key) + default: + err = fmt.Errorf("unknown operation") + } + if err != nil { + return err + } + } + + return nil +} + +func (k *AtomicKV) EndApply(ctx context.Context) error { + k.mu.Lock() + defer k.mu.Unlock() + + if k.currentTx == nil { + return ErrTxnNotActive + } + + err := k.currentTx.Commit() + if err != nil { + return err + } + + k.currentTx = nil + + return nil +} + +func (k *AtomicKV) Cancel(ctx context.Context) { + k.mu.Lock() + defer k.mu.Unlock() + + if k.currentTx != nil { + k.currentTx.Discard() + } + + k.currentTx = nil + k.inSession = false + k.uncommittedData = make([]*keyValue, 0) +} + +func (k *AtomicKV) ID(ctx context.Context) ([]byte, error) { + k.mu.Lock() + defer k.mu.Unlock() + + if !k.inSession { + return nil, ErrSessionNotActive + } + + hash := sha256.New() + for _, v := range k.uncommittedData { + bts, err := v.MarshalBinary() + if err != nil { + return nil, err + } + + _, err = hash.Write(bts) + if err != nil { + return nil, err + } + } + + return hash.Sum(nil), nil +} + +// flushUncommittedData returns the uncommitted data and clears the uncommitted data +func (k *AtomicKV) flushUncommittedData() ([]byte, error) { + bts, err := serialization.SerializeSlice(k.uncommittedData) + if err != nil { + return nil, err + } + + k.uncommittedData = make([]*keyValue, 0) + return bts, nil +} diff --git a/pkg/kv/atomic/errors.go b/pkg/kv/atomic/errors.go new file mode 100644 index 000000000..1e9c3ad3f --- /dev/null +++ b/pkg/kv/atomic/errors.go @@ -0,0 +1,10 @@ +package atomic + +import "errors" + +var ( + ErrSessionActive = errors.New("session already active") + ErrSessionNotActive = errors.New("session not active") + ErrTxnActive = errors.New("transaction already active") + ErrTxnNotActive = errors.New("transaction not active") +) diff --git a/pkg/kv/atomic/kv.go b/pkg/kv/atomic/kv.go new file mode 100644 index 000000000..15f20a511 --- /dev/null +++ b/pkg/kv/atomic/kv.go @@ -0,0 +1,104 @@ +package atomic + +import ( + "sync" + + "github.com/kwilteam/kwil-db/pkg/kv" + "github.com/kwilteam/kwil-db/pkg/sessions" +) + +// NewAtomicKV creates a new atomic key value store. +// It is compatible with Kwil's 2pc protocol. +func NewAtomicKV(store kv.KVStore) (*AtomicKV, error) { + // return an interface for newPrefix + return &AtomicKV{ + baseKV: &baseKV{ + db: store, + inSession: false, + uncommittedData: []*keyValue{}, + }, + prefix: []byte{}, + }, nil +} + +// AtomicKV is a threadsafe, linearizable key/value store. +type AtomicKV struct { + *baseKV + // prefix is the prefix for this store. + prefix []byte +} + +type baseKV struct { + mu sync.RWMutex + + // db is the underlying badger database. + // you should not write to this directly. + db kv.KVStore + + // inSession is true if we are currently in a session. + // if in a session, data is not written to the database, + // but instead stored to be written when the session is committed. + inSession bool + + //uncommittedData is a map of keys to values that have not yet been committed. + uncommittedData []*keyValue + + // currentTxn is the current transaction. + currentTx kv.Transaction +} + +var _ sessions.Committable = &AtomicKV{} +var _ kv.KVWriter = &AtomicKV{} + +// Write writes a key/value pair to the database. +func (k *AtomicKV) Set(key []byte, value []byte) error { + k.mu.Lock() + defer k.mu.Unlock() + + if k.inSession { + k.uncommittedData = append(k.uncommittedData, &keyValue{ + Operation: kvOperationSet, + Key: append(k.prefix, key...), + Value: value, + }) + return nil + } + + return k.db.Set(append(k.prefix, key...), value) +} + +// Read reads a key from the database. +func (k *AtomicKV) Get(key []byte) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + return k.db.Get(append(k.prefix, key...)) +} + +// Delete deletes a key from the database. +func (k *AtomicKV) Delete(key []byte) error { + k.mu.Lock() + defer k.mu.Unlock() + + if k.inSession { + k.uncommittedData = append(k.uncommittedData, &keyValue{ + Operation: kvOperationDelete, + Key: append(k.prefix, key...), + }) + return nil + } + + return k.db.Delete(append(k.prefix, key...)) +} + +// NewPrefix creates a new writer with a prefix for the current store. +func (k *AtomicKV) NewPrefix(prefix []byte) *AtomicKV { + return &AtomicKV{ + baseKV: &baseKV{ + db: k.db, + inSession: k.inSession, + uncommittedData: k.uncommittedData, + }, + prefix: append(k.prefix, prefix...), + } +} diff --git a/pkg/kv/atomic/kv_test.go b/pkg/kv/atomic/kv_test.go new file mode 100644 index 000000000..3aee47403 --- /dev/null +++ b/pkg/kv/atomic/kv_test.go @@ -0,0 +1,197 @@ +package atomic_test + +import ( + "context" + "testing" + + "github.com/kwilteam/kwil-db/pkg/kv" + "github.com/kwilteam/kwil-db/pkg/kv/atomic" + kvTesting "github.com/kwilteam/kwil-db/pkg/kv/atomic/testing" + "github.com/stretchr/testify/assert" +) + +// tests basic KV functionality; anything that is not the sessions.Committable interface +func Test_BasicKV(t *testing.T) { + dbType := kvTesting.TestKVFlagInMemory + type testCase struct { + name string + testFunc func(t *testing.T, db *atomic.AtomicKV) + } + + testCases := []testCase{ + { + name: "successful set, get, delete", + testFunc: func(t *testing.T, db *atomic.AtomicKV) { + err := db.Set(ser("key"), ser("value")) + assert.NoError(t, err) + + value, err := db.Get(ser("key")) + assert.NoError(t, err) + + assert.Equal(t, ser("value"), value) + + err = db.Delete(ser("key")) + assert.NoError(t, err) + + _, err = db.Get(ser("key")) + assert.ErrorIs(t, err, kv.ErrKeyNotFound) + }, + }, + { + name: "nested prefixes can manually append to the key", + testFunc: func(t *testing.T, db *atomic.AtomicKV) { + prefDb := db.NewPrefix(ser("prefix")) + doublePrefDb := prefDb.NewPrefix(ser("prefix2")) + + err := doublePrefDb.Set(ser("key"), ser("value")) + assert.NoError(t, err) + + value, err := doublePrefDb.Get(ser("key")) + assert.NoError(t, err) + value2, err := prefDb.Get(ser("prefix2", "key")) + assert.NoError(t, err) + value3, err := db.Get(ser("prefix", "prefix2", "key")) + assert.NoError(t, err) + + assert.Equal(t, value, value2) + assert.Equal(t, value2, value3) + + err = doublePrefDb.Delete(ser("key")) + assert.NoError(t, err) + + _, err = doublePrefDb.Get(ser("key")) + assert.ErrorIs(t, err, kv.ErrKeyNotFound) + _, err = prefDb.Get(ser("prefix2", "key")) + assert.ErrorIs(t, err, kv.ErrKeyNotFound) + _, err = db.Get(ser("prefix", "prefix2", "key")) + assert.ErrorIs(t, err, kv.ErrKeyNotFound) + }, + }, + { + name: "successful atomic commit", + testFunc: func(t *testing.T, db *atomic.AtomicKV) { + ctx := context.Background() + + // begin with some data + err := db.Set([]byte("original"), []byte("value")) + assert.NoError(t, err) + + err = db.BeginCommit(ctx) + assert.NoError(t, err) + + err = db.Set([]byte("key"), []byte("value")) + assert.NoError(t, err) + + err = db.Delete([]byte("original")) + assert.NoError(t, err) + + appender := newCommitAppender() + + testIds(t, db) + + err = db.EndCommit(ctx, appender.Append) + assert.NoError(t, err) + + err = db.BeginApply(ctx) + assert.NoError(t, err) + + // there should only be one, but this may change + for _, commit := range appender.commits { + err = db.Apply(ctx, commit) + assert.NoError(t, err) + } + + err = db.EndApply(ctx) + assert.NoError(t, err) + + value, err := db.Get([]byte("key")) + assert.NoError(t, err) + + assert.Equal(t, []byte("value"), value) + + _, err = db.Get([]byte("original")) + assert.ErrorIs(t, err, kv.ErrKeyNotFound) + }, + }, + { + name: "canceled atomic commit", + testFunc: func(t *testing.T, db *atomic.AtomicKV) { + ctx := context.Background() + err := db.BeginCommit(ctx) + assert.NoError(t, err) + + err = db.Set([]byte("key"), []byte("value")) + assert.NoError(t, err) + + appender := newCommitAppender() + + err = db.EndCommit(ctx, appender.Append) + assert.NoError(t, err) + + err = db.BeginApply(ctx) + assert.NoError(t, err) + + // there should only be one, but this may change + for _, commit := range appender.commits { + err = db.Apply(ctx, commit) + assert.NoError(t, err) + } + + db.Cancel(ctx) + + _, err = db.Get([]byte("key")) + assert.ErrorIs(t, err, kv.ErrKeyNotFound) + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + db, td, err := kvTesting.OpenTestKv(context.Background(), "kv_test", dbType) + if err != nil { + t.Fatal(err) + } + defer td() + + tc.testFunc(t, db) + }) + } +} + +func testIds(t *testing.T, db *atomic.AtomicKV) { + ctx := context.Background() + lastId, err := db.ID(ctx) + assert.NoError(t, err) + + for i := 0; i < 100; i++ { + id, err := db.ID(ctx) + assert.NoError(t, err) + + assert.Equal(t, lastId, id) + lastId = id + } +} + +func newCommitAppender() *commitAppender { + return &commitAppender{ + commits: make([][]byte, 0), + } +} + +type commitAppender struct { + commits [][]byte +} + +func (c *commitAppender) Append(v []byte) error { + c.commits = append(c.commits, v) + return nil +} + +// ser is a helper function to convert a list of strings to a byte slice +func ser(str ...string) []byte { + var result []byte + for _, s := range str { + result = append(result, []byte(s)...) + } + return result +} diff --git a/pkg/kv/atomic/testing/testing.go b/pkg/kv/atomic/testing/testing.go new file mode 100644 index 000000000..5a33ae0ab --- /dev/null +++ b/pkg/kv/atomic/testing/testing.go @@ -0,0 +1,43 @@ +package testing + +import ( + "context" + "fmt" + + "github.com/kwilteam/kwil-db/pkg/kv/atomic" + badgerTesting "github.com/kwilteam/kwil-db/pkg/kv/badger/testing" + kvTesting "github.com/kwilteam/kwil-db/pkg/kv/testing" +) + +type TestKVFlag uint8 + +const ( + TestKVFlagInMemory TestKVFlag = iota + TestKVFlagBadger +) + +// OpenTestKv opens a new test kv store +// It returns a teardown function. If a teardown +// function is not necessary, it does nothing +func OpenTestKv(ctx context.Context, name string, flag TestKVFlag) (*atomic.AtomicKV, func() error, error) { + + switch flag { + case TestKVFlagInMemory: + fn := func() error { + return nil + } + + db, err := atomic.NewAtomicKV(kvTesting.NewMemoryKV()) + return db, fn, err + case TestKVFlagBadger: + badgerDB, td, err := badgerTesting.NewTestBadgerDB(ctx, name, nil) + if err != nil { + return nil, nil, err + } + + db, err := atomic.NewAtomicKV(badgerDB) + return db, td, err + default: + return nil, nil, fmt.Errorf("unknown flag: %d", flag) + } +} diff --git a/pkg/kv/badger/db.go b/pkg/kv/badger/db.go new file mode 100644 index 000000000..fbe089cbc --- /dev/null +++ b/pkg/kv/badger/db.go @@ -0,0 +1,237 @@ +package badger + +import ( + "context" + "fmt" + "sync" + "time" + + badger "github.com/dgraph-io/badger/v3" + "github.com/kwilteam/kwil-db/pkg/kv" + "github.com/kwilteam/kwil-db/pkg/log" + "go.uber.org/zap" +) + +// NewBadgerDB creates a new BadgerDB. +// It takes a path, like path/to/db, where the database will be stored. +func NewBadgerDB(ctx context.Context, path string, options *Options) (*BadgerDB, error) { + b := &BadgerDB{ + logger: log.NewNoOp(), + gcInterval: 5 * time.Minute, + gcDiscardRatio: 0.5, + } + + badgerOpts := badger.DefaultOptions(path) + + if options != nil { + options.applyToBadgerOpts(&badgerOpts) + options.applyToDB(b) + } + + badgerOpts.Logger = &badgerLogger{log: b.logger} + + var err error + b.db, err = badger.Open(badgerOpts) + if err != nil { + return nil, err + } + + go b.runGC(ctx) + + return b, nil +} + +// BadgerDB is a basic threadsafe key-value store. +type BadgerDB struct { + // db is the underlying badger database. + db *badger.DB + + // mu is a mutex to protect the database. + mu sync.Mutex + + // gcInterval is the interval at which the database is garbage collected. + gcInterval time.Duration + + // gcDiscardRatio is the ratio of discarded keys to total keys. + gcDiscardRatio float64 + + // logger is the logger for the database. + logger log.Logger +} + +var _ kv.KVStore = (*BadgerDB)(nil) + +// Close closes the underlying database. +func (d *BadgerDB) Close() error { + d.mu.Lock() + defer d.mu.Unlock() + + d.logger.Info("closing KV store") + + return d.db.Close() +} + +// Get retrieves a value from the database. +func (d *BadgerDB) Get(key []byte) ([]byte, error) { + d.mu.Lock() + defer d.mu.Unlock() + + var val []byte + err := d.db.View(func(txn *badger.Txn) error { + item, err := txn.Get(key) + if err == badger.ErrKeyNotFound { + return kv.ErrKeyNotFound + } + if err != nil { + return err + } + val, err = item.ValueCopy(nil) + return err + }) + return val, err +} + +func (d *BadgerDB) runGC(ctx context.Context) { + ticker := time.NewTicker(d.gcInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + err := d.db.RunValueLogGC(0.5) + if err == badger.ErrNoRewrite { + d.logger.Debug("no GC required") + continue + } + if err != nil { + d.logger.Error("error running GC", zap.Error(err)) + } + case <-ctx.Done(): + return + } + } +} + +// Set sets a value in the database. +func (d *BadgerDB) Set(key, val []byte) error { + d.mu.Lock() + defer d.mu.Unlock() + + return d.db.Update(func(txn *badger.Txn) error { + return txn.Set(key, val) + }) +} + +// Delete deletes a value from the database. +func (d *BadgerDB) Delete(key []byte) error { + d.mu.Lock() + defer d.mu.Unlock() + + return d.db.Update(func(txn *badger.Txn) error { + return txn.Delete(key) + }) +} + +// BeginTransaction creates a new transaction. +func (d *BadgerDB) BeginTransaction() kv.Transaction { + d.mu.Lock() + defer d.mu.Unlock() + + return &Transaction{txn: d.db.NewTransaction(true)} +} + +// a Transaction is a basic wrapper around a badger to handle commits and rollbacks +type Transaction struct { + txn *badger.Txn +} + +func (t *Transaction) Commit() error { + return t.txn.Commit() +} + +func (t *Transaction) Discard() { + t.txn.Discard() +} + +func (t *Transaction) Set(key, val []byte) error { + return t.txn.Set(key, val) +} + +func (t *Transaction) Delete(key []byte) error { + return t.txn.Delete(key) +} + +func (t *Transaction) Get(key []byte) ([]byte, error) { + var val []byte + item, err := t.txn.Get(key) + if err != nil { + return nil, err + } + val, err = item.ValueCopy(nil) + return val, err +} + +// Options are options for the BadgerDB. +// These get translated into Badger's options. +// We provide this abstraction layer since Badger has a lot of options, +// and I don't want future users of this to worry about all of them. +type Options struct { + // GuaranteeFSync guarantees that all writes to the wal are fsynced before + // attempting to be written to the LSM tree. + GuaranteeFSync bool + + // GarbageCollectionInterval is the interval at which the garbage collector + // runs. + GarbageCollectionInterval time.Duration + + // Logger is the logger to use for the database. + Logger log.Logger + + // GarbageCollectionDiscardRatio is the ratio at which the garbage collector discards + // old versions of a value. It must be between 0 and 1. + // Lower values will have a higher performance hit, but will use less disk space. + GarbageCollectionDiscardRatio float64 +} + +// applyToBadgerOpts applies the options to the badger options. +func (o *Options) applyToBadgerOpts(opts *badger.Options) { + opts.SyncWrites = o.GuaranteeFSync + opts.CompactL0OnClose = true + opts.NumCompactors = 2 +} + +func (o *Options) applyToDB(db *BadgerDB) { + if o.Logger.L != nil { + db.logger = o.Logger + } + + if o.GarbageCollectionInterval != 0 { + db.gcInterval = o.GarbageCollectionInterval + } + + if o.GarbageCollectionDiscardRatio != 0 { + db.gcDiscardRatio = o.GarbageCollectionDiscardRatio + } + +} + +// badgerLogger implements the badger.Logger interface. +type badgerLogger struct { + log log.Logger +} + +func (b *badgerLogger) Debugf(p0 string, p1 ...any) { + b.log.Debug(fmt.Sprintf(p0, p1...)) +} + +func (b *badgerLogger) Errorf(p0 string, p1 ...any) { + b.log.Error(fmt.Sprintf(p0, p1...)) +} + +func (b *badgerLogger) Infof(p0 string, p1 ...any) { + b.log.Info(fmt.Sprintf(p0, p1...)) +} + +func (b *badgerLogger) Warningf(p0 string, p1 ...any) { + b.log.Warn(fmt.Sprintf(p0, p1...)) +} diff --git a/pkg/kv/badger/db_test.go b/pkg/kv/badger/db_test.go new file mode 100644 index 000000000..56192f5db --- /dev/null +++ b/pkg/kv/badger/db_test.go @@ -0,0 +1,27 @@ +package badger_test + +import ( + "context" + "testing" + + badgerTesting "github.com/kwilteam/kwil-db/pkg/kv/badger/testing" +) + +// testing double write does not produce an error +func Test_BadgerKV(t *testing.T) { + db, td, err := badgerTesting.NewTestBadgerDB(context.Background(), "test", nil) + if err != nil { + t.Fatal(err) + } + defer td() + + err = db.Set([]byte("key"), []byte("value")) + if err != nil { + t.Fatal(err) + } + + err = db.Set([]byte("key"), []byte("value2")) + if err != nil { + t.Fatal(err) + } +} diff --git a/pkg/kv/badger/testing/db.go b/pkg/kv/badger/testing/db.go new file mode 100644 index 000000000..93ef40cea --- /dev/null +++ b/pkg/kv/badger/testing/db.go @@ -0,0 +1,32 @@ +package testing + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/kwilteam/kwil-db/pkg/kv/badger" +) + +const defaultPath = "./tmp/" + +// NewTestBadgerDB returns a new badger db for testing +// it also returns a teardown function, which will remove +// the db and the directory +func NewTestBadgerDB(ctx context.Context, name string, options *badger.Options) (*badger.BadgerDB, func() error, error) { + directory := fmt.Sprintf("%s%s", defaultPath, name) + + db, err := badger.NewBadgerDB(ctx, directory, nil) + if err != nil { + return nil, nil, err + } + + fn := func() error { + return errors.Join( + db.Close(), + os.RemoveAll(defaultPath), + ) + } + return db, fn, err +} diff --git a/pkg/kv/common.go b/pkg/kv/common.go new file mode 100644 index 000000000..a818b2c1b --- /dev/null +++ b/pkg/kv/common.go @@ -0,0 +1,28 @@ +package kv + +import "errors" + +var ( + ErrKeyNotFound = errors.New("key not found") +) + +// KVStore is a key-value store that supports transactions. +type KVStore interface { + KVWriter + BeginTransaction() Transaction +} + +// KVWriter is a subset of the KVStore interface that only allows for +// CRUD operations. +type KVWriter interface { + Get(key []byte) ([]byte, error) + Set(key []byte, value []byte) error + Delete(key []byte) error +} + +// Transaction is a read-write transaction on a KVStore. +type Transaction interface { + KVWriter + Commit() error + Discard() +} diff --git a/pkg/kv/testing/memory.go b/pkg/kv/testing/memory.go new file mode 100644 index 000000000..63dbc0e61 --- /dev/null +++ b/pkg/kv/testing/memory.go @@ -0,0 +1,106 @@ +package testing + +import "github.com/kwilteam/kwil-db/pkg/kv" + +func NewMemoryKV() *MemoryKV { + return &MemoryKV{ + values: make(map[string][]byte), + } +} + +type MemoryKV struct { + values map[string][]byte +} + +var _ kv.KVStore = (*MemoryKV)(nil) + +func (m *MemoryKV) BeginTransaction() kv.Transaction { + + return &MemoryTransaction{ + kv: m, + currentTx: make(map[string][]byte), + currentDeletes: make(map[string]struct{}), + } +} + +func (m *MemoryKV) Delete(key []byte) error { + _, ok := m.values[string(key)] + if !ok { + return kv.ErrKeyNotFound + } + + delete(m.values, string(key)) + + return nil +} + +func (m *MemoryKV) Get(key []byte) ([]byte, error) { + val, ok := m.values[string(key)] + if !ok { + return nil, kv.ErrKeyNotFound + } + + return val, nil +} + +func (m *MemoryKV) Set(key []byte, value []byte) error { + m.values[string(key)] = value + + return nil +} + +type MemoryTransaction struct { + currentTx map[string][]byte + currentDeletes map[string]struct{} + kv *MemoryKV +} + +func (m *MemoryTransaction) Commit() error { + for k, v := range m.currentTx { + m.kv.values[k] = v + } + + for k := range m.currentDeletes { + delete(m.kv.values, k) + } + + m.currentTx = nil + + return nil +} + +func (m *MemoryTransaction) Delete(key []byte) error { + _, err := m.Get(key) + if err != nil { + return err + } + + m.currentDeletes[string(key)] = struct{}{} + + return nil +} + +func (m *MemoryTransaction) Discard() { + m.currentTx = nil + m.currentDeletes = nil +} + +func (m *MemoryTransaction) Get(key []byte) ([]byte, error) { + val, ok := m.currentTx[string(key)] + if ok { + return val, nil + } + + val, ok = m.kv.values[string(key)] + if ok { + return val, nil + } + + return nil, kv.ErrKeyNotFound +} + +func (m *MemoryTransaction) Set(key []byte, value []byte) error { + m.currentTx[string(key)] = value + + return nil +} diff --git a/pkg/modules/snapshots/interfaces.go b/pkg/modules/snapshots/interfaces.go deleted file mode 100644 index e6389bb4f..000000000 --- a/pkg/modules/snapshots/interfaces.go +++ /dev/null @@ -1,12 +0,0 @@ -package snapshots - -import "github.com/kwilteam/kwil-db/pkg/snapshots" - -type Snapshotter interface { - StartSnapshotSession(height uint64) error - EndSnapshotSession() error - CreateSnapshot() error - LoadSnapshotChunk(height uint64, format uint32, chunkID uint32) ([]byte, error) - DeleteOldestSnapshot() error - ListSnapshots() ([]snapshots.Snapshot, error) -} diff --git a/pkg/serialize/encode.go b/pkg/serialize/encode.go index f523428ff..a6149df9b 100644 --- a/pkg/serialize/encode.go +++ b/pkg/serialize/encode.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/rlp" + "github.com/kwilteam/kwil-db/pkg/utils/serialization" ) type SerializedData = []byte @@ -18,6 +19,7 @@ const ( var currentEncodingType = encodingTypeRLP +// Encode encodes the given value into a serialized data format. func Encode(val any) (SerializedData, error) { var btsVal []byte var err error @@ -34,6 +36,7 @@ func Encode(val any) (SerializedData, error) { return addSerializedTypePrefix(currentEncodingType, btsVal) } +// Decode decodes the given serialized data into the given value. func Decode[T any](bts SerializedData) (*T, error) { encType, val, err := removeSerializedTypePrefix(bts) if err != nil { @@ -48,6 +51,91 @@ func Decode[T any](bts SerializedData) (*T, error) { } } +func EncodeSlice[T any](kvs []T) ([]byte, error) { + marshaller := make([]*serialBinaryMarshaller[T], len(kvs)) + for i, kv := range kvs { + marshaller[i] = &serialBinaryMarshaller[T]{kv} + } + return serialization.SerializeSlice[*serialBinaryMarshaller[T]](marshaller) +} + +func DecodeSlice[T any](bts []byte) ([]*T, error) { + marshaller, err := serialization.DeserializeSlice[*serialBinaryMarshaller[T]](bts, func() *serialBinaryMarshaller[T] { + return &serialBinaryMarshaller[T]{} + }) + if err != nil { + return nil, err + } + + result := make([]*T, len(marshaller)) + for i, m := range marshaller { + result[i] = &m.val + } + + return result, nil +} + +// serialBinaryMarshaller is a helper struct that implements the BinaryMarshaler and BinaryUnmarshaler interfaces +type serialBinaryMarshaller[T any] struct { + val T +} + +func (m *serialBinaryMarshaller[T]) MarshalBinary() ([]byte, error) { + return Encode(m.val) +} + +func (m *serialBinaryMarshaller[T]) UnmarshalBinary(bts []byte) error { + val, err := Decode[T](bts) + if err != nil { + return err + } + + m.val = *val + return nil +} + +/* + +// EncodeSlice serializes a slice into a byte slice +func EncodeSlice[T any](kvs []T) ([]byte, error) { + var result []byte + for _, kv := range kvs { + data, err := Encode(kv) + if err != nil { + return nil, err + } + length := uint64(len(data)) + result = append(result, append(make([]byte, 8), data...)...) + binary.BigEndian.PutUint64(result[len(result)-len(data)-8:len(result)-len(data)], length) + } + return result, nil +} + +// DecodeSlice deserializes a byte slice into a slice +// It is important this is only given the results of EncodeSlice +func DecodeSlice[T any](bts []byte) ([]*T, error) { + var result []*T + for len(bts) > 0 { + if len(bts) < 8 { + return nil, fmt.Errorf("insufficient bytes") + } + length := binary.BigEndian.Uint64(bts[:8]) + if uint64(len(bts[8:])) < length { + return nil, fmt.Errorf("invalid length") + } + bts = bts[8:] + value, err := Decode[T](bts[:length]) + if err != nil { + return nil, err + } + + result = append(result, value) + bts = bts[length:] + } + return result, nil +} +*/ + func encodeRLP(val any) ([]byte, error) { return rlp.EncodeToBytes(val) } diff --git a/pkg/serialize/encode_test.go b/pkg/serialize/encode_test.go index cccbb9777..3ab542db7 100644 --- a/pkg/serialize/encode_test.go +++ b/pkg/serialize/encode_test.go @@ -7,6 +7,27 @@ import ( "github.com/stretchr/testify/assert" ) +type TestStruct1 struct { + Val1 uint64 + Val2 string + Val3 []byte + Val4 bool +} + +type InvalidStructSignedInt struct { + Val1 int64 // RLPEncode only supports unsigned integers +} + +type InvalidStructMap struct { + Val1 map[string]string // RLPEncode does not support maps +} + +// will not error, but will not encode +type StructUnexportedField struct { + val1 uint64 // RLPEncode only supports exported fields + Val2 string +} + func Test_Encoding(t *testing.T) { type testCase struct { name string @@ -72,16 +93,12 @@ func Test_Encoding(t *testing.T) { return } - decoded, err := serialize.Decode[any](output) + _, err = serialize.Decode[any](output) if err != nil { t.Errorf("Expected no error, got %v", err) } if err != nil { - return - } - - if *decoded == tc.output { - assert.Equal(t, tc.output, *decoded) + t.Errorf("Expected no error, got %v", err) } var v any @@ -96,23 +113,116 @@ func Test_Encoding(t *testing.T) { } } -type TestStruct1 struct { - Val1 uint64 - Val2 string - Val3 []byte - Val4 bool +func Test_EncodeSlice(t *testing.T) { + + // this is an atypical way of testing, made to work with generics + type testCase struct { + name string + testFunc testable + } + + testCases := []testCase{ + { + testFunc: genericSliceTestCase[TestStruct1]{ + input: []*TestStruct1{ + { + Val1: 1, + Val3: []byte("test"), + Val2: "test", + Val4: true, + }, + { + Val1: 2, + Val3: []byte("test2"), + Val2: "test2", + Val4: false, + }, + }, + output: []*TestStruct1{ + { + Val1: 1, + Val2: "test", + Val3: []byte("test"), + Val4: true, + }, + { + Val1: 2, + Val2: "test2", + Val3: []byte("test2"), + Val4: false, + }, + }, + isEqual: true, + }, + }, + { + name: "valid struct, invalid values", + testFunc: genericSliceTestCase[TestStruct1]{ + input: []*TestStruct1{ + { + Val1: 1, + Val3: []byte("test"), + Val2: "test", + Val4: true, + }, + { + Val1: 2, + Val3: []byte("test2"), + Val2: "test2", + Val4: false, + }, + }, + output: []*TestStruct1{ + { + Val1: 1, + Val2: "test", + Val3: []byte("test"), + Val4: true, + }, + { + Val1: 2000000, + Val2: "test2", + Val3: []byte("test2"), + Val4: false, + }, + }, + isEqual: false, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, tc.testFunc.runTest) + } } -type InvalidStructSignedInt struct { - Val1 int64 // RLPEncode only supports unsigned integers +type testable interface { + runTest(t *testing.T) } -type InvalidStructMap struct { - Val1 map[string]string // RLPEncode does not support maps +type genericSliceTestCase[T any] struct { + input []*T + output []*T + isEqual bool } -// will not error, but will not encode -type StructUnexportedField struct { - val1 uint64 // RLPEncode only supports exported fields - Val2 string +func (g genericSliceTestCase[T]) runTest(t *testing.T) { + out, err := serialize.EncodeSlice(g.input) + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + + result, err := serialize.DecodeSlice[T](out) + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + + if g.isEqual { + assert.EqualValuesf(t, g.output, result, "Expected result to be %v, got %v", g.output, result) + return + } else { + assert.NotEqualValuesf(t, g.output, result, "Expected result to be %v, got %v", g.output, result) + return + } + } diff --git a/pkg/sessions/errors.go b/pkg/sessions/errors.go index a74149bf8..8d780f1af 100644 --- a/pkg/sessions/errors.go +++ b/pkg/sessions/errors.go @@ -13,6 +13,10 @@ var ( ErrBeginApply = errors.New("error beginning apply") ErrApply = errors.New("error applying changes") ErrEndApply = errors.New("error ending apply") + ErrID = errors.New("error generating session ID") + ErrAlreadyRegistered = errors.New("committable already registered") + ErrUnknownCommittable = errors.New("unknown committable") + ErrClosed = errors.New("session closed") ) // wrapError wraps an error with a message. diff --git a/pkg/sessions/interfaces.go b/pkg/sessions/interfaces.go index 981c7787f..a1da332e0 100644 --- a/pkg/sessions/interfaces.go +++ b/pkg/sessions/interfaces.go @@ -20,7 +20,7 @@ type Committable interface { // The commit id is used to track the state of the committable. // EndCommit can only be called once per session, per committable. // When EndCommit is called, the committer should write ALL changes to AppendFunc. - EndCommit(ctx context.Context, appender func([]byte) error) (commitId []byte, err error) + EndCommit(ctx context.Context, appender func([]byte) error) (err error) // BeginApply is used to signal to the committable that changes are about to be applied // to its datastore(s). @@ -38,6 +38,10 @@ type Committable interface { // Cancel is used to cancel a session. Cancel(ctx context.Context) + + // ID returns a unique ID representative of the state changes that have occurred so far for this committable. + // It should be deterministic, and should change if and only if the committable has changed. + ID(ctx context.Context) ([]byte, error) } // Wal is an interface for a write-ahead log. @@ -45,10 +49,11 @@ type Wal interface { // Append appends a new entry to the WAL Append(ctx context.Context, data []byte) error // ReadNext reads the next entry from the WAL - // the io.Reader will return an io.EOF when it has reached the end of the record - // the ReadNext method will return an io.EOF when it has reached the end of the WAL + // the ReadNext method will return an io.EOF when it has reached the end of the WAL, + // or if the WAL is empty, or corrupt. ReadNext(ctx context.Context) ([]byte, error) // Truncate truncates the WAL, deleting all entries (if any exist) + // If none exist, it should return nil Truncate(ctx context.Context) error } diff --git a/pkg/sessions/mock_test.go b/pkg/sessions/mock_test.go index 56a787760..974214cd0 100644 --- a/pkg/sessions/mock_test.go +++ b/pkg/sessions/mock_test.go @@ -121,12 +121,12 @@ func (m *mockCommittable) BeginCommit(ctx context.Context) error { return nil } -func (m *mockCommittable) EndCommit(ctx context.Context, appender func([]byte) error) (commitId []byte, err error) { +func (m *mockCommittable) EndCommit(ctx context.Context, appender func([]byte) error) (err error) { if !m.isInCommit { - return nil, fmt.Errorf("not in commit") + return fmt.Errorf("not in commit") } if m.isInApply { - return nil, fmt.Errorf("cannot end commit while in apply") + return fmt.Errorf("cannot end commit while in apply") } m.isInCommit = false @@ -137,16 +137,16 @@ func (m *mockCommittable) EndCommit(ctx context.Context, appender func([]byte) e Value: value, }) if err != nil { - return nil, err + return err } err = appender(bts) if err != nil { - return nil, err + return err } } - return m.commitId, nil + return nil } func (m *mockCommittable) BeginApply(ctx context.Context) error { @@ -200,6 +200,10 @@ func (m *mockCommittable) Cancel(ctx context.Context) { m.canceled = true } +func (m *mockCommittable) ID(ctx context.Context) ([]byte, error) { + return m.commitId, nil +} + type mockCommittableWithErrors struct { *mockCommittable @@ -223,17 +227,17 @@ func (m *mockCommittableWithErrors) BeginCommit(ctx context.Context) error { return nil } -func (m *mockCommittableWithErrors) EndCommit(ctx context.Context, appender func([]byte) error) (commitId []byte, err error) { - commitId, err = m.mockCommittable.EndCommit(ctx, appender) +func (m *mockCommittableWithErrors) EndCommit(ctx context.Context, appender func([]byte) error) (err error) { + err = m.mockCommittable.EndCommit(ctx, appender) if err != nil { - return nil, err + return err } if m.errInEndCommit { - return nil, fmt.Errorf("error in EndCommit") + return fmt.Errorf("error in EndCommit") } - return commitId, nil + return nil } func (m *mockCommittableWithErrors) BeginApply(ctx context.Context) error { diff --git a/pkg/sessions/session.go b/pkg/sessions/session.go index 81ffe0643..49290bd01 100644 --- a/pkg/sessions/session.go +++ b/pkg/sessions/session.go @@ -17,10 +17,11 @@ import ( "errors" "fmt" "io" - "sort" "sync" + "time" "github.com/kwilteam/kwil-db/pkg/log" + "github.com/kwilteam/kwil-db/pkg/utils/order" "go.uber.org/zap" ) @@ -42,6 +43,15 @@ type AtomicCommitter struct { // State to indicate whether the session is in progress or not inProgress bool + + // closed is set to true when the committer is closed. + // this is to protect against AtomicCommitter consumers + // from calling methods on a closed committer, which could + // lead to an inconsistent state. + closed bool + + // timeout is the amount of time to wait on shutdown + timeout time.Duration } // CommittableId is the unique identifier for a committable. @@ -56,78 +66,134 @@ func (id CommittableId) Bytes() []byte { } // NewAtomicCommitter creates a new atomic session. -func NewAtomicCommitter(ctx context.Context, committables map[string]Committable, wal Wal, opts ...CommiterOpt) (*AtomicCommitter, error) { - committablesMap := make(map[CommittableId]Committable) - for id, committable := range committables { - committablesMap[CommittableId(id)] = committable - } - +func NewAtomicCommitter(ctx context.Context, wal Wal, opts ...CommiterOpt) *AtomicCommitter { a := &AtomicCommitter{ - committables: committablesMap, + committables: make(map[CommittableId]Committable), wal: &sessionWal{wal}, log: log.NewNoOp(), + timeout: 5 * time.Second, } for _, opt := range opts { opt(a) } - err := a.flushWal(ctx) - if err != nil { - return nil, err + return a +} + +// ClearWal clears the wal. This method will check if there are values in the WAL. +// If so, it will attempt to commit them. If no commit record is found, then it will +// discard the WAL. +// This should be called on startup or recovery. +func (a *AtomicCommitter) ClearWal(ctx context.Context) error { + a.mu.Lock() + defer a.mu.Unlock() + + if a.closed { + return ErrClosed + } + + if a.inProgress { + return ErrSessionInProgress } - return a, nil + return a.applyWal(ctx) } +// Begin begins a new session. +// It will signal to all committables that a session has begun. func (a *AtomicCommitter) Begin(ctx context.Context) (err error) { a.mu.Lock() defer a.mu.Unlock() - defer a.handleErr(ctx, &err) + if a.closed { + return ErrClosed + } if a.inProgress { return ErrSessionInProgress } a.inProgress = true + // we handle errors after checking to see if a session + // is in progress because, if begin is called while a session + // is in progress, it will cancel the session. + defer a.handleErr(ctx, &err) + return a.beginCommit(ctx) } // Commit commits the atomic session. -// It aggregates all commit ids from the committables and returns them as a single Sha256 hash. // It can be given a callback function to handle any errors that occur during the apply phase (which proceeds asynchronously) after this function returns. -func (a *AtomicCommitter) Commit(ctx context.Context, applyCallback func(error)) (commitId []byte, err error) { +func (a *AtomicCommitter) Commit(ctx context.Context, applyCallback func(error)) (err error) { a.mu.Lock() - defer a.mu.Unlock() + // if no session in progress, then return without cancelling + if !a.inProgress { + a.mu.Unlock() + return ErrNoSessionInProgress + } + a.inProgress = false + + // if error, cancel the session defer a.handleErr(ctx, &err) - if !a.inProgress { - return nil, ErrNoSessionInProgress + // if session is in progress but the committer is closed, then cancel the session + if a.closed { + a.mu.Unlock() + return ErrClosed } - err = a.wal.Begin(ctx) + // begin the commit in the WAL + err = a.wal.WriteBegin(ctx) if err != nil { - return nil, err + a.mu.Unlock() + return err } - commitId, err = a.endCommit(ctx) + // tell all committables to finish phase 1, and submit + // any changes to the WAL + err = a.endCommit(ctx) if err != nil { - return nil, err + a.mu.Unlock() + return err } - err = a.wal.Commit(ctx) + // commit the WAL + err = a.wal.WriteCommit(ctx) if err != nil { - return nil, err + a.mu.Unlock() + return err } go func() { err2 := a.apply(ctx) applyCallback(err2) + a.mu.Unlock() }() - return commitId, nil + return nil +} + +// ID returns a deterministic identifier representative of all state changes that have occurred in the session. +// It can only be called in between Begin and Commit. +func (a *AtomicCommitter) ID(ctx context.Context) (id []byte, err error) { + a.mu.Lock() + defer a.mu.Unlock() + + if !a.inProgress { + return nil, ErrNoSessionInProgress + } + + // this comes after checking if a session is in progress because + // we do not want to call cancel if a session is not in progress. + defer a.handleErr(ctx, &err) + + if a.closed { + return nil, ErrClosed + } + + return a.id(ctx) } // Apply applies the atomic session. @@ -186,19 +252,22 @@ func (a *AtomicCommitter) cancel(ctx context.Context) { } } -// handleErr checks if an error is nil or not. If it is not nil, it logs it, and notifies the committables that the session has been cancelled. +// handleErr checks if an error is nil or not. +// If it is not nil, it logs it, and notifies the committables that the session has been cancelled. +// It then sets the session state to not in progress. func (a *AtomicCommitter) handleErr(ctx context.Context, err *error) { if *err != nil { a.log.Error("error during atomic commit", zap.Error(*err)) a.cancel(ctx) + a.inProgress = false } } -// flushWal will try to apply all changes in the WAL to the committables. +// applyWal will try to apply all changes in the WAL to the committables. // If the wal does not contain a commit record, it will delete all changes in the WAL. // If the wal contains a commit record, it will apply all changes in the WAL to the committables. // If the wal contains a commit record, but the commit fails, it will return an error. -func (a *AtomicCommitter) flushWal(ctx context.Context) (err error) { +func (a *AtomicCommitter) applyWal(ctx context.Context) (err error) { beginRecord, err := a.wal.ReadNext(ctx) if err == io.EOF { return a.wal.Truncate(ctx) @@ -243,7 +312,10 @@ func (a *AtomicCommitter) flushWal(ctx context.Context) (err error) { break } - committable := a.committables[record.CommittableId] + committable, ok := a.committables[record.CommittableId] + if !ok { + a.log.Error("cannot find target data store for wal record", zap.String("committable_id", record.CommittableId.String())) + } err = committable.Apply(ctx, record.Data) if err != nil { applyErrs = append(applyErrs, err) @@ -271,27 +343,17 @@ func (a *AtomicCommitter) beginCommit(ctx context.Context) error { // endCommit calls EndCommit on all committables. // it orders the committables alphabetically by their unique identifier, to ensure that the commit id is deterministic. -func (a *AtomicCommitter) endCommit(ctx context.Context) ([]byte, error) { - orderedCommittables := orderAlphabetically(a.committables) - - hash := sha256.New() - for _, c := range orderedCommittables { - commitId, err := c.committable.EndCommit(ctx, func(b []byte) error { - return a.wal.WriteChangeset(ctx, c.id, b) +func (a *AtomicCommitter) endCommit(ctx context.Context) error { + for id, c := range a.committables { + err := c.EndCommit(ctx, func(b []byte) error { + return a.wal.WriteChangeset(ctx, id, b) }) if err != nil { - return nil, wrapError(ErrEndCommit, err) - } - - fmt.Println("commitId", commitId) - - _, err = hash.Write(commitId) - if err != nil { - return nil, wrapError(ErrEndCommit, err) + return wrapError(ErrEndCommit, err) } } - return hash.Sum(nil), nil + return nil } // beginApply calls BeginApply on all committables. @@ -308,6 +370,26 @@ func (a *AtomicCommitter) endApply(ctx context.Context) error { }) } +// id calls ID on all committables. +// it orders the committables alphabetically by their unique identifier, to ensure that the commit id is deterministic. +func (a *AtomicCommitter) id(ctx context.Context) (id []byte, err error) { + hash := sha256.New() + + for _, c := range order.OrderMapLexicographically[CommittableId, Committable](a.committables) { + commitId, err := c.Value.ID(ctx) + if err != nil { + return nil, wrapError(ErrID, err) + } + + _, err = hash.Write(commitId) + if err != nil { + return nil, wrapError(ErrID, err) + } + } + + return hash.Sum(nil), nil +} + func (a *AtomicCommitter) callAll(errType error, f func(Committable) error) error { errs := []error{} for _, committable := range a.committables { @@ -325,34 +407,75 @@ func (a *AtomicCommitter) callAll(errType error, f func(Committable) error) erro return nil } -// orderAlphabetically orders the committables alphabetically by their unique identifier. -func orderAlphabetically(commitableMap map[CommittableId]Committable) []*struct { - id CommittableId - committable Committable -} { - // Extracting keys - keys := make([]string, 0, len(commitableMap)) - for k := range commitableMap { - keys = append(keys, k.String()) - } - - // Sorting keys - sort.Strings(keys) - - // Creating output slice - datasets := make([]*struct { - id CommittableId - committable Committable - }, 0) - - for _, k := range keys { - datasets = append(datasets, &struct { - id CommittableId - committable Committable - }{ - id: CommittableId(k), - committable: commitableMap[CommittableId(k)], - }) +// TODO: we need to test register and unregister + +// Register registers a committable with the atomic committer. +// If a session is already in progress, the newly registered committer will be added to the session, +// and BeginCommit will immediately be called on the committable. +// If BeginCommit fails, the entire session will be cancelled. +func (a *AtomicCommitter) Register(ctx context.Context, id string, committable Committable) (err error) { + a.mu.Lock() + defer a.mu.Unlock() + + _, ok := a.committables[CommittableId(id)] + if ok { + return ErrAlreadyRegistered + } + a.committables[CommittableId(id)] = committable + + if !a.inProgress { + return nil + } + + defer a.handleErr(ctx, &err) + + err = committable.BeginApply(ctx) + if err != nil { + return wrapError(ErrBeginApply, err) + } + + return nil +} + +// Unregister unregisters a committable from the atomic committer. +// If a session is already in progress, Cancel will immediately be called on the committable. +func (a *AtomicCommitter) Unregister(ctx context.Context, id string) error { + a.mu.Lock() + defer a.mu.Unlock() + + committable, ok := a.committables[CommittableId(id)] + if !ok { + return wrapError(ErrUnknownCommittable, fmt.Errorf("committable id: %s", id)) + } + delete(a.committables, CommittableId(id)) + + if a.inProgress { + committable.Cancel(ctx) } - return datasets + + return nil +} + +// Close closes the atomic committer. +// If a session is in progress, it will cancel the session. +// If a session is not in progress, it will close immediately. +// We only have to worry about this being called outside of a session, +// or in the middle of phase 1. Since the committer mutex is locked +// from the end of phase1 to the end of phase2, we know that this +// function will not be called in the middle of phase 2. +func (a *AtomicCommitter) Close() error { + a.mu.Lock() + defer a.mu.Unlock() + + a.log.Info("closing atomic committer") + + if !a.inProgress { + return nil + } + + ctx, cancel := context.WithTimeout(context.Background(), a.timeout) + defer cancel() + + a.cancel(ctx) + return nil } diff --git a/pkg/sessions/sessions_test.go b/pkg/sessions/sessions_test.go index 9f3ec8f18..90a98b699 100644 --- a/pkg/sessions/sessions_test.go +++ b/pkg/sessions/sessions_test.go @@ -13,6 +13,8 @@ import ( ) // TODO: test calling things like begin, end, apply, etc. out of order / multiple times +// TODO: test register and unregister; and try calling them at different times +// e.g. calling register after begin, or unregister after end, etc. func Test_Session(t *testing.T) { type fields struct { @@ -125,7 +127,17 @@ func Test_Session(t *testing.T) { var id []byte outErr := func() error { ctx := context.Background() - committer, err := sessions.NewAtomicCommitter(ctx, tt.fields.committables, tt.fields.wal) + committer := sessions.NewAtomicCommitter(ctx, tt.fields.wal) + + for id, committable := range tt.fields.committables { + err := committer.Register(ctx, id, committable) + if err != nil { + return err + } + } + + defer committer.Close() + err := committer.ClearWal(ctx) if err != nil { return err } @@ -139,8 +151,13 @@ func Test_Session(t *testing.T) { return err } + id, err = committer.ID(ctx) + if err != nil { + return err + } + applyErr := make(chan error) - id, err = committer.Commit(ctx, func(err error) { + err = committer.Commit(ctx, func(err error) { applyErr <- err }) if err != nil { @@ -239,16 +256,16 @@ func Test_ExistingWal(t *testing.T) { wal sessions.Wal } - type commitableData struct { - id string - commitable sessions.Committable - resultData map[string]any + type committableData struct { + id string + committable sessions.Committable + resultData map[string]any } type testCase struct { name string fields fields - commitableData []commitableData + commitableData []committableData err error } @@ -262,16 +279,16 @@ func Test_ExistingWal(t *testing.T) { walRecordCs2, }...), }, - commitableData: []commitableData{ + commitableData: []committableData{ { - id: "c1", - commitable: mockCommittable1(), - resultData: map[string]any{}, + id: "c1", + committable: mockCommittable1(), + resultData: map[string]any{}, }, { - id: "c2", - commitable: mockCommittable2(), - resultData: map[string]any{}, + id: "c2", + committable: mockCommittable2(), + resultData: map[string]any{}, }, }, }, @@ -285,17 +302,17 @@ func Test_ExistingWal(t *testing.T) { walRecordCommit, }...), }, - commitableData: []commitableData{ + commitableData: []committableData{ { - id: "c1", - commitable: mockCommittable1(), + id: "c1", + committable: mockCommittable1(), resultData: map[string]any{ "key1": "c1_changeset_1", }, }, { - id: "c2", - commitable: mockCommittable2(), + id: "c2", + committable: mockCommittable2(), resultData: map[string]any{ "key1": "c2_changeset_1", }, @@ -311,16 +328,16 @@ func Test_ExistingWal(t *testing.T) { walRecordCommit, }...), }, - commitableData: []commitableData{ + commitableData: []committableData{ { - id: "c1", - commitable: mockCommittable1(), - resultData: map[string]any{}, + id: "c1", + committable: mockCommittable1(), + resultData: map[string]any{}, }, { - id: "c2", - commitable: mockCommittable2(), - resultData: map[string]any{}, + id: "c2", + committable: mockCommittable2(), + resultData: map[string]any{}, }, }, }, @@ -330,12 +347,19 @@ func Test_ExistingWal(t *testing.T) { t.Run(tt.name, func(t *testing.T) { commitableMap := map[string]sessions.Committable{} for _, data := range tt.commitableData { - commitableMap[data.id] = data.commitable + commitableMap[data.id] = data.committable } ctx := context.Background() - _, err := sessions.NewAtomicCommitter(ctx, commitableMap, tt.fields.wal) + committer := sessions.NewAtomicCommitter(ctx, tt.fields.wal) + for id, committable := range commitableMap { + err := committer.Register(ctx, id, committable) + if err != nil { + t.Fatal(err) + } + } + err := committer.ClearWal(ctx) assertError(t, err, tt.err) if tt.err != nil { assertAllCanceled(t, commitableMap) @@ -349,7 +373,7 @@ func Test_ExistingWal(t *testing.T) { } for _, data := range tt.commitableData { - for key, value := range data.commitable.(*mockCommittable).appliedData { + for key, value := range data.committable.(*mockCommittable).appliedData { if value != data.resultData[key] { t.Fatalf("expected value %v, got %v", data.resultData[key], value) } diff --git a/pkg/sessions/sql-session/session.go b/pkg/sessions/sql-session/session.go index 8739ddf33..5dda32b24 100644 --- a/pkg/sessions/sql-session/session.go +++ b/pkg/sessions/sql-session/session.go @@ -8,6 +8,7 @@ import ( "io" "github.com/kwilteam/kwil-db/pkg/log" + "github.com/kwilteam/kwil-db/pkg/sessions" "github.com/kwilteam/kwil-db/pkg/sql" "go.uber.org/zap" ) @@ -21,6 +22,8 @@ type SqlCommitable struct { log log.Logger } +var _ sessions.Committable = (*SqlCommitable)(nil) + // NewSqlCommitable creates a new SqlCommitable. func NewSqlCommitable(db SqlDB, opts ...SqlCommittableOpt) *SqlCommitable { s := &SqlCommitable{ @@ -62,50 +65,35 @@ func (s *SqlCommitable) BeginCommit(ctx context.Context) error { } // EndCommit ends the current session and commits the changes. -func (s *SqlCommitable) EndCommit(ctx context.Context, appender func([]byte) error) (commitId []byte, err error) { +func (s *SqlCommitable) EndCommit(ctx context.Context, appender func([]byte) error) (err error) { if s.session == nil { - return nil, fmt.Errorf("session not started") + return fmt.Errorf("session not started") } if s.savepoint == nil { - return nil, fmt.Errorf("savepoint not active") + return fmt.Errorf("savepoint not active") } - defer s.savepoint.Rollback() + defer func() { + err = errors.Join(s.savepoint.Rollback(), s.session.Delete()) + s.savepoint = nil + s.session = nil + if err != nil { + s.log.Error("failed to rollback savepoint", zap.Error(err)) + } + }() changes, err := s.session.GenerateChangeset() if err != nil { - return nil, err - } - - id, err := changes.ID() - if err != nil { - return nil, err + return err } + defer changes.Close() data, err := changes.Export() if err != nil { - return nil, err - } - - err = appender(data) - if err != nil { - return nil, err - } - - errs := []error{} - err = changes.Close() - if err != nil { - errs = append(errs, err) - } - - err = s.session.Delete() - if err != nil { - errs = append(errs, err) + return err } - s.session = nil - - return id, errors.Join(errs...) + return appender(data) } // BeginApply starts a new savepoint for applying changes. @@ -166,6 +154,24 @@ func (s *SqlCommitable) Cancel(ctx context.Context) { } } +// ID returns the ID of the current session. +func (s *SqlCommitable) ID(ctx context.Context) ([]byte, error) { + if s.session == nil { + return nil, fmt.Errorf("session not started") + } + if s.savepoint == nil { + return nil, fmt.Errorf("savepoint not active") + } + + changes, err := s.session.GenerateChangeset() + if err != nil { + return nil, err + } + defer changes.Close() + + return changes.ID() +} + type SqlCommittableOpt func(*SqlCommitable) func WithLogger(logger log.Logger) SqlCommittableOpt { diff --git a/pkg/sessions/wal.go b/pkg/sessions/wal.go index 115da51f7..a152faf68 100644 --- a/pkg/sessions/wal.go +++ b/pkg/sessions/wal.go @@ -11,8 +11,8 @@ type sessionWal struct { wal Wal } -// Begin writes a begin record to the WAL. This should be called before any changes are written to the WAL. -func (w *sessionWal) Begin(ctx context.Context) error { +// WriteBegin writes a begin record to the WAL. This should be called before any changes are written to the WAL. +func (w *sessionWal) WriteBegin(ctx context.Context) error { bts, err := SerializeWalRecord(&WalRecord{ Type: WalRecordTypeBegin, }) @@ -23,9 +23,9 @@ func (w *sessionWal) Begin(ctx context.Context) error { return w.wal.Append(ctx, bts) } -// Commit writes a commit record to the WAL. +// WriteCommit writes a commit record to the WAL. // This should be called after all changes have been written to the WAL. -func (w *sessionWal) Commit(ctx context.Context) error { +func (w *sessionWal) WriteCommit(ctx context.Context) error { bts, err := SerializeWalRecord(&WalRecord{ Type: WalRecordTypeCommit, }) @@ -36,6 +36,20 @@ func (w *sessionWal) Commit(ctx context.Context) error { return w.wal.Append(ctx, bts) } +// WriteChangeset writes a changeset for a specific comittableId to the WAL +func (w *sessionWal) WriteChangeset(ctx context.Context, committable CommittableId, changeset []byte) error { + bts, err := SerializeWalRecord(&WalRecord{ + Type: WalRecordTypeChangeset, + CommittableId: committable, + Data: changeset, + }) + if err != nil { + return err + } + + return w.wal.Append(ctx, bts) +} + // ReadNext reads the next entry from the WAL and returns it func (w *sessionWal) ReadNext(ctx context.Context) (*WalRecord, error) { data, err := w.wal.ReadNext(ctx) @@ -55,20 +69,6 @@ func (w *sessionWal) Truncate(ctx context.Context) error { return w.wal.Truncate(ctx) } -// WriteChangeset writes a changeset for a specific comittableId to the WAL -func (w *sessionWal) WriteChangeset(ctx context.Context, committable CommittableId, changeset []byte) error { - bts, err := SerializeWalRecord(&WalRecord{ - Type: WalRecordTypeChangeset, - CommittableId: committable, - Data: changeset, - }) - if err != nil { - return err - } - - return w.wal.Append(ctx, bts) -} - type WalRecordType uint8 const ( diff --git a/pkg/sessions/wal/wal.go b/pkg/sessions/wal/wal.go new file mode 100644 index 000000000..7f1ff97d6 --- /dev/null +++ b/pkg/sessions/wal/wal.go @@ -0,0 +1,119 @@ +package wal + +import ( + "context" + "io" + "os" + "sync" + + "github.com/tidwall/wal" +) + +const ( + startingWriteIdx = 1 + startingReadIdx = 1 +) + +// Wal is a basic write-ahead log. +// This can and should be improved on. +// At the time of its creation, this is +// only made to implement sessions.Wal. +type Wal struct { + path string + + mu sync.Mutex + + // tidwall/wal starts indexing at 1. + wal *wal.Log + + writeIdx uint64 + readIdx uint64 +} + +// OpenWal opens a wal at the given path. +// If the wal does not exist, it will be created. +// For example, passing in "/tmp/wal" will create +// a wal at "/tmp/wal.wal". +func OpenWal(path string) (*Wal, error) { + w, err := wal.Open(path, nil) + if err != nil { + return nil, err + } + + return &Wal{ + path: path, + wal: w, + writeIdx: startingWriteIdx, + readIdx: startingReadIdx, + }, nil +} + +// Append appends a new entry to the WAL +func (w *Wal) Append(ctx context.Context, data []byte) error { + w.mu.Lock() + defer w.mu.Unlock() + + err := w.wal.Write(w.writeIdx, data) + if err != nil { + return err + } + + w.writeIdx++ + + return nil +} + +// ReadNext reads the next entry from the WAL +// it will return an io.EOF when it has reached the end of the WAL +// it will also return an io.EOF if the wal is corrupt +func (w *Wal) ReadNext(ctx context.Context) ([]byte, error) { + w.mu.Lock() + defer w.mu.Unlock() + + data, err := w.wal.Read(w.readIdx) + if err == wal.ErrNotFound || err == wal.ErrCorrupt { + return nil, io.EOF + } + if err != nil { + return nil, err + } + + w.readIdx++ + + return data, nil +} + +// Truncate deletes the entire WAL +// and opens a new one. +func (w *Wal) Truncate(ctx context.Context) error { + w.mu.Lock() + defer w.mu.Unlock() + + err := w.wal.Close() + if err != nil { + return err + } + + err = os.RemoveAll(w.path) + if err != nil { + return err + } + + w.wal, err = wal.Open(w.path, nil) + if err != nil { + return err + } + + w.writeIdx = startingWriteIdx + w.readIdx = startingReadIdx + + return nil +} + +// Close closes the WAL +func (w *Wal) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + + return w.wal.Close() +} diff --git a/pkg/sessions/wal/wal_test.go b/pkg/sessions/wal/wal_test.go new file mode 100644 index 000000000..34cacb52a --- /dev/null +++ b/pkg/sessions/wal/wal_test.go @@ -0,0 +1,96 @@ +package wal_test + +import ( + "context" + "errors" + "io" + "os" + "testing" + + "github.com/kwilteam/kwil-db/pkg/sessions/wal" + "github.com/stretchr/testify/assert" +) + +const directory = "./tmp" +const path = directory + "/wal" + +func Test_Wal(t *testing.T) { + type testCase struct { + name string + testFunc func(t *testing.T, w *wal.Wal) + } + + testCases := []testCase{ + { + name: "intended use of Wal", + testFunc: func(t *testing.T, w *wal.Wal) { + ctx := context.Background() + err := w.Append(ctx, []byte("hello")) + assert.NoError(t, err) + + err = w.Append(ctx, []byte("world")) + assert.NoError(t, err) + + hello, err := w.ReadNext(ctx) + assert.NoError(t, err) + assert.Equal(t, []byte("hello"), hello) + + world, err := w.ReadNext(ctx) + assert.NoError(t, err) + assert.Equal(t, []byte("world"), world) + + _, err = w.ReadNext(ctx) + assert.ErrorIs(t, err, io.EOF) + + err = w.Truncate(ctx) + assert.NoError(t, err) + }, + }, + { + name: "test total truncation", + // write two records, truncate, then check that the file is empty + // test that truncating new wal does nothing + testFunc: func(t *testing.T, w *wal.Wal) { + ctx := context.Background() + err := w.Append(ctx, []byte("hello")) + assert.NoError(t, err) + + err = w.Append(ctx, []byte("world")) + assert.NoError(t, err) + + hello, err := w.ReadNext(ctx) + assert.NoError(t, err) + assert.Equal(t, []byte("hello"), hello) + + err = w.Truncate(ctx) + assert.NoError(t, err) + + _, err = w.ReadNext(ctx) + assert.ErrorIs(t, err, io.EOF) + + err = w.Truncate(ctx) + assert.NoError(t, err) + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + w, err := wal.OpenWal(path) + if err != nil { + t.Fatal(err) + } + defer func() { + err := errors.Join( + w.Close(), + os.RemoveAll(directory), + ) + if err != nil { + t.Fatal(err) + } + }() + + tc.testFunc(t, w) + }) + } +} diff --git a/pkg/modules/snapshots/snapshot_store.go b/pkg/snapshots/snapshot_store.go similarity index 87% rename from pkg/modules/snapshots/snapshot_store.go rename to pkg/snapshots/snapshot_store.go index e0840b2c6..a7d33898e 100644 --- a/pkg/modules/snapshots/snapshot_store.go +++ b/pkg/snapshots/snapshot_store.go @@ -2,7 +2,6 @@ package snapshots import ( "github.com/kwilteam/kwil-db/pkg/log" - "github.com/kwilteam/kwil-db/pkg/snapshots" ) type SnapshotStoreOpts func(*SnapshotStore) @@ -18,11 +17,11 @@ type SnapshotStore struct { numSnapshots uint64 // current number of snapshots log log.Logger - snapshotter Snapshotter // Snapshotter instance to create a snapshot, instantiated at the beginning of snapshot process + snapshotter *Snapshotter // Snapshotter instance to create a snapshot, instantiated at the beginning of snapshot process } func NewSnapshotStore(databaseDir string, snapshotDir string, height uint64, maxSnapshots uint64, opts ...SnapshotStoreOpts) *SnapshotStore { - snapshotter := snapshots.NewSnapshotter(snapshotDir, databaseDir, 16*1024*1024) + snapshotter := NewSnapshotter(snapshotDir, databaseDir, 16*1024*1024) ss := &SnapshotStore{ enabled: true, numSnapshots: 0, @@ -64,7 +63,7 @@ func (s *SnapshotStore) CreateSnapshot(height uint64) error { } if s.snapshotter == nil { - s.snapshotter = snapshots.NewSnapshotter(s.snapshotDir, s.databaseDir, s.chunkSize) + s.snapshotter = NewSnapshotter(s.snapshotDir, s.databaseDir, s.chunkSize) } // Initialize snapshot session @@ -94,7 +93,7 @@ func (s *SnapshotStore) CreateSnapshot(height uint64) error { } // Lists the snapshot metadata of all the existing snapshots -func (s *SnapshotStore) ListSnapshots() ([]snapshots.Snapshot, error) { +func (s *SnapshotStore) ListSnapshots() ([]Snapshot, error) { return s.snapshotter.ListSnapshots() } diff --git a/pkg/modules/snapshots/snapshot_store_test.go b/pkg/snapshots/snapshot_store_test.go similarity index 94% rename from pkg/modules/snapshots/snapshot_store_test.go rename to pkg/snapshots/snapshot_store_test.go index a15a837d0..653958de9 100644 --- a/pkg/modules/snapshots/snapshot_store_test.go +++ b/pkg/snapshots/snapshot_store_test.go @@ -4,7 +4,7 @@ import ( "path/filepath" "testing" - "github.com/kwilteam/kwil-db/pkg/modules/snapshots" + "github.com/kwilteam/kwil-db/pkg/snapshots" "github.com/stretchr/testify/assert" ) diff --git a/pkg/transactions/transaction.go b/pkg/transactions/transaction.go index ca87fc0ac..f4b15e3a7 100644 --- a/pkg/transactions/transaction.go +++ b/pkg/transactions/transaction.go @@ -112,6 +112,9 @@ func (t *Transaction) MarshalBinary() (serialize.SerializedData, error) { return serialize.Encode(t) } +// TODO: I am not sure if this will actually work, since it is unserializing into an interface +// I am quite sure it wont; an alternative is to decode into a struct where public key is bytes, and +// create the public key from there func (t *Transaction) UnmarshalBinary(data serialize.SerializedData) error { res, err := serialize.Decode[Transaction](data) if err != nil { diff --git a/pkg/utils/order/order.go b/pkg/utils/order/order.go new file mode 100644 index 000000000..28cba3616 --- /dev/null +++ b/pkg/utils/order/order.go @@ -0,0 +1,57 @@ +package order + +import "sort" + +// OrderMapLexicographically orders a map lexicographically by its keys. +// It permits any map with keys that are generically orderable. +// TODO: once upgraded to go 1.21, an equivalent is in the standard library +func OrderMapLexicographically[S Ordered, T any](m map[S]T) []*struct { + Id S + Value T +} { + keys := make([]S, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + + sort.Slice(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + result := make([]*struct { + Id S + Value T + }, 0, len(m)) + + for _, k := range keys { + result = append(result, &struct { + Id S + Value T + }{ + Id: k, + Value: m[k], + }) + } + + return result +} + +type Ordered interface { + Integer | Float | ~string +} + +type Float interface { + ~float32 | ~float64 +} + +type Integer interface { + Signed | Unsigned +} + +type Unsigned interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +type Signed interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} diff --git a/pkg/utils/serialization/slice.go b/pkg/utils/serialization/slice.go new file mode 100644 index 000000000..37e850fe0 --- /dev/null +++ b/pkg/utils/serialization/slice.go @@ -0,0 +1,52 @@ +package serialization + +import ( + "encoding" + "encoding/binary" + "fmt" +) + +// SerializeSlice serializes a slice of binary marshalable items. +// It prepends the length of each item to the serialized data. +func SerializeSlice[T encoding.BinaryMarshaler](slice []T) ([]byte, error) { + var result []byte + for _, item := range slice { + data, err := item.MarshalBinary() + if err != nil { + return nil, err + } + + length := uint64(len(data)) + result = append(result, append(make([]byte, 8), data...)...) + binary.BigEndian.PutUint64(result[len(result)-len(data)-8:len(result)-len(data)], length) + } + + return result, nil +} + +// DeserializeSlice deserializes a slice of binary marshalable items. +// It expects bytes, as well as a function to create a new item of the slice type. +func DeserializeSlice[T encoding.BinaryUnmarshaler](bts []byte, newFn func() T) ([]T, error) { + var result []T + for len(bts) > 0 { + if len(bts) < 8 { + return nil, fmt.Errorf("insufficient bytes") + } + length := binary.BigEndian.Uint64(bts[:8]) + if uint64(len(bts[8:])) < length { + return nil, fmt.Errorf("invalid length") + } + bts = bts[8:] + + value := newFn() + err := value.UnmarshalBinary(bts[:length]) + if err != nil { + return nil, err + } + + result = append(result, value) + bts = bts[length:] + } + + return result, nil +}