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 +}