diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 4dc80047f552..101398baeecc 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -24,3 +24,22 @@ jobs: args: release --rm-dist --release-notes ./RELEASE_NOTES.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + release-success: + needs: release + if: ${{ success() }} + runs-on: ubuntu-latest + steps: + - name: Notify Slack on success + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_CHANNEL: cosmos-sdk + SLACK_USERNAME: Cosmos SDK Release Bot + SLACK_ICON: https://avatars.githubusercontent.com/t/5997665?size=64 + SLACK_COLOR: good + SLACK_TITLE: "Cosmos SDK ${{ github.ref_name }} is tagged :tada:" + SLACK_MESSAGE: "@channel :point_right: https://github.com/cosmos/cosmos-sdk/releases/tag/${{ github.ref_name }}" + SLACK_FOOTER: "" + SLACK_LINK_NAMES: true + MSG_MINIMAL: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fcae988e4f3..7cbfc79ed9d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,49 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +## v0.45.12 - 2023-01-23 + +### Improvements + +* [#13881](https://github.com/cosmos/cosmos-sdk/pull/13881) Optimize iteration on nested cached KV stores and other operations in general. +* (store) [#11646](https://github.com/cosmos/cosmos-sdk/pull/11646) Add store name in tracekv-emitted store traces +* (deps) Bump Tendermint version to [v0.34.24](https://github.com/tendermint/tendermint/releases/tag/v0.34.24) and use Informal Systems fork. + +### API Breaking Changes + +* (store) [#13516](https://github.com/cosmos/cosmos-sdk/pull/13516) Update State Streaming APIs: + * Add method `ListenCommit` to `ABCIListener` + * Move `ListeningEnabled` and `AddListener` methods to `CommitMultiStore` + * Remove `CacheWrapWithListeners` from `CacheWrap` and `CacheWrapper` interfaces + * Remove listening APIs from the caching layer (it should only listen to the `rootmulti.Store`) + * Add three new options to file streaming service constructor. + * Modify `ABCIListener` such that any error from any method will always halt the app via `panic` + +### Bug Fixes + +* (store) [#13516](https://github.com/cosmos/cosmos-sdk/pull/13516) Fix state listener that was observing writes at wrong time. +* (store) [#12945](https://github.com/cosmos/cosmos-sdk/pull/12945) Fix nil end semantics in store/cachekv/iterator when iterating a dirty cache. + +## v0.45.11 - 2022-11-09 + +### Improvements + +* [#13896](https://github.com/cosmos/cosmos-sdk/pull/13896) Queries on pruned height returns error instead of empty values. +* (deps) Bump Tendermint version to [v0.34.23](https://github.com/tendermint/tendermint/releases/tag/v0.34.23). +* (deps) Bump IAVL version to [v0.19.4](https://github.com/cosmos/iavl/releases/tag/v0.19.4). + +### Bug Fixes + +* [#13673](https://github.com/cosmos/cosmos-sdk/pull/13673) Fix `--dry-run` flag not working when using tx command. + +### CLI Breaking Changes + +* [#13656](https://github.com/cosmos/cosmos-sdk/pull/13660) Rename `server.FlagIAVLFastNode` to `server.FlagDisableIAVLFastNode` for clarity. + +### API Breaking Changes + +* [#13673](https://github.com/cosmos/cosmos-sdk/pull/13673) The `GetFromFields` function now takes `Context` as an argument and removes `genOnly`. + ## v0.45.10 - 2022-10-24 ### Features diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f253c0ec036c..2c53f93b494a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,18 @@ -# Cosmos SDK v0.45.10 Release Notes +# Cosmos SDK v0.45.12 Release Notes -This release introduces a number of bug fixes, features and improvements. +This release introduces a number of bug fixes and improvements. Notably with an update to State Streaming APIs. + +Moreover, this release contains a store fix. The changes have been tested against the Cosmos Hub and Juno mainnet with no issues. However, there is a low probability of an edge case happening. Hence, it is recommended to do a **coordinated upgrade** to avoid any issues. Please see the [CHANGELOG](https://github.com/cosmos/cosmos-sdk/blob/release/v0.45.x/CHANGELOG.md) for an exhaustive list of changes. -**Full Commit History**: https://github.com/cosmos/cosmos-sdk/compare/v0.45.9...v0.45.10 +**Full Commit History**: https://github.com/cosmos/cosmos-sdk/compare/v0.45.11...v0.45.12 + +**NOTE:** The changes mentioned in `v0.45.9` are **no longer required**. The following replace directive can be removed from the chains. + +```go +# Can be deleted from go.mod +replace github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 +``` + +Instead, `github.com/confio/ics23/go` must be **bumped to `v0.9.0`**. diff --git a/baseapp/abci.go b/baseapp/abci.go index b934255da462..985e4ae3b385 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -182,8 +182,9 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg // call the hooks with the BeginBlock messages for _, streamingListener := range app.abciListeners { - if err := streamingListener.ListenBeginBlock(app.deliverState.ctx, req, res); err != nil { - app.logger.Error("BeginBlock listening hook failed", "height", req.Header.Height, "err", err) + goCtx := sdk.WrapSDKContext(app.deliverState.ctx) + if err := streamingListener.ListenBeginBlock(goCtx, req, res); err != nil { + panic(fmt.Errorf("BeginBlock listening hook failed, height: %d, err: %w", req.Header.Height, err)) } } @@ -209,8 +210,9 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc // call the streaming service hooks with the EndBlock messages for _, streamingListener := range app.abciListeners { - if err := streamingListener.ListenEndBlock(app.deliverState.ctx, req, res); err != nil { - app.logger.Error("EndBlock listening hook failed", "height", req.Height, "err", err) + goCtx := sdk.WrapSDKContext(app.deliverState.ctx) + if err := streamingListener.ListenEndBlock(goCtx, req, res); err != nil { + panic(fmt.Errorf("EndBlock listening hook failed, height: %d, err: %w", req.Height, err)) } } @@ -263,8 +265,9 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliv defer func() { for _, streamingListener := range app.abciListeners { - if err := streamingListener.ListenDeliverTx(app.deliverState.ctx, req, res); err != nil { - app.logger.Error("DeliverTx listening hook failed", "err", err) + goCtx := sdk.WrapSDKContext(app.deliverState.ctx) + if err := streamingListener.ListenDeliverTx(goCtx, req, res); err != nil { + panic(fmt.Errorf("DeliverTx listening hook failed: %w", err)) } } }() @@ -301,7 +304,7 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliv // defined in config, Commit will execute a deferred function call to check // against that height and gracefully halt if it matches the latest committed // height. -func (app *BaseApp) Commit() (res abci.ResponseCommit) { +func (app *BaseApp) Commit() abci.ResponseCommit { defer telemetry.MeasureSince(time.Now(), "abci", "commit") header := app.deliverState.ctx.BlockHeader() @@ -312,6 +315,20 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { // MultiStore (app.cms) so when Commit() is called is persists those values. app.deliverState.ms.Write() commitID := app.cms.Commit() + + res := abci.ResponseCommit{ + Data: commitID.Hash, + RetainHeight: retainHeight, + } + + // call the hooks with the Commit message + for _, streamingListener := range app.abciListeners { + goCtx := sdk.WrapSDKContext(app.deliverState.ctx) + if err := streamingListener.ListenCommit(goCtx, res); err != nil { + panic(fmt.Errorf("Commit listening hook failed, height: %d, err: %w", header.Height, err)) + } + } + app.logger.Info("commit synced", "commit", fmt.Sprintf("%X", commitID)) // Reset the Check state to the latest committed. @@ -345,10 +362,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { go app.snapshot(header.Height) } - return abci.ResponseCommit{ - Data: commitID.Hash, - RetainHeight: retainHeight, - } + return res } // halt attempts to gracefully shutdown the node via SIGINT and SIGTERM falling diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index f9cdfcb71438..d7b8c4b7fbd3 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -108,7 +108,7 @@ func TestLoadVersionPruning(t *testing.T) { for _, v := range []int64{1, 2, 4} { _, err = app.cms.CacheMultiStoreWithVersion(v) - require.NoError(t, err) + require.Error(t, err) } for _, v := range []int64{3, 5, 6, 7} { diff --git a/baseapp/streaming.go b/baseapp/streaming.go index 39e0f1ca6e9b..b8b382ae05b3 100644 --- a/baseapp/streaming.go +++ b/baseapp/streaming.go @@ -1,23 +1,27 @@ package baseapp import ( + "context" "io" "sync" abci "github.com/tendermint/tendermint/abci/types" store "github.com/cosmos/cosmos-sdk/store/types" - "github.com/cosmos/cosmos-sdk/types" ) -// ABCIListener interface used to hook into the ABCI message processing of the BaseApp +// ABCIListener interface used to hook into the ABCI message processing of the BaseApp. +// the error results are propagated to consensus state machine, +// if you don't want to affect consensus, handle the errors internally and always return `nil` in these APIs. type ABCIListener interface { // ListenBeginBlock updates the streaming service with the latest BeginBlock messages - ListenBeginBlock(ctx types.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) error + ListenBeginBlock(ctx context.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) error // ListenEndBlock updates the steaming service with the latest EndBlock messages - ListenEndBlock(ctx types.Context, req abci.RequestEndBlock, res abci.ResponseEndBlock) error + ListenEndBlock(ctx context.Context, req abci.RequestEndBlock, res abci.ResponseEndBlock) error // ListenDeliverTx updates the steaming service with the latest DeliverTx messages - ListenDeliverTx(ctx types.Context, req abci.RequestDeliverTx, res abci.ResponseDeliverTx) error + ListenDeliverTx(ctx context.Context, req abci.RequestDeliverTx, res abci.ResponseDeliverTx) error + // ListenCommit updates the steaming service with the latest Commit event + ListenCommit(ctx context.Context, res abci.ResponseCommit) error } // StreamingService interface for registering WriteListeners with the BaseApp and updating the service with the ABCI messages using the hooks diff --git a/client/cmd.go b/client/cmd.go index 6ea3b3e66fba..af0d2d6a7407 100644 --- a/client/cmd.go +++ b/client/cmd.go @@ -235,7 +235,7 @@ func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, err if clientCtx.From == "" || flagSet.Changed(flags.FlagFrom) { from, _ := flagSet.GetString(flags.FlagFrom) - fromAddr, fromName, keyType, err := GetFromFields(clientCtx.Keyring, from, clientCtx.GenerateOnly) + fromAddr, fromName, keyType, err := GetFromFields(clientCtx, clientCtx.Keyring, from) if err != nil { return clientCtx, err } diff --git a/client/context.go b/client/context.go index eedbdf6fdb65..ecea496c5490 100644 --- a/client/context.go +++ b/client/context.go @@ -333,13 +333,19 @@ func (ctx Context) printOutput(out []byte) error { // GetFromFields returns a from account address, account name and keyring type, given either // an address or key name. If genOnly is true, only a valid Bech32 cosmos // address is returned. -func GetFromFields(kr keyring.Keyring, from string, genOnly bool) (sdk.AccAddress, string, keyring.KeyType, error) { +func GetFromFields(clientCtx Context, kr keyring.Keyring, from string) (sdk.AccAddress, string, keyring.KeyType, error) { if from == "" { return nil, "", 0, nil } - if genOnly { - addr, err := sdk.AccAddressFromBech32(from) + addr, err := sdk.AccAddressFromBech32(from) + switch { + case clientCtx.Simulate: + if err != nil { + return nil, "", 0, errors.Wrap(err, "a valid bech32 address must be provided in simulation mode") + } + return addr, "", 0, nil + case clientCtx.GenerateOnly: if err != nil { return nil, "", 0, errors.Wrap(err, "must provide a valid Bech32 address in generate-only mode") } @@ -348,7 +354,7 @@ func GetFromFields(kr keyring.Keyring, from string, genOnly bool) (sdk.AccAddres } var info keyring.Info - if addr, err := sdk.AccAddressFromBech32(from); err == nil { + if err == nil { info, err = kr.KeyByAddress(addr) if err != nil { return nil, "", 0, err @@ -365,7 +371,7 @@ func GetFromFields(kr keyring.Keyring, from string, genOnly bool) (sdk.AccAddres // NewKeyringFromBackend gets a Keyring object from a backend func NewKeyringFromBackend(ctx Context, backend string) (keyring.Keyring, error) { - if ctx.GenerateOnly || ctx.Simulate { + if ctx.Simulate { return keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, ctx.KeyringDir, ctx.Input, ctx.KeyringOptions...) } diff --git a/client/context_test.go b/client/context_test.go index 9c2e8d4ab19e..e94fbff3b563 100644 --- a/client/context_test.go +++ b/client/context_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "os" + "strings" "testing" "github.com/spf13/viper" @@ -13,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/testutil/network" "github.com/cosmos/cosmos-sdk/testutil/testdata" @@ -113,3 +115,119 @@ func TestCLIQueryConn(t *testing.T) { require.NoError(t, err) require.Equal(t, "hello", res.Message) } + +func TestGetFromFields(t *testing.T) { + ctx := client.Context{} + path := hd.CreateHDPath(118, 0, 0).String() + + testCases := []struct { + name string + clientCtx client.Context + keyring func() keyring.Keyring + from string + expectedErr string + }{ + { + name: "valid key alice from memory keyring", + keyring: func() keyring.Keyring { + kb := keyring.NewInMemory() + + _, _, err := kb.NewMnemonic("alice", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + + return kb + }, + from: "alice", + }, + { + name: "valid key alice from test keyring", + keyring: func() keyring.Keyring { + kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, ctx.KeyringOptions...) + require.NoError(t, err) + + _, _, err = kb.NewMnemonic("alice", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + + return kb + }, + from: "alice", + }, + { + name: "address not present in memory keyring", + keyring: func() keyring.Keyring { + return keyring.NewInMemory() + }, + from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5", + expectedErr: "key with address 8953EB4F1B47C7982A698DEB7C557D6E4F4CD923 not found: key not found", + }, + { + name: "key is not from test keyring", + keyring: func() keyring.Keyring { + kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, ctx.KeyringOptions...) + require.NoError(t, err) + return kb + }, + from: "alice", + expectedErr: "alice.info: key not found", + }, + { + name: "valid bech32 address is allowed when simulation is true", + keyring: func() keyring.Keyring { + return keyring.NewInMemory() + }, + from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5", + clientCtx: client.Context{}.WithSimulation(true), + }, + { + name: "only bech32 address is allowed as from key in simulation mode", + keyring: func() keyring.Keyring { + return keyring.NewInMemory() + }, + from: "alice", + clientCtx: client.Context{}.WithSimulation(true), + expectedErr: "a valid bech32 address must be provided in simulation mode", + }, + { + name: "valid bech32 address is allowed when generate-only is true", + keyring: func() keyring.Keyring { + return keyring.NewInMemory() + }, + from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5", + clientCtx: client.Context{}.WithGenerateOnly(true), + }, + { + name: "only bech32 address is allowed as from key in generate-only mode", + keyring: func() keyring.Keyring { + return keyring.NewInMemory() + }, + from: "alice", + clientCtx: client.Context{}.WithGenerateOnly(true), + expectedErr: "must provide a valid Bech32 address in generate-only mode", + }, + { + name: "only bech32 address is allowed as from key even when key is present in the keyring", + keyring: func() keyring.Keyring { + kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, ctx.KeyringOptions...) + require.NoError(t, err) + + _, _, err = kb.NewMnemonic("alice", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + + return kb + }, + clientCtx: client.Context{}.WithGenerateOnly(true), + from: "alice", + expectedErr: "must provide a valid Bech32 address in generate-only mode", + }, + } + + for _, tc := range testCases { + _, _, _, err := client.GetFromFields(tc.clientCtx, tc.keyring(), tc.from) + if tc.expectedErr == "" { + require.NoError(t, err) + } else { + require.True(t, strings.HasPrefix(err.Error(), tc.expectedErr)) + } + + } +} diff --git a/client/flags/flags.go b/client/flags/flags.go index cfc0242c1023..d29036f94fc2 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -107,7 +107,7 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { cmd.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device") cmd.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ") cmd.Flags().StringP(FlagBroadcastMode, "b", BroadcastSync, "Transaction broadcasting mode (sync|async|block)") - cmd.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it") + cmd.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible)") cmd.Flags().Bool(FlagGenerateOnly, false, "Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase is not accessible)") cmd.Flags().Bool(FlagOffline, false, "Offline mode (does not allow any online functionality") cmd.Flags().BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation") diff --git a/client/tx/factory.go b/client/tx/factory.go index ebd43b7480ad..6297d00f65ec 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -284,7 +284,7 @@ func (f Factory) BuildSimTx(msgs ...sdk.Msg) ([]byte, error) { var pk cryptotypes.PubKey = &secp256k1.PubKey{} // use default public key type - if f.keybase != nil { + if f.simulateAndExecute && f.keybase != nil { infos, _ := f.keybase.List() if len(infos) == 0 { return nil, errors.New("cannot build signature for simulation, key infos slice is empty") diff --git a/contrib/images/simd-env/Dockerfile b/contrib/images/simd-env/Dockerfile index 8adbc8dd8ef2..b83c3b831bac 100644 --- a/contrib/images/simd-env/Dockerfile +++ b/contrib/images/simd-env/Dockerfile @@ -2,7 +2,6 @@ FROM golang:1.18-alpine AS build RUN apk add build-base git linux-headers WORKDIR /work COPY go.mod go.sum /work/ -COPY ./ics23/go/go.mod /work/ics23/go/go.mod RUN go mod download COPY ./ /work diff --git a/crypto/armor.go b/crypto/armor.go index 23f17406b786..9288947bd11a 100644 --- a/crypto/armor.go +++ b/crypto/armor.go @@ -4,12 +4,12 @@ import ( "encoding/hex" "fmt" - "github.com/tendermint/crypto/bcrypt" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/armor" "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" "github.com/cosmos/cosmos-sdk/codec/legacy" + "github.com/cosmos/cosmos-sdk/crypto/keys/bcrypt" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/crypto/armor_test.go b/crypto/armor_test.go index 8c7c0c5257d7..610ac8e72e2b 100644 --- a/crypto/armor_test.go +++ b/crypto/armor_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/tendermint/crypto/bcrypt" tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/armor" "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" @@ -17,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/crypto/keys/bcrypt" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types" diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index d41152978ad2..3a6ec10c0cdc 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -13,13 +13,13 @@ import ( "github.com/99designs/keyring" bip39 "github.com/cosmos/go-bip39" "github.com/pkg/errors" - "github.com/tendermint/crypto/bcrypt" tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/client/input" "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keys/bcrypt" "github.com/cosmos/cosmos-sdk/crypto/ledger" "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -450,11 +450,11 @@ func (ks keystore) Delete(uid string) error { func (ks keystore) KeyByAddress(address sdk.Address) (Info, error) { ik, err := ks.db.Get(addrHexKeyAsString(address)) if err != nil { - return nil, wrapKeyNotFound(err, fmt.Sprint("key with address", address, "not found")) + return nil, wrapKeyNotFound(err, fmt.Sprint("key with address ", address, " not found")) } if len(ik.Data) == 0 { - return nil, wrapKeyNotFound(err, fmt.Sprint("key with address", address, "not found")) + return nil, wrapKeyNotFound(err, fmt.Sprint("key with address ", address, " not found")) } return ks.key(string(ik.Data)) } diff --git a/crypto/keys/bcrypt/base64.go b/crypto/keys/bcrypt/base64.go new file mode 100644 index 000000000000..fc3116090818 --- /dev/null +++ b/crypto/keys/bcrypt/base64.go @@ -0,0 +1,35 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bcrypt + +import "encoding/base64" + +const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +var bcEncoding = base64.NewEncoding(alphabet) + +func base64Encode(src []byte) []byte { + n := bcEncoding.EncodedLen(len(src)) + dst := make([]byte, n) + bcEncoding.Encode(dst, src) + for dst[n-1] == '=' { + n-- + } + return dst[:n] +} + +func base64Decode(src []byte) ([]byte, error) { + numOfEquals := 4 - (len(src) % 4) + for i := 0; i < numOfEquals; i++ { + src = append(src, '=') + } + + dst := make([]byte, bcEncoding.DecodedLen(len(src))) + n, err := bcEncoding.Decode(dst, src) + if err != nil { + return nil, err + } + return dst[:n], nil +} diff --git a/crypto/keys/bcrypt/bcrypt.go b/crypto/keys/bcrypt/bcrypt.go new file mode 100644 index 000000000000..4093f8cdb192 --- /dev/null +++ b/crypto/keys/bcrypt/bcrypt.go @@ -0,0 +1,291 @@ +// MODIFIED BY TENDERMINT TO EXPOSE `salt` in `GenerateFromPassword`. +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing +// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf +package bcrypt + +// The code is a port of Provos and Mazières's C implementation. +import ( + "crypto/subtle" + "errors" + "fmt" + "strconv" + + "golang.org/x/crypto/blowfish" //nolint:staticcheck // used in original https://cs.opensource.google/go/x/crypto/+/master:bcrypt/bcrypt.go +) + +const ( + MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword + MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword + DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword +) + +// ErrMismatchedHashAndPassword is returned from CompareHashAndPassword when a password and hash do +// not match. +var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password") + +// ErrHashTooShort is returned from CompareHashAndPassword when a hash is too short to +// be a bcrypt hash. +var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password") + +// The error returned from CompareHashAndPassword when a hash was created with +// a bcrypt algorithm newer than this implementation. +type HashVersionTooNewError byte + +func (hv HashVersionTooNewError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion) +} + +// The error returned from CompareHashAndPassword when a hash starts with something other than '$' +type InvalidHashPrefixError byte + +func (ih InvalidHashPrefixError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih)) +} + +type InvalidCostError int + +func (ic InvalidCostError) Error() string { + return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), MinCost, MaxCost) +} + +const ( + majorVersion = '2' + minorVersion = 'a' + maxSaltSize = 16 + maxCryptedHashSize = 23 + encodedSaltSize = 22 + encodedHashSize = 31 + minHashSize = 59 +) + +// magicCipherData is an IV for the 64 Blowfish encryption calls in +// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes. +var magicCipherData = []byte{ + 0x4f, 0x72, 0x70, 0x68, + 0x65, 0x61, 0x6e, 0x42, + 0x65, 0x68, 0x6f, 0x6c, + 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, + 0x6f, 0x75, 0x62, 0x74, +} + +type hashed struct { + hash []byte + salt []byte + cost int // allowed range is MinCost to MaxCost + major byte + minor byte +} + +// GenerateFromPassword returns the bcrypt hash of the password at the given +// cost. If the cost given is less than MinCost, the cost will be set to +// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, +// to compare the returned hashed password with its cleartext version. +func GenerateFromPassword(salt []byte, password []byte, cost int) ([]byte, error) { + if len(salt) != maxSaltSize { + return nil, fmt.Errorf("salt len must be %v", maxSaltSize) + } + p, err := newFromPassword(salt, password, cost) + if err != nil { + return nil, err + } + return p.Hash(), nil +} + +// CompareHashAndPassword compares a bcrypt hashed password with its possible +// plaintext equivalent. Returns nil on success, or an error on failure. +func CompareHashAndPassword(hashedPassword, password []byte) error { + p, err := newFromHash(hashedPassword) + if err != nil { + return err + } + + otherHash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return err + } + + otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor} + if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 { + return nil + } + + return ErrMismatchedHashAndPassword +} + +// Cost returns the hashing cost used to create the given hashed +// password. When, in the future, the hashing cost of a password system needs +// to be increased in order to adjust for greater computational power, this +// function allows one to establish which passwords need to be updated. +func Cost(hashedPassword []byte) (int, error) { + p, err := newFromHash(hashedPassword) + if err != nil { + return 0, err + } + return p.cost, nil +} + +func newFromPassword(salt []byte, password []byte, cost int) (*hashed, error) { + if cost < MinCost { + cost = DefaultCost + } + p := new(hashed) + p.major = majorVersion + p.minor = minorVersion + + err := checkCost(cost) + if err != nil { + return nil, err + } + p.cost = cost + + p.salt = base64Encode(salt) + hash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return nil, err + } + p.hash = hash + return p, err +} + +func newFromHash(hashedSecret []byte) (*hashed, error) { + if len(hashedSecret) < minHashSize { + return nil, ErrHashTooShort + } + p := new(hashed) + n, err := p.decodeVersion(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + n, err = p.decodeCost(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + + // The "+2" is here because we'll have to append at most 2 '=' to the salt + // when base64 decoding it in expensiveBlowfishSetup(). + p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2) + copy(p.salt, hashedSecret[:encodedSaltSize]) + + hashedSecret = hashedSecret[encodedSaltSize:] + p.hash = make([]byte, len(hashedSecret)) + copy(p.hash, hashedSecret) + + return p, nil +} + +func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) { + cipherData := make([]byte, len(magicCipherData)) + copy(cipherData, magicCipherData) + + c, err := expensiveBlowfishSetup(password, uint32(cost), salt) + if err != nil { + return nil, err + } + + for i := 0; i < 24; i += 8 { + for j := 0; j < 64; j++ { + c.Encrypt(cipherData[i:i+8], cipherData[i:i+8]) + } + } + + // Bug compatibility with C bcrypt implementations. We only encode 23 of + // the 24 bytes encrypted. + hsh := base64Encode(cipherData[:maxCryptedHashSize]) + return hsh, nil +} + +func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) { + csalt, err := base64Decode(salt) + if err != nil { + return nil, err + } + + // Bug compatibility with C bcrypt implementations. They use the trailing + // NULL in the key string during expansion. + // We copy the key to prevent changing the underlying array. + ckey := append(key[:len(key):len(key)], 0) //nolint:gocritic // used in original https://cs.opensource.google/go/x/crypto/+/master:bcrypt/bcrypt.go + + c, err := blowfish.NewSaltedCipher(ckey, csalt) + if err != nil { + return nil, err + } + + var i, rounds uint64 + rounds = 1 << cost + for i = 0; i < rounds; i++ { + blowfish.ExpandKey(ckey, c) + blowfish.ExpandKey(csalt, c) + } + + return c, nil +} + +func (p *hashed) Hash() []byte { + arr := make([]byte, 60) + arr[0] = '$' + arr[1] = p.major + n := 2 + if p.minor != 0 { + arr[2] = p.minor + n = 3 + } + arr[n] = '$' + n++ + copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost))) + n += 2 + arr[n] = '$' + n++ + copy(arr[n:], p.salt) + n += encodedSaltSize + copy(arr[n:], p.hash) + n += encodedHashSize + return arr[:n] +} + +func (p *hashed) decodeVersion(sbytes []byte) (int, error) { + if sbytes[0] != '$' { + return -1, InvalidHashPrefixError(sbytes[0]) + } + if sbytes[1] > majorVersion { + return -1, HashVersionTooNewError(sbytes[1]) + } + p.major = sbytes[1] + n := 3 + if sbytes[2] != '$' { + p.minor = sbytes[2] + n++ + } + return n, nil +} + +// sbytes should begin where decodeVersion left off. +func (p *hashed) decodeCost(sbytes []byte) (int, error) { + cost, err := strconv.Atoi(string(sbytes[0:2])) + if err != nil { + return -1, err + } + err = checkCost(cost) + if err != nil { + return -1, err + } + p.cost = cost + return 3, nil +} + +func (p *hashed) String() string { + return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor) +} + +func checkCost(cost int) error { + if cost < MinCost || cost > MaxCost { + return InvalidCostError(cost) + } + return nil +} diff --git a/crypto/keys/utils.go b/crypto/keys/utils.go new file mode 100644 index 000000000000..2b81337d33c8 --- /dev/null +++ b/crypto/keys/utils.go @@ -0,0 +1,13 @@ +package keys + +import ( + "math/big" + + "github.com/cosmos/cosmos-sdk/crypto/keys/internal/ecdsa" +) + +// Replicates https://github.com/cosmos/cosmos-sdk/blob/44fbb0df9cea049d588e76bf930177d777552cf3/crypto/ledger/ledger_secp256k1.go#L228 +// DO NOT USE. This is a temporary workaround that is cleaned-up in v0.47+ +func IsOverHalfOrder(sigS *big.Int) bool { + return !ecdsa.IsSNormalized(sigS) +} diff --git a/crypto/ledger/ledger_mock.go b/crypto/ledger/ledger_mock.go index 6be29aafb212..97c6f65f43bb 100644 --- a/crypto/ledger/ledger_mock.go +++ b/crypto/ledger/ledger_mock.go @@ -9,10 +9,8 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/pkg/errors" - secp256k1 "github.com/tendermint/btcd/btcec" - "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/go-bip39" + "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/crypto/hd" csecp256k1 "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -39,11 +37,11 @@ func (mock LedgerSECP256K1Mock) Close() error { // as per the original API, it returns an uncompressed key func (mock LedgerSECP256K1Mock) GetPublicKeySECP256K1(derivationPath []uint32) ([]byte, error) { if derivationPath[0] != 44 { - return nil, errors.New("Invalid derivation path") + return nil, errors.New("invalid derivation path") } if derivationPath[1] != sdk.GetConfig().GetCoinType() { - return nil, errors.New("Invalid derivation path") + return nil, errors.New("invalid derivation path") } seed, err := bip39.NewSeedWithErrorChecking(testdata.TestMnemonic, "") @@ -58,7 +56,7 @@ func (mock LedgerSECP256K1Mock) GetPublicKeySECP256K1(derivationPath []uint32) ( return nil, err } - _, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), derivedPriv[:]) + _, pubkeyObject := btcec.PrivKeyFromBytes(btcec.S256(), derivedPriv) return pubkeyObject.SerializeUncompressed(), nil } @@ -72,7 +70,7 @@ func (mock LedgerSECP256K1Mock) GetAddressPubKeySECP256K1(derivationPath []uint3 } // re-serialize in the 33-byte compressed format - cmp, err := btcec.ParsePubKey(pk[:], btcec.S256()) + cmp, err := btcec.ParsePubKey(pk, btcec.S256()) if err != nil { return nil, "", fmt.Errorf("error parsing public key: %v", err) } @@ -99,16 +97,13 @@ func (mock LedgerSECP256K1Mock) SignSECP256K1(derivationPath []uint32, message [ return nil, err } - priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), derivedPriv[:]) - + priv, _ := btcec.PrivKeyFromBytes(btcec.S256(), derivedPriv) sig, err := priv.Sign(crypto.Sha256(message)) if err != nil { return nil, err } - // Need to return DER as the ledger does - sig2 := btcec.Signature{R: sig.R, S: sig.S} - return sig2.Serialize(), nil + return sig.Serialize(), nil } // ShowAddressSECP256K1 shows the address for the corresponding bip32 derivation path diff --git a/crypto/ledger/ledger_secp256k1.go b/crypto/ledger/ledger_secp256k1.go index 91051a037518..bab06fd40cef 100644 --- a/crypto/ledger/ledger_secp256k1.go +++ b/crypto/ledger/ledger_secp256k1.go @@ -2,14 +2,14 @@ package ledger import ( "fmt" + "math/big" "os" "github.com/btcsuite/btcd/btcec" "github.com/pkg/errors" - tmbtcec "github.com/tendermint/btcd/btcec" - "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -175,8 +175,22 @@ func convertDERtoBER(signatureDER []byte) ([]byte, error) { if err != nil { return nil, err } - sigBER := tmbtcec.Signature{R: sigDER.R, S: sigDER.S} - return sigBER.Serialize(), nil + + // based on https://github.com/tendermint/btcd/blob/ec996c5/btcec/signature.go#L33-L50 + // low 'S' malleability breaker + sigS := sigDER.S + if keys.IsOverHalfOrder(sigS) { + sigS = new(big.Int).Sub(btcec.S256().N, sigS) + } + + rBytes := sigDER.R.Bytes() + sBytes := sigS.Bytes() + sigBytes := make([]byte, 64) + // 0 pad the byte arrays from the left if they aren't big enough. + copy(sigBytes[32-len(rBytes):32], rBytes) + copy(sigBytes[64-len(sBytes):64], sBytes) + + return sigBytes, nil } func getDevice() (SECP256K1, error) { diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 2144772fd7ae..3b4b4efd25e6 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -33,9 +33,9 @@ module.exports = { editLinks: true, label: "sdk", algolia: { - id: "BH4D9OD16A", - key: "ac317234e6a42074175369b2f42e9754", - index: "cosmos-sdk" + id: "QLS2QSP47E", + key: "067b84458bfa80c295e1d4f12c461911", + index: "cosmos_network_vue" }, versions: [ { diff --git a/docs/architecture/adr-038-state-listening.md b/docs/architecture/adr-038-state-listening.md index e6d321e8cfbd..74f92d2f67b5 100644 --- a/docs/architecture/adr-038-state-listening.md +++ b/docs/architecture/adr-038-state-listening.md @@ -2,7 +2,12 @@ ## Changelog -- 11/23/2020: Initial draft +* 11/23/2020: Initial draft +* 10/14/2022: + * Add `ListenCommit`, flatten the state writes in a block to a single batch. + * Remove listeners from cache stores, should only listen to `rootmulti.Store`. + * Remove `HaltAppOnDeliveryError()`, the errors are propogated by default, the implementations should return nil if don't want to propogate errors. + ## Status @@ -20,8 +25,8 @@ In addition to these request/response queries, it would be beneficial to have a ## Decision -We will modify the `MultiStore` interface and its concrete (`rootmulti` and `cachemulti`) implementations and introduce a new `listenkv.Store` to allow listening to state changes in underlying KVStores. -We will also introduce the tooling for writing these state changes out to files and configuring this service. +We will modify the `CommitMultiStore` interface and its concrete (`rootmulti`) implementations and introduce a new `listenkv.Store` to allow listening to state changes in underlying KVStores. We don't need to listen to cache stores, because we can't be sure that the writes will be committed eventually, and the writes are duplicated in `rootmulti.Store` eventually, so we should only listen to `rootmulti.Store`. +We will introduce a plugin system for configuring and running streaming services that write these state changes and their surrounding ABCI message context to different destinations. ### Listening interface @@ -31,16 +36,16 @@ In a new file, `store/types/listening.go`, we will create a `WriteListener` inte // WriteListener interface for streaming data out from a listenkv.Store type WriteListener interface { // if value is nil then it was deleted - // storeKey indicates the source KVStore, to facilitate using the the same WriteListener across separate KVStores + // storeKey indicates the source KVStore, to facilitate using the same WriteListener across separate KVStores // delete bool indicates if it was a delete; true: delete, false: set - OnWrite(storeKey StoreKey, key []byte, value []byte, delete bool) error + OnWrite(storeKey StoreKey, key []byte, value []byte, delete bool) error } ``` ### Listener type -We will create a concrete implementation of the `WriteListener` interface in `store/types/listening.go`, that writes out protobuf -encoded KV pairs to an underlying `io.Writer`. +We will create two concrete implementations of the `WriteListener` interface in `store/types/listening.go`, that writes out protobuf +encoded KV pairs to an underlying `io.Writer`, and simply accumulate them in memory. This will include defining a simple protobuf type for the KV pairs. In addition to the key and value fields this message will include the StoreKey for the originating KVStore so that we can write out from separate KVStores to the same stream/file @@ -73,19 +78,55 @@ func NewStoreKVPairWriteListener(w io.Writer, m codec.BinaryCodec) *StoreKVPairW // OnWrite satisfies the WriteListener interface by writing length-prefixed protobuf encoded StoreKVPairs func (wl *StoreKVPairWriteListener) OnWrite(storeKey types.StoreKey, key []byte, value []byte, delete bool) error error { - kvPair := new(types.StoreKVPair) - kvPair.StoreKey = storeKey.Name() - kvPair.Delete = Delete - kvPair.Key = key - kvPair.Value = value - by, err := wl.marshaller.MarshalBinaryLengthPrefixed(kvPair) - if err != nil { - return err - } - if _, err := wl.writer.Write(by); err != nil { - return err - } - return nil + kvPair := new(types.StoreKVPair) + kvPair.StoreKey = storeKey.Name() + kvPair.Delete = Delete + kvPair.Key = key + kvPair.Value = value + by, err := wl.marshaller.MarshalBinaryLengthPrefixed(kvPair) + if err != nil { + return err + } + if _, err := wl.writer.Write(by); err != nil { + return err + } + return nil +} +``` + +```golang +// MemoryListener listens to the state writes and accumulate the records in memory. +type MemoryListener struct { + key StoreKey + stateCache []StoreKVPair +} + +// NewMemoryListener creates a listener that accumulate the state writes in memory. +func NewMemoryListener(key StoreKey) *MemoryListener { + return &MemoryListener{key: key} +} + +// OnWrite implements WriteListener interface +func (fl *MemoryListener) OnWrite(storeKey StoreKey, key []byte, value []byte, delete bool) error { + fl.stateCache = append(fl.stateCache, StoreKVPair{ + StoreKey: storeKey.Name(), + Delete: delete, + Key: key, + Value: value, + }) + return nil +} + +// PopStateCache returns the current state caches and set to nil +func (fl *MemoryListener) PopStateCache() []StoreKVPair { + res := fl.stateCache + fl.stateCache = nil + return res +} + +// StoreKey returns the storeKey it listens to +func (fl *MemoryListener) StoreKey() StoreKey { + return fl.key } ``` @@ -99,333 +140,148 @@ We can configure the `Store` with a set of `WriteListener`s which stream the out // Operations are traced on each core KVStore call and written to any of the // underlying listeners with the proper key and operation permissions type Store struct { - parent types.KVStore - listeners []types.WriteListener - parentStoreKey types.StoreKey + parent types.KVStore + listeners []types.WriteListener + parentStoreKey types.StoreKey } // NewStore returns a reference to a new traceKVStore given a parent // KVStore implementation and a buffered writer. func NewStore(parent types.KVStore, psk types.StoreKey, listeners []types.WriteListener) *Store { - return &Store{parent: parent, listeners: listeners, parentStoreKey: psk} + return &Store{parent: parent, listeners: listeners, parentStoreKey: psk} } // Set implements the KVStore interface. It traces a write operation and // delegates the Set call to the parent KVStore. func (s *Store) Set(key []byte, value []byte) { - types.AssertValidKey(key) - s.parent.Set(key, value) - s.onWrite(false, key, value) + types.AssertValidKey(key) + s.parent.Set(key, value) + s.onWrite(false, key, value) } // Delete implements the KVStore interface. It traces a write operation and // delegates the Delete call to the parent KVStore. func (s *Store) Delete(key []byte) { - s.parent.Delete(key) - s.onWrite(true, key, nil) + s.parent.Delete(key) + s.onWrite(true, key, nil) } -// onWrite writes a KVStore operation to all of the WriteListeners +// onWrite writes a KVStore operation to all the WriteListeners func (s *Store) onWrite(delete bool, key, value []byte) { - for _, l := range s.listeners { - if err := l.OnWrite(s.parentStoreKey, key, value, delete); err != nil { - // log error - } - } + for _, l := range s.listeners { + if err := l.OnWrite(s.parentStoreKey, key, value, delete); err != nil { + // log error + } + } } ``` ### MultiStore interface updates -We will update the `MultiStore` interface to allow us to wrap a set of listeners around a specific `KVStore`. -Additionally, we will update the `CacheWrap` and `CacheWrapper` interfaces to enable listening in the caching layer. - -```go -type MultiStore interface { - ... - - // ListeningEnabled returns if listening is enabled for the KVStore belonging the provided StoreKey - ListeningEnabled(key StoreKey) bool - - // AddListeners adds WriteListeners for the KVStore belonging to the provided StoreKey - // It appends the listeners to a current set, if one already exists - AddListeners(key StoreKey, listeners []WriteListener) -} -``` +We will update the `CommitMultiStore` interface to allow us to wrap a set of listeners around a specific `KVStore`. ```go -type CacheWrap interface { - ... - - // CacheWrapWithListeners recursively wraps again with listening enabled - CacheWrapWithListeners(storeKey types.StoreKey, listeners []WriteListener) CacheWrap -} +type CommitMultiStore interface { + ... -type CacheWrapper interface { - ... + // ListeningEnabled returns if listening is enabled for the KVStore belonging the provided StoreKey + ListeningEnabled(key StoreKey) bool - // CacheWrapWithListeners recursively wraps again with listening enabled - CacheWrapWithListeners(storeKey types.StoreKey, listeners []WriteListener) CacheWrap + // AddListeners adds WriteListeners for the KVStore belonging to the provided StoreKey + // It appends the listeners to a current set, if one already exists + AddListeners(key StoreKey, listeners []WriteListener) } ``` ### MultiStore implementation updates -We will modify all of the `Store` and `MultiStore` implementations to satisfy these new interfaces, and adjust the `rootmulti` `GetKVStore` method +We will modify all of the `CommitMultiStore` implementations to satisfy these new interfaces, and adjust the `rootmulti` `GetKVStore` method to wrap the returned `KVStore` with a `listenkv.Store` if listening is turned on for that `Store`. ```go func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore { - store := rs.stores[key].(types.KVStore) + store := rs.stores[key].(types.KVStore) - if rs.TracingEnabled() { - store = tracekv.NewStore(store, rs.traceWriter, rs.traceContext) - } - if rs.ListeningEnabled(key) { - store = listenkv.NewStore(key, store, rs.listeners[key]) - } + if rs.TracingEnabled() { + store = tracekv.NewStore(store, rs.traceWriter, rs.traceContext) + } + if rs.ListeningEnabled(key) { + store = listenkv.NewStore(key, store, rs.listeners[key]) + } - return store + return store } ``` -We will also adjust the `cachemulti` constructor methods and the `rootmulti` `CacheMultiStore` method to forward the listeners -to and enable listening in the cache layer. +We will also adjust the `rootmulti` `CacheMultiStore` method to wrap the stores with `listenkv.Store` to enable listening when the cache layer writes. ```go func (rs *Store) CacheMultiStore() types.CacheMultiStore { stores := make(map[types.StoreKey]types.CacheWrapper) for k, v := range rs.stores { - stores[k] = v + store := v.(types.KVStore) + // Wire the listenkv.Store to allow listeners to observe the writes from the cache store, + // set same listeners on cache store will observe duplicated writes. + if rs.ListeningEnabled(k) { + store = listenkv.NewStore(store, k, rs.listeners[k]) + } + stores[k] = store } - return cachemulti.NewStore(rs.db, stores, rs.keysByName, rs.traceWriter, rs.traceContext, rs.listeners) + return cachemulti.NewStore(rs.db, stores, rs.keysByName, rs.traceWriter, rs.getTracingContext()) } ``` ### Exposing the data +#### Streaming service + We will introduce a new `StreamingService` interface for exposing `WriteListener` data streams to external consumers. -In addition to streaming state changes as `StoreKVPair`s, the interface satisfies an `ABCIListener` interface that plugs into the BaseApp -and relays ABCI requests and responses so that the service can group the state changes with the ABCI requests that affected them and the ABCI responses they affected. +In addition to streaming state changes as `StoreKVPair`s, the interface satisfies an `ABCIListener` interface that plugs +into the BaseApp and relays ABCI requests and responses so that the service can observe those block metadatas as well. + +The `WriteListener`s of `StreamingService` listens to the `rootmulti.Store`, which is only written into at commit event by the cache store of `deliverState`. ```go // ABCIListener interface used to hook into the ABCI message processing of the BaseApp type ABCIListener interface { - // ListenBeginBlock updates the streaming service with the latest BeginBlock messages - ListenBeginBlock(ctx types.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) error - // ListenEndBlock updates the steaming service with the latest EndBlock messages - ListenEndBlock(ctx types.Context, req abci.RequestEndBlock, res abci.ResponseEndBlock) error - // ListenDeliverTx updates the steaming service with the latest DeliverTx messages - ListenDeliverTx(ctx types.Context, req abci.RequestDeliverTx, res abci.ResponseDeliverTx) error + // ListenBeginBlock updates the streaming service with the latest BeginBlock messages + ListenBeginBlock(ctx types.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) error + // ListenEndBlock updates the steaming service with the latest EndBlock messages + ListenEndBlock(ctx types.Context, req abci.RequestEndBlock, res abci.ResponseEndBlock) error + // ListenDeliverTx updates the steaming service with the latest DeliverTx messages + ListenDeliverTx(ctx types.Context, req abci.RequestDeliverTx, res abci.ResponseDeliverTx) error + // ListenCommit updates the steaming service with the latest Commit message, + // All the state writes of current block should have notified before this message. + ListenCommit(ctx types.Context, res abci.ResponseCommit) error } // StreamingService interface for registering WriteListeners with the BaseApp and updating the service with the ABCI messages using the hooks type StreamingService interface { - // Stream is the streaming service loop, awaits kv pairs and writes them to some destination stream or file - Stream(wg *sync.WaitGroup) error - // Listeners returns the streaming service's listeners for the BaseApp to register - Listeners() map[types.StoreKey][]store.WriteListener - // ABCIListener interface for hooking into the ABCI messages from inside the BaseApp - ABCIListener - // Closer interface - io.Closer -} -``` - -#### Writing state changes to files - -We will introduce an implementation of `StreamingService` which writes state changes out to files as length-prefixed protobuf encoded `StoreKVPair`s. -This service uses the same `StoreKVPairWriteListener` for every KVStore, writing all the KV pairs from every KVStore -out to the same files, relying on the `StoreKey` field in the `StoreKVPair` protobuf message to later distinguish the source for each pair. - -Writing to a file is the simplest approach for streaming the data out to consumers. -This approach also provides the advantages of being persistent and durable, and the files can be read directly, -or an auxiliary streaming services can read from the files and serve the data over a remote interface. - -##### Encoding - -For each pair of `BeginBlock` requests and responses, a file is created and named `block-{N}-begin`, where N is the block number. -At the head of this file the length-prefixed protobuf encoded `BeginBlock` request is written. -At the tail of this file the length-prefixed protobuf encoded `BeginBlock` response is written. -In between these two encoded messages, the state changes that occurred due to the `BeginBlock` request are written chronologically as -a series of length-prefixed protobuf encoded `StoreKVPair`s representing `Set` and `Delete` operations within the KVStores the service -is configured to listen to. - -For each pair of `DeliverTx` requests and responses, a file is created and named `block-{N}-tx-{M}` where N is the block number and M -is the tx number in the block (i.e. 0, 1, 2...). -At the head of this file the length-prefixed protobuf encoded `DeliverTx` request is written. -At the tail of this file the length-prefixed protobuf encoded `DeliverTx` response is written. -In between these two encoded messages, the state changes that occurred due to the `DeliverTx` request are written chronologically as -a series of length-prefixed protobuf encoded `StoreKVPair`s representing `Set` and `Delete` operations within the KVStores the service -is configured to listen to. - -For each pair of `EndBlock` requests and responses, a file is created and named `block-{N}-end`, where N is the block number. -At the head of this file the length-prefixed protobuf encoded `EndBlock` request is written. -At the tail of this file the length-prefixed protobuf encoded `EndBlock` response is written. -In between these two encoded messages, the state changes that occurred due to the `EndBlock` request are written chronologically as -a series of length-prefixed protobuf encoded `StoreKVPair`s representing `Set` and `Delete` operations within the KVStores the service -is configured to listen to. - -##### Decoding - -To decode the files written in the above format we read all the bytes from a given file into memory and segment them into proto -messages based on the length-prefixing of each message. Once segmented, it is known that the first message is the ABCI request, -the last message is the ABCI response, and that every message in between is a `StoreKVPair`. This enables us to decode each segment into -the appropriate message type. - -The type of ABCI req/res, the block height, and the transaction index (where relevant) is known -from the file name, and the KVStore each `StoreKVPair` originates from is known since the `StoreKey` is included as a field in the proto message. - -##### Implementation example - -```go -// FileStreamingService is a concrete implementation of StreamingService that writes state changes out to a file -type FileStreamingService struct { - listeners map[sdk.StoreKey][]storeTypes.WriteListener // the listeners that will be initialized with BaseApp - srcChan <-chan []byte // the channel that all of the WriteListeners write their data out to - filePrefix string // optional prefix for each of the generated files - writeDir string // directory to write files into - dstFile *os.File // the current write output file - marshaller codec.BinaryCodec // marshaller used for re-marshalling the ABCI messages to write them out to the destination files - stateCache [][]byte // cache the protobuf binary encoded StoreKVPairs in the order they are received -} -``` - -This streaming service uses a single instance of a simple intermediate `io.Writer` as the underlying `io.Writer` for its single `StoreKVPairWriteListener`, -It collects KV pairs from every KVStore synchronously off of the same channel, caching them in the order they are received, and then writing -them out to a file generated in response to an ABCI message hook. Files are named as outlined above, with optional prefixes to avoid potential naming collisions -across separate instances. - -```go -// intermediateWriter is used so that we do not need to update the underlying io.Writer inside the StoreKVPairWriteListener -// everytime we begin writing to a new file -type intermediateWriter struct { - outChan chan <-[]byte -} - -// NewIntermediateWriter create an instance of an intermediateWriter that sends to the provided channel -func NewIntermediateWriter(outChan chan <-[]byte) *intermediateWriter { - return &intermediateWriter{ - outChan: outChan, - } -} - -// Write satisfies io.Writer -func (iw *intermediateWriter) Write(b []byte) (int, error) { - iw.outChan <- b - return len(b), nil -} - -// NewFileStreamingService creates a new FileStreamingService for the provided writeDir, (optional) filePrefix, and storeKeys -func NewFileStreamingService(writeDir, filePrefix string, storeKeys []sdk.StoreKey, m codec.BinaryCodec) (*FileStreamingService, error) { - listenChan := make(chan []byte, 0) - iw := NewIntermediateWriter(listenChan) - listener := listen.NewStoreKVPairWriteListener(iw, m) - listners := make(map[sdk.StoreKey][]storeTypes.WriteListener, len(storeKeys)) - // in this case, we are using the same listener for each Store - for _, key := range storeKeys { - listeners[key] = listener - } - // check that the writeDir exists and is writeable so that we can catch the error here at initialization if it is not - // we don't open a dstFile until we receive our first ABCI message - if err := fileutil.IsDirWriteable(writeDir); err != nil { - return nil, err - } - return &FileStreamingService{ - listeners: listeners, - srcChan: listenChan, - filePrefix: filePrefix, - writeDir: writeDir, - marshaller: m, - stateCache: make([][]byte, 0), - }, nil -} - -// Listeners returns the StreamingService's underlying WriteListeners, use for registering them with the BaseApp -func (fss *FileStreamingService) Listeners() map[sdk.StoreKey][]storeTypes.WriteListener { - return fss.listeners -} - -func (fss *FileStreamingService) ListenBeginBlock(ctx sdk.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) { - // NOTE: this could either be done synchronously or asynchronously - // create a new file with the req info according to naming schema - // write req to file - // write all state changes cached for this stage to file - // reset cache - // write res to file - // close file -} - -func (fss *FileStreamingService) ListenEndBlock(ctx sdk.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) { - // NOTE: this could either be done synchronously or asynchronously - // create a new file with the req info according to naming schema - // write req to file - // write all state changes cached for this stage to file - // reset cache - // write res to file - // close file -} - -func (fss *FileStreamingService) ListenDeliverTx(ctx sdk.Context, req abci.RequestDeliverTx, res abci.ResponseDeliverTx) { - // NOTE: this could either be done synchronously or asynchronously - // create a new file with the req info according to naming schema - // NOTE: if the tx failed, handle accordingly - // write req to file - // write all state changes cached for this stage to file - // reset cache - // write res to file - // close file -} - -// Stream spins up a goroutine select loop which awaits length-prefixed binary encoded KV pairs and caches them in the order they were received -func (fss *FileStreamingService) Stream(wg *sync.WaitGroup, quitChan <-chan struct{}) { - wg.Add(1) - go func() { - defer wg.Done() - for { - select { - case <-quitChan: - return - case by := <-fss.srcChan: - fss.stateCache = append(fss.stateCache, by) - } - } - }() + // Stream is the streaming service loop, awaits kv pairs and writes them to a destination stream or file + Stream(wg *sync.WaitGroup) error + // Listeners returns the streaming service's listeners for the BaseApp to register + Listeners() map[types.StoreKey][]store.WriteListener + // ABCIListener interface for hooking into the ABCI messages from inside the BaseApp + ABCIListener + // Closer interface + io.Closer } ``` -#### Auxiliary streaming service - -We will create a separate standalone process that reads and internally queues the state as it is written out to these files -and serves the data over a gRPC API. This API will allow filtering of requested data, e.g. by block number, block/tx hash, ABCI message type, -whether a DeliverTx message failed or succeeded, etc. In addition to unary RPC endpoints this service will expose `stream` RPC endpoints for realtime subscriptions. - -#### File pruning - -Without pruning the number of files can grow indefinitely, this may need to be managed by -the developer in an application or even module-specific manner (e.g. log rotation). -The file naming schema facilitates pruning by block number and/or ABCI message. -The gRPC auxiliary streaming service introduced above will include an option to remove the files as it consumes their data. - -### Configuration - -We will provide detailed documentation on how to configure a `FileStreamingService` from within an app's `AppCreator`, -using the provided `AppOptions` and TOML configuration fields. - #### BaseApp registration We will add a new method to the `BaseApp` to enable the registration of `StreamingService`s: ```go -// SetStreamingService is used to register a streaming service with the BaseApp +// SetStreamingService is used to set a streaming service into the BaseApp hooks and load the listeners into the multistore func (app *BaseApp) SetStreamingService(s StreamingService) { - // set the listeners for each StoreKey + // add the listeners for each StoreKey for key, lis := range s.Listeners() { app.cms.AddListeners(key, lis) } - // register the streaming service hooks within the BaseApp - // BaseApp will pass BeginBlock, DeliverTx, and EndBlock requests and responses to the streaming services to update their ABCI context using these hooks - app.hooks = append(app.hooks, s) + // register the StreamingService within the BaseApp + // BaseApp will pass BeginBlock, DeliverTx, and EndBlock requests and responses to the streaming services to update their ABCI context + app.abciListeners = append(app.abciListeners, s) } ``` @@ -437,10 +293,14 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg ... - // Call the streaming service hooks with the BeginBlock messages - for _, hook := range app.hooks { - hook.ListenBeginBlock(app.deliverState.ctx, req, res) - } + defer func() { + // call the hooks with the BeginBlock messages + for _, streamingListener := range app.abciListeners { + if err := streamingListener.ListenBeginBlock(app.deliverState.ctx, req, res); err != nil { + panic(sdkerrors.Wrapf(err, "BeginBlock listening hook failed, height: %d", req.Header.Height)) + } + } + }() return res } @@ -451,189 +311,179 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc ... - // Call the streaming service hooks with the EndBlock messages - for _, hook := range app.hooks { - hook.ListenEndBlock(app.deliverState.ctx, req, res) - } + defer func() { + // Call the streaming service hooks with the EndBlock messages + for _, streamingListener := range app.abciListeners { + if err := streamingListener.ListenEndBlock(app.deliverState.ctx, req, res); err != nil { + panic(sdkerrors.Wrapf(err, "EndBlock listening hook failed, height: %d", req.Height)) + } + } + }() return res } ``` ```go -func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx { +func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliverTx) { + + defer func() { + // call the hooks with the DeliverTx messages + for _, streamingListener := range app.abciListeners { + if err := streamingListener.ListenDeliverTx(app.deliverState.ctx, req, res); err != nil { + panic(sdkerrors.Wrap(err, "DeliverTx listening hook failed")) + } + } + }() ... - gInfo, result, err := app.runTx(runTxModeDeliver, req.Tx) - if err != nil { - resultStr = "failed" - res := sdkerrors.ResponseDeliverTx(err, gInfo.GasWanted, gInfo.GasUsed, app.trace) - // If we throw and error, be sure to still call the streaming service's hook - for _, hook := range app.hooks { - hook.ListenDeliverTx(app.deliverState.ctx, req, res) - } - return res - } + return res +} +``` - res := abci.ResponseDeliverTx{ - GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints? - GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints? - Log: result.Log, - Data: result.Data, - Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents), +```golang +func (app *BaseApp) Commit() abci.ResponseCommit { + header := app.deliverState.ctx.BlockHeader() + retainHeight := app.GetBlockRetentionHeight(header.Height) + + // Write the DeliverTx state into branched storage and commit the MultiStore. + // The write to the DeliverTx state writes all state transitions to the root + // MultiStore (app.cms) so when Commit() is called is persists those values. + app.deliverState.ms.Write() + commitID := app.cms.Commit() + + res := abci.ResponseCommit{ + Data: commitID.Hash, + RetainHeight: retainHeight, } - // Call the streaming service hooks with the DeliverTx messages - for _, hook := range app.hooks { - hook.ListenDeliverTx(app.deliverState.ctx, req, res) + // call the hooks with the Commit message + for _, streamingListener := range app.abciListeners { + if err := streamingListener.ListenCommit(app.deliverState.ctx, res); err != nil { + panic(sdkerrors.Wrapf(err, "Commit listening hook failed, height: %d", header.Height)) + } } - return res + app.logger.Info("commit synced", "commit", fmt.Sprintf("%X", commitID)) + ... } ``` -#### TOML Configuration +#### Error Handling And Async Consumers -We will provide standard TOML configuration options for configuring a `FileStreamingService` for specific `Store`s. -Note: the actual namespace is TBD. +`ABCIListener`s are called synchronously inside the consensus state machine, the returned error causes panic which in turn halt the consensus state machine. The implementer should be careful not to break consensus unexpectedly or slow down it too much. -```toml -[store] - streamers = [ # if len(streamers) > 0 we are streaming - "file", - ] - -[streamers] - [streamers.file] - keys = ["list", "of", "store", "keys", "we", "want", "to", "expose", "for", "this", "streaming", "service"] - write_dir = "path to the write directory" - prefix = "optional prefix to prepend to the generated file names" +For some async use cases, one can spawn a go-routine internanlly to avoid slow down consensus state machine, and handle the errors internally and always returns `nil` to avoid halting consensus state machine on error. + +Furthermore, for most of the cases, we only need to use the builtin file streamer to listen to state changes directly inside cosmos-sdk, the other consumers should subscribe to the file streamer output externally. + +#### File Streamer + +We provide a minimal filesystem based implementation inside cosmos-sdk, and provides options to write output files reliably, the output files can be further consumed by external consumers, so most of the state listeners actually don't need to live inside the sdk and node, which improves the node robustness and simplify sdk internals. + +The file streamer can be wired in app like this: +```golang +exposeStoreKeys := ... // decide the key list to listen +service, err := file.NewStreamingService(streamingDir, "", exposeStoreKeys, appCodec, logger) +bApp.SetStreamingService(service) ``` -We will also provide a mapping of the TOML `store.streamers` "file" configuration option to a helper functions for constructing the specified -streaming service. In the future, as other streaming services are added, their constructors will be added here as well. +#### Plugin system -Each configured streamer will receive the +We propose a plugin architecture to load and run `StreamingService` implementations. We will introduce a plugin +loading/preloading system that is used to load, initialize, inject, run, and stop Cosmos-SDK plugins. Each plugin +must implement the following interface: ```go -// ServiceConstructor is used to construct a streaming service -type ServiceConstructor func(opts serverTypes.AppOptions, keys []sdk.StoreKey, marshaller codec.BinaryMarshaler) (sdk.StreamingService, error) - -// ServiceType enum for specifying the type of StreamingService -type ServiceType int - -const ( - Unknown ServiceType = iota - File - // add more in the future -) - -// NewStreamingServiceType returns the streaming.ServiceType corresponding to the provided name -func NewStreamingServiceType(name string) ServiceType { - switch strings.ToLower(name) { - case "file", "f": - return File - default: - return Unknown - } -} +// Plugin is the base interface for all kinds of cosmos-sdk plugins +// It will be included in interfaces of different Plugins +type Plugin interface { + // Name should return unique name of the plugin + Name() string -// String returns the string name of a streaming.ServiceType -func (sst ServiceType) String() string { - switch sst { - case File: - return "file" - default: - return "" - } -} + // Version returns current version of the plugin + Version() string -// ServiceConstructorLookupTable is a mapping of streaming.ServiceTypes to streaming.ServiceConstructors -var ServiceConstructorLookupTable = map[ServiceType]ServiceConstructor{ - File: NewFileStreamingService, -} + // Init is called once when the Plugin is being loaded + // The plugin is passed the AppOptions for configuration + // A plugin will not necessarily have a functional Init + Init(env serverTypes.AppOptions) error -// ServiceTypeFromString returns the streaming.ServiceConstructor corresponding to the provided name -func ServiceTypeFromString(name string) (ServiceConstructor, error) { - ssType := NewStreamingServiceType(name) - if ssType == Unknown { - return nil, fmt.Errorf("unrecognized streaming service name %s", name) - } - if constructor, ok := ServiceConstructorLookupTable[ssType]; ok { - return constructor, nil - } - return nil, fmt.Errorf("streaming service constructor of type %s not found", ssType.String()) + // Closer interface for shutting down the plugin process + io.Closer } +``` + +The `Name` method returns a plugin's name. +The `Version` method returns a plugin's version. +The `Init` method initializes a plugin with the provided `AppOptions`. +The io.Closer is used to shut down the plugin service. + +For the purposes of this ADR we introduce a single kind of plugin- a state streaming plugin. +We will define a `StateStreamingPlugin` interface which extends the above `Plugin` interface to support a state streaming service. + +```go +// StateStreamingPlugin interface for plugins that load a baseapp.StreamingService onto a baseapp.BaseApp +type StateStreamingPlugin interface { + // Register configures and registers the plugin streaming service with the BaseApp + Register(bApp *baseapp.BaseApp, marshaller codec.BinaryCodec, keys map[string]*types.KVStoreKey) error -// NewFileStreamingService is the streaming.ServiceConstructor function for creating a FileStreamingService -func NewFileStreamingService(opts serverTypes.AppOptions, keys []sdk.StoreKey, marshaller codec.BinaryMarshaler) (sdk.StreamingService, error) { - filePrefix := cast.ToString(opts.Get("streamers.file.prefix")) - fileDir := cast.ToString(opts.Get("streamers.file.write_dir")) - return file.NewStreamingService(fileDir, filePrefix, keys, marshaller) + // Start starts the background streaming process of the plugin streaming service + Start(wg *sync.WaitGroup) error + + // Plugin is the base Plugin interface + Plugin } ``` -#### Example configuration +The `Register` method is used during App construction to register the plugin's streaming service with an App's BaseApp using the BaseApp's `SetStreamingService` method. +The `Start` method is used during App construction to start the registered plugin streaming services and maintain synchronization with them. -As a demonstration, we will implement the state watching features as part of SimApp. -For example, the below is a very rudimentary integration of the state listening features into the SimApp `AppCreator` function: +e.g. in `NewSimApp`: ```go func NewSimApp( - logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool, - homePath string, invCheckPeriod uint, encodingConfig simappparams.EncodingConfig, - appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + loadLatest bool, + appOpts servertypes.AppOptions, + baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { ... keys := sdk.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, - minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, - evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, ) - // configure state listening capabilities using AppOptions - listeners := cast.ToStringSlice(appOpts.Get("store.streamers")) - for _, listenerName := range listeners { - // get the store keys allowed to be exposed for this streaming service - exposeKeyStrs := cast.ToStringSlice(appOpts.Get(fmt.Sprintf("streamers.%s.keys", streamerName))) - var exposeStoreKeys []sdk.StoreKey - if exposeAll(exposeKeyStrs) { // if list contains `*`, expose all StoreKeys - exposeStoreKeys = make([]sdk.StoreKey, 0, len(keys)) - for _, storeKey := range keys { - exposeStoreKeys = append(exposeStoreKeys, storeKey) - } - } else { - exposeStoreKeys = make([]sdk.StoreKey, 0, len(exposeKeyStrs)) - for _, keyStr := range exposeKeyStrs { - if storeKey, ok := keys[keyStr]; ok { - exposeStoreKeys = append(exposeStoreKeys, storeKey) - } - } - } - if len(exposeStoreKeys) == 0 { // short circuit if we are not exposing anything - continue - } - // get the constructor for this listener name - constructor, err := baseapp.NewStreamingServiceConstructor(listenerName) + pluginsOnKey := fmt.Sprintf("%s.%s", plugin.PLUGINS_TOML_KEY, plugin.PLUGINS_ON_TOML_KEY) + if cast.ToBool(appOpts.Get(pluginsOnKey)) { + // this loads the preloaded and any plugins found in `plugins.dir` + pluginLoader, err := loader.NewPluginLoader(appOpts, logger) if err != nil { - tmos.Exit(err.Error()) // or continue? + // handle error } - // generate the streaming service using the constructor, appOptions, and the StoreKeys we want to expose - streamingService, err := constructor(appOpts, exposeStoreKeys, appCodec) - if err != nil { - tmos.Exit(err.Error()) + + // initialize the loaded plugins + if err := pluginLoader.Initialize(); err != nil { + // handle error + } + + // register the plugin(s) with the BaseApp + if err := pluginLoader.Inject(bApp, appCodec, keys); err != nil { + // handle error } - // register the streaming service with the BaseApp - bApp.RegisterStreamingService(streamingService) - // waitgroup and quit channel for optional shutdown coordination of the streaming service + + // start the plugin services, optionally use wg to synchronize shutdown using io.Closer wg := new(sync.WaitGroup) - quitChan := make(chan struct{})) - // kick off the background streaming service loop - streamingService.Stream(wg, quitChan) // maybe this should be done from inside BaseApp instead? + if err := pluginLoader.Start(wg); err != nil { + // handler error + } } ... @@ -642,23 +492,78 @@ func NewSimApp( } ``` + +#### Configuration + +The plugin system will be configured within an app's app.toml file. + +```toml +[plugins] + on = false # turn the plugin system, as a whole, on or off + enabled = ["list", "of", "plugin", "names", "to", "enable"] + dir = "the directory to load non-preloaded plugins from; defaults to cosmos-sdk/plugin/plugins" +``` + +There will be three parameters for configuring the plugin system: `plugins.on`, `plugins.enabled` and `plugins.dir`. +`plugins.on` is a bool that turns on or off the plugin system at large, `plugins.dir` directs the system to a directory +to load plugins from, and `plugins.enabled` provides `opt-in` semantics to plugin names to enable (including preloaded plugins). + +Configuration of a given plugin is ultimately specific to the plugin, but we will introduce some standards here: + +Plugin TOML configuration should be split into separate sub-tables for each kind of plugin (e.g. `plugins.streaming`). + +Within these sub-tables, the parameters for a specific plugin of that kind are included in another sub-table (e.g. `plugins.streaming.file`). +It is generally expected, but not required, that a streaming service plugin can be configured with a set of store keys +(e.g. `plugins.streaming.file.keys`) for the stores it listens to and a flag (e.g. `plugins.streaming.file.halt_app_on_delivery_error`) +that signifies whether the service operates in a fire-and-forget capacity, or stop the BaseApp when an error occurs in +any of `ListenBeginBlock`, `ListenEndBlock` and `ListenDeliverTx`. + +e.g. + +```toml +[plugins] + on = false # turn the plugin system, as a whole, on or off + enabled = ["list", "of", "plugin", "names", "to", "enable"] + dir = "the directory to load non-preloaded plugins from; defaults to " + [plugins.streaming] # a mapping of plugin-specific streaming service parameters, mapped to their plugin name + [plugins.streaming.file] # the specific parameters for the file streaming service plugin + keys = ["list", "of", "store", "keys", "we", "want", "to", "expose", "for", "this", "streaming", "service"] + write_dir = "path to the write directory" + prefix = "optional prefix to prepend to the generated file names" + halt_app_on_delivery_error = "false" # false == fire-and-forget; true == stop the application + [plugins.streaming.kafka] + keys = [] + topic_prefix = "block" # Optional prefix for topic names where data will be stored. + flush_timeout_ms = 5000 # Flush and wait for outstanding messages and requests to complete delivery when calling `StreamingService.Close(). (milliseconds) + halt_app_on_delivery_error = true # Whether or not to halt the application when plugin fails to deliver message(s). + ... +``` + +#### Encoding and decoding streams + +ADR-038 introduces the interfaces and types for streaming state changes out from KVStores, associating this +data with their related ABCI requests and responses, and registering a service for consuming this data and streaming it to some destination in a final format. +Instead of prescribing a final data format in this ADR, it is left to a specific plugin implementation to define and document this format. +We take this approach because flexibility in the final format is necessary to support a wide range of streaming service plugins. For example, +the data format for a streaming service that writes the data out to a set of files will differ from the data format that is written to a Kafka topic. + ## Consequences These changes will provide a means of subscribing to KVStore state changes in real time. ### Backwards Compatibility -- This ADR changes the `MultiStore`, `CacheWrap`, and `CacheWrapper` interfaces, implementations supporting the previous version of these interfaces will not support the new ones +* This ADR changes the `CommitMultiStore` interface, implementations supporting the previous version of these interfaces will not support the new ones ### Positive -- Ability to listen to KVStore state changes in real time and expose these events to external consumers +* Ability to listen to KVStore state changes in real time and expose these events to external consumers ### Negative -- Changes `MultiStore`, `CacheWrap`, and `CacheWrapper` interfaces +* Changes `CommitMultiStore`interface ### Neutral -- Introduces additional- but optional- complexity to configuring and running a cosmos application -- If an application developer opts to use these features to expose data, they need to be aware of the ramifications/risks of that data exposure as it pertains to the specifics of their application +* Introduces additional- but optional- complexity to configuring and running a cosmos application +* If an application developer opts to use these features to expose data, they need to be aware of the ramifications/risks of that data exposure as it pertains to the specifics of their application diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 68f6526dc448..c39486bbab45 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -185,6 +185,8 @@ - [StoreInfo](#cosmos.base.store.v1beta1.StoreInfo) - [cosmos/base/store/v1beta1/listening.proto](#cosmos/base/store/v1beta1/listening.proto) + - [BlockMetadata](#cosmos.base.store.v1beta1.BlockMetadata) + - [BlockMetadata.DeliverTx](#cosmos.base.store.v1beta1.BlockMetadata.DeliverTx) - [StoreKVPair](#cosmos.base.store.v1beta1.StoreKVPair) - [cosmos/base/tendermint/v1beta1/query.proto](#cosmos/base/tendermint/v1beta1/query.proto) @@ -3006,6 +3008,43 @@ between a store name and the commit ID. + + +### BlockMetadata +BlockMetadata contains all the abci event data of a block +the file streamer dump them into files together with the state changes. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `request_begin_block` | [tendermint.abci.RequestBeginBlock](#tendermint.abci.RequestBeginBlock) | | | +| `response_begin_block` | [tendermint.abci.ResponseBeginBlock](#tendermint.abci.ResponseBeginBlock) | | | +| `deliver_txs` | [BlockMetadata.DeliverTx](#cosmos.base.store.v1beta1.BlockMetadata.DeliverTx) | repeated | | +| `request_end_block` | [tendermint.abci.RequestEndBlock](#tendermint.abci.RequestEndBlock) | | | +| `response_end_block` | [tendermint.abci.ResponseEndBlock](#tendermint.abci.ResponseEndBlock) | | | +| `response_commit` | [tendermint.abci.ResponseCommit](#tendermint.abci.ResponseCommit) | | | + + + + + + + + +### BlockMetadata.DeliverTx +DeliverTx encapulate deliver tx request and response. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `request` | [tendermint.abci.RequestDeliverTx](#tendermint.abci.RequestDeliverTx) | | | +| `response` | [tendermint.abci.ResponseDeliverTx](#tendermint.abci.ResponseDeliverTx) | | | + + + + + + ### StoreKVPair diff --git a/go.mod b/go.mod index c36e4a74cb85..891ed06a1e51 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,18 @@ -go 1.18 - module github.com/cosmos/cosmos-sdk +go 1.18 + require ( github.com/99designs/keyring v1.1.6 - github.com/armon/go-metrics v0.3.10 - github.com/bgentry/speakeasy v0.1.0 - github.com/btcsuite/btcd v0.22.1 + github.com/armon/go-metrics v0.4.0 + github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 + github.com/btcsuite/btcd v0.22.2 github.com/coinbase/rosetta-sdk-go v0.7.0 - github.com/confio/ics23/go v0.7.0 + github.com/confio/ics23/go v0.9.0 github.com/cosmos/btcutil v1.0.4 github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/iavl v0.19.3 - github.com/cosmos/ledger-cosmos-go v0.11.1 + github.com/cosmos/iavl v0.19.4 + github.com/cosmos/ledger-cosmos-go v0.12.2 github.com/gogo/gateway v1.1.0 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 @@ -24,7 +24,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 github.com/improbable-eng/grpc-web v0.14.1 - github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b + github.com/jhump/protoreflect v1.13.1-0.20220928232736-101791cb1b4c github.com/magiconair/properties v1.8.6 github.com/mattn/go-isatty v0.0.16 github.com/otiai10/copy v1.6.0 @@ -35,51 +35,50 @@ require ( github.com/regen-network/cosmos-proto v0.3.1 github.com/rs/zerolog v1.27.0 github.com/spf13/cast v1.5.0 - github.com/spf13/cobra v1.5.0 + github.com/spf13/cobra v1.6.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.13.0 - github.com/stretchr/testify v1.8.0 - github.com/tendermint/btcd v0.1.1 - github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 + github.com/spf13/viper v1.14.0 + github.com/stretchr/testify v1.8.1 github.com/tendermint/go-amino v0.16.0 - github.com/tendermint/tendermint v0.34.22 + github.com/tendermint/tendermint v0.34.24 github.com/tendermint/tm-db v0.6.6 - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa + github.com/tidwall/btree v1.5.0 + golang.org/x/crypto v0.2.0 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e - google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b - google.golang.org/grpc v1.50.0 - google.golang.org/protobuf v1.28.1 + google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e + google.golang.org/grpc v1.50.1 + google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 gopkg.in/yaml.v2 v2.4.0 ) require ( filippo.io/edwards25519 v1.0.0-beta.2 // indirect + github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/DataDog/zstd v1.4.5 // indirect github.com/Workiva/go-datastructures v1.0.53 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cosmos/ledger-go v0.9.2 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect - github.com/danieljoos/wincred v1.0.2 // indirect + github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect + github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c // indirect github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/fsnotify/fsnotify v1.6.0 // 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/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect - github.com/golang/snappy v0.0.3 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.0.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect @@ -90,8 +89,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect - github.com/klauspost/compress v1.15.9 // indirect + github.com/klauspost/compress v1.15.11 // indirect github.com/lib/pq v1.10.6 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -105,38 +103,46 @@ require ( github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/cors v1.8.2 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/afero v1.9.2 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.4.1 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect - github.com/zondax/hid v0.9.0 // indirect + github.com/zondax/hid v0.9.1 // indirect + github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect - golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect - golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/net v0.2.0 // indirect + golang.org/x/sys v0.2.0 // indirect + golang.org/x/term v0.2.0 // indirect + golang.org/x/text v0.4.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect ) replace ( - github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76 + // Use cosmos keyring + github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 - // vendor ics23 - github.com/confio/ics23/go => ./ics23/go + // dgrijalva/jwt-go is deprecated and doesn't receive security updates. + // TODO: remove it: https://github.com/cosmos/cosmos-sdk/issues/13134 + github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2 // Fix upstream GHSA-h395-qcrw-5vmq vulnerability. // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 - github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0 + github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.8.1 + + // Use regen gogoproto fork + // This for is replaced by cosmos/gogoproto in future versions github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 github.com/jhump/protoreflect => github.com/jhump/protoreflect v1.9.0 + // use informal system fork of tendermint + github.com/tendermint/tendermint => github.com/informalsystems/tendermint v0.34.24 // latest grpc doesn't work with with our modified proto compiler, so we need to enforce // the following version across all dependencies. diff --git a/go.sum b/go.sum index 08be076135a9..e217efc966cf 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-beta.2 h1:/BZRNzm8N4K4eWfK28dL4yescorxtO7YG1yun8fy+pI= filippo.io/edwards25519 v1.0.0-beta.2/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= @@ -60,7 +62,7 @@ github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -89,8 +91,8 @@ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1: github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= @@ -101,18 +103,18 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= +github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= -github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= -github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd v0.22.2 h1:vBZ+lGGd1XubpOWO67ITJpAEsICWhA0YzqkcpkgNBfo= +github.com/btcsuite/btcd v0.22.2/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= @@ -146,6 +148,8 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= github.com/coinbase/rosetta-sdk-go v0.7.0/go.mod h1:7nD3oBPIiHqhRprqvMgPoGxe/nyq3yftRmpsy29coWE= +github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= +github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= 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= @@ -158,27 +162,27 @@ github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/Tv github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= -github.com/cosmos/iavl v0.19.3 h1:cESO0OwTTxQm5rmyESKW+zESheDUYI7CcZDWWDwnuxg= -github.com/cosmos/iavl v0.19.3/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= -github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76 h1:DdzS1m6o/pCqeZ8VOAit/gyATedRgjvkVI+UCrLpyuU= -github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76/go.mod h1:0mkLWIoZuQ7uBoospo5Q9zIpqq6rYCPJDSUdeCJvPM8= -github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= -github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= -github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= -github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= +github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok= +github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= +github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= +github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= +github.com/cosmos/ledger-cosmos-go v0.12.2/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI= 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.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= -github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= @@ -187,7 +191,6 @@ github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDm github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI= github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -195,13 +198,13 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b h1:HBah4D48ypg3J7Np4N+HY/ZR76fx3HEUGxDU6Uk39oQ= -github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= +github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= @@ -229,14 +232,14 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= -github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -256,12 +259,12 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -271,11 +274,14 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -310,8 +316,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -325,7 +331,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= @@ -428,6 +434,8 @@ github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7P github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/informalsystems/tendermint v0.34.24 h1:2beNEg5tp+U5oj/Md+0xDBsMHGbdue31T3OrstS6xS0= +github.com/informalsystems/tendermint v0.34.24/go.mod h1:rXVrl4OYzmIa1I91av3iLv2HS0fGSiucyW9J4aMTpKI= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -455,28 +463,29 @@ github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= -github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= 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.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= @@ -548,6 +557,7 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -569,7 +579,7 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= +github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -596,6 +606,7 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP 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= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= @@ -605,6 +616,7 @@ github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCr github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -649,8 +661,9 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= @@ -665,7 +678,9 @@ github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRr github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= @@ -698,15 +713,15 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -715,8 +730,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= -github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= +github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= +github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= @@ -725,9 +740,9 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify 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= @@ -735,24 +750,22 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/syndtr/goleveldb v1.0.1-0.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/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= -github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= -github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= -github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/tendermint v0.34.22 h1:XMhtC8s8QqJO4l/dn+TkQvevTRSow3Vixjclr41o+2Q= -github.com/tendermint/tendermint v0.34.22/go.mod h1:YpP5vBEAKUT4g6oyfjKgFeZmdB/GjkJAxfF+cgmJg6Y= github.com/tendermint/tm-db v0.6.6 h1:EzhaOfR0bdKyATqcd5PNeyeq8r+V4bRPHBfyFdD9kGM= github.com/tendermint/tm-db v0.6.6/go.mod h1:wP8d49A85B7/erz/r4YbKssKw6ylsO/hKtFk7E1aWZI= +github.com/tidwall/btree v1.5.0 h1:iV0yVY/frd7r6qGBXfEYs7DH0gTDgrKTrDjS7xt/IyQ= +github.com/tidwall/btree v1.5.0/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE= github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -763,11 +776,11 @@ github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+l github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= @@ -781,8 +794,10 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= -github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo= +github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-go v0.14.1 h1:Pip65OOl4iJ84WTpA4BKChvOufMhhbxED3BaihoZN4c= +github.com/zondax/ledger-go v0.14.1/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= @@ -821,9 +836,10 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= +golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= 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= @@ -863,6 +879,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -911,8 +928,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -953,7 +970,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/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-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1002,17 +1018,19 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-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-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U= -golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= 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= @@ -1021,8 +1039,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1084,11 +1103,12 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1158,8 +1178,8 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b h1:SfSkJugek6xm7lWywqth4r2iTrYLpD8lOj1nMIIhMNM= -google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e h1:S9GbmC1iCgvbLyAokVCwiO6tVIrU9Y7c5oMx1V/ki/Y= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1175,13 +1195,16 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk= +google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1201,7 +1224,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/ics23/.gitignore b/ics23/.gitignore deleted file mode 100644 index 22d0d82f8095..000000000000 --- a/ics23/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vendor diff --git a/ics23/go/Makefile b/ics23/go/Makefile deleted file mode 100644 index aebfcb20d751..000000000000 --- a/ics23/go/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -.PHONY: protoc test - -# make sure we turn on go modules -export GO111MODULE := on - -# PROTOC_FLAGS := -I=.. -I=./vendor -I=$(GOPATH)/src -PROTOC_FLAGS := -I=.. -I=$(GOPATH)/src - -test: - go test . - -protoc: -# @go mod vendor - protoc --gocosmos_out=plugins=interfacetype+grpc,Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types:. $(PROTOC_FLAGS) ../proofs.proto - -install-proto-dep: - @echo "Installing protoc-gen-gocosmos..." - @go install github.com/regen-network/cosmos-proto/protoc-gen-gocosmos - - diff --git a/ics23/go/compress.go b/ics23/go/compress.go deleted file mode 100644 index ebe3275e3897..000000000000 --- a/ics23/go/compress.go +++ /dev/null @@ -1,157 +0,0 @@ -package ics23 - -// IsCompressed returns true if the proof was compressed -func IsCompressed(proof *CommitmentProof) bool { - return proof.GetCompressed() != nil -} - -// Compress will return a CompressedBatchProof if the input is BatchProof -// Otherwise it will return the input. -// This is safe to call multiple times (idempotent) -func Compress(proof *CommitmentProof) *CommitmentProof { - batch := proof.GetBatch() - if batch == nil { - return proof - } - return &CommitmentProof{ - Proof: &CommitmentProof_Compressed{ - Compressed: compress(batch), - }, - } -} - -// Decompress will return a BatchProof if the input is CompressedBatchProof -// Otherwise it will return the input. -// This is safe to call multiple times (idempotent) -func Decompress(proof *CommitmentProof) *CommitmentProof { - comp := proof.GetCompressed() - if comp != nil { - return &CommitmentProof{ - Proof: &CommitmentProof_Batch{ - Batch: decompress(comp), - }, - } - } - return proof -} - -func compress(batch *BatchProof) *CompressedBatchProof { - var centries []*CompressedBatchEntry - var lookup []*InnerOp - registry := make(map[string]int32) - - for _, entry := range batch.Entries { - centry := compressEntry(entry, &lookup, registry) - centries = append(centries, centry) - } - - return &CompressedBatchProof{ - Entries: centries, - LookupInners: lookup, - } -} - -func compressEntry(entry *BatchEntry, lookup *[]*InnerOp, registry map[string]int32) *CompressedBatchEntry { - if exist := entry.GetExist(); exist != nil { - return &CompressedBatchEntry{ - Proof: &CompressedBatchEntry_Exist{ - Exist: compressExist(exist, lookup, registry), - }, - } - } - - non := entry.GetNonexist() - return &CompressedBatchEntry{ - Proof: &CompressedBatchEntry_Nonexist{ - Nonexist: &CompressedNonExistenceProof{ - Key: non.Key, - Left: compressExist(non.Left, lookup, registry), - Right: compressExist(non.Right, lookup, registry), - }, - }, - } -} - -func compressExist(exist *ExistenceProof, lookup *[]*InnerOp, registry map[string]int32) *CompressedExistenceProof { - if exist == nil { - return nil - } - res := &CompressedExistenceProof{ - Key: exist.Key, - Value: exist.Value, - Leaf: exist.Leaf, - Path: make([]int32, len(exist.Path)), - } - for i, step := range exist.Path { - res.Path[i] = compressStep(step, lookup, registry) - } - return res -} - -func compressStep(step *InnerOp, lookup *[]*InnerOp, registry map[string]int32) int32 { - bz, err := step.Marshal() - if err != nil { - panic(err) - } - sig := string(bz) - - // load from cache if there - if num, ok := registry[sig]; ok { - return num - } - - // create new step if not there - num := int32(len(*lookup)) - *lookup = append(*lookup, step) - registry[sig] = num - return num -} - -func decompress(comp *CompressedBatchProof) *BatchProof { - lookup := comp.LookupInners - - var entries []*BatchEntry - - for _, centry := range comp.Entries { - entry := decompressEntry(centry, lookup) - entries = append(entries, entry) - } - - return &BatchProof{ - Entries: entries, - } -} - -// TendermintSpec constrains the format from proofs-tendermint (crypto/merkle SimpleProof) -var TendermintSpec = &ProofSpec{ - LeafSpec: &LeafOp{ - Prefix: []byte{0}, - PrehashKey: HashOp_NO_HASH, - Hash: HashOp_SHA256, - PrehashValue: HashOp_SHA256, - Length: LengthOp_VAR_PROTO, - }, - InnerSpec: &InnerSpec{ - ChildOrder: []int32{0, 1}, - MinPrefixLength: 1, - MaxPrefixLength: 1, - ChildSize: 32, // (no length byte) - Hash: HashOp_SHA256, - }, -} - -func decompressExist(exist *CompressedExistenceProof, lookup []*InnerOp) *ExistenceProof { - if exist == nil { - return nil - } - res := &ExistenceProof{ - Key: exist.Key, - Value: exist.Value, - Leaf: exist.Leaf, - Path: make([]*InnerOp, len(exist.Path)), - } - for i, step := range exist.Path { - res.Path[i] = lookup[step] - } - return res -} diff --git a/ics23/go/go.mod b/ics23/go/go.mod deleted file mode 100644 index 4588c6961d28..000000000000 --- a/ics23/go/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/confio/ics23/go - -go 1.14 - -require ( - github.com/gogo/protobuf v1.3.1 - github.com/pkg/errors v0.8.1 - github.com/stretchr/testify v1.8.0 // indirect - golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 -) diff --git a/ics23/go/go.sum b/ics23/go/go.sum deleted file mode 100644 index 9f866e054cf4..000000000000 --- a/ics23/go/go.sum +++ /dev/null @@ -1,28 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/ics23/go/ics23.go b/ics23/go/ics23.go deleted file mode 100644 index 9a79dc3fc302..000000000000 --- a/ics23/go/ics23.go +++ /dev/null @@ -1,175 +0,0 @@ -/* -* -This implements the client side functions as specified in -https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments - -In particular: - - // Assumes ExistenceProof - type verifyMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key, value: Value) => boolean - - // Assumes NonExistenceProof - type verifyNonMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key) => boolean - - // Assumes BatchProof - required ExistenceProofs may be a subset of all items proven - type batchVerifyMembership = (root: CommitmentRoot, proof: CommitmentProof, items: Map) => boolean - - // Assumes BatchProof - required NonExistenceProofs may be a subset of all items proven - type batchVerifyNonMembership = (root: CommitmentRoot, proof: CommitmentProof, keys: Set) => boolean - -We make an adjustment to accept a Spec to ensure the provided proof is in the format of the expected merkle store. -This can avoid an range of attacks on fake preimages, as we need to be careful on how to map key, value -> leaf -and determine neighbors -*/ -package ics23 - -import ( - "bytes" - "fmt" -) - -// CommitmentRoot is a byte slice that represents the merkle root of a tree that can be used to validate proofs -type CommitmentRoot []byte - -// VerifyMembership returns true iff -// proof is (contains) an ExistenceProof for the given key and value AND -// calculating the root for the ExistenceProof matches the provided CommitmentRoot -func VerifyMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, key []byte, value []byte) bool { - // decompress it before running code (no-op if not compressed) - proof = Decompress(proof) - ep := getExistProofForKey(proof, key) - if ep == nil { - return false - } - err := ep.Verify(spec, root, key, value) - return err == nil -} - -// VerifyNonMembership returns true iff -// proof is (contains) a NonExistenceProof -// both left and right sub-proofs are valid existence proofs (see above) or nil -// left and right proofs are neighbors (or left/right most if one is nil) -// provided key is between the keys of the two proofs -func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, key []byte) bool { - // decompress it before running code (no-op if not compressed) - proof = Decompress(proof) - np := getNonExistProofForKey(proof, key) - if np == nil { - return false - } - err := np.Verify(spec, root, key) - return err == nil -} - -// BatchVerifyMembership will ensure all items are also proven by the CommitmentProof (which should be a BatchProof, -// unless there is one item, when a ExistenceProof may work) -func BatchVerifyMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, items map[string][]byte) bool { - // decompress it before running code (no-op if not compressed) - once for batch - proof = Decompress(proof) - for k, v := range items { - valid := VerifyMembership(spec, root, proof, []byte(k), v) - if !valid { - return false - } - } - return true -} - -// BatchVerifyNonMembership will ensure all items are also proven to not be in the Commitment by the CommitmentProof -// (which should be a BatchProof, unless there is one item, when a NonExistenceProof may work) -func BatchVerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, keys [][]byte) bool { - // decompress it before running code (no-op if not compressed) - once for batch - proof = Decompress(proof) - for _, k := range keys { - valid := VerifyNonMembership(spec, root, proof, k) - if !valid { - return false - } - } - return true -} - -// CombineProofs takes a number of commitment proofs (simple or batch) and -// converts them into a batch and compresses them. -// -// This is designed for proof generation libraries to create efficient batches -func CombineProofs(proofs []*CommitmentProof) (*CommitmentProof, error) { - var entries []*BatchEntry - - for _, proof := range proofs { - if ex := proof.GetExist(); ex != nil { - entry := &BatchEntry{ - Proof: &BatchEntry_Exist{ - Exist: ex, - }, - } - entries = append(entries, entry) - } else if non := proof.GetNonexist(); non != nil { - entry := &BatchEntry{ - Proof: &BatchEntry_Nonexist{ - Nonexist: non, - }, - } - entries = append(entries, entry) - } else if batch := proof.GetBatch(); batch != nil { - entries = append(entries, batch.Entries...) - } else if comp := proof.GetCompressed(); comp != nil { - decomp := Decompress(proof) - entries = append(entries, decomp.GetBatch().Entries...) - } else { - return nil, fmt.Errorf("proof neither exist or nonexist: %#v", proof.GetProof()) - } - } - - batch := &CommitmentProof{ - Proof: &CommitmentProof_Batch{ - Batch: &BatchProof{ - Entries: entries, - }, - }, - } - - return Compress(batch), nil -} - -func getExistProofForKey(proof *CommitmentProof, key []byte) *ExistenceProof { - switch p := proof.Proof.(type) { - case *CommitmentProof_Exist: - ep := p.Exist - if bytes.Equal(ep.Key, key) { - return ep - } - case *CommitmentProof_Batch: - for _, sub := range p.Batch.Entries { - if ep := sub.GetExist(); ep != nil && bytes.Equal(ep.Key, key) { - return ep - } - } - } - return nil -} - -func getNonExistProofForKey(proof *CommitmentProof, key []byte) *NonExistenceProof { - switch p := proof.Proof.(type) { - case *CommitmentProof_Nonexist: - np := p.Nonexist - if isLeft(np.Left, key) && isRight(np.Right, key) { - return np - } - case *CommitmentProof_Batch: - for _, sub := range p.Batch.Entries { - if np := sub.GetNonexist(); np != nil && isLeft(np.Left, key) && isRight(np.Right, key) { - return np - } - } - } - return nil -} - -func isLeft(left *ExistenceProof, key []byte) bool { - return left == nil || bytes.Compare(left.Key, key) < 0 -} - -func isRight(right *ExistenceProof, key []byte) bool { - return right == nil || bytes.Compare(right.Key, key) > 0 -} diff --git a/ics23/go/ops.go b/ics23/go/ops.go deleted file mode 100644 index 6666dac5c00c..000000000000 --- a/ics23/go/ops.go +++ /dev/null @@ -1,250 +0,0 @@ -package ics23 - -import ( - "bytes" - "crypto" - "encoding/binary" - "fmt" - "hash" - - // adds sha256 capability to crypto.SHA256 - _ "crypto/sha256" - // adds sha512 capability to crypto.SHA512 - _ "crypto/sha512" - - // adds ripemd160 capability to crypto.RIPEMD160 - _ "golang.org/x/crypto/ripemd160" - - "github.com/pkg/errors" -) - -// validate the IAVL Ops -func z(op opType, b int) error { - r := bytes.NewReader(op.GetPrefix()) - - values := []int64{} - for i := 0; i < 3; i++ { - varInt, err := binary.ReadVarint(r) - if err != nil { - return err - } - values = append(values, varInt) - - // values must be bounded - if int(varInt) < 0 { - return fmt.Errorf("wrong value in IAVL leaf op") - } - } - if int(values[0]) < b { - return fmt.Errorf("wrong value in IAVL leaf op") - } - - r2 := r.Len() - if b == 0 { - if r2 != 0 { - return fmt.Errorf("invalid op") - } - } else { - if !(r2^(0xff&0x01) == 0 || r2 == (0xde+int('v'))/10) { - return fmt.Errorf("invalid op") - } - if op.GetHash()^1 != 0 { - return fmt.Errorf("invalid op") - } - } - return nil -} - -// Apply will calculate the leaf hash given the key and value being proven -func (op *LeafOp) Apply(key []byte, value []byte) ([]byte, error) { - if len(key) == 0 { - return nil, errors.New("Leaf op needs key") - } - if len(value) == 0 { - return nil, errors.New("Leaf op needs value") - } - pkey, err := prepareLeafData(op.PrehashKey, op.Length, key) - if err != nil { - return nil, errors.Wrap(err, "prehash key") - } - pvalue, err := prepareLeafData(op.PrehashValue, op.Length, value) - if err != nil { - return nil, errors.Wrap(err, "prehash value") - } - data := append(op.Prefix, pkey...) - data = append(data, pvalue...) - return doHash(op.Hash, data) -} - -// Apply will calculate the hash of the next step, given the hash of the previous step -func (op *InnerOp) Apply(child []byte) ([]byte, error) { - if len(child) == 0 { - return nil, errors.Errorf("Inner op needs child value") - } - preimage := append(op.Prefix, child...) - preimage = append(preimage, op.Suffix...) - return doHash(op.Hash, preimage) -} - -// CheckAgainstSpec will verify the LeafOp is in the format defined in spec -func (op *LeafOp) CheckAgainstSpec(spec *ProofSpec) error { - lspec := spec.LeafSpec - - if g(spec) { - fmt.Println("Dragonberry Active") - err := z(op, 0) - if err != nil { - return err - } - } - - if op.Hash != lspec.Hash { - return errors.Errorf("Unexpected HashOp: %d", op.Hash) - } - if op.PrehashKey != lspec.PrehashKey { - return errors.Errorf("Unexpected PrehashKey: %d", op.PrehashKey) - } - if op.PrehashValue != lspec.PrehashValue { - return errors.Errorf("Unexpected PrehashValue: %d", op.PrehashValue) - } - if op.Length != lspec.Length { - return errors.Errorf("Unexpected LengthOp: %d", op.Length) - } - if !bytes.HasPrefix(op.Prefix, lspec.Prefix) { - return errors.Errorf("Leaf Prefix doesn't start with %X", lspec.Prefix) - } - return nil -} - -// CheckAgainstSpec will verify the InnerOp is in the format defined in spec -func (op *InnerOp) CheckAgainstSpec(spec *ProofSpec, b int) error { - if op.Hash != spec.InnerSpec.Hash { - return errors.Errorf("Unexpected HashOp: %d", op.Hash) - } - - if g(spec) { - err := z(op, b) - if err != nil { - return err - } - } - - leafPrefix := spec.LeafSpec.Prefix - if bytes.HasPrefix(op.Prefix, leafPrefix) { - return errors.Errorf("Inner Prefix starts with %X", leafPrefix) - } - if len(op.Prefix) < int(spec.InnerSpec.MinPrefixLength) { - return errors.Errorf("InnerOp prefix too short (%d)", len(op.Prefix)) - } - maxLeftChildBytes := (len(spec.InnerSpec.ChildOrder) - 1) * int(spec.InnerSpec.ChildSize) - if len(op.Prefix) > int(spec.InnerSpec.MaxPrefixLength)+maxLeftChildBytes { - return errors.Errorf("InnerOp prefix too long (%d)", len(op.Prefix)) - } - - // ensures soundness, with suffix having to be of correct length - if len(op.Suffix)%int(spec.InnerSpec.ChildSize) != 0 { - return errors.Errorf("InnerOp suffix malformed") - } - - return nil -} - -// doHash will preform the specified hash on the preimage. -// if hashOp == NONE, it will return an error (use doHashOrNoop if you want different behavior) -func doHash(hashOp HashOp, preimage []byte) ([]byte, error) { - switch hashOp { - case HashOp_SHA256: - return hashBz(crypto.SHA256, preimage) - case HashOp_SHA512: - return hashBz(crypto.SHA512, preimage) - case HashOp_RIPEMD160: - return hashBz(crypto.RIPEMD160, preimage) - case HashOp_BITCOIN: - // ripemd160(sha256(x)) - sha := crypto.SHA256.New() - sha.Write(preimage) - tmp := sha.Sum(nil) - hash := crypto.RIPEMD160.New() - hash.Write(tmp) - return hash.Sum(nil), nil - case HashOp_SHA512_256: - hash := crypto.SHA512_256.New() - hash.Write(preimage) - return hash.Sum(nil), nil - } - return nil, errors.Errorf("Unsupported hashop: %d", hashOp) -} - -type hasher interface { - New() hash.Hash -} - -func hashBz(h hasher, preimage []byte) ([]byte, error) { - hh := h.New() - hh.Write(preimage) - return hh.Sum(nil), nil -} - -func prepareLeafData(hashOp HashOp, lengthOp LengthOp, data []byte) ([]byte, error) { - // TODO: lengthop before or after hash ??? - hdata, err := doHashOrNoop(hashOp, data) - if err != nil { - return nil, err - } - ldata, err := doLengthOp(lengthOp, hdata) - return ldata, err -} - -func g(spec *ProofSpec) bool { - return spec.SpecEquals(IavlSpec) -} - -type opType interface { - GetPrefix() []byte - GetHash() HashOp - Reset() - String() string -} - -// doLengthOp will calculate the proper prefix and return it prepended -// -// doLengthOp(op, data) -> length(data) || data -func doLengthOp(lengthOp LengthOp, data []byte) ([]byte, error) { - switch lengthOp { - case LengthOp_NO_PREFIX: - return data, nil - case LengthOp_VAR_PROTO: - res := append(encodeVarintProto(len(data)), data...) - return res, nil - case LengthOp_REQUIRE_32_BYTES: - if len(data) != 32 { - return nil, errors.Errorf("Data was %d bytes, not 32", len(data)) - } - return data, nil - case LengthOp_REQUIRE_64_BYTES: - if len(data) != 64 { - return nil, errors.Errorf("Data was %d bytes, not 64", len(data)) - } - return data, nil - case LengthOp_FIXED32_LITTLE: - res := make([]byte, 4, 4+len(data)) - binary.LittleEndian.PutUint32(res[:4], uint32(len(data))) - res = append(res, data...) - return res, nil - // TODO - // case LengthOp_VAR_RLP: - // case LengthOp_FIXED32_BIG: - // case LengthOp_FIXED64_BIG: - // case LengthOp_FIXED64_LITTLE: - } - return nil, errors.Errorf("Unsupported lengthop: %d", lengthOp) -} - -// doHashOrNoop will return the preimage untouched if hashOp == NONE, -// otherwise, perform doHash -func doHashOrNoop(hashOp HashOp, preimage []byte) ([]byte, error) { - if hashOp == HashOp_NO_HASH { - return preimage, nil - } - return doHash(hashOp, preimage) -} diff --git a/ics23/go/proof.go b/ics23/go/proof.go deleted file mode 100644 index cec590590fe7..000000000000 --- a/ics23/go/proof.go +++ /dev/null @@ -1,452 +0,0 @@ -package ics23 - -import ( - "bytes" - - "github.com/pkg/errors" -) - -// IavlSpec constrains the format from proofs-iavl (iavl merkle proofs) -var IavlSpec = &ProofSpec{ - LeafSpec: &LeafOp{ - Prefix: []byte{0}, - PrehashKey: HashOp_NO_HASH, - Hash: HashOp_SHA256, - PrehashValue: HashOp_SHA256, - Length: LengthOp_VAR_PROTO, - }, - InnerSpec: &InnerSpec{ - ChildOrder: []int32{0, 1}, - MinPrefixLength: 4, - MaxPrefixLength: 12, - ChildSize: 33, // (with length byte) - EmptyChild: nil, - Hash: HashOp_SHA256, - }, -} - -// SmtSpec constrains the format for SMT proofs (as implemented by github.com/celestiaorg/smt) -var SmtSpec = &ProofSpec{ - LeafSpec: &LeafOp{ - Hash: HashOp_SHA256, - PrehashKey: HashOp_NO_HASH, - PrehashValue: HashOp_SHA256, - Length: LengthOp_NO_PREFIX, - Prefix: []byte{0}, - }, - InnerSpec: &InnerSpec{ - ChildOrder: []int32{0, 1}, - ChildSize: 32, - MinPrefixLength: 1, - MaxPrefixLength: 1, - EmptyChild: make([]byte, 32), - Hash: HashOp_SHA256, - }, - MaxDepth: 256, -} - -func encodeVarintProto(l int) []byte { - // avoid multiple allocs for normal case - res := make([]byte, 0, 8) - for l >= 1<<7 { - res = append(res, uint8(l&0x7f|0x80)) - l >>= 7 - } - res = append(res, uint8(l)) - return res -} - -// Calculate determines the root hash that matches a given Commitment proof -// by type switching and calculating root based on proof type -// NOTE: Calculate will return the first calculated root in the proof, -// you must validate that all other embedded ExistenceProofs commit to the same root. -// This can be done with the Verify method -func (p *CommitmentProof) Calculate() (CommitmentRoot, error) { - switch v := p.Proof.(type) { - case *CommitmentProof_Exist: - return v.Exist.Calculate() - case *CommitmentProof_Nonexist: - return v.Nonexist.Calculate() - case *CommitmentProof_Batch: - if len(v.Batch.GetEntries()) == 0 || v.Batch.GetEntries()[0] == nil { - return nil, errors.New("batch proof has empty entry") - } - if e := v.Batch.GetEntries()[0].GetExist(); e != nil { - return e.Calculate() - } - if n := v.Batch.GetEntries()[0].GetNonexist(); n != nil { - return n.Calculate() - } - case *CommitmentProof_Compressed: - proof := Decompress(p) - return proof.Calculate() - default: - return nil, errors.New("unrecognized proof type") - } - return nil, errors.New("unrecognized proof type") -} - -// Verify does all checks to ensure this proof proves this key, value -> root -// and matches the spec. -func (p *ExistenceProof) Verify(spec *ProofSpec, root CommitmentRoot, key []byte, value []byte) error { - if err := p.CheckAgainstSpec(spec); err != nil { - return err - } - - if !bytes.Equal(key, p.Key) { - return errors.Errorf("Provided key doesn't match proof") - } - if !bytes.Equal(value, p.Value) { - return errors.Errorf("Provided value doesn't match proof") - } - - calc, err := p.calculate(spec) - if err != nil { - return errors.Wrap(err, "Error calculating root") - } - if !bytes.Equal(root, calc) { - return errors.Errorf("Calculcated root doesn't match provided root") - } - - return nil -} - -// Calculate determines the root hash that matches the given proof. -// You must validate the result is what you have in a header. -// Returns error if the calculations cannot be performed. -func (p *ExistenceProof) Calculate() (CommitmentRoot, error) { - return p.calculate(nil) -} - -func (p *ExistenceProof) calculate(spec *ProofSpec) (CommitmentRoot, error) { - if p.GetLeaf() == nil { - return nil, errors.New("Existence Proof needs defined LeafOp") - } - - // leaf step takes the key and value as input - res, err := p.Leaf.Apply(p.Key, p.Value) - if err != nil { - return nil, errors.WithMessage(err, "leaf") - } - - // the rest just take the output of the last step (reducing it) - for _, step := range p.Path { - res, err = step.Apply(res) - if err != nil { - return nil, errors.WithMessage(err, "inner") - } - if spec != nil { - if len(res) > int(spec.InnerSpec.ChildSize) && int(spec.InnerSpec.ChildSize) >= 32 { - return nil, errors.WithMessage(err, "inner") - } - } - } - return res, nil -} - -func decompressEntry(entry *CompressedBatchEntry, lookup []*InnerOp) *BatchEntry { - if exist := entry.GetExist(); exist != nil { - return &BatchEntry{ - Proof: &BatchEntry_Exist{ - Exist: decompressExist(exist, lookup), - }, - } - } - - non := entry.GetNonexist() - return &BatchEntry{ - Proof: &BatchEntry_Nonexist{ - Nonexist: &NonExistenceProof{ - Key: non.Key, - Left: decompressExist(non.Left, lookup), - Right: decompressExist(non.Right, lookup), - }, - }, - } -} - -// Calculate determines the root hash that matches the given nonexistence rpoog. -// You must validate the result is what you have in a header. -// Returns error if the calculations cannot be performed. -func (p *NonExistenceProof) Calculate() (CommitmentRoot, error) { - // A Nonexist proof may have left or right proof nil - switch { - case p.Left != nil: - return p.Left.Calculate() - case p.Right != nil: - return p.Right.Calculate() - default: - return nil, errors.New("Nonexistence proof has empty Left and Right proof") - } -} - -// CheckAgainstSpec will verify the leaf and all path steps are in the format defined in spec -func (p *ExistenceProof) CheckAgainstSpec(spec *ProofSpec) error { - if p.GetLeaf() == nil { - return errors.New("Existence Proof needs defined LeafOp") - } - err := p.Leaf.CheckAgainstSpec(spec) - if err != nil { - return errors.WithMessage(err, "leaf") - } - if spec.MinDepth > 0 && len(p.Path) < int(spec.MinDepth) { - return errors.Errorf("InnerOps depth too short: %d", len(p.Path)) - } - if spec.MaxDepth > 0 && len(p.Path) > int(spec.MaxDepth) { - return errors.Errorf("InnerOps depth too long: %d", len(p.Path)) - } - - layerNum := 1 - - for _, inner := range p.Path { - if err := inner.CheckAgainstSpec(spec, layerNum); err != nil { - return errors.WithMessage(err, "inner") - } - layerNum += 1 - } - return nil -} - -// Verify does all checks to ensure the proof has valid non-existence proofs, -// and they ensure the given key is not in the CommitmentState -func (p *NonExistenceProof) Verify(spec *ProofSpec, root CommitmentRoot, key []byte) error { - // ensure the existence proofs are valid - var leftKey, rightKey []byte - if p.Left != nil { - if err := p.Left.Verify(spec, root, p.Left.Key, p.Left.Value); err != nil { - return errors.Wrap(err, "left proof") - } - leftKey = p.Left.Key - } - if p.Right != nil { - if err := p.Right.Verify(spec, root, p.Right.Key, p.Right.Value); err != nil { - return errors.Wrap(err, "right proof") - } - rightKey = p.Right.Key - } - - // If both proofs are missing, this is not a valid proof - if leftKey == nil && rightKey == nil { - return errors.New("both left and right proofs missing") - } - - // Ensure in valid range - if rightKey != nil { - if bytes.Compare(key, rightKey) >= 0 { - return errors.New("key is not left of right proof") - } - } - if leftKey != nil { - if bytes.Compare(key, leftKey) <= 0 { - return errors.New("key is not right of left proof") - } - } - - if leftKey == nil { - if !IsLeftMost(spec.InnerSpec, p.Right.Path) { - return errors.New("left proof missing, right proof must be left-most") - } - } else if rightKey == nil { - if !IsRightMost(spec.InnerSpec, p.Left.Path) { - return errors.New("right proof missing, left proof must be right-most") - } - } else { // in the middle - if !IsLeftNeighbor(spec.InnerSpec, p.Left.Path, p.Right.Path) { - return errors.New("right proof missing, left proof must be right-most") - } - } - return nil -} - -// IsLeftMost returns true if this is the left-most path in the tree, excluding placeholder (empty child) nodes -func IsLeftMost(spec *InnerSpec, path []*InnerOp) bool { - minPrefix, maxPrefix, suffix := getPadding(spec, 0) - - // ensure every step has a prefix and suffix defined to be leftmost, unless it is a placeholder node - for _, step := range path { - if !hasPadding(step, minPrefix, maxPrefix, suffix) && !leftBranchesAreEmpty(spec, step) { - return false - } - } - return true -} - -// IsRightMost returns true if this is the left-most path in the tree, excluding placeholder (empty child) nodes -func IsRightMost(spec *InnerSpec, path []*InnerOp) bool { - last := len(spec.ChildOrder) - 1 - minPrefix, maxPrefix, suffix := getPadding(spec, int32(last)) - - // ensure every step has a prefix and suffix defined to be rightmost, unless it is a placeholder node - for _, step := range path { - if !hasPadding(step, minPrefix, maxPrefix, suffix) && !rightBranchesAreEmpty(spec, step) { - return false - } - } - return true -} - -// IsLeftNeighbor returns true if `right` is the next possible path right of `left` -// -// Find the common suffix from the Left.Path and Right.Path and remove it. We have LPath and RPath now, which must be neighbors. -// Validate that LPath[len-1] is the left neighbor of RPath[len-1] -// For step in LPath[0..len-1], validate step is right-most node -// For step in RPath[0..len-1], validate step is left-most node -func IsLeftNeighbor(spec *InnerSpec, left []*InnerOp, right []*InnerOp) bool { - // count common tail (from end, near root) - left, topleft := left[:len(left)-1], left[len(left)-1] - right, topright := right[:len(right)-1], right[len(right)-1] - for bytes.Equal(topleft.Prefix, topright.Prefix) && bytes.Equal(topleft.Suffix, topright.Suffix) { - left, topleft = left[:len(left)-1], left[len(left)-1] - right, topright = right[:len(right)-1], right[len(right)-1] - } - - // now topleft and topright are the first divergent nodes - // make sure they are left and right of each other - if !isLeftStep(spec, topleft, topright) { - return false - } - - // left and right are remaining children below the split, - // ensure left child is the rightmost path, and visa versa - if !IsRightMost(spec, left) { - return false - } - if !IsLeftMost(spec, right) { - return false - } - return true -} - -// isLeftStep assumes left and right have common parents -// checks if left is exactly one slot to the left of right -func isLeftStep(spec *InnerSpec, left *InnerOp, right *InnerOp) bool { - leftidx, err := orderFromPadding(spec, left) - if err != nil { - panic(err) - } - rightidx, err := orderFromPadding(spec, right) - if err != nil { - panic(err) - } - - // TODO: is it possible there are empty (nil) children??? - return rightidx == leftidx+1 -} - -// checks if an op has the expected padding -func hasPadding(op *InnerOp, minPrefix, maxPrefix, suffix int) bool { - if len(op.Prefix) < minPrefix { - return false - } - if len(op.Prefix) > maxPrefix { - return false - } - return len(op.Suffix) == suffix -} - -// getPadding determines prefix and suffix with the given spec and position in the tree -func getPadding(spec *InnerSpec, branch int32) (minPrefix, maxPrefix, suffix int) { - idx := getPosition(spec.ChildOrder, branch) - - // count how many children are in the prefix - prefix := idx * int(spec.ChildSize) - minPrefix = prefix + int(spec.MinPrefixLength) - maxPrefix = prefix + int(spec.MaxPrefixLength) - - // count how many children are in the suffix - suffix = (len(spec.ChildOrder) - 1 - idx) * int(spec.ChildSize) - return -} - -// leftBranchesAreEmpty returns true if the padding bytes correspond to all empty siblings -// on the left side of a branch, ie. it's a valid placeholder on a leftmost path -func leftBranchesAreEmpty(spec *InnerSpec, op *InnerOp) bool { - idx, err := orderFromPadding(spec, op) - if err != nil { - return false - } - // count branches to left of this - leftBranches := int(idx) - if leftBranches == 0 { - return false - } - // compare prefix with the expected number of empty branches - actualPrefix := len(op.Prefix) - leftBranches*int(spec.ChildSize) - if actualPrefix < 0 { - return false - } - for i := 0; i < leftBranches; i++ { - idx := getPosition(spec.ChildOrder, int32(i)) - from := actualPrefix + idx*int(spec.ChildSize) - if !bytes.Equal(spec.EmptyChild, op.Prefix[from:from+int(spec.ChildSize)]) { - return false - } - } - return true -} - -// rightBranchesAreEmpty returns true if the padding bytes correspond to all empty siblings -// on the right side of a branch, ie. it's a valid placeholder on a rightmost path -func rightBranchesAreEmpty(spec *InnerSpec, op *InnerOp) bool { - idx, err := orderFromPadding(spec, op) - if err != nil { - return false - } - // count branches to right of this one - rightBranches := len(spec.ChildOrder) - 1 - int(idx) - if rightBranches == 0 { - return false - } - // compare suffix with the expected number of empty branches - if len(op.Suffix) != rightBranches*int(spec.ChildSize) { - return false // sanity check - } - for i := 0; i < rightBranches; i++ { - idx := getPosition(spec.ChildOrder, int32(i)) - from := idx * int(spec.ChildSize) - if !bytes.Equal(spec.EmptyChild, op.Suffix[from:from+int(spec.ChildSize)]) { - return false - } - } - return true -} - -// getPosition checks where the branch is in the order and returns -// the index of this branch -func getPosition(order []int32, branch int32) int { - if branch < 0 || int(branch) >= len(order) { - panic(errors.Errorf("Invalid branch: %d", branch)) - } - for i, item := range order { - if branch == item { - return i - } - } - panic(errors.Errorf("Branch %d not found in order %v", branch, order)) -} - -// This will look at the proof and determine which order it is... -// So we can see if it is branch 0, 1, 2 etc... to determine neighbors -func orderFromPadding(spec *InnerSpec, inner *InnerOp) (int32, error) { - maxbranch := int32(len(spec.ChildOrder)) - for branch := int32(0); branch < maxbranch; branch++ { - minp, maxp, suffix := getPadding(spec, branch) - if hasPadding(inner, minp, maxp, suffix) { - return branch, nil - } - } - return 0, errors.New("Cannot find any valid spacing for this node") -} - -// over-declares equality, which we cosnider fine for now. -func (p *ProofSpec) SpecEquals(spec *ProofSpec) bool { - return p.LeafSpec.Hash == spec.LeafSpec.Hash && - p.LeafSpec.PrehashKey == spec.LeafSpec.PrehashKey && - p.LeafSpec.PrehashValue == spec.LeafSpec.PrehashValue && - p.LeafSpec.Length == spec.LeafSpec.Length && - p.InnerSpec.Hash == spec.InnerSpec.Hash && - p.InnerSpec.MinPrefixLength == spec.InnerSpec.MinPrefixLength && - p.InnerSpec.MaxPrefixLength == spec.InnerSpec.MaxPrefixLength && - p.InnerSpec.ChildSize == spec.InnerSpec.ChildSize && - len(p.InnerSpec.ChildOrder) == len(spec.InnerSpec.ChildOrder) -} diff --git a/ics23/go/proofs.pb.go b/ics23/go/proofs.pb.go deleted file mode 100644 index 7ebd4a61f43a..000000000000 --- a/ics23/go/proofs.pb.go +++ /dev/null @@ -1,4548 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: proofs.proto - -package ics23 - -import ( - fmt "fmt" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type HashOp int32 - -const ( - // NO_HASH is the default if no data passed. Note this is an illegal argument some places. - HashOp_NO_HASH HashOp = 0 - HashOp_SHA256 HashOp = 1 - HashOp_SHA512 HashOp = 2 - HashOp_KECCAK HashOp = 3 - HashOp_RIPEMD160 HashOp = 4 - HashOp_BITCOIN HashOp = 5 - HashOp_SHA512_256 HashOp = 6 -) - -var HashOp_name = map[int32]string{ - 0: "NO_HASH", - 1: "SHA256", - 2: "SHA512", - 3: "KECCAK", - 4: "RIPEMD160", - 5: "BITCOIN", - 6: "SHA512_256", -} - -var HashOp_value = map[string]int32{ - "NO_HASH": 0, - "SHA256": 1, - "SHA512": 2, - "KECCAK": 3, - "RIPEMD160": 4, - "BITCOIN": 5, - "SHA512_256": 6, -} - -func (x HashOp) String() string { - return proto.EnumName(HashOp_name, int32(x)) -} - -func (HashOp) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{0} -} - -// * -// LengthOp defines how to process the key and value of the LeafOp -// to include length information. After encoding the length with the given -// algorithm, the length will be prepended to the key and value bytes. -// (Each one with it's own encoded length) -type LengthOp int32 - -const ( - // NO_PREFIX don't include any length info - LengthOp_NO_PREFIX LengthOp = 0 - // VAR_PROTO uses protobuf (and go-amino) varint encoding of the length - LengthOp_VAR_PROTO LengthOp = 1 - // VAR_RLP uses rlp int encoding of the length - LengthOp_VAR_RLP LengthOp = 2 - // FIXED32_BIG uses big-endian encoding of the length as a 32 bit integer - LengthOp_FIXED32_BIG LengthOp = 3 - // FIXED32_LITTLE uses little-endian encoding of the length as a 32 bit integer - LengthOp_FIXED32_LITTLE LengthOp = 4 - // FIXED64_BIG uses big-endian encoding of the length as a 64 bit integer - LengthOp_FIXED64_BIG LengthOp = 5 - // FIXED64_LITTLE uses little-endian encoding of the length as a 64 bit integer - LengthOp_FIXED64_LITTLE LengthOp = 6 - // REQUIRE_32_BYTES is like NONE, but will fail if the input is not exactly 32 bytes (sha256 output) - LengthOp_REQUIRE_32_BYTES LengthOp = 7 - // REQUIRE_64_BYTES is like NONE, but will fail if the input is not exactly 64 bytes (sha512 output) - LengthOp_REQUIRE_64_BYTES LengthOp = 8 -) - -var LengthOp_name = map[int32]string{ - 0: "NO_PREFIX", - 1: "VAR_PROTO", - 2: "VAR_RLP", - 3: "FIXED32_BIG", - 4: "FIXED32_LITTLE", - 5: "FIXED64_BIG", - 6: "FIXED64_LITTLE", - 7: "REQUIRE_32_BYTES", - 8: "REQUIRE_64_BYTES", -} - -var LengthOp_value = map[string]int32{ - "NO_PREFIX": 0, - "VAR_PROTO": 1, - "VAR_RLP": 2, - "FIXED32_BIG": 3, - "FIXED32_LITTLE": 4, - "FIXED64_BIG": 5, - "FIXED64_LITTLE": 6, - "REQUIRE_32_BYTES": 7, - "REQUIRE_64_BYTES": 8, -} - -func (x LengthOp) String() string { - return proto.EnumName(LengthOp_name, int32(x)) -} - -func (LengthOp) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{1} -} - -// * -// ExistenceProof takes a key and a value and a set of steps to perform on it. -// The result of peforming all these steps will provide a "root hash", which can -// be compared to the value in a header. -// -// Since it is computationally infeasible to produce a hash collission for any of the used -// cryptographic hash functions, if someone can provide a series of operations to transform -// a given key and value into a root hash that matches some trusted root, these key and values -// must be in the referenced merkle tree. -// -// The only possible issue is maliablity in LeafOp, such as providing extra prefix data, -// which should be controlled by a spec. Eg. with lengthOp as NONE, -// prefix = FOO, key = BAR, value = CHOICE -// and -// prefix = F, key = OOBAR, value = CHOICE -// would produce the same value. -// -// With LengthOp this is tricker but not impossible. Which is why the "leafPrefixEqual" field -// in the ProofSpec is valuable to prevent this mutability. And why all trees should -// length-prefix the data before hashing it. -type ExistenceProof struct { - Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` - Leaf *LeafOp `protobuf:"bytes,3,opt,name=leaf,proto3" json:"leaf,omitempty"` - Path []*InnerOp `protobuf:"bytes,4,rep,name=path,proto3" json:"path,omitempty"` -} - -func (m *ExistenceProof) Reset() { *m = ExistenceProof{} } -func (m *ExistenceProof) String() string { return proto.CompactTextString(m) } -func (*ExistenceProof) ProtoMessage() {} -func (*ExistenceProof) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{0} -} -func (m *ExistenceProof) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ExistenceProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ExistenceProof.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ExistenceProof) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExistenceProof.Merge(m, src) -} -func (m *ExistenceProof) XXX_Size() int { - return m.Size() -} -func (m *ExistenceProof) XXX_DiscardUnknown() { - xxx_messageInfo_ExistenceProof.DiscardUnknown(m) -} - -var xxx_messageInfo_ExistenceProof proto.InternalMessageInfo - -func (m *ExistenceProof) GetKey() []byte { - if m != nil { - return m.Key - } - return nil -} - -func (m *ExistenceProof) GetValue() []byte { - if m != nil { - return m.Value - } - return nil -} - -func (m *ExistenceProof) GetLeaf() *LeafOp { - if m != nil { - return m.Leaf - } - return nil -} - -func (m *ExistenceProof) GetPath() []*InnerOp { - if m != nil { - return m.Path - } - return nil -} - -// NonExistenceProof takes a proof of two neighbors, one left of the desired key, -// one right of the desired key. If both proofs are valid AND they are neighbors, -// then there is no valid proof for the given key. -type NonExistenceProof struct { - Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Left *ExistenceProof `protobuf:"bytes,2,opt,name=left,proto3" json:"left,omitempty"` - Right *ExistenceProof `protobuf:"bytes,3,opt,name=right,proto3" json:"right,omitempty"` -} - -func (m *NonExistenceProof) Reset() { *m = NonExistenceProof{} } -func (m *NonExistenceProof) String() string { return proto.CompactTextString(m) } -func (*NonExistenceProof) ProtoMessage() {} -func (*NonExistenceProof) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{1} -} -func (m *NonExistenceProof) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *NonExistenceProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_NonExistenceProof.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *NonExistenceProof) XXX_Merge(src proto.Message) { - xxx_messageInfo_NonExistenceProof.Merge(m, src) -} -func (m *NonExistenceProof) XXX_Size() int { - return m.Size() -} -func (m *NonExistenceProof) XXX_DiscardUnknown() { - xxx_messageInfo_NonExistenceProof.DiscardUnknown(m) -} - -var xxx_messageInfo_NonExistenceProof proto.InternalMessageInfo - -func (m *NonExistenceProof) GetKey() []byte { - if m != nil { - return m.Key - } - return nil -} - -func (m *NonExistenceProof) GetLeft() *ExistenceProof { - if m != nil { - return m.Left - } - return nil -} - -func (m *NonExistenceProof) GetRight() *ExistenceProof { - if m != nil { - return m.Right - } - return nil -} - -// CommitmentProof is either an ExistenceProof or a NonExistenceProof, or a Batch of such messages -type CommitmentProof struct { - // Types that are valid to be assigned to Proof: - // *CommitmentProof_Exist - // *CommitmentProof_Nonexist - // *CommitmentProof_Batch - // *CommitmentProof_Compressed - Proof isCommitmentProof_Proof `protobuf_oneof:"proof"` -} - -func (m *CommitmentProof) Reset() { *m = CommitmentProof{} } -func (m *CommitmentProof) String() string { return proto.CompactTextString(m) } -func (*CommitmentProof) ProtoMessage() {} -func (*CommitmentProof) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{2} -} -func (m *CommitmentProof) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *CommitmentProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_CommitmentProof.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *CommitmentProof) XXX_Merge(src proto.Message) { - xxx_messageInfo_CommitmentProof.Merge(m, src) -} -func (m *CommitmentProof) XXX_Size() int { - return m.Size() -} -func (m *CommitmentProof) XXX_DiscardUnknown() { - xxx_messageInfo_CommitmentProof.DiscardUnknown(m) -} - -var xxx_messageInfo_CommitmentProof proto.InternalMessageInfo - -type isCommitmentProof_Proof interface { - isCommitmentProof_Proof() - MarshalTo([]byte) (int, error) - Size() int -} - -type CommitmentProof_Exist struct { - Exist *ExistenceProof `protobuf:"bytes,1,opt,name=exist,proto3,oneof" json:"exist,omitempty"` -} -type CommitmentProof_Nonexist struct { - Nonexist *NonExistenceProof `protobuf:"bytes,2,opt,name=nonexist,proto3,oneof" json:"nonexist,omitempty"` -} -type CommitmentProof_Batch struct { - Batch *BatchProof `protobuf:"bytes,3,opt,name=batch,proto3,oneof" json:"batch,omitempty"` -} -type CommitmentProof_Compressed struct { - Compressed *CompressedBatchProof `protobuf:"bytes,4,opt,name=compressed,proto3,oneof" json:"compressed,omitempty"` -} - -func (*CommitmentProof_Exist) isCommitmentProof_Proof() {} -func (*CommitmentProof_Nonexist) isCommitmentProof_Proof() {} -func (*CommitmentProof_Batch) isCommitmentProof_Proof() {} -func (*CommitmentProof_Compressed) isCommitmentProof_Proof() {} - -func (m *CommitmentProof) GetProof() isCommitmentProof_Proof { - if m != nil { - return m.Proof - } - return nil -} - -func (m *CommitmentProof) GetExist() *ExistenceProof { - if x, ok := m.GetProof().(*CommitmentProof_Exist); ok { - return x.Exist - } - return nil -} - -func (m *CommitmentProof) GetNonexist() *NonExistenceProof { - if x, ok := m.GetProof().(*CommitmentProof_Nonexist); ok { - return x.Nonexist - } - return nil -} - -func (m *CommitmentProof) GetBatch() *BatchProof { - if x, ok := m.GetProof().(*CommitmentProof_Batch); ok { - return x.Batch - } - return nil -} - -func (m *CommitmentProof) GetCompressed() *CompressedBatchProof { - if x, ok := m.GetProof().(*CommitmentProof_Compressed); ok { - return x.Compressed - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*CommitmentProof) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*CommitmentProof_Exist)(nil), - (*CommitmentProof_Nonexist)(nil), - (*CommitmentProof_Batch)(nil), - (*CommitmentProof_Compressed)(nil), - } -} - -// * -// LeafOp represents the raw key-value data we wish to prove, and -// must be flexible to represent the internal transformation from -// the original key-value pairs into the basis hash, for many existing -// merkle trees. -// -// key and value are passed in. So that the signature of this operation is: -// leafOp(key, value) -> output -// -// To process this, first prehash the keys and values if needed (ANY means no hash in this case): -// hkey = prehashKey(key) -// hvalue = prehashValue(value) -// -// Then combine the bytes, and hash it -// output = hash(prefix || length(hkey) || hkey || length(hvalue) || hvalue) -type LeafOp struct { - Hash HashOp `protobuf:"varint,1,opt,name=hash,proto3,enum=ics23.HashOp" json:"hash,omitempty"` - PrehashKey HashOp `protobuf:"varint,2,opt,name=prehash_key,json=prehashKey,proto3,enum=ics23.HashOp" json:"prehash_key,omitempty"` - PrehashValue HashOp `protobuf:"varint,3,opt,name=prehash_value,json=prehashValue,proto3,enum=ics23.HashOp" json:"prehash_value,omitempty"` - Length LengthOp `protobuf:"varint,4,opt,name=length,proto3,enum=ics23.LengthOp" json:"length,omitempty"` - // prefix is a fixed bytes that may optionally be included at the beginning to differentiate - // a leaf node from an inner node. - Prefix []byte `protobuf:"bytes,5,opt,name=prefix,proto3" json:"prefix,omitempty"` -} - -func (m *LeafOp) Reset() { *m = LeafOp{} } -func (m *LeafOp) String() string { return proto.CompactTextString(m) } -func (*LeafOp) ProtoMessage() {} -func (*LeafOp) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{3} -} -func (m *LeafOp) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *LeafOp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_LeafOp.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *LeafOp) XXX_Merge(src proto.Message) { - xxx_messageInfo_LeafOp.Merge(m, src) -} -func (m *LeafOp) XXX_Size() int { - return m.Size() -} -func (m *LeafOp) XXX_DiscardUnknown() { - xxx_messageInfo_LeafOp.DiscardUnknown(m) -} - -var xxx_messageInfo_LeafOp proto.InternalMessageInfo - -func (m *LeafOp) GetHash() HashOp { - if m != nil { - return m.Hash - } - return HashOp_NO_HASH -} - -func (m *LeafOp) GetPrehashKey() HashOp { - if m != nil { - return m.PrehashKey - } - return HashOp_NO_HASH -} - -func (m *LeafOp) GetPrehashValue() HashOp { - if m != nil { - return m.PrehashValue - } - return HashOp_NO_HASH -} - -func (m *LeafOp) GetLength() LengthOp { - if m != nil { - return m.Length - } - return LengthOp_NO_PREFIX -} - -func (m *LeafOp) GetPrefix() []byte { - if m != nil { - return m.Prefix - } - return nil -} - -// * -// InnerOp represents a merkle-proof step that is not a leaf. -// It represents concatenating two children and hashing them to provide the next result. -// -// The result of the previous step is passed in, so the signature of this op is: -// innerOp(child) -> output -// -// The result of applying InnerOp should be: -// output = op.hash(op.prefix || child || op.suffix) -// -// where the || operator is concatenation of binary data, -// and child is the result of hashing all the tree below this step. -// -// Any special data, like prepending child with the length, or prepending the entire operation with -// some value to differentiate from leaf nodes, should be included in prefix and suffix. -// If either of prefix or suffix is empty, we just treat it as an empty string -type InnerOp struct { - Hash HashOp `protobuf:"varint,1,opt,name=hash,proto3,enum=ics23.HashOp" json:"hash,omitempty"` - Prefix []byte `protobuf:"bytes,2,opt,name=prefix,proto3" json:"prefix,omitempty"` - Suffix []byte `protobuf:"bytes,3,opt,name=suffix,proto3" json:"suffix,omitempty"` -} - -func (m *InnerOp) Reset() { *m = InnerOp{} } -func (m *InnerOp) String() string { return proto.CompactTextString(m) } -func (*InnerOp) ProtoMessage() {} -func (*InnerOp) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{4} -} -func (m *InnerOp) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *InnerOp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_InnerOp.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *InnerOp) XXX_Merge(src proto.Message) { - xxx_messageInfo_InnerOp.Merge(m, src) -} -func (m *InnerOp) XXX_Size() int { - return m.Size() -} -func (m *InnerOp) XXX_DiscardUnknown() { - xxx_messageInfo_InnerOp.DiscardUnknown(m) -} - -var xxx_messageInfo_InnerOp proto.InternalMessageInfo - -func (m *InnerOp) GetHash() HashOp { - if m != nil { - return m.Hash - } - return HashOp_NO_HASH -} - -func (m *InnerOp) GetPrefix() []byte { - if m != nil { - return m.Prefix - } - return nil -} - -func (m *InnerOp) GetSuffix() []byte { - if m != nil { - return m.Suffix - } - return nil -} - -// * -// ProofSpec defines what the expected parameters are for a given proof type. -// This can be stored in the client and used to validate any incoming proofs. -// -// verify(ProofSpec, Proof) -> Proof | Error -// -// As demonstrated in tests, if we don't fix the algorithm used to calculate the -// LeafHash for a given tree, there are many possible key-value pairs that can -// generate a given hash (by interpretting the preimage differently). -// We need this for proper security, requires client knows a priori what -// tree format server uses. But not in code, rather a configuration object. -type ProofSpec struct { - // any field in the ExistenceProof must be the same as in this spec. - // except Prefix, which is just the first bytes of prefix (spec can be longer) - LeafSpec *LeafOp `protobuf:"bytes,1,opt,name=leaf_spec,json=leafSpec,proto3" json:"leaf_spec,omitempty"` - InnerSpec *InnerSpec `protobuf:"bytes,2,opt,name=inner_spec,json=innerSpec,proto3" json:"inner_spec,omitempty"` - // max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries) - MaxDepth int32 `protobuf:"varint,3,opt,name=max_depth,json=maxDepth,proto3" json:"max_depth,omitempty"` - // min_depth (if > 0) is the minimum number of InnerOps allowed (mainly for fixed-depth tries) - MinDepth int32 `protobuf:"varint,4,opt,name=min_depth,json=minDepth,proto3" json:"min_depth,omitempty"` -} - -func (m *ProofSpec) Reset() { *m = ProofSpec{} } -func (m *ProofSpec) String() string { return proto.CompactTextString(m) } -func (*ProofSpec) ProtoMessage() {} -func (*ProofSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{5} -} -func (m *ProofSpec) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ProofSpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ProofSpec.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ProofSpec) XXX_Merge(src proto.Message) { - xxx_messageInfo_ProofSpec.Merge(m, src) -} -func (m *ProofSpec) XXX_Size() int { - return m.Size() -} -func (m *ProofSpec) XXX_DiscardUnknown() { - xxx_messageInfo_ProofSpec.DiscardUnknown(m) -} - -var xxx_messageInfo_ProofSpec proto.InternalMessageInfo - -func (m *ProofSpec) GetLeafSpec() *LeafOp { - if m != nil { - return m.LeafSpec - } - return nil -} - -func (m *ProofSpec) GetInnerSpec() *InnerSpec { - if m != nil { - return m.InnerSpec - } - return nil -} - -func (m *ProofSpec) GetMaxDepth() int32 { - if m != nil { - return m.MaxDepth - } - return 0 -} - -func (m *ProofSpec) GetMinDepth() int32 { - if m != nil { - return m.MinDepth - } - return 0 -} - -// InnerSpec contains all store-specific structure info to determine if two proofs from a -// given store are neighbors. -// -// This enables: -// -// isLeftMost(spec: InnerSpec, op: InnerOp) -// isRightMost(spec: InnerSpec, op: InnerOp) -// isLeftNeighbor(spec: InnerSpec, left: InnerOp, right: InnerOp) -type InnerSpec struct { - // Child order is the ordering of the children node, must count from 0 - // iavl tree is [0, 1] (left then right) - // merk is [0, 2, 1] (left, right, here) - ChildOrder []int32 `protobuf:"varint,1,rep,packed,name=child_order,json=childOrder,proto3" json:"child_order,omitempty"` - ChildSize int32 `protobuf:"varint,2,opt,name=child_size,json=childSize,proto3" json:"child_size,omitempty"` - MinPrefixLength int32 `protobuf:"varint,3,opt,name=min_prefix_length,json=minPrefixLength,proto3" json:"min_prefix_length,omitempty"` - MaxPrefixLength int32 `protobuf:"varint,4,opt,name=max_prefix_length,json=maxPrefixLength,proto3" json:"max_prefix_length,omitempty"` - // empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0) - EmptyChild []byte `protobuf:"bytes,5,opt,name=empty_child,json=emptyChild,proto3" json:"empty_child,omitempty"` - // hash is the algorithm that must be used for each InnerOp - Hash HashOp `protobuf:"varint,6,opt,name=hash,proto3,enum=ics23.HashOp" json:"hash,omitempty"` -} - -func (m *InnerSpec) Reset() { *m = InnerSpec{} } -func (m *InnerSpec) String() string { return proto.CompactTextString(m) } -func (*InnerSpec) ProtoMessage() {} -func (*InnerSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{6} -} -func (m *InnerSpec) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *InnerSpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_InnerSpec.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *InnerSpec) XXX_Merge(src proto.Message) { - xxx_messageInfo_InnerSpec.Merge(m, src) -} -func (m *InnerSpec) XXX_Size() int { - return m.Size() -} -func (m *InnerSpec) XXX_DiscardUnknown() { - xxx_messageInfo_InnerSpec.DiscardUnknown(m) -} - -var xxx_messageInfo_InnerSpec proto.InternalMessageInfo - -func (m *InnerSpec) GetChildOrder() []int32 { - if m != nil { - return m.ChildOrder - } - return nil -} - -func (m *InnerSpec) GetChildSize() int32 { - if m != nil { - return m.ChildSize - } - return 0 -} - -func (m *InnerSpec) GetMinPrefixLength() int32 { - if m != nil { - return m.MinPrefixLength - } - return 0 -} - -func (m *InnerSpec) GetMaxPrefixLength() int32 { - if m != nil { - return m.MaxPrefixLength - } - return 0 -} - -func (m *InnerSpec) GetEmptyChild() []byte { - if m != nil { - return m.EmptyChild - } - return nil -} - -func (m *InnerSpec) GetHash() HashOp { - if m != nil { - return m.Hash - } - return HashOp_NO_HASH -} - -// BatchProof is a group of multiple proof types than can be compressed -type BatchProof struct { - Entries []*BatchEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` -} - -func (m *BatchProof) Reset() { *m = BatchProof{} } -func (m *BatchProof) String() string { return proto.CompactTextString(m) } -func (*BatchProof) ProtoMessage() {} -func (*BatchProof) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{7} -} -func (m *BatchProof) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BatchProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BatchProof.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *BatchProof) XXX_Merge(src proto.Message) { - xxx_messageInfo_BatchProof.Merge(m, src) -} -func (m *BatchProof) XXX_Size() int { - return m.Size() -} -func (m *BatchProof) XXX_DiscardUnknown() { - xxx_messageInfo_BatchProof.DiscardUnknown(m) -} - -var xxx_messageInfo_BatchProof proto.InternalMessageInfo - -func (m *BatchProof) GetEntries() []*BatchEntry { - if m != nil { - return m.Entries - } - return nil -} - -// Use BatchEntry not CommitmentProof, to avoid recursion -type BatchEntry struct { - // Types that are valid to be assigned to Proof: - // *BatchEntry_Exist - // *BatchEntry_Nonexist - Proof isBatchEntry_Proof `protobuf_oneof:"proof"` -} - -func (m *BatchEntry) Reset() { *m = BatchEntry{} } -func (m *BatchEntry) String() string { return proto.CompactTextString(m) } -func (*BatchEntry) ProtoMessage() {} -func (*BatchEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{8} -} -func (m *BatchEntry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BatchEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BatchEntry.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *BatchEntry) XXX_Merge(src proto.Message) { - xxx_messageInfo_BatchEntry.Merge(m, src) -} -func (m *BatchEntry) XXX_Size() int { - return m.Size() -} -func (m *BatchEntry) XXX_DiscardUnknown() { - xxx_messageInfo_BatchEntry.DiscardUnknown(m) -} - -var xxx_messageInfo_BatchEntry proto.InternalMessageInfo - -type isBatchEntry_Proof interface { - isBatchEntry_Proof() - MarshalTo([]byte) (int, error) - Size() int -} - -type BatchEntry_Exist struct { - Exist *ExistenceProof `protobuf:"bytes,1,opt,name=exist,proto3,oneof" json:"exist,omitempty"` -} -type BatchEntry_Nonexist struct { - Nonexist *NonExistenceProof `protobuf:"bytes,2,opt,name=nonexist,proto3,oneof" json:"nonexist,omitempty"` -} - -func (*BatchEntry_Exist) isBatchEntry_Proof() {} -func (*BatchEntry_Nonexist) isBatchEntry_Proof() {} - -func (m *BatchEntry) GetProof() isBatchEntry_Proof { - if m != nil { - return m.Proof - } - return nil -} - -func (m *BatchEntry) GetExist() *ExistenceProof { - if x, ok := m.GetProof().(*BatchEntry_Exist); ok { - return x.Exist - } - return nil -} - -func (m *BatchEntry) GetNonexist() *NonExistenceProof { - if x, ok := m.GetProof().(*BatchEntry_Nonexist); ok { - return x.Nonexist - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*BatchEntry) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*BatchEntry_Exist)(nil), - (*BatchEntry_Nonexist)(nil), - } -} - -type CompressedBatchProof struct { - Entries []*CompressedBatchEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` - LookupInners []*InnerOp `protobuf:"bytes,2,rep,name=lookup_inners,json=lookupInners,proto3" json:"lookup_inners,omitempty"` -} - -func (m *CompressedBatchProof) Reset() { *m = CompressedBatchProof{} } -func (m *CompressedBatchProof) String() string { return proto.CompactTextString(m) } -func (*CompressedBatchProof) ProtoMessage() {} -func (*CompressedBatchProof) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{9} -} -func (m *CompressedBatchProof) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *CompressedBatchProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_CompressedBatchProof.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *CompressedBatchProof) XXX_Merge(src proto.Message) { - xxx_messageInfo_CompressedBatchProof.Merge(m, src) -} -func (m *CompressedBatchProof) XXX_Size() int { - return m.Size() -} -func (m *CompressedBatchProof) XXX_DiscardUnknown() { - xxx_messageInfo_CompressedBatchProof.DiscardUnknown(m) -} - -var xxx_messageInfo_CompressedBatchProof proto.InternalMessageInfo - -func (m *CompressedBatchProof) GetEntries() []*CompressedBatchEntry { - if m != nil { - return m.Entries - } - return nil -} - -func (m *CompressedBatchProof) GetLookupInners() []*InnerOp { - if m != nil { - return m.LookupInners - } - return nil -} - -// Use BatchEntry not CommitmentProof, to avoid recursion -type CompressedBatchEntry struct { - // Types that are valid to be assigned to Proof: - // *CompressedBatchEntry_Exist - // *CompressedBatchEntry_Nonexist - Proof isCompressedBatchEntry_Proof `protobuf_oneof:"proof"` -} - -func (m *CompressedBatchEntry) Reset() { *m = CompressedBatchEntry{} } -func (m *CompressedBatchEntry) String() string { return proto.CompactTextString(m) } -func (*CompressedBatchEntry) ProtoMessage() {} -func (*CompressedBatchEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{10} -} -func (m *CompressedBatchEntry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *CompressedBatchEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_CompressedBatchEntry.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *CompressedBatchEntry) XXX_Merge(src proto.Message) { - xxx_messageInfo_CompressedBatchEntry.Merge(m, src) -} -func (m *CompressedBatchEntry) XXX_Size() int { - return m.Size() -} -func (m *CompressedBatchEntry) XXX_DiscardUnknown() { - xxx_messageInfo_CompressedBatchEntry.DiscardUnknown(m) -} - -var xxx_messageInfo_CompressedBatchEntry proto.InternalMessageInfo - -type isCompressedBatchEntry_Proof interface { - isCompressedBatchEntry_Proof() - MarshalTo([]byte) (int, error) - Size() int -} - -type CompressedBatchEntry_Exist struct { - Exist *CompressedExistenceProof `protobuf:"bytes,1,opt,name=exist,proto3,oneof" json:"exist,omitempty"` -} -type CompressedBatchEntry_Nonexist struct { - Nonexist *CompressedNonExistenceProof `protobuf:"bytes,2,opt,name=nonexist,proto3,oneof" json:"nonexist,omitempty"` -} - -func (*CompressedBatchEntry_Exist) isCompressedBatchEntry_Proof() {} -func (*CompressedBatchEntry_Nonexist) isCompressedBatchEntry_Proof() {} - -func (m *CompressedBatchEntry) GetProof() isCompressedBatchEntry_Proof { - if m != nil { - return m.Proof - } - return nil -} - -func (m *CompressedBatchEntry) GetExist() *CompressedExistenceProof { - if x, ok := m.GetProof().(*CompressedBatchEntry_Exist); ok { - return x.Exist - } - return nil -} - -func (m *CompressedBatchEntry) GetNonexist() *CompressedNonExistenceProof { - if x, ok := m.GetProof().(*CompressedBatchEntry_Nonexist); ok { - return x.Nonexist - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*CompressedBatchEntry) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*CompressedBatchEntry_Exist)(nil), - (*CompressedBatchEntry_Nonexist)(nil), - } -} - -type CompressedExistenceProof struct { - Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` - Leaf *LeafOp `protobuf:"bytes,3,opt,name=leaf,proto3" json:"leaf,omitempty"` - // these are indexes into the lookup_inners table in CompressedBatchProof - Path []int32 `protobuf:"varint,4,rep,packed,name=path,proto3" json:"path,omitempty"` -} - -func (m *CompressedExistenceProof) Reset() { *m = CompressedExistenceProof{} } -func (m *CompressedExistenceProof) String() string { return proto.CompactTextString(m) } -func (*CompressedExistenceProof) ProtoMessage() {} -func (*CompressedExistenceProof) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{11} -} -func (m *CompressedExistenceProof) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *CompressedExistenceProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_CompressedExistenceProof.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *CompressedExistenceProof) XXX_Merge(src proto.Message) { - xxx_messageInfo_CompressedExistenceProof.Merge(m, src) -} -func (m *CompressedExistenceProof) XXX_Size() int { - return m.Size() -} -func (m *CompressedExistenceProof) XXX_DiscardUnknown() { - xxx_messageInfo_CompressedExistenceProof.DiscardUnknown(m) -} - -var xxx_messageInfo_CompressedExistenceProof proto.InternalMessageInfo - -func (m *CompressedExistenceProof) GetKey() []byte { - if m != nil { - return m.Key - } - return nil -} - -func (m *CompressedExistenceProof) GetValue() []byte { - if m != nil { - return m.Value - } - return nil -} - -func (m *CompressedExistenceProof) GetLeaf() *LeafOp { - if m != nil { - return m.Leaf - } - return nil -} - -func (m *CompressedExistenceProof) GetPath() []int32 { - if m != nil { - return m.Path - } - return nil -} - -type CompressedNonExistenceProof struct { - Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Left *CompressedExistenceProof `protobuf:"bytes,2,opt,name=left,proto3" json:"left,omitempty"` - Right *CompressedExistenceProof `protobuf:"bytes,3,opt,name=right,proto3" json:"right,omitempty"` -} - -func (m *CompressedNonExistenceProof) Reset() { *m = CompressedNonExistenceProof{} } -func (m *CompressedNonExistenceProof) String() string { return proto.CompactTextString(m) } -func (*CompressedNonExistenceProof) ProtoMessage() {} -func (*CompressedNonExistenceProof) Descriptor() ([]byte, []int) { - return fileDescriptor_855156e15e7b8e99, []int{12} -} -func (m *CompressedNonExistenceProof) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *CompressedNonExistenceProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_CompressedNonExistenceProof.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *CompressedNonExistenceProof) XXX_Merge(src proto.Message) { - xxx_messageInfo_CompressedNonExistenceProof.Merge(m, src) -} -func (m *CompressedNonExistenceProof) XXX_Size() int { - return m.Size() -} -func (m *CompressedNonExistenceProof) XXX_DiscardUnknown() { - xxx_messageInfo_CompressedNonExistenceProof.DiscardUnknown(m) -} - -var xxx_messageInfo_CompressedNonExistenceProof proto.InternalMessageInfo - -func (m *CompressedNonExistenceProof) GetKey() []byte { - if m != nil { - return m.Key - } - return nil -} - -func (m *CompressedNonExistenceProof) GetLeft() *CompressedExistenceProof { - if m != nil { - return m.Left - } - return nil -} - -func (m *CompressedNonExistenceProof) GetRight() *CompressedExistenceProof { - if m != nil { - return m.Right - } - return nil -} - -func init() { - proto.RegisterEnum("ics23.HashOp", HashOp_name, HashOp_value) - proto.RegisterEnum("ics23.LengthOp", LengthOp_name, LengthOp_value) - proto.RegisterType((*ExistenceProof)(nil), "ics23.ExistenceProof") - proto.RegisterType((*NonExistenceProof)(nil), "ics23.NonExistenceProof") - proto.RegisterType((*CommitmentProof)(nil), "ics23.CommitmentProof") - proto.RegisterType((*LeafOp)(nil), "ics23.LeafOp") - proto.RegisterType((*InnerOp)(nil), "ics23.InnerOp") - proto.RegisterType((*ProofSpec)(nil), "ics23.ProofSpec") - proto.RegisterType((*InnerSpec)(nil), "ics23.InnerSpec") - proto.RegisterType((*BatchProof)(nil), "ics23.BatchProof") - proto.RegisterType((*BatchEntry)(nil), "ics23.BatchEntry") - proto.RegisterType((*CompressedBatchProof)(nil), "ics23.CompressedBatchProof") - proto.RegisterType((*CompressedBatchEntry)(nil), "ics23.CompressedBatchEntry") - proto.RegisterType((*CompressedExistenceProof)(nil), "ics23.CompressedExistenceProof") - proto.RegisterType((*CompressedNonExistenceProof)(nil), "ics23.CompressedNonExistenceProof") -} - -func init() { proto.RegisterFile("proofs.proto", fileDescriptor_855156e15e7b8e99) } - -var fileDescriptor_855156e15e7b8e99 = []byte{ - // 940 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4b, 0x6f, 0xe3, 0x54, - 0x14, 0xce, 0x4d, 0x62, 0x27, 0x39, 0x69, 0x53, 0xf7, 0xaa, 0x20, 0x4b, 0x15, 0x69, 0xf1, 0x86, - 0x4e, 0x47, 0x14, 0x26, 0x99, 0x06, 0xb1, 0x40, 0xa2, 0x49, 0x3d, 0xc4, 0x6a, 0x69, 0xc2, 0x4d, - 0x18, 0x0d, 0x12, 0x92, 0xe5, 0x49, 0x6f, 0x26, 0xd6, 0x24, 0xb6, 0x65, 0xbb, 0x28, 0x19, 0x81, - 0x90, 0xf8, 0x05, 0xac, 0x61, 0xc7, 0x96, 0x3f, 0xc2, 0xb2, 0x4b, 0x96, 0xa8, 0x5d, 0xb0, 0xe0, - 0x4f, 0xa0, 0xfb, 0x88, 0x9b, 0x27, 0xed, 0x02, 0xcd, 0xee, 0x9e, 0xef, 0x7c, 0xe7, 0x71, 0xcf, - 0xc3, 0xd7, 0xb0, 0x11, 0x84, 0xbe, 0xdf, 0x8f, 0x8e, 0x82, 0xd0, 0x8f, 0x7d, 0xac, 0xb8, 0xbd, - 0xa8, 0x52, 0x35, 0x7e, 0x84, 0x92, 0x39, 0x76, 0xa3, 0x98, 0x7a, 0x3d, 0xda, 0x66, 0x7a, 0xac, - 0x41, 0xe6, 0x35, 0x9d, 0xe8, 0x68, 0x1f, 0x1d, 0x6c, 0x10, 0x76, 0xc4, 0x3b, 0xa0, 0x7c, 0xe7, - 0x0c, 0xaf, 0xa8, 0x9e, 0xe6, 0x98, 0x10, 0xf0, 0xfb, 0x90, 0x1d, 0x52, 0xa7, 0xaf, 0x67, 0xf6, - 0xd1, 0x41, 0xb1, 0xb2, 0x79, 0xc4, 0xfd, 0x1d, 0x9d, 0x53, 0xa7, 0xdf, 0x0a, 0x08, 0x57, 0x61, - 0x03, 0xb2, 0x81, 0x13, 0x0f, 0xf4, 0xec, 0x7e, 0xe6, 0xa0, 0x58, 0x29, 0x49, 0x8a, 0xe5, 0x79, - 0x34, 0x64, 0x1c, 0xa6, 0x33, 0x7e, 0x80, 0xed, 0x0b, 0xdf, 0xbb, 0x37, 0x87, 0x47, 0x2c, 0x5a, - 0x3f, 0xe6, 0x29, 0x14, 0x2b, 0xef, 0x48, 0x57, 0xf3, 0x66, 0x84, 0x53, 0xf0, 0x63, 0x50, 0x42, - 0xf7, 0xd5, 0x20, 0x96, 0x99, 0xad, 0xe1, 0x0a, 0x8e, 0xf1, 0x0f, 0x82, 0xad, 0x86, 0x3f, 0x1a, - 0xb9, 0xf1, 0x88, 0x7a, 0xb1, 0x88, 0xfe, 0x21, 0x28, 0x94, 0x91, 0x79, 0xfc, 0x75, 0x0e, 0x9a, - 0x29, 0x22, 0x58, 0xb8, 0x06, 0x79, 0xcf, 0xf7, 0x84, 0x85, 0x48, 0x4f, 0x97, 0x16, 0x4b, 0x17, - 0x6b, 0xa6, 0x48, 0xc2, 0xc5, 0x8f, 0x40, 0x79, 0xe9, 0xc4, 0xbd, 0x81, 0xcc, 0x73, 0x5b, 0x1a, - 0xd5, 0x19, 0x96, 0x84, 0xe0, 0x0c, 0xfc, 0x19, 0x40, 0xcf, 0x1f, 0x05, 0x21, 0x8d, 0x22, 0x7a, - 0xa9, 0x67, 0x39, 0x7f, 0x57, 0xf2, 0x1b, 0x89, 0x62, 0xce, 0x72, 0xc6, 0xa0, 0x9e, 0x03, 0x85, - 0xf7, 0xde, 0xb8, 0x46, 0xa0, 0x8a, 0x0e, 0xb1, 0xf6, 0x0d, 0x9c, 0x68, 0xc0, 0xef, 0x58, 0x4a, - 0xda, 0xd7, 0x74, 0xa2, 0x01, 0x6b, 0x0d, 0x53, 0xe1, 0x23, 0x28, 0x06, 0x21, 0x65, 0x47, 0x9b, - 0x75, 0x23, 0xbd, 0x8a, 0x09, 0x92, 0x71, 0x46, 0x27, 0xb8, 0x02, 0x9b, 0x53, 0xbe, 0x98, 0x97, - 0xcc, 0x2a, 0x8b, 0x0d, 0xc9, 0x79, 0xce, 0xa7, 0xe8, 0x03, 0x50, 0x87, 0xd4, 0x7b, 0xc5, 0x87, - 0x84, 0x91, 0xb7, 0x92, 0x39, 0x62, 0x60, 0x2b, 0x20, 0x52, 0x8d, 0xdf, 0x05, 0x35, 0x08, 0x69, - 0xdf, 0x1d, 0xeb, 0x0a, 0x9f, 0x0a, 0x29, 0x19, 0xdf, 0x42, 0x4e, 0x0e, 0xd4, 0x43, 0xae, 0x74, - 0xe7, 0x25, 0x3d, 0xeb, 0x85, 0xe1, 0xd1, 0x55, 0x9f, 0xe1, 0x19, 0x81, 0x0b, 0xc9, 0xf8, 0x0d, - 0x41, 0x81, 0x57, 0xb4, 0x13, 0xd0, 0x1e, 0x3e, 0x84, 0x02, 0x9b, 0x6b, 0x3b, 0x0a, 0x68, 0x4f, - 0x0e, 0xc7, 0xc2, 0xdc, 0xe7, 0x99, 0x9e, 0x73, 0x3f, 0x02, 0x70, 0x59, 0x5e, 0x82, 0x2c, 0xe6, - 0x42, 0x9b, 0xdd, 0x00, 0xc6, 0x22, 0x05, 0x77, 0x7a, 0xc4, 0xbb, 0x50, 0x18, 0x39, 0x63, 0xfb, - 0x92, 0x06, 0xb1, 0x18, 0x09, 0x85, 0xe4, 0x47, 0xce, 0xf8, 0x94, 0xc9, 0x5c, 0xe9, 0x7a, 0x52, - 0x99, 0x95, 0x4a, 0xd7, 0xe3, 0x4a, 0xe3, 0x6f, 0x04, 0x85, 0xc4, 0x25, 0xde, 0x83, 0x62, 0x6f, - 0xe0, 0x0e, 0x2f, 0x6d, 0x3f, 0xbc, 0xa4, 0xa1, 0x8e, 0xf6, 0x33, 0x07, 0x0a, 0x01, 0x0e, 0xb5, - 0x18, 0x82, 0xdf, 0x03, 0x21, 0xd9, 0x91, 0xfb, 0x46, 0xec, 0xb4, 0x42, 0x0a, 0x1c, 0xe9, 0xb8, - 0x6f, 0x28, 0x3e, 0x84, 0x6d, 0x16, 0x4a, 0x14, 0xc6, 0x96, 0xcd, 0x11, 0xf9, 0x6c, 0x8d, 0x5c, - 0xaf, 0xcd, 0x71, 0xd1, 0x1e, 0xce, 0x75, 0xc6, 0x0b, 0xdc, 0xac, 0xe4, 0x3a, 0xe3, 0x39, 0xee, - 0x1e, 0x14, 0xe9, 0x28, 0x88, 0x27, 0x36, 0x0f, 0x25, 0xbb, 0x08, 0x1c, 0x6a, 0x30, 0x24, 0x69, - 0x9f, 0xba, 0xb6, 0x7d, 0xc6, 0xa7, 0x00, 0x77, 0x43, 0x8e, 0x1f, 0x43, 0x8e, 0x7a, 0x71, 0xe8, - 0xd2, 0x88, 0xdf, 0x72, 0x61, 0x85, 0x4c, 0x2f, 0x0e, 0x27, 0x64, 0xca, 0x30, 0xbe, 0x97, 0xa6, - 0x1c, 0x7e, 0x4b, 0x2b, 0x7e, 0xb7, 0x78, 0x3f, 0x21, 0xd8, 0x59, 0xb5, 0xa8, 0xf8, 0x78, 0xf1, - 0x0e, 0x6b, 0xd6, 0x7a, 0xfe, 0x36, 0xb8, 0x0a, 0x9b, 0x43, 0xdf, 0x7f, 0x7d, 0x15, 0xd8, 0x7c, - 0x80, 0x22, 0x3d, 0xbd, 0xf2, 0x13, 0xbb, 0x21, 0x48, 0x5c, 0x8c, 0x8c, 0x5f, 0x96, 0x93, 0x10, - 0xd5, 0xf8, 0x64, 0xbe, 0x1a, 0x7b, 0x4b, 0x29, 0xac, 0xab, 0xcb, 0xe7, 0x4b, 0x75, 0x31, 0x96, - 0x6c, 0x1f, 0x58, 0xa1, 0x09, 0xe8, 0xeb, 0xe2, 0xfd, 0x9f, 0x4f, 0x12, 0x9e, 0x79, 0x92, 0x14, - 0xf9, 0x04, 0xfd, 0x8a, 0x60, 0xf7, 0x3f, 0xf2, 0x5d, 0x11, 0xbe, 0x3a, 0xf7, 0x1a, 0xdd, 0x57, - 0x2f, 0xf9, 0x2e, 0x1d, 0xcf, 0xbf, 0x4b, 0xf7, 0x5a, 0x09, 0xf6, 0x21, 0x05, 0x55, 0xec, 0x00, - 0x2e, 0x42, 0xee, 0xa2, 0x65, 0x37, 0x4f, 0x3a, 0x4d, 0x2d, 0x85, 0x01, 0xd4, 0x4e, 0xf3, 0xa4, - 0x72, 0x5c, 0xd3, 0x90, 0x3c, 0x1f, 0x3f, 0xa9, 0x68, 0x69, 0x76, 0x3e, 0x33, 0x1b, 0x8d, 0x93, - 0x33, 0x2d, 0x83, 0x37, 0xa1, 0x40, 0xac, 0xb6, 0xf9, 0xe5, 0xe9, 0x93, 0xda, 0xc7, 0x5a, 0x96, - 0xd9, 0xd7, 0xad, 0x6e, 0xa3, 0x65, 0x5d, 0x68, 0x0a, 0x2e, 0x01, 0x08, 0x1b, 0x9b, 0xf9, 0x50, - 0x0f, 0x7f, 0x47, 0x90, 0x9f, 0x7e, 0x74, 0x99, 0xe1, 0x45, 0xcb, 0x6e, 0x13, 0xf3, 0x99, 0xf5, - 0x42, 0x4b, 0x31, 0xf1, 0xf9, 0x09, 0xb1, 0xdb, 0xa4, 0xd5, 0x6d, 0x69, 0x88, 0xf9, 0x61, 0x22, - 0x39, 0x6f, 0x6b, 0x69, 0xbc, 0x05, 0xc5, 0x67, 0xd6, 0x0b, 0xf3, 0xb4, 0x5a, 0xb1, 0xeb, 0xd6, - 0x17, 0x5a, 0x06, 0x63, 0x28, 0x4d, 0x81, 0x73, 0xab, 0xdb, 0x3d, 0x37, 0xb5, 0x6c, 0x42, 0xaa, - 0x3d, 0xe5, 0x24, 0x25, 0x21, 0xd5, 0x9e, 0x4e, 0x49, 0x2a, 0xde, 0x01, 0x8d, 0x98, 0x5f, 0x7d, - 0x6d, 0x11, 0xd3, 0x66, 0xce, 0xbe, 0xe9, 0x9a, 0x1d, 0x2d, 0x37, 0x8b, 0x32, 0x6b, 0x8e, 0xe6, - 0xeb, 0xfa, 0x1f, 0x37, 0x65, 0x74, 0x7d, 0x53, 0x46, 0x7f, 0xdd, 0x94, 0xd1, 0xcf, 0xb7, 0xe5, - 0xd4, 0xf5, 0x6d, 0x39, 0xf5, 0xe7, 0x6d, 0x39, 0xf5, 0x52, 0xe5, 0xbf, 0x37, 0xd5, 0x7f, 0x03, - 0x00, 0x00, 0xff, 0xff, 0xd4, 0x7d, 0x87, 0x8f, 0xee, 0x08, 0x00, 0x00, -} - -func (m *ExistenceProof) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ExistenceProof) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ExistenceProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Path) > 0 { - for iNdEx := len(m.Path) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Path[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - } - if m.Leaf != nil { - { - size, err := m.Leaf.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - if len(m.Value) > 0 { - i -= len(m.Value) - copy(dAtA[i:], m.Value) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Value))) - i-- - dAtA[i] = 0x12 - } - if len(m.Key) > 0 { - i -= len(m.Key) - copy(dAtA[i:], m.Key) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Key))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *NonExistenceProof) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *NonExistenceProof) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *NonExistenceProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Right != nil { - { - size, err := m.Right.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - if m.Left != nil { - { - size, err := m.Left.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if len(m.Key) > 0 { - i -= len(m.Key) - copy(dAtA[i:], m.Key) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Key))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *CommitmentProof) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CommitmentProof) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CommitmentProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Proof != nil { - { - size := m.Proof.Size() - i -= size - if _, err := m.Proof.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *CommitmentProof_Exist) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CommitmentProof_Exist) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Exist != nil { - { - size, err := m.Exist.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} -func (m *CommitmentProof_Nonexist) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CommitmentProof_Nonexist) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Nonexist != nil { - { - size, err := m.Nonexist.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - return len(dAtA) - i, nil -} -func (m *CommitmentProof_Batch) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CommitmentProof_Batch) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Batch != nil { - { - size, err := m.Batch.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - return len(dAtA) - i, nil -} -func (m *CommitmentProof_Compressed) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CommitmentProof_Compressed) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Compressed != nil { - { - size, err := m.Compressed.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - return len(dAtA) - i, nil -} -func (m *LeafOp) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *LeafOp) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *LeafOp) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Prefix) > 0 { - i -= len(m.Prefix) - copy(dAtA[i:], m.Prefix) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Prefix))) - i-- - dAtA[i] = 0x2a - } - if m.Length != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.Length)) - i-- - dAtA[i] = 0x20 - } - if m.PrehashValue != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.PrehashValue)) - i-- - dAtA[i] = 0x18 - } - if m.PrehashKey != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.PrehashKey)) - i-- - dAtA[i] = 0x10 - } - if m.Hash != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.Hash)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *InnerOp) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *InnerOp) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *InnerOp) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Suffix) > 0 { - i -= len(m.Suffix) - copy(dAtA[i:], m.Suffix) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Suffix))) - i-- - dAtA[i] = 0x1a - } - if len(m.Prefix) > 0 { - i -= len(m.Prefix) - copy(dAtA[i:], m.Prefix) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Prefix))) - i-- - dAtA[i] = 0x12 - } - if m.Hash != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.Hash)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *ProofSpec) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ProofSpec) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ProofSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.MinDepth != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.MinDepth)) - i-- - dAtA[i] = 0x20 - } - if m.MaxDepth != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.MaxDepth)) - i-- - dAtA[i] = 0x18 - } - if m.InnerSpec != nil { - { - size, err := m.InnerSpec.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if m.LeafSpec != nil { - { - size, err := m.LeafSpec.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *InnerSpec) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *InnerSpec) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *InnerSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Hash != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.Hash)) - i-- - dAtA[i] = 0x30 - } - if len(m.EmptyChild) > 0 { - i -= len(m.EmptyChild) - copy(dAtA[i:], m.EmptyChild) - i = encodeVarintProofs(dAtA, i, uint64(len(m.EmptyChild))) - i-- - dAtA[i] = 0x2a - } - if m.MaxPrefixLength != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.MaxPrefixLength)) - i-- - dAtA[i] = 0x20 - } - if m.MinPrefixLength != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.MinPrefixLength)) - i-- - dAtA[i] = 0x18 - } - if m.ChildSize != 0 { - i = encodeVarintProofs(dAtA, i, uint64(m.ChildSize)) - i-- - dAtA[i] = 0x10 - } - if len(m.ChildOrder) > 0 { - dAtA11 := make([]byte, len(m.ChildOrder)*10) - var j10 int - for _, num1 := range m.ChildOrder { - num := uint64(num1) - for num >= 1<<7 { - dAtA11[j10] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j10++ - } - dAtA11[j10] = uint8(num) - j10++ - } - i -= j10 - copy(dAtA[i:], dAtA11[:j10]) - i = encodeVarintProofs(dAtA, i, uint64(j10)) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *BatchProof) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *BatchProof) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BatchProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Entries) > 0 { - for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *BatchEntry) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *BatchEntry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BatchEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Proof != nil { - { - size := m.Proof.Size() - i -= size - if _, err := m.Proof.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *BatchEntry_Exist) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BatchEntry_Exist) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Exist != nil { - { - size, err := m.Exist.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} -func (m *BatchEntry_Nonexist) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BatchEntry_Nonexist) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Nonexist != nil { - { - size, err := m.Nonexist.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - return len(dAtA) - i, nil -} -func (m *CompressedBatchProof) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CompressedBatchProof) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CompressedBatchProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.LookupInners) > 0 { - for iNdEx := len(m.LookupInners) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.LookupInners[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if len(m.Entries) > 0 { - for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *CompressedBatchEntry) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CompressedBatchEntry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CompressedBatchEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Proof != nil { - { - size := m.Proof.Size() - i -= size - if _, err := m.Proof.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *CompressedBatchEntry_Exist) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CompressedBatchEntry_Exist) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Exist != nil { - { - size, err := m.Exist.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} -func (m *CompressedBatchEntry_Nonexist) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CompressedBatchEntry_Nonexist) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Nonexist != nil { - { - size, err := m.Nonexist.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - return len(dAtA) - i, nil -} -func (m *CompressedExistenceProof) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CompressedExistenceProof) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CompressedExistenceProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Path) > 0 { - dAtA17 := make([]byte, len(m.Path)*10) - var j16 int - for _, num1 := range m.Path { - num := uint64(num1) - for num >= 1<<7 { - dAtA17[j16] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j16++ - } - dAtA17[j16] = uint8(num) - j16++ - } - i -= j16 - copy(dAtA[i:], dAtA17[:j16]) - i = encodeVarintProofs(dAtA, i, uint64(j16)) - i-- - dAtA[i] = 0x22 - } - if m.Leaf != nil { - { - size, err := m.Leaf.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - if len(m.Value) > 0 { - i -= len(m.Value) - copy(dAtA[i:], m.Value) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Value))) - i-- - dAtA[i] = 0x12 - } - if len(m.Key) > 0 { - i -= len(m.Key) - copy(dAtA[i:], m.Key) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Key))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *CompressedNonExistenceProof) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CompressedNonExistenceProof) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CompressedNonExistenceProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Right != nil { - { - size, err := m.Right.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - if m.Left != nil { - { - size, err := m.Left.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProofs(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if len(m.Key) > 0 { - i -= len(m.Key) - copy(dAtA[i:], m.Key) - i = encodeVarintProofs(dAtA, i, uint64(len(m.Key))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintProofs(dAtA []byte, offset int, v uint64) int { - offset -= sovProofs(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *ExistenceProof) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Key) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - l = len(m.Value) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - if m.Leaf != nil { - l = m.Leaf.Size() - n += 1 + l + sovProofs(uint64(l)) - } - if len(m.Path) > 0 { - for _, e := range m.Path { - l = e.Size() - n += 1 + l + sovProofs(uint64(l)) - } - } - return n -} - -func (m *NonExistenceProof) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Key) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - if m.Left != nil { - l = m.Left.Size() - n += 1 + l + sovProofs(uint64(l)) - } - if m.Right != nil { - l = m.Right.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} - -func (m *CommitmentProof) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Proof != nil { - n += m.Proof.Size() - } - return n -} - -func (m *CommitmentProof_Exist) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Exist != nil { - l = m.Exist.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} -func (m *CommitmentProof_Nonexist) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Nonexist != nil { - l = m.Nonexist.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} -func (m *CommitmentProof_Batch) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Batch != nil { - l = m.Batch.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} -func (m *CommitmentProof_Compressed) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Compressed != nil { - l = m.Compressed.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} -func (m *LeafOp) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Hash != 0 { - n += 1 + sovProofs(uint64(m.Hash)) - } - if m.PrehashKey != 0 { - n += 1 + sovProofs(uint64(m.PrehashKey)) - } - if m.PrehashValue != 0 { - n += 1 + sovProofs(uint64(m.PrehashValue)) - } - if m.Length != 0 { - n += 1 + sovProofs(uint64(m.Length)) - } - l = len(m.Prefix) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - return n -} - -func (m *InnerOp) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Hash != 0 { - n += 1 + sovProofs(uint64(m.Hash)) - } - l = len(m.Prefix) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - l = len(m.Suffix) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - return n -} - -func (m *ProofSpec) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.LeafSpec != nil { - l = m.LeafSpec.Size() - n += 1 + l + sovProofs(uint64(l)) - } - if m.InnerSpec != nil { - l = m.InnerSpec.Size() - n += 1 + l + sovProofs(uint64(l)) - } - if m.MaxDepth != 0 { - n += 1 + sovProofs(uint64(m.MaxDepth)) - } - if m.MinDepth != 0 { - n += 1 + sovProofs(uint64(m.MinDepth)) - } - return n -} - -func (m *InnerSpec) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.ChildOrder) > 0 { - l = 0 - for _, e := range m.ChildOrder { - l += sovProofs(uint64(e)) - } - n += 1 + sovProofs(uint64(l)) + l - } - if m.ChildSize != 0 { - n += 1 + sovProofs(uint64(m.ChildSize)) - } - if m.MinPrefixLength != 0 { - n += 1 + sovProofs(uint64(m.MinPrefixLength)) - } - if m.MaxPrefixLength != 0 { - n += 1 + sovProofs(uint64(m.MaxPrefixLength)) - } - l = len(m.EmptyChild) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - if m.Hash != 0 { - n += 1 + sovProofs(uint64(m.Hash)) - } - return n -} - -func (m *BatchProof) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Entries) > 0 { - for _, e := range m.Entries { - l = e.Size() - n += 1 + l + sovProofs(uint64(l)) - } - } - return n -} - -func (m *BatchEntry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Proof != nil { - n += m.Proof.Size() - } - return n -} - -func (m *BatchEntry_Exist) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Exist != nil { - l = m.Exist.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} -func (m *BatchEntry_Nonexist) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Nonexist != nil { - l = m.Nonexist.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} -func (m *CompressedBatchProof) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Entries) > 0 { - for _, e := range m.Entries { - l = e.Size() - n += 1 + l + sovProofs(uint64(l)) - } - } - if len(m.LookupInners) > 0 { - for _, e := range m.LookupInners { - l = e.Size() - n += 1 + l + sovProofs(uint64(l)) - } - } - return n -} - -func (m *CompressedBatchEntry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Proof != nil { - n += m.Proof.Size() - } - return n -} - -func (m *CompressedBatchEntry_Exist) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Exist != nil { - l = m.Exist.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} -func (m *CompressedBatchEntry_Nonexist) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Nonexist != nil { - l = m.Nonexist.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} -func (m *CompressedExistenceProof) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Key) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - l = len(m.Value) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - if m.Leaf != nil { - l = m.Leaf.Size() - n += 1 + l + sovProofs(uint64(l)) - } - if len(m.Path) > 0 { - l = 0 - for _, e := range m.Path { - l += sovProofs(uint64(e)) - } - n += 1 + sovProofs(uint64(l)) + l - } - return n -} - -func (m *CompressedNonExistenceProof) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Key) - if l > 0 { - n += 1 + l + sovProofs(uint64(l)) - } - if m.Left != nil { - l = m.Left.Size() - n += 1 + l + sovProofs(uint64(l)) - } - if m.Right != nil { - l = m.Right.Size() - n += 1 + l + sovProofs(uint64(l)) - } - return n -} - -func sovProofs(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozProofs(x uint64) (n int) { - return sovProofs(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *ExistenceProof) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ExistenceProof: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ExistenceProof: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) - if m.Key == nil { - m.Key = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) - if m.Value == nil { - m.Value = []byte{} - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Leaf", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Leaf == nil { - m.Leaf = &LeafOp{} - } - if err := m.Leaf.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Path = append(m.Path, &InnerOp{}) - if err := m.Path[len(m.Path)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *NonExistenceProof) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: NonExistenceProof: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: NonExistenceProof: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) - if m.Key == nil { - m.Key = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Left", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Left == nil { - m.Left = &ExistenceProof{} - } - if err := m.Left.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Right", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Right == nil { - m.Right = &ExistenceProof{} - } - if err := m.Right.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CommitmentProof) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CommitmentProof: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CommitmentProof: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Exist", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &ExistenceProof{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Proof = &CommitmentProof_Exist{v} - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Nonexist", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &NonExistenceProof{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Proof = &CommitmentProof_Nonexist{v} - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Batch", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &BatchProof{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Proof = &CommitmentProof_Batch{v} - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Compressed", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &CompressedBatchProof{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Proof = &CommitmentProof_Compressed{v} - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *LeafOp) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: LeafOp: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: LeafOp: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) - } - m.Hash = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Hash |= HashOp(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PrehashKey", wireType) - } - m.PrehashKey = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PrehashKey |= HashOp(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PrehashValue", wireType) - } - m.PrehashValue = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PrehashValue |= HashOp(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Length", wireType) - } - m.Length = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Length |= LengthOp(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Prefix", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Prefix = append(m.Prefix[:0], dAtA[iNdEx:postIndex]...) - if m.Prefix == nil { - m.Prefix = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *InnerOp) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: InnerOp: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: InnerOp: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) - } - m.Hash = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Hash |= HashOp(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Prefix", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Prefix = append(m.Prefix[:0], dAtA[iNdEx:postIndex]...) - if m.Prefix == nil { - m.Prefix = []byte{} - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Suffix", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Suffix = append(m.Suffix[:0], dAtA[iNdEx:postIndex]...) - if m.Suffix == nil { - m.Suffix = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ProofSpec) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ProofSpec: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ProofSpec: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LeafSpec", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.LeafSpec == nil { - m.LeafSpec = &LeafOp{} - } - if err := m.LeafSpec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field InnerSpec", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.InnerSpec == nil { - m.InnerSpec = &InnerSpec{} - } - if err := m.InnerSpec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxDepth", wireType) - } - m.MaxDepth = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MaxDepth |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MinDepth", wireType) - } - m.MinDepth = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MinDepth |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *InnerSpec) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: InnerSpec: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: InnerSpec: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType == 0 { - var v int32 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.ChildOrder = append(m.ChildOrder, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.ChildOrder) == 0 { - m.ChildOrder = make([]int32, 0, elementCount) - } - for iNdEx < postIndex { - var v int32 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.ChildOrder = append(m.ChildOrder, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field ChildOrder", wireType) - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ChildSize", wireType) - } - m.ChildSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ChildSize |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MinPrefixLength", wireType) - } - m.MinPrefixLength = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MinPrefixLength |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxPrefixLength", wireType) - } - m.MaxPrefixLength = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MaxPrefixLength |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EmptyChild", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.EmptyChild = append(m.EmptyChild[:0], dAtA[iNdEx:postIndex]...) - if m.EmptyChild == nil { - m.EmptyChild = []byte{} - } - iNdEx = postIndex - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) - } - m.Hash = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Hash |= HashOp(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BatchProof) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: BatchProof: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BatchProof: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Entries = append(m.Entries, &BatchEntry{}) - if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BatchEntry) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: BatchEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BatchEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Exist", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &ExistenceProof{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Proof = &BatchEntry_Exist{v} - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Nonexist", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &NonExistenceProof{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Proof = &BatchEntry_Nonexist{v} - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CompressedBatchProof) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CompressedBatchProof: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CompressedBatchProof: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Entries = append(m.Entries, &CompressedBatchEntry{}) - if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LookupInners", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.LookupInners = append(m.LookupInners, &InnerOp{}) - if err := m.LookupInners[len(m.LookupInners)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CompressedBatchEntry) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CompressedBatchEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CompressedBatchEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Exist", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &CompressedExistenceProof{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Proof = &CompressedBatchEntry_Exist{v} - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Nonexist", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &CompressedNonExistenceProof{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Proof = &CompressedBatchEntry_Nonexist{v} - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CompressedExistenceProof) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CompressedExistenceProof: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CompressedExistenceProof: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) - if m.Key == nil { - m.Key = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) - if m.Value == nil { - m.Value = []byte{} - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Leaf", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Leaf == nil { - m.Leaf = &LeafOp{} - } - if err := m.Leaf.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType == 0 { - var v int32 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Path = append(m.Path, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.Path) == 0 { - m.Path = make([]int32, 0, elementCount) - } - for iNdEx < postIndex { - var v int32 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Path = append(m.Path, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) - } - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CompressedNonExistenceProof) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CompressedNonExistenceProof: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CompressedNonExistenceProof: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) - if m.Key == nil { - m.Key = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Left", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Left == nil { - m.Left = &CompressedExistenceProof{} - } - if err := m.Left.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Right", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProofs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProofs - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProofs - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Right == nil { - m.Right = &CompressedExistenceProof{} - } - if err := m.Right.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProofs(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProofs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipProofs(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProofs - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProofs - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProofs - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthProofs - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupProofs - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthProofs - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthProofs = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowProofs = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupProofs = fmt.Errorf("proto: unexpected end of group") -) diff --git a/proto/cosmos/base/store/v1beta1/listening.proto b/proto/cosmos/base/store/v1beta1/listening.proto index 359997109c10..753f7c165512 100644 --- a/proto/cosmos/base/store/v1beta1/listening.proto +++ b/proto/cosmos/base/store/v1beta1/listening.proto @@ -1,6 +1,8 @@ syntax = "proto3"; package cosmos.base.store.v1beta1; +import "tendermint/abci/types.proto"; + option go_package = "github.com/cosmos/cosmos-sdk/store/types"; // StoreKVPair is a KVStore KVPair used for listening to state changes (Sets and Deletes) @@ -14,3 +16,19 @@ message StoreKVPair { bytes key = 3; bytes value = 4; } + +// BlockMetadata contains all the abci event data of a block +// the file streamer dump them into files together with the state changes. +message BlockMetadata { + // DeliverTx encapulate deliver tx request and response. + message DeliverTx { + tendermint.abci.RequestDeliverTx request = 1; + tendermint.abci.ResponseDeliverTx response = 2; + } + tendermint.abci.RequestBeginBlock request_begin_block = 1; + tendermint.abci.ResponseBeginBlock response_begin_block = 2; + repeated DeliverTx deliver_txs = 3; + tendermint.abci.RequestEndBlock request_end_block = 4; + tendermint.abci.ResponseEndBlock response_end_block = 5; + tendermint.abci.ResponseCommit response_commit = 6; +} diff --git a/server/config/config.go b/server/config/config.go index 39f07558e42a..aa7039dc1e43 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -163,6 +163,37 @@ type StateSyncConfig struct { SnapshotKeepRecent uint32 `mapstructure:"snapshot-keep-recent"` } +type ( + // StoreConfig defines application configuration for state streaming and other + // storage related operations. + StoreConfig struct { + Streamers []string `mapstructure:"streamers"` + } + + // StreamersConfig defines concrete state streaming configuration options. These + // fields are required to be set when state streaming is enabled via a non-empty + // list defined by 'StoreConfig.Streamers'. + StreamersConfig struct { + File FileStreamerConfig `mapstructure:"file"` + } + + // FileStreamerConfig defines the file streaming configuration options. + FileStreamerConfig struct { + Keys []string `mapstructure:"keys"` + WriteDir string `mapstructure:"write_dir"` + Prefix string `mapstructure:"prefix"` + // OutputMetadata specifies if output the block metadata file which includes + // the abci requests/responses, otherwise only the data file is outputted. + OutputMetadata bool `mapstructure:"output-metadata"` + // StopNodeOnError specifies if propagate the streamer errors to the consensus + // state machine, it's nesserary for data integrity of output. + StopNodeOnError bool `mapstructure:"stop-node-on-error"` + // Fsync specifies if calling fsync after writing the files, it slows down + // the commit, but don't lose data in face of system crash. + Fsync bool `mapstructure:"fsync"` + } +) + // Config defines the server's top level configuration type Config struct { BaseConfig `mapstructure:",squash"` @@ -174,6 +205,8 @@ type Config struct { Rosetta RosettaConfig `mapstructure:"rosetta"` GRPCWeb GRPCWebConfig `mapstructure:"grpc-web"` StateSync StateSyncConfig `mapstructure:"state-sync"` + Store StoreConfig `mapstructure:"store"` + Streamers StreamersConfig `mapstructure:"streamers"` } // SetMinGasPrices sets the validator's minimum gas prices. @@ -250,83 +283,30 @@ func DefaultConfig() *Config { SnapshotInterval: 0, SnapshotKeepRecent: 2, }, + Store: StoreConfig{ + Streamers: []string{}, + }, + Streamers: StreamersConfig{ + File: FileStreamerConfig{ + Keys: []string{"*"}, + WriteDir: "", + OutputMetadata: true, + StopNodeOnError: true, + // NOTICE: The default config doesn't protect the streamer data integrity + // in face of system crash. + Fsync: false, + }, + }, } } // GetConfig returns a fully parsed Config object. func GetConfig(v *viper.Viper) (Config, error) { - globalLabelsRaw, ok := v.Get("telemetry.global-labels").([]interface{}) - if !ok { - return Config{}, fmt.Errorf("failed to parse global-labels config") + conf := DefaultConfig() + if err := v.Unmarshal(conf); err != nil { + return Config{}, fmt.Errorf("error extracting app config: %w", err) } - - globalLabels := make([][]string, 0, len(globalLabelsRaw)) - for idx, glr := range globalLabelsRaw { - labelsRaw, ok := glr.([]interface{}) - if !ok { - return Config{}, fmt.Errorf("failed to parse global label number %d from config", idx) - } - if len(labelsRaw) == 2 { - globalLabels = append(globalLabels, []string{labelsRaw[0].(string), labelsRaw[1].(string)}) - } - } - - return Config{ - BaseConfig: BaseConfig{ - MinGasPrices: v.GetString("minimum-gas-prices"), - InterBlockCache: v.GetBool("inter-block-cache"), - Pruning: v.GetString("pruning"), - PruningKeepRecent: v.GetString("pruning-keep-recent"), - PruningKeepEvery: v.GetString("pruning-keep-every"), - PruningInterval: v.GetString("pruning-interval"), - HaltHeight: v.GetUint64("halt-height"), - HaltTime: v.GetUint64("halt-time"), - IndexEvents: v.GetStringSlice("index-events"), - MinRetainBlocks: v.GetUint64("min-retain-blocks"), - IAVLCacheSize: v.GetUint64("iavl-cache-size"), - IAVLDisableFastNode: v.GetBool("iavl-disable-fastnode"), - }, - Telemetry: telemetry.Config{ - ServiceName: v.GetString("telemetry.service-name"), - Enabled: v.GetBool("telemetry.enabled"), - EnableHostname: v.GetBool("telemetry.enable-hostname"), - EnableHostnameLabel: v.GetBool("telemetry.enable-hostname-label"), - EnableServiceLabel: v.GetBool("telemetry.enable-service-label"), - PrometheusRetentionTime: v.GetInt64("telemetry.prometheus-retention-time"), - GlobalLabels: globalLabels, - }, - API: APIConfig{ - Enable: v.GetBool("api.enable"), - Swagger: v.GetBool("api.swagger"), - Address: v.GetString("api.address"), - MaxOpenConnections: v.GetUint("api.max-open-connections"), - RPCReadTimeout: v.GetUint("api.rpc-read-timeout"), - RPCWriteTimeout: v.GetUint("api.rpc-write-timeout"), - RPCMaxBodyBytes: v.GetUint("api.rpc-max-body-bytes"), - EnableUnsafeCORS: v.GetBool("api.enabled-unsafe-cors"), - }, - Rosetta: RosettaConfig{ - Enable: v.GetBool("rosetta.enable"), - Address: v.GetString("rosetta.address"), - Blockchain: v.GetString("rosetta.blockchain"), - Network: v.GetString("rosetta.network"), - Retries: v.GetInt("rosetta.retries"), - Offline: v.GetBool("rosetta.offline"), - }, - GRPC: GRPCConfig{ - Enable: v.GetBool("grpc.enable"), - Address: v.GetString("grpc.address"), - }, - GRPCWeb: GRPCWebConfig{ - Enable: v.GetBool("grpc-web.enable"), - Address: v.GetString("grpc-web.address"), - EnableUnsafeCORS: v.GetBool("grpc-web.enable-unsafe-cors"), - }, - StateSync: StateSyncConfig{ - SnapshotInterval: v.GetUint64("state-sync.snapshot-interval"), - SnapshotKeepRecent: v.GetUint32("state-sync.snapshot-keep-recent"), - }, - }, nil + return *conf, nil } // ValidateBasic returns an error if min-gas-prices field is empty in BaseConfig. Otherwise, it returns nil. diff --git a/server/config/toml.go b/server/config/toml.go index 523e97b9e368..ebacf240f451 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -209,6 +209,29 @@ snapshot-interval = {{ .StateSync.SnapshotInterval }} # snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). snapshot-keep-recent = {{ .StateSync.SnapshotKeepRecent }} + +############################################################################### +### Store / State Streaming ### +############################################################################### + +[store] +streamers = [{{ range .Store.Streamers }}{{ printf "%q, " . }}{{end}}] + +[streamers] +[streamers.file] +keys = [{{ range .Streamers.File.Keys }}{{ printf "%q, " . }}{{end}}] +write_dir = "{{ .Streamers.File.WriteDir }}" +prefix = "{{ .Streamers.File.Prefix }}" + +# output-metadata specifies if output the metadata file which includes the abci request/responses +# during processing the block. +output-metadata = "{{ .Streamers.File.OutputMetadata }}" + +# stop-node-on-error specifies if propagate the file streamer errors to consensus state machine. +stop-node-on-error = "{{ .Streamers.File.StopNodeOnError }}" + +# fsync specifies if call fsync after writing the files. +fsync = "{{ .Streamers.File.Fsync }}" ` var configTemplate *template.Template diff --git a/server/start.go b/server/start.go index 53f266a49537..5cde25f340b2 100644 --- a/server/start.go +++ b/server/start.go @@ -47,14 +47,14 @@ const ( FlagTrace = "trace" FlagInvCheckPeriod = "inv-check-period" - FlagPruning = "pruning" - FlagPruningKeepRecent = "pruning-keep-recent" - FlagPruningKeepEvery = "pruning-keep-every" - FlagPruningInterval = "pruning-interval" - FlagIndexEvents = "index-events" - FlagMinRetainBlocks = "min-retain-blocks" - FlagIAVLCacheSize = "iavl-cache-size" - FlagIAVLFastNode = "iavl-disable-fastnode" + FlagPruning = "pruning" + FlagPruningKeepRecent = "pruning-keep-recent" + FlagPruningKeepEvery = "pruning-keep-every" + FlagPruningInterval = "pruning-interval" + FlagIndexEvents = "index-events" + FlagMinRetainBlocks = "min-retain-blocks" + FlagIAVLCacheSize = "iavl-cache-size" + FlagDisableIAVLFastNode = "iavl-disable-fastnode" // state sync-related flags FlagStateSyncSnapshotInterval = "state-sync.snapshot-interval" @@ -165,7 +165,7 @@ is performed. Note, when enabled, gRPC will also be automatically enabled. cmd.Flags().Uint64(FlagStateSyncSnapshotInterval, 0, "State sync snapshot interval") cmd.Flags().Uint32(FlagStateSyncSnapshotKeepRecent, 2, "State sync snapshot to keep") - cmd.Flags().Bool(FlagIAVLFastNode, true, "Enable fast node for IAVL tree") + cmd.Flags().Bool(FlagDisableIAVLFastNode, true, "Disable fast node for IAVL tree") // add support for all Tendermint-specific command line options tcmd.AddNodeFlags(cmd) @@ -299,7 +299,9 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App // service if API or gRPC is enabled, and avoid doing so in the general // case, because it spawns a new local tendermint RPC client. if (config.API.Enable || config.GRPC.Enable) && tmNode != nil { - clientCtx := clientCtx.WithClient(local.New(tmNode)) + // re-assign for making the client available below + // do not use := to avoid shadowing clientCtx + clientCtx = clientCtx.WithClient(local.New(tmNode)) app.RegisterTxService(clientCtx) app.RegisterTendermintService(clientCtx) diff --git a/simapp/app.go b/simapp/app.go index f8386e42e5e0..a25c150488e8 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -2,6 +2,7 @@ package simapp import ( "encoding/json" + "fmt" "io" "net/http" "os" @@ -214,10 +215,10 @@ func NewSimApp( // not include this key. memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, "testingkey") - // configure state listening capabilities using AppOptions - // we are doing nothing with the returned streamingServices and waitGroup in this case + // load state streaming if enabled if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, keys); err != nil { - tmos.Exit(err.Error()) + fmt.Printf("failed to load state streaming: %s", err) + os.Exit(1) } app := &SimApp{ diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 9f8660a27f54..122569e79af0 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -276,7 +276,7 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, a baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval))), baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), - baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagIAVLFastNode))), + baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))), ) } diff --git a/store/cachekv/benchmark_test.go b/store/cachekv/benchmark_test.go new file mode 100644 index 000000000000..2db62ba5d6c6 --- /dev/null +++ b/store/cachekv/benchmark_test.go @@ -0,0 +1,161 @@ +package cachekv_test + +import ( + fmt "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" +) + +func DoBenchmarkDeepContextStack(b *testing.B, depth int) { + begin := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + end := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + key := storetypes.NewKVStoreKey("test") + + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, storetypes.StoreTypeIAVL, db) + cms.LoadLatestVersion() + ctx := sdk.NewContext(cms, tmproto.Header{}, false, log.NewNopLogger()) + + var stack ContextStack + stack.Reset(ctx) + + for i := 0; i < depth; i++ { + stack.Snapshot() + + store := stack.CurrentContext().KVStore(key) + store.Set(begin, []byte("value")) + } + + store := stack.CurrentContext().KVStore(key) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + it := store.Iterator(begin, end) + it.Valid() + it.Key() + it.Value() + it.Next() + it.Close() + } +} + +func BenchmarkDeepContextStack1(b *testing.B) { + DoBenchmarkDeepContextStack(b, 1) +} + +func BenchmarkDeepContextStack3(b *testing.B) { + DoBenchmarkDeepContextStack(b, 3) +} +func BenchmarkDeepContextStack10(b *testing.B) { + DoBenchmarkDeepContextStack(b, 10) +} + +func BenchmarkDeepContextStack13(b *testing.B) { + DoBenchmarkDeepContextStack(b, 13) +} + +// cachedContext is a pair of cache context and its corresponding commit method. +// They are obtained from the return value of `context.CacheContext()`. +type cachedContext struct { + ctx sdk.Context + commit func() +} + +// ContextStack manages the initial context and a stack of cached contexts, +// to support the `StateDB.Snapshot` and `StateDB.RevertToSnapshot` methods. +// +// Copied from an old version of ethermint +type ContextStack struct { + // Context of the initial state before transaction execution. + // It's the context used by `StateDB.CommitedState`. + initialCtx sdk.Context + cachedContexts []cachedContext +} + +// CurrentContext returns the top context of cached stack, +// if the stack is empty, returns the initial context. +func (cs *ContextStack) CurrentContext() sdk.Context { + l := len(cs.cachedContexts) + if l == 0 { + return cs.initialCtx + } + return cs.cachedContexts[l-1].ctx +} + +// Reset sets the initial context and clear the cache context stack. +func (cs *ContextStack) Reset(ctx sdk.Context) { + cs.initialCtx = ctx + if len(cs.cachedContexts) > 0 { + cs.cachedContexts = []cachedContext{} + } +} + +// IsEmpty returns true if the cache context stack is empty. +func (cs *ContextStack) IsEmpty() bool { + return len(cs.cachedContexts) == 0 +} + +// Commit commits all the cached contexts from top to bottom in order and clears the stack by setting an empty slice of cache contexts. +func (cs *ContextStack) Commit() { + // commit in order from top to bottom + for i := len(cs.cachedContexts) - 1; i >= 0; i-- { + if cs.cachedContexts[i].commit == nil { + panic(fmt.Sprintf("commit function at index %d should not be nil", i)) + } else { + cs.cachedContexts[i].commit() + } + } + cs.cachedContexts = []cachedContext{} +} + +// CommitToRevision commit the cache after the target revision, +// to improve efficiency of db operations. +func (cs *ContextStack) CommitToRevision(target int) error { + if target < 0 || target >= len(cs.cachedContexts) { + return fmt.Errorf("snapshot index %d out of bound [%d..%d)", target, 0, len(cs.cachedContexts)) + } + + // commit in order from top to bottom + for i := len(cs.cachedContexts) - 1; i > target; i-- { + if cs.cachedContexts[i].commit == nil { + return fmt.Errorf("commit function at index %d should not be nil", i) + } + cs.cachedContexts[i].commit() + } + cs.cachedContexts = cs.cachedContexts[0 : target+1] + + return nil +} + +// Snapshot pushes a new cached context to the stack, +// and returns the index of it. +func (cs *ContextStack) Snapshot() int { + i := len(cs.cachedContexts) + ctx, commit := cs.CurrentContext().CacheContext() + cs.cachedContexts = append(cs.cachedContexts, cachedContext{ctx: ctx, commit: commit}) + return i +} + +// RevertToSnapshot pops all the cached contexts after the target index (inclusive). +// the target should be snapshot index returned by `Snapshot`. +// This function panics if the index is out of bounds. +func (cs *ContextStack) RevertToSnapshot(target int) { + if target < 0 || target >= len(cs.cachedContexts) { + panic(fmt.Errorf("snapshot index %d out of bound [%d..%d)", target, 0, len(cs.cachedContexts))) + } + cs.cachedContexts = cs.cachedContexts[:target] +} + +// RevertAll discards all the cache contexts. +func (cs *ContextStack) RevertAll() { + if len(cs.cachedContexts) > 0 { + cs.RevertToSnapshot(0) + } +} diff --git a/store/cachekv/internal/btree.go b/store/cachekv/internal/btree.go new file mode 100644 index 000000000000..142f754bbd38 --- /dev/null +++ b/store/cachekv/internal/btree.go @@ -0,0 +1,80 @@ +package internal + +import ( + "bytes" + "errors" + + "github.com/tidwall/btree" +) + +const ( + // The approximate number of items and children per B-tree node. Tuned with benchmarks. + // copied from memdb. + bTreeDegree = 32 +) + +var errKeyEmpty = errors.New("key cannot be empty") + +// BTree implements the sorted cache for cachekv store, +// we don't use MemDB here because cachekv is used extensively in sdk core path, +// we need it to be as fast as possible, while `MemDB` is mainly used as a mocking db in unit tests. +// +// We choose tidwall/btree over google/btree here because it provides API to implement step iterator directly. +type BTree struct { + tree btree.BTreeG[item] +} + +// NewBTree creates a wrapper around `btree.BTreeG`. +func NewBTree() *BTree { + return &BTree{tree: *btree.NewBTreeGOptions(byKeys, btree.Options{ + Degree: bTreeDegree, + // Contract: cachekv store must not be called concurrently + NoLocks: true, + })} +} + +func (bt *BTree) Set(key, value []byte) { + bt.tree.Set(newItem(key, value)) +} + +func (bt *BTree) Get(key []byte) []byte { + i, found := bt.tree.Get(newItem(key, nil)) + if !found { + return nil + } + return i.value +} + +func (bt *BTree) Delete(key []byte) { + bt.tree.Delete(newItem(key, nil)) +} + +func (bt *BTree) Iterator(start, end []byte) (*memIterator, error) { + if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) { + return nil, errKeyEmpty + } + return NewMemIterator(start, end, bt, make(map[string]struct{}), true), nil +} + +func (bt *BTree) ReverseIterator(start, end []byte) (*memIterator, error) { + if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) { + return nil, errKeyEmpty + } + return NewMemIterator(start, end, bt, make(map[string]struct{}), false), nil +} + +// item is a btree item with byte slices as keys and values +type item struct { + key []byte + value []byte +} + +// byKeys compares the items by key +func byKeys(a, b item) bool { + return bytes.Compare(a.key, b.key) == -1 +} + +// newItem creates a new pair item. +func newItem(key, value []byte) item { + return item{key: key, value: value} +} diff --git a/store/cachekv/internal/btree_test.go b/store/cachekv/internal/btree_test.go new file mode 100644 index 000000000000..f85a8bbaf109 --- /dev/null +++ b/store/cachekv/internal/btree_test.go @@ -0,0 +1,202 @@ +package internal + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestGetSetDelete(t *testing.T) { + db := NewBTree() + + // A nonexistent key should return nil. + value := db.Get([]byte("a")) + require.Nil(t, value) + + // Set and get a value. + db.Set([]byte("a"), []byte{0x01}) + db.Set([]byte("b"), []byte{0x02}) + value = db.Get([]byte("a")) + require.Equal(t, []byte{0x01}, value) + + value = db.Get([]byte("b")) + require.Equal(t, []byte{0x02}, value) + + // Deleting a non-existent value is fine. + db.Delete([]byte("x")) + + // Delete a value. + db.Delete([]byte("a")) + + value = db.Get([]byte("a")) + require.Nil(t, value) + + db.Delete([]byte("b")) + + value = db.Get([]byte("b")) + require.Nil(t, value) +} + +func TestDBIterator(t *testing.T) { + db := NewBTree() + + for i := 0; i < 10; i++ { + if i != 6 { // but skip 6. + db.Set(int642Bytes(int64(i)), []byte{}) + } + } + + // Blank iterator keys should error + _, err := db.ReverseIterator([]byte{}, nil) + require.Equal(t, errKeyEmpty, err) + _, err = db.ReverseIterator(nil, []byte{}) + require.Equal(t, errKeyEmpty, err) + + itr, err := db.Iterator(nil, nil) + require.NoError(t, err) + verifyIterator(t, itr, []int64{0, 1, 2, 3, 4, 5, 7, 8, 9}, "forward iterator") + + ritr, err := db.ReverseIterator(nil, nil) + require.NoError(t, err) + verifyIterator(t, ritr, []int64{9, 8, 7, 5, 4, 3, 2, 1, 0}, "reverse iterator") + + itr, err = db.Iterator(nil, int642Bytes(0)) + require.NoError(t, err) + verifyIterator(t, itr, []int64(nil), "forward iterator to 0") + + ritr, err = db.ReverseIterator(int642Bytes(10), nil) + require.NoError(t, err) + verifyIterator(t, ritr, []int64(nil), "reverse iterator from 10 (ex)") + + itr, err = db.Iterator(int642Bytes(0), nil) + require.NoError(t, err) + verifyIterator(t, itr, []int64{0, 1, 2, 3, 4, 5, 7, 8, 9}, "forward iterator from 0") + + itr, err = db.Iterator(int642Bytes(1), nil) + require.NoError(t, err) + verifyIterator(t, itr, []int64{1, 2, 3, 4, 5, 7, 8, 9}, "forward iterator from 1") + + ritr, err = db.ReverseIterator(nil, int642Bytes(10)) + require.NoError(t, err) + verifyIterator(t, ritr, + []int64{9, 8, 7, 5, 4, 3, 2, 1, 0}, "reverse iterator from 10 (ex)") + + ritr, err = db.ReverseIterator(nil, int642Bytes(9)) + require.NoError(t, err) + verifyIterator(t, ritr, + []int64{8, 7, 5, 4, 3, 2, 1, 0}, "reverse iterator from 9 (ex)") + + ritr, err = db.ReverseIterator(nil, int642Bytes(8)) + require.NoError(t, err) + verifyIterator(t, ritr, + []int64{7, 5, 4, 3, 2, 1, 0}, "reverse iterator from 8 (ex)") + + itr, err = db.Iterator(int642Bytes(5), int642Bytes(6)) + require.NoError(t, err) + verifyIterator(t, itr, []int64{5}, "forward iterator from 5 to 6") + + itr, err = db.Iterator(int642Bytes(5), int642Bytes(7)) + require.NoError(t, err) + verifyIterator(t, itr, []int64{5}, "forward iterator from 5 to 7") + + itr, err = db.Iterator(int642Bytes(5), int642Bytes(8)) + require.NoError(t, err) + verifyIterator(t, itr, []int64{5, 7}, "forward iterator from 5 to 8") + + itr, err = db.Iterator(int642Bytes(6), int642Bytes(7)) + require.NoError(t, err) + verifyIterator(t, itr, []int64(nil), "forward iterator from 6 to 7") + + itr, err = db.Iterator(int642Bytes(6), int642Bytes(8)) + require.NoError(t, err) + verifyIterator(t, itr, []int64{7}, "forward iterator from 6 to 8") + + itr, err = db.Iterator(int642Bytes(7), int642Bytes(8)) + require.NoError(t, err) + verifyIterator(t, itr, []int64{7}, "forward iterator from 7 to 8") + + ritr, err = db.ReverseIterator(int642Bytes(4), int642Bytes(5)) + require.NoError(t, err) + verifyIterator(t, ritr, []int64{4}, "reverse iterator from 5 (ex) to 4") + + ritr, err = db.ReverseIterator(int642Bytes(4), int642Bytes(6)) + require.NoError(t, err) + verifyIterator(t, ritr, + []int64{5, 4}, "reverse iterator from 6 (ex) to 4") + + ritr, err = db.ReverseIterator(int642Bytes(4), int642Bytes(7)) + require.NoError(t, err) + verifyIterator(t, ritr, + []int64{5, 4}, "reverse iterator from 7 (ex) to 4") + + ritr, err = db.ReverseIterator(int642Bytes(5), int642Bytes(6)) + require.NoError(t, err) + verifyIterator(t, ritr, []int64{5}, "reverse iterator from 6 (ex) to 5") + + ritr, err = db.ReverseIterator(int642Bytes(5), int642Bytes(7)) + require.NoError(t, err) + verifyIterator(t, ritr, []int64{5}, "reverse iterator from 7 (ex) to 5") + + ritr, err = db.ReverseIterator(int642Bytes(6), int642Bytes(7)) + require.NoError(t, err) + verifyIterator(t, ritr, + []int64(nil), "reverse iterator from 7 (ex) to 6") + + ritr, err = db.ReverseIterator(int642Bytes(10), nil) + require.NoError(t, err) + verifyIterator(t, ritr, []int64(nil), "reverse iterator to 10") + + ritr, err = db.ReverseIterator(int642Bytes(6), nil) + require.NoError(t, err) + verifyIterator(t, ritr, []int64{9, 8, 7}, "reverse iterator to 6") + + ritr, err = db.ReverseIterator(int642Bytes(5), nil) + require.NoError(t, err) + verifyIterator(t, ritr, []int64{9, 8, 7, 5}, "reverse iterator to 5") + + ritr, err = db.ReverseIterator(int642Bytes(8), int642Bytes(9)) + require.NoError(t, err) + verifyIterator(t, ritr, []int64{8}, "reverse iterator from 9 (ex) to 8") + + ritr, err = db.ReverseIterator(int642Bytes(2), int642Bytes(4)) + require.NoError(t, err) + verifyIterator(t, ritr, + []int64{3, 2}, "reverse iterator from 4 (ex) to 2") + + ritr, err = db.ReverseIterator(int642Bytes(4), int642Bytes(2)) + require.NoError(t, err) + verifyIterator(t, ritr, + []int64(nil), "reverse iterator from 2 (ex) to 4") + + // Ensure that the iterators don't panic with an empty database. + db2 := NewBTree() + + itr, err = db2.Iterator(nil, nil) + require.NoError(t, err) + verifyIterator(t, itr, nil, "forward iterator with empty db") + + ritr, err = db2.ReverseIterator(nil, nil) + require.NoError(t, err) + verifyIterator(t, ritr, nil, "reverse iterator with empty db") +} + +func verifyIterator(t *testing.T, itr *memIterator, expected []int64, msg string) { + i := 0 + for itr.Valid() { + key := itr.Key() + require.Equal(t, expected[i], bytes2Int64(key), "iterator: %d mismatches", i) + itr.Next() + i++ + } + require.Equal(t, i, len(expected), "expected to have fully iterated over all the elements in iter") + require.NoError(t, itr.Close()) +} + +func int642Bytes(i int64) []byte { + return sdk.Uint64ToBigEndian(uint64(i)) +} + +func bytes2Int64(buf []byte) int64 { + return int64(sdk.BigEndianToUint64(buf)) +} diff --git a/store/cachekv/internal/memiterator.go b/store/cachekv/internal/memiterator.go new file mode 100644 index 000000000000..2bceb8bc77df --- /dev/null +++ b/store/cachekv/internal/memiterator.go @@ -0,0 +1,137 @@ +package internal + +import ( + "bytes" + "errors" + + "github.com/cosmos/cosmos-sdk/store/types" + "github.com/tidwall/btree" +) + +var _ types.Iterator = (*memIterator)(nil) + +// memIterator iterates over iterKVCache items. +// if key is nil, means it was deleted. +// Implements Iterator. +type memIterator struct { + iter btree.GenericIter[item] + + start []byte + end []byte + ascending bool + lastKey []byte + deleted map[string]struct{} + valid bool +} + +func NewMemIterator(start, end []byte, items *BTree, deleted map[string]struct{}, ascending bool) *memIterator { + iter := items.tree.Iter() + var valid bool + if ascending { + if start != nil { + valid = iter.Seek(newItem(start, nil)) + } else { + valid = iter.First() + } + } else { + if end != nil { + valid = iter.Seek(newItem(end, nil)) + if !valid { + valid = iter.Last() + } else { + // end is exclusive + valid = iter.Prev() + } + } else { + valid = iter.Last() + } + } + + mi := &memIterator{ + iter: iter, + start: start, + end: end, + ascending: ascending, + lastKey: nil, + deleted: deleted, + valid: valid, + } + + if mi.valid { + mi.valid = mi.keyInRange(mi.Key()) + } + + return mi +} + +func (mi *memIterator) Domain() (start []byte, end []byte) { + return mi.start, mi.end +} + +func (mi *memIterator) Close() error { + mi.iter.Release() + return nil +} + +func (mi *memIterator) Error() error { + if !mi.Valid() { + return errors.New("invalid memIterator") + } + return nil +} + +func (mi *memIterator) Valid() bool { + return mi.valid +} + +func (mi *memIterator) Next() { + mi.assertValid() + + if mi.ascending { + mi.valid = mi.iter.Next() + } else { + mi.valid = mi.iter.Prev() + } + + if mi.valid { + mi.valid = mi.keyInRange(mi.Key()) + } +} + +func (mi *memIterator) keyInRange(key []byte) bool { + if mi.ascending && mi.end != nil && bytes.Compare(key, mi.end) >= 0 { + return false + } + if !mi.ascending && mi.start != nil && bytes.Compare(key, mi.start) < 0 { + return false + } + return true +} + +func (mi *memIterator) Key() []byte { + return mi.iter.Item().key +} + +func (mi *memIterator) Value() []byte { + item := mi.iter.Item() + key := item.key + // We need to handle the case where deleted is modified and includes our current key + // We handle this by maintaining a lastKey object in the iterator. + // If the current key is the same as the last key (and last key is not nil / the start) + // then we are calling value on the same thing as last time. + // Therefore we don't check the mi.deleted to see if this key is included in there. + if _, ok := mi.deleted[string(key)]; ok { + if mi.lastKey == nil || !bytes.Equal(key, mi.lastKey) { + // not re-calling on old last key + return nil + } + } + mi.lastKey = key + return item.value +} + +func (mi *memIterator) assertValid() { + if err := mi.Error(); err != nil { + panic(err) + } +} diff --git a/store/cachekv/mergeiterator.go b/store/cachekv/internal/mergeiterator.go similarity index 87% rename from store/cachekv/mergeiterator.go rename to store/cachekv/internal/mergeiterator.go index b8bbee6c5ddf..b25ad6fcbc3f 100644 --- a/store/cachekv/mergeiterator.go +++ b/store/cachekv/internal/mergeiterator.go @@ -1,4 +1,4 @@ -package cachekv +package internal import ( "bytes" @@ -18,17 +18,20 @@ type cacheMergeIterator struct { parent types.Iterator cache types.Iterator ascending bool + + valid bool } var _ types.Iterator = (*cacheMergeIterator)(nil) -func newCacheMergeIterator(parent, cache types.Iterator, ascending bool) *cacheMergeIterator { +func NewCacheMergeIterator(parent, cache types.Iterator, ascending bool) *cacheMergeIterator { iter := &cacheMergeIterator{ parent: parent, cache: cache, ascending: ascending, } + iter.valid = iter.skipUntilExistsOrInvalid() return iter } @@ -56,42 +59,38 @@ func (iter *cacheMergeIterator) Domain() (start, end []byte) { // Valid implements Iterator. func (iter *cacheMergeIterator) Valid() bool { - return iter.skipUntilExistsOrInvalid() + return iter.valid } // Next implements Iterator func (iter *cacheMergeIterator) Next() { - iter.skipUntilExistsOrInvalid() iter.assertValid() - // If parent is invalid, get the next cache item. - if !iter.parent.Valid() { + switch { + case !iter.parent.Valid(): + // If parent is invalid, get the next cache item. iter.cache.Next() - return - } - - // If cache is invalid, get the next parent item. - if !iter.cache.Valid() { + case !iter.cache.Valid(): + // If cache is invalid, get the next parent item. iter.parent.Next() - return - } - - // Both are valid. Compare keys. - keyP, keyC := iter.parent.Key(), iter.cache.Key() - switch iter.compare(keyP, keyC) { - case -1: // parent < cache - iter.parent.Next() - case 0: // parent == cache - iter.parent.Next() - iter.cache.Next() - case 1: // parent > cache - iter.cache.Next() + default: + // Both are valid. Compare keys. + keyP, keyC := iter.parent.Key(), iter.cache.Key() + switch iter.compare(keyP, keyC) { + case -1: // parent < cache + iter.parent.Next() + case 0: // parent == cache + iter.parent.Next() + iter.cache.Next() + case 1: // parent > cache + iter.cache.Next() + } } + iter.valid = iter.skipUntilExistsOrInvalid() } // Key implements Iterator func (iter *cacheMergeIterator) Key() []byte { - iter.skipUntilExistsOrInvalid() iter.assertValid() // If parent is invalid, get the cache key. @@ -122,7 +121,6 @@ func (iter *cacheMergeIterator) Key() []byte { // Value implements Iterator func (iter *cacheMergeIterator) Value() []byte { - iter.skipUntilExistsOrInvalid() iter.assertValid() // If parent is invalid, get the cache value. @@ -153,11 +151,12 @@ func (iter *cacheMergeIterator) Value() []byte { // Close implements Iterator func (iter *cacheMergeIterator) Close() error { + err1 := iter.cache.Close() if err := iter.parent.Close(); err != nil { return err } - return iter.cache.Close() + return err1 } // Error returns an error if the cacheMergeIterator is invalid defined by the diff --git a/store/cachekv/memiterator.go b/store/cachekv/memiterator.go deleted file mode 100644 index 04df40ff56aa..000000000000 --- a/store/cachekv/memiterator.go +++ /dev/null @@ -1,56 +0,0 @@ -package cachekv - -import ( - "bytes" - - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/store/types" -) - -// Iterates over iterKVCache items. -// if key is nil, means it was deleted. -// Implements Iterator. -type memIterator struct { - types.Iterator - - lastKey []byte - deleted map[string]struct{} -} - -func newMemIterator(start, end []byte, items *dbm.MemDB, deleted map[string]struct{}, ascending bool) *memIterator { - var iter types.Iterator - var err error - - if ascending { - iter, err = items.Iterator(start, end) - } else { - iter, err = items.ReverseIterator(start, end) - } - - if err != nil { - panic(err) - } - - return &memIterator{ - Iterator: iter, - - lastKey: nil, - deleted: deleted, - } -} - -func (mi *memIterator) Value() []byte { - key := mi.Iterator.Key() - // We need to handle the case where deleted is modified and includes our current key - // We handle this by maintaining a lastKey object in the iterator. - // If the current key is the same as the last key (and last key is not nil / the start) - // then we are calling value on the same thing as last time. - // Therefore we don't check the mi.deleted to see if this key is included in there. - reCallingOnOldLastKey := (mi.lastKey != nil) && bytes.Equal(key, mi.lastKey) - if _, ok := mi.deleted[string(key)]; ok && !reCallingOnOldLastKey { - return nil - } - mi.lastKey = key - return mi.Iterator.Value() -} diff --git a/store/cachekv/search_benchmark_test.go b/store/cachekv/search_benchmark_test.go index 921bff4e3864..4007c7cda202 100644 --- a/store/cachekv/search_benchmark_test.go +++ b/store/cachekv/search_benchmark_test.go @@ -4,7 +4,7 @@ import ( "strconv" "testing" - db "github.com/tendermint/tm-db" + "github.com/cosmos/cosmos-sdk/store/cachekv/internal" ) func BenchmarkLargeUnsortedMisses(b *testing.B) { @@ -39,6 +39,6 @@ func generateStore() *Store { return &Store{ cache: cache, unsortedCache: unsorted, - sortedCache: db.NewMemDB(), + sortedCache: internal.NewBTree(), } } diff --git a/store/cachekv/store.go b/store/cachekv/store.go index e596689877f8..b52d98e21bc1 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -10,7 +10,7 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/internal/conv" - "github.com/cosmos/cosmos-sdk/store/listenkv" + "github.com/cosmos/cosmos-sdk/store/cachekv/internal" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/telemetry" @@ -31,7 +31,7 @@ type Store struct { cache map[string]*cValue deleted map[string]struct{} unsortedCache map[string]struct{} - sortedCache *dbm.MemDB // always ascending sorted + sortedCache *internal.BTree // always ascending sorted parent types.KVStore } @@ -43,7 +43,7 @@ func NewStore(parent types.KVStore) *Store { cache: make(map[string]*cValue), deleted: make(map[string]struct{}), unsortedCache: make(map[string]struct{}), - sortedCache: dbm.NewMemDB(), + sortedCache: internal.NewBTree(), parent: parent, } } @@ -104,6 +104,11 @@ func (store *Store) Write() { defer store.mtx.Unlock() defer telemetry.MeasureSince(time.Now(), "store", "cachekv", "write") + if len(store.cache) == 0 && len(store.deleted) == 0 && len(store.unsortedCache) == 0 { + store.sortedCache = internal.NewBTree() + return + } + // We need a copy of all of the keys. // Not the best, but probably not a bottleneck depending. keys := make([]string, 0, len(store.cache)) @@ -147,7 +152,7 @@ func (store *Store) Write() { for key := range store.unsortedCache { delete(store.unsortedCache, key) } - store.sortedCache = dbm.NewMemDB() + store.sortedCache = internal.NewBTree() } // CacheWrap implements CacheWrapper. @@ -160,11 +165,6 @@ func (store *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types return NewStore(tracekv.NewStore(store, w, tc)) } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (store *Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { - return NewStore(listenkv.NewStore(store, storeKey, listeners)) -} - //---------------------------------------- // Iteration @@ -191,9 +191,9 @@ func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator { } store.dirtyItems(start, end) - cache = newMemIterator(start, end, store.sortedCache, store.deleted, ascending) + cache = internal.NewMemIterator(start, end, store.sortedCache, store.deleted, ascending) - return newCacheMergeIterator(parent, cache, ascending) + return internal.NewCacheMergeIterator(parent, cache, ascending) } func findStartIndex(strL []string, startQ string) int { @@ -281,7 +281,7 @@ const minSortSize = 1024 // Constructs a slice of dirty items, to use w/ memIterator. func (store *Store) dirtyItems(start, end []byte) { startStr, endStr := conv.UnsafeBytesToStr(start), conv.UnsafeBytesToStr(end) - if startStr > endStr { + if end != nil && startStr > endStr { // Nothing to do here. return } @@ -296,6 +296,7 @@ func (store *Store) dirtyItems(start, end []byte) { // than just not having the cache. if n < minSortSize { for key := range store.unsortedCache { + // dbm.IsKeyInDomain is nil safe and returns true iff key is greater than start if dbm.IsKeyInDomain(conv.UnsafeStrToBytes(key), start, end) { cacheValue := store.cache[key] unsorted = append(unsorted, &kv.Pair{Key: []byte(key), Value: cacheValue.value}) @@ -313,7 +314,7 @@ func (store *Store) dirtyItems(start, end []byte) { } sort.Strings(strL) - startIndex, endIndex := findStartEndIndex(strL, startStr, endStr) + startIndex, endIndex := findStartEndIndex(strL, startStr, endStr, end) // Since we spent cycles to sort the values, we should process and remove a reasonable amount // ensure start to end is at least minSortSize in size @@ -337,18 +338,24 @@ func (store *Store) dirtyItems(start, end []byte) { store.clearUnsortedCacheSubset(kvL, stateAlreadySorted) } -func findStartEndIndex(strL []string, startStr, endStr string) (int, int) { +func findStartEndIndex(strL []string, startStr, endStr string, end []byte) (int, int) { // Now find the values within the domain // [start, end) startIndex := findStartIndex(strL, startStr) - endIndex := findEndIndex(strL, endStr) + if startIndex < 0 { + startIndex = 0 + } - if endIndex < 0 { + var endIndex int + if end == nil { endIndex = len(strL) - 1 + } else { + endIndex = findEndIndex(strL, endStr) } - if startIndex < 0 { - startIndex = 0 + if endIndex < 0 { + endIndex = len(strL) - 1 } + return startIndex, endIndex } @@ -365,14 +372,11 @@ func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair, sortState sort if item.Value == nil { // deleted element, tracked by store.deleted // setting arbitrary value - // TODO: Don't ignore this error. store.sortedCache.Set(item.Key, []byte{}) continue } - err := store.sortedCache.Set(item.Key, item.Value) - if err != nil { - panic(err) - } + + store.sortedCache.Set(item.Key, item.Value) } } diff --git a/store/cachekv/store_test.go b/store/cachekv/store_test.go index d589932d30fc..3ef99fd6f144 100644 --- a/store/cachekv/store_test.go +++ b/store/cachekv/store_test.go @@ -120,6 +120,7 @@ func TestCacheKVIteratorBounds(t *testing.T) { i++ } require.Equal(t, nItems, i) + require.NoError(t, itr.Close()) // iterate over none itr = st.Iterator(bz("money"), nil) @@ -128,6 +129,7 @@ func TestCacheKVIteratorBounds(t *testing.T) { i++ } require.Equal(t, 0, i) + require.NoError(t, itr.Close()) // iterate over lower itr = st.Iterator(keyFmt(0), keyFmt(3)) @@ -139,6 +141,7 @@ func TestCacheKVIteratorBounds(t *testing.T) { i++ } require.Equal(t, 3, i) + require.NoError(t, itr.Close()) // iterate over upper itr = st.Iterator(keyFmt(2), keyFmt(4)) @@ -150,6 +153,64 @@ func TestCacheKVIteratorBounds(t *testing.T) { i++ } require.Equal(t, 4, i) + require.NoError(t, itr.Close()) +} + +func TestCacheKVReverseIteratorBounds(t *testing.T) { + st := newCacheKVStore() + + // set some items + nItems := 5 + for i := 0; i < nItems; i++ { + st.Set(keyFmt(i), valFmt(i)) + } + + // iterate over all of them + itr := st.ReverseIterator(nil, nil) + i := 0 + for ; itr.Valid(); itr.Next() { + k, v := itr.Key(), itr.Value() + require.Equal(t, keyFmt(nItems-1-i), k) + require.Equal(t, valFmt(nItems-1-i), v) + i++ + } + require.Equal(t, nItems, i) + require.NoError(t, itr.Close()) + + // iterate over none + itr = st.ReverseIterator(bz("money"), nil) + i = 0 + for ; itr.Valid(); itr.Next() { + i++ + } + require.Equal(t, 0, i) + require.NoError(t, itr.Close()) + + // iterate over lower + end := 3 + itr = st.ReverseIterator(keyFmt(0), keyFmt(end)) + i = 0 + for ; itr.Valid(); itr.Next() { + i++ + k, v := itr.Key(), itr.Value() + require.Equal(t, keyFmt(end-i), k) + require.Equal(t, valFmt(end-i), v) + } + require.Equal(t, 3, i) + require.NoError(t, itr.Close()) + + // iterate over upper + end = 4 + itr = st.ReverseIterator(keyFmt(2), keyFmt(end)) + i = 0 + for ; itr.Valid(); itr.Next() { + i++ + k, v := itr.Key(), itr.Value() + require.Equal(t, keyFmt(end-i), k) + require.Equal(t, valFmt(end-i), v) + } + require.Equal(t, 2, i) + require.NoError(t, itr.Close()) } func TestCacheKVMergeIteratorBasics(t *testing.T) { @@ -291,6 +352,25 @@ func TestCacheKVMergeIteratorChunks(t *testing.T) { assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 35}, {38, 40}, {45, 80}}) } +func TestCacheKVMergeIteratorDomain(t *testing.T) { + st := newCacheKVStore() + + itr := st.Iterator(nil, nil) + start, end := itr.Domain() + require.Equal(t, start, end) + require.NoError(t, itr.Close()) + + itr = st.Iterator(keyFmt(40), keyFmt(60)) + start, end = itr.Domain() + require.Equal(t, keyFmt(40), start) + require.Equal(t, keyFmt(60), end) + require.NoError(t, itr.Close()) + + start, end = st.ReverseIterator(keyFmt(0), keyFmt(80)).Domain() + require.Equal(t, keyFmt(0), start) + require.Equal(t, keyFmt(80), end) +} + func TestCacheKVMergeIteratorRandom(t *testing.T) { st := newCacheKVStore() truth := dbm.NewMemDB() @@ -306,6 +386,67 @@ func TestCacheKVMergeIteratorRandom(t *testing.T) { } } +func TestNilEndIterator(t *testing.T) { + const SIZE = 3000 + + tests := []struct { + name string + write bool + startIndex int + end []byte + }{ + {name: "write=false, end=nil", write: false, end: nil, startIndex: 1000}, + {name: "write=false, end=nil; full key scan", write: false, end: nil, startIndex: 2000}, + {name: "write=true, end=nil", write: true, end: nil, startIndex: 1000}, + {name: "write=false, end=non-nil", write: false, end: keyFmt(3000), startIndex: 1000}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + st := newCacheKVStore() + + for i := 0; i < SIZE; i++ { + kstr := keyFmt(i) + st.Set(kstr, valFmt(i)) + } + + if tt.write { + st.Write() + } + + itr := st.Iterator(keyFmt(tt.startIndex), tt.end) + i := tt.startIndex + j := 0 + for itr.Valid() { + require.Equal(t, keyFmt(i), itr.Key()) + require.Equal(t, valFmt(i), itr.Value()) + itr.Next() + i++ + j++ + } + + require.Equal(t, SIZE-tt.startIndex, j) + require.NoError(t, itr.Close()) + }) + } +} + +// TestIteratorDeadlock demonstrate the deadlock issue in cache store. +func TestIteratorDeadlock(t *testing.T) { + mem := dbadapter.Store{DB: dbm.NewMemDB()} + store := cachekv.NewStore(mem) + // the channel buffer is 64 and received once, so put at least 66 elements. + for i := 0; i < 66; i++ { + store.Set([]byte(fmt.Sprintf("key%d", i)), []byte{1}) + } + it := store.Iterator(nil, nil) + defer it.Close() + store.Set([]byte("key20"), []byte{1}) + // it'll be blocked here with previous version, or enable lock on btree. + it2 := store.Iterator(nil, nil) + defer it2.Close() +} + //------------------------------------------------------------------------------------------- // do some random ops @@ -388,6 +529,7 @@ func assertIterateDomain(t *testing.T, st types.KVStore, expectedN int) { i++ } require.Equal(t, expectedN, i) + require.NoError(t, itr.Close()) } func assertIterateDomainCheck(t *testing.T, st types.KVStore, mem dbm.DB, r []keyRange) { @@ -419,6 +561,8 @@ func assertIterateDomainCheck(t *testing.T, st types.KVStore, mem dbm.DB, r []ke require.False(t, itr.Valid()) require.False(t, itr2.Valid()) + require.NoError(t, itr.Close()) + require.NoError(t, itr2.Close()) } func assertIterateDomainCompare(t *testing.T, st types.KVStore, mem dbm.DB) { @@ -428,6 +572,8 @@ func assertIterateDomainCompare(t *testing.T, st types.KVStore, mem dbm.DB) { require.NoError(t, err) checkIterators(t, itr, itr2) checkIterators(t, itr2, itr) + require.NoError(t, itr.Close()) + require.NoError(t, itr2.Close()) } func checkIterators(t *testing.T, itr, itr2 types.Iterator) { diff --git a/store/cachemulti/store.go b/store/cachemulti/store.go index d64dc03aca12..cf15b13d16d7 100644 --- a/store/cachemulti/store.go +++ b/store/cachemulti/store.go @@ -8,11 +8,14 @@ import ( "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/dbadapter" - "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" ) +// storeNameCtxKey is the TraceContext metadata key that identifies +// the store which emitted a given trace. +const storeNameCtxKey = "store_name" + //---------------------------------------- // Store @@ -27,8 +30,6 @@ type Store struct { traceWriter io.Writer traceContext types.TraceContext - - listeners map[types.StoreKey][]types.WriteListener } var _ types.CacheMultiStore = Store{} @@ -39,26 +40,22 @@ var _ types.CacheMultiStore = Store{} func NewFromKVStore( store types.KVStore, stores map[types.StoreKey]types.CacheWrapper, keys map[string]types.StoreKey, traceWriter io.Writer, traceContext types.TraceContext, - listeners map[types.StoreKey][]types.WriteListener, ) Store { - if listeners == nil { - listeners = make(map[types.StoreKey][]types.WriteListener) - } cms := Store{ db: cachekv.NewStore(store), stores: make(map[types.StoreKey]types.CacheWrap, len(stores)), keys: keys, traceWriter: traceWriter, traceContext: traceContext, - listeners: listeners, } for key, store := range stores { if cms.TracingEnabled() { - store = tracekv.NewStore(store.(types.KVStore), cms.traceWriter, cms.traceContext) - } - if cms.ListeningEnabled(key) { - store = listenkv.NewStore(store.(types.KVStore), key, listeners[key]) + tctx := cms.traceContext.Clone().Merge(types.TraceContext{ + storeNameCtxKey: key.Name(), + }) + + store = tracekv.NewStore(store.(types.KVStore), cms.traceWriter, tctx) } cms.stores[key] = cachekv.NewStore(store.(types.KVStore)) } @@ -70,9 +67,9 @@ func NewFromKVStore( // CacheWrapper objects. Each CacheWrapper store is a branched store. func NewStore( db dbm.DB, stores map[types.StoreKey]types.CacheWrapper, keys map[string]types.StoreKey, - traceWriter io.Writer, traceContext types.TraceContext, listeners map[types.StoreKey][]types.WriteListener, + traceWriter io.Writer, traceContext types.TraceContext, ) Store { - return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext, listeners) + return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext) } func newCacheMultiStoreFromCMS(cms Store) Store { @@ -81,8 +78,7 @@ func newCacheMultiStoreFromCMS(cms Store) Store { stores[k] = v } - // don't pass listeners to nested cache store. - return NewFromKVStore(cms.db, stores, nil, cms.traceWriter, cms.traceContext, nil) + return NewFromKVStore(cms.db, stores, nil, cms.traceWriter, cms.traceContext) } // SetTracer sets the tracer for the MultiStore that the underlying @@ -113,23 +109,6 @@ func (cms Store) TracingEnabled() bool { return cms.traceWriter != nil } -// AddListeners adds listeners for a specific KVStore -func (cms Store) AddListeners(key types.StoreKey, listeners []types.WriteListener) { - if ls, ok := cms.listeners[key]; ok { - cms.listeners[key] = append(ls, listeners...) - } else { - cms.listeners[key] = listeners - } -} - -// ListeningEnabled returns if listening is enabled for a specific KVStore -func (cms Store) ListeningEnabled(key types.StoreKey) bool { - if ls, ok := cms.listeners[key]; ok { - return len(ls) != 0 - } - return false -} - // GetStoreType returns the type of the store. func (cms Store) GetStoreType() types.StoreType { return types.StoreTypeMulti @@ -153,11 +132,6 @@ func (cms Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cac return cms.CacheWrap() } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (cms Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { - return cms.CacheWrap() -} - // Implements MultiStore. func (cms Store) CacheMultiStore() types.CacheMultiStore { return newCacheMultiStoreFromCMS(cms) diff --git a/store/dbadapter/store.go b/store/dbadapter/store.go index 2f0ceb5df54a..e9ea4f847d14 100644 --- a/store/dbadapter/store.go +++ b/store/dbadapter/store.go @@ -6,7 +6,6 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/cachekv" - "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -86,10 +85,5 @@ func (dsa Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Ca return cachekv.NewStore(tracekv.NewStore(dsa, w, tc)) } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (dsa Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { - return cachekv.NewStore(listenkv.NewStore(dsa, storeKey, listeners)) -} - // dbm.DB implements KVStore so we can CacheKVStore it. var _ types.KVStore = Store{} diff --git a/store/dbadapter/store_test.go b/store/dbadapter/store_test.go index 9f8ac71b25cf..658b9d1b999e 100644 --- a/store/dbadapter/store_test.go +++ b/store/dbadapter/store_test.go @@ -84,7 +84,4 @@ func TestCacheWraps(t *testing.T) { cacheWrappedWithTrace := store.CacheWrapWithTrace(nil, nil) require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace) - - cacheWrappedWithListeners := store.CacheWrapWithListeners(nil, nil) - require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners) } diff --git a/store/gaskv/store.go b/store/gaskv/store.go index f36119169c76..13c12f36af57 100644 --- a/store/gaskv/store.go +++ b/store/gaskv/store.go @@ -96,11 +96,6 @@ func (gs *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cac panic("cannot CacheWrapWithTrace a GasKVStore") } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (gs *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { - panic("cannot CacheWrapWithListeners a GasKVStore") -} - func (gs *Store) iterator(start, end []byte, ascending bool) types.Iterator { var parent types.Iterator if ascending { diff --git a/store/gaskv/store_test.go b/store/gaskv/store_test.go index 90137f344bac..eacdf181bb7f 100644 --- a/store/gaskv/store_test.go +++ b/store/gaskv/store_test.go @@ -25,7 +25,6 @@ func TestGasKVStoreBasic(t *testing.T) { require.Equal(t, types.StoreTypeDB, st.GetStoreType()) require.Panics(t, func() { st.CacheWrap() }) require.Panics(t, func() { st.CacheWrapWithTrace(nil, nil) }) - require.Panics(t, func() { st.CacheWrapWithListeners(nil, nil) }) require.Panics(t, func() { st.Set(nil, []byte("value")) }, "setting a nil key should panic") require.Panics(t, func() { st.Set([]byte(""), []byte("value")) }, "setting an empty key should panic") diff --git a/store/iavl/store.go b/store/iavl/store.go index a44cc1d531b3..d27aa6d39dbe 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -14,7 +14,6 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/cachekv" - "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/telemetry" @@ -109,7 +108,7 @@ func UnsafeNewStore(tree *iavl.MutableTree) *Store { // Any mutable operations executed will result in a panic. func (st *Store) GetImmutable(version int64) (*Store, error) { if !st.VersionExists(version) { - return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}}, nil + return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}}, fmt.Errorf("version mismatch on immutable IAVL tree; version does not exist. Version has either been pruned, or is for a future block height") } iTree, err := st.tree.GetImmutable(version) @@ -188,11 +187,6 @@ func (st *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Ca return cachekv.NewStore(tracekv.NewStore(st, w, tc)) } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (st *Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { - return cachekv.NewStore(listenkv.NewStore(st, storeKey, listeners)) -} - // Implements types.KVStore. func (st *Store) Set(key, value []byte) { types.AssertValidKey(key) diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index f1cd586e36a0..8379779c158b 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -127,7 +127,7 @@ func TestGetImmutable(t *testing.T) { require.Nil(t, err) _, err = store.GetImmutable(cID.Version + 1) - require.NoError(t, err) + require.Error(t, err) newStore, err := store.GetImmutable(cID.Version - 1) require.NoError(t, err) @@ -655,7 +655,4 @@ func TestCacheWraps(t *testing.T) { cacheWrappedWithTrace := store.CacheWrapWithTrace(nil, nil) require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace) - - cacheWrappedWithListeners := store.CacheWrapWithListeners(nil, nil) - require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners) } diff --git a/store/listenkv/store.go b/store/listenkv/store.go index dfb6dea46c2f..4595d0fe56d1 100644 --- a/store/listenkv/store.go +++ b/store/listenkv/store.go @@ -141,12 +141,6 @@ func (s *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cach panic("cannot CacheWrapWithTrace a ListenKVStore") } -// CacheWrapWithListeners implements the KVStore interface. It panics as a -// Store cannot be cache wrapped. -func (s *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { - panic("cannot CacheWrapWithListeners a ListenKVStore") -} - // onWrite writes a KVStore operation to all of the WriteListeners func (s *Store) onWrite(delete bool, key, value []byte) { for _, l := range s.listeners { diff --git a/store/listenkv/store_test.go b/store/listenkv/store_test.go index 8d0510ba49ce..44be4120427b 100644 --- a/store/listenkv/store_test.go +++ b/store/listenkv/store_test.go @@ -292,8 +292,3 @@ func TestListenKVStoreCacheWrapWithTrace(t *testing.T) { store := newEmptyListenKVStore(nil) require.Panics(t, func() { store.CacheWrapWithTrace(nil, nil) }) } - -func TestListenKVStoreCacheWrapWithListeners(t *testing.T) { - store := newEmptyListenKVStore(nil) - require.Panics(t, func() { store.CacheWrapWithListeners(nil, nil) }) -} diff --git a/store/mem/mem_test.go b/store/mem/mem_test.go index a2fc6add8a3e..893a4d286fbd 100644 --- a/store/mem/mem_test.go +++ b/store/mem/mem_test.go @@ -33,9 +33,6 @@ func TestStore(t *testing.T) { cacheWrappedWithTrace := db.CacheWrapWithTrace(nil, nil) require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace) - - cacheWrappedWithListeners := db.CacheWrapWithListeners(nil, nil) - require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners) } func TestCommit(t *testing.T) { diff --git a/store/mem/store.go b/store/mem/store.go index b7eda8b1297f..ef4e70089e56 100644 --- a/store/mem/store.go +++ b/store/mem/store.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/dbadapter" - "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -46,11 +45,6 @@ func (s Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Cach return cachekv.NewStore(tracekv.NewStore(s, w, tc)) } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (s Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { - return cachekv.NewStore(listenkv.NewStore(s, storeKey, listeners)) -} - // Commit performs a no-op as entries are persistent between commitments. func (s *Store) Commit() (id types.CommitID) { return } diff --git a/store/prefix/store.go b/store/prefix/store.go index 295278a0a853..4f9d5a75e087 100644 --- a/store/prefix/store.go +++ b/store/prefix/store.go @@ -6,7 +6,6 @@ import ( "io" "github.com/cosmos/cosmos-sdk/store/cachekv" - "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -58,11 +57,6 @@ func (s Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Cach return cachekv.NewStore(tracekv.NewStore(s, w, tc)) } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (s Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { - return cachekv.NewStore(listenkv.NewStore(s, storeKey, listeners)) -} - // Implements KVStore func (s Store) Get(key []byte) []byte { res := s.parent.Get(s.key(key)) diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index 25e07cbb1ae3..8da075dc9031 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -438,7 +438,4 @@ func TestCacheWraps(t *testing.T) { cacheWrappedWithTrace := store.CacheWrapWithTrace(nil, nil) require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace) - - cacheWrappedWithListeners := store.CacheWrapWithListeners(nil, nil) - require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 7e5d032850e3..f34159e29e51 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -331,13 +331,7 @@ func (rs *Store) SetTracer(w io.Writer) types.MultiStore { func (rs *Store) SetTracingContext(tc types.TraceContext) types.MultiStore { rs.traceContextMutex.Lock() defer rs.traceContextMutex.Unlock() - if rs.traceContext != nil { - for k, v := range tc { - rs.traceContext[k] = v - } - } else { - rs.traceContext = tc - } + rs.traceContext = rs.traceContext.Merge(tc) return rs } @@ -478,19 +472,20 @@ func (rs *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cac return rs.CacheWrap() } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (rs *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { - return rs.CacheWrap() -} - // CacheMultiStore creates ephemeral branch of the multi-store and returns a CacheMultiStore. // It implements the MultiStore interface. func (rs *Store) CacheMultiStore() types.CacheMultiStore { stores := make(map[types.StoreKey]types.CacheWrapper) for k, v := range rs.stores { - stores[k] = v + store := types.KVStore(v) + // Wire the listenkv.Store to allow listeners to observe the writes from the cache store, + // set same listeners on cache store will observe duplicated writes. + if rs.ListeningEnabled(k) { + store = listenkv.NewStore(store, k, rs.listeners[k]) + } + stores[k] = store } - return cachemulti.NewStore(rs.db, stores, rs.keysByName, rs.traceWriter, rs.getTracingContext(), rs.listeners) + return cachemulti.NewStore(rs.db, stores, rs.keysByName, rs.traceWriter, rs.getTracingContext()) } // CacheMultiStoreWithVersion is analogous to CacheMultiStore except that it @@ -500,6 +495,7 @@ func (rs *Store) CacheMultiStore() types.CacheMultiStore { func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStore, error) { cachedStores := make(map[types.StoreKey]types.CacheWrapper) for key, store := range rs.stores { + var cacheStore types.KVStore switch store.GetStoreType() { case types.StoreTypeIAVL: // If the store is wrapped with an inter-block cache, we must first unwrap @@ -508,19 +504,25 @@ func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStor // Attempt to lazy-load an already saved IAVL store version. If the // version does not exist or is pruned, an error should be returned. - iavlStore, err := store.(*iavl.Store).GetImmutable(version) + var err error + cacheStore, err = store.(*iavl.Store).GetImmutable(version) if err != nil { return nil, err } - - cachedStores[key] = iavlStore - default: - cachedStores[key] = store + cacheStore = store } + + // Wire the listenkv.Store to allow listeners to observe the writes from the cache store, + // set same listeners on cache store will observe duplicated writes. + if rs.ListeningEnabled(key) { + cacheStore = listenkv.NewStore(cacheStore, key, rs.listeners[key]) + } + + cachedStores[key] = cacheStore } - return cachemulti.NewStore(rs.db, cachedStores, rs.keysByName, rs.traceWriter, rs.getTracingContext(), rs.listeners), nil + return cachemulti.NewStore(rs.db, cachedStores, rs.keysByName, rs.traceWriter, rs.getTracingContext()), nil } // GetStore returns a mounted Store for a given StoreKey. If the StoreKey does @@ -549,7 +551,7 @@ func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore { if s == nil { panic(fmt.Sprintf("store does not exist for key: %s", key.Name())) } - store := s.(types.KVStore) + store := types.KVStore(s) if rs.TracingEnabled() { store = tracekv.NewStore(store, rs.traceWriter, rs.getTracingContext()) diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index fd706dd3c987..e5719b23b1f8 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -85,9 +85,9 @@ func TestCacheMultiStoreWithVersion(t *testing.T) { cID := ms.Commit() require.Equal(t, int64(1), cID.Version) - // require no failure when given an invalid or pruned version + // require error when given an invalid or pruned version _, err = ms.CacheMultiStoreWithVersion(cID.Version + 1) - require.NoError(t, err) + require.Error(t, err) // require a valid version can be cache-loaded cms, err := ms.CacheMultiStoreWithVersion(cID.Version) @@ -499,7 +499,7 @@ func TestMultiStore_Pruning(t *testing.T) { saved []int64 }{ {"prune nothing", 10, types.PruneNothing, nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, - {"prune everything", 10, types.PruneEverything, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}}, + {"prune everything", 10, types.PruneEverything, []int64{1, 2, 3, 4, 5, 6, 7}, []int64{8, 9, 10}}, {"prune some; no batch", 10, types.NewPruningOptions(2, 3, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}}, {"prune some; small batch", 10, types.NewPruningOptions(2, 3, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}}, {"prune some; large batch", 10, types.NewPruningOptions(2, 3, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, @@ -519,12 +519,12 @@ func TestMultiStore_Pruning(t *testing.T) { for _, v := range tc.saved { _, err := ms.CacheMultiStoreWithVersion(v) - require.NoError(t, err, "expected error when loading height: %d", v) + require.NoError(t, err, "expected no error when loading height: %d", v) } for _, v := range tc.deleted { _, err := ms.CacheMultiStoreWithVersion(v) - require.NoError(t, err, "expected error when loading height: %d", v) + require.Error(t, err, "expected error when loading height: %d", v) } }) } @@ -560,7 +560,7 @@ func TestMultiStore_PruningRestart(t *testing.T) { for _, v := range pruneHeights { _, err := ms.CacheMultiStoreWithVersion(v) - require.NoError(t, err, "expected error when loading height: %d", v) + require.Error(t, err, "expected error when loading height: %d", v) } } @@ -696,9 +696,6 @@ func TestCacheWraps(t *testing.T) { cacheWrappedWithTrace := multi.CacheWrapWithTrace(nil, nil) require.IsType(t, cachemulti.Store{}, cacheWrappedWithTrace) - - cacheWrappedWithListeners := multi.CacheWrapWithListeners(nil, nil) - require.IsType(t, cachemulti.Store{}, cacheWrappedWithListeners) } func TestTraceConcurrency(t *testing.T) { diff --git a/store/streaming/constructor.go b/store/streaming/constructor.go index e576f84b83d1..02b5f34f472c 100644 --- a/store/streaming/constructor.go +++ b/store/streaming/constructor.go @@ -2,20 +2,24 @@ package streaming import ( "fmt" + "os" + "path" "strings" "sync" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" serverTypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/store/streaming/file" "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cast" ) // ServiceConstructor is used to construct a streaming service -type ServiceConstructor func(opts serverTypes.AppOptions, keys []types.StoreKey, marshaller codec.BinaryCodec) (baseapp.StreamingService, error) +type ServiceConstructor func(serverTypes.AppOptions, []types.StoreKey, codec.BinaryCodec) (baseapp.StreamingService, error) // ServiceType enum for specifying the type of StreamingService type ServiceType int @@ -23,14 +27,26 @@ type ServiceType int const ( Unknown ServiceType = iota File - // add more in the future ) -// ServiceTypeFromString returns the streaming.ServiceType corresponding to the provided name +// Streaming option keys +const ( + OptStreamersFilePrefix = "streamers.file.prefix" + OptStreamersFileWriteDir = "streamers.file.write_dir" + OptStreamersFileOutputMetadata = "streamers.file.output-metadata" + OptStreamersFileStopNodeOnError = "streamers.file.stop-node-on-error" + OptStreamersFileFsync = "streamers.file.fsync" + + OptStoreStreamers = "store.streamers" +) + +// ServiceTypeFromString returns the streaming.ServiceType corresponding to the +// provided name. func ServiceTypeFromString(name string) ServiceType { switch strings.ToLower(name) { case "file", "f": return File + default: return Unknown } @@ -41,48 +57,87 @@ func (sst ServiceType) String() string { switch sst { case File: return "file" + default: return "unknown" } } -// ServiceConstructorLookupTable is a mapping of streaming.ServiceTypes to streaming.ServiceConstructors +// ServiceConstructorLookupTable is a mapping of streaming.ServiceTypes to +// streaming.ServiceConstructors types. var ServiceConstructorLookupTable = map[ServiceType]ServiceConstructor{ File: NewFileStreamingService, } -// NewServiceConstructor returns the streaming.ServiceConstructor corresponding to the provided name +// NewServiceConstructor returns the streaming.ServiceConstructor corresponding +// to the provided name. func NewServiceConstructor(name string) (ServiceConstructor, error) { ssType := ServiceTypeFromString(name) if ssType == Unknown { return nil, fmt.Errorf("unrecognized streaming service name %s", name) } + if constructor, ok := ServiceConstructorLookupTable[ssType]; ok && constructor != nil { return constructor, nil } + return nil, fmt.Errorf("streaming service constructor of type %s not found", ssType.String()) } -// NewFileStreamingService is the streaming.ServiceConstructor function for creating a FileStreamingService -func NewFileStreamingService(opts serverTypes.AppOptions, keys []types.StoreKey, marshaller codec.BinaryCodec) (baseapp.StreamingService, error) { - filePrefix := cast.ToString(opts.Get("streamers.file.prefix")) - fileDir := cast.ToString(opts.Get("streamers.file.write_dir")) - return file.NewStreamingService(fileDir, filePrefix, keys, marshaller) +// NewFileStreamingService is the streaming.ServiceConstructor function for +// creating a FileStreamingService. +func NewFileStreamingService( + opts serverTypes.AppOptions, + keys []types.StoreKey, + marshaller codec.BinaryCodec, +) (baseapp.StreamingService, error) { + homePath := cast.ToString(opts.Get(flags.FlagHome)) + filePrefix := cast.ToString(opts.Get(OptStreamersFilePrefix)) + fileDir := cast.ToString(opts.Get(OptStreamersFileWriteDir)) + outputMetadata := cast.ToBool(opts.Get(OptStreamersFileOutputMetadata)) + stopNodeOnErr := cast.ToBool(opts.Get(OptStreamersFileStopNodeOnError)) + fsync := cast.ToBool(opts.Get(OptStreamersFileFsync)) + + // relative path is based on node home directory. + if !path.IsAbs(fileDir) { + fileDir = path.Join(homePath, fileDir) + } + + // try to create output directory if it does not exist + if _, err := os.Stat(fileDir); os.IsNotExist(err) { + if err = os.MkdirAll(fileDir, os.ModePerm); err != nil { + return nil, err + } + } + + return file.NewStreamingService(fileDir, filePrefix, keys, marshaller, outputMetadata, stopNodeOnErr, fsync) } -// LoadStreamingServices is a function for loading StreamingServices onto the BaseApp using the provided AppOptions, codec, and keys -// It returns the WaitGroup and quit channel used to synchronize with the streaming services and any error that occurs during the setup -func LoadStreamingServices(bApp *baseapp.BaseApp, appOpts serverTypes.AppOptions, appCodec codec.BinaryCodec, keys map[string]*types.KVStoreKey) ([]baseapp.StreamingService, *sync.WaitGroup, error) { +// LoadStreamingServices is a function for loading StreamingServices onto the +// BaseApp using the provided AppOptions, codec, and keys. It returns the +// WaitGroup and quit channel used to synchronize with the streaming services +// and any error that occurs during the setup. +func LoadStreamingServices( + bApp *baseapp.BaseApp, + appOpts serverTypes.AppOptions, + appCodec codec.BinaryCodec, + keys map[string]*types.KVStoreKey, +) ([]baseapp.StreamingService, *sync.WaitGroup, error) { // waitgroup and quit channel for optional shutdown coordination of the streaming service(s) wg := new(sync.WaitGroup) + // configure state listening capabilities using AppOptions - streamers := cast.ToStringSlice(appOpts.Get("store.streamers")) + streamers := cast.ToStringSlice(appOpts.Get(OptStoreStreamers)) activeStreamers := make([]baseapp.StreamingService, 0, len(streamers)) + for _, streamerName := range streamers { + var exposeStoreKeys []types.StoreKey + // get the store keys allowed to be exposed for this streaming service exposeKeyStrs := cast.ToStringSlice(appOpts.Get(fmt.Sprintf("streamers.%s.keys", streamerName))) - var exposeStoreKeys []types.StoreKey - if exposeAll(exposeKeyStrs) { // if list contains `*`, expose all StoreKeys + + // if list contains '*', expose all store keys + if sdk.SliceContains(exposeKeyStrs, "*") { exposeStoreKeys = make([]types.StoreKey, 0, len(keys)) for _, storeKey := range keys { exposeStoreKeys = append(exposeStoreKeys, storeKey) @@ -95,43 +150,46 @@ func LoadStreamingServices(bApp *baseapp.BaseApp, appOpts serverTypes.AppOptions } } } - if len(exposeStoreKeys) == 0 { // short circuit if we are not exposing anything + + if len(exposeStoreKeys) == 0 { continue } - // get the constructor for this streamer name + constructor, err := NewServiceConstructor(streamerName) if err != nil { - // close any services we may have already spun up before hitting the error on this one + // Close any services we may have already spun up before hitting the error + // on this one. for _, activeStreamer := range activeStreamers { activeStreamer.Close() } + return nil, nil, err } - // generate the streaming service using the constructor, appOptions, and the StoreKeys we want to expose + + // Generate the streaming service using the constructor, appOptions, and the + // StoreKeys we want to expose. streamingService, err := constructor(appOpts, exposeStoreKeys, appCodec) if err != nil { - // close any services we may have already spun up before hitting the error on this one + // Close any services we may have already spun up before hitting the error + // on this one. for _, activeStreamer := range activeStreamers { activeStreamer.Close() } + return nil, nil, err } + // register the streaming service with the BaseApp bApp.SetStreamingService(streamingService) + // kick off the background streaming service loop streamingService.Stream(wg) + // add to the list of active streamers activeStreamers = append(activeStreamers, streamingService) } - // if there are no active streamers, activeStreamers is empty (len == 0) and the waitGroup is not waiting on anything - return activeStreamers, wg, nil -} -func exposeAll(list []string) bool { - for _, ele := range list { - if ele == "*" { - return true - } - } - return false + // If there are no active streamers, activeStreamers is empty (len == 0) and + // the waitGroup is not waiting on anything. + return activeStreamers, wg, nil } diff --git a/store/streaming/constructor_test.go b/store/streaming/constructor_test.go index 5f9d58016f68..f23fa499e827 100644 --- a/store/streaming/constructor_test.go +++ b/store/streaming/constructor_test.go @@ -1,20 +1,32 @@ -package streaming +package streaming_test import ( "testing" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" codecTypes "github.com/cosmos/cosmos-sdk/codec/types" + serverTypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/store/streaming" "github.com/cosmos/cosmos-sdk/store/streaming/file" "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" "github.com/stretchr/testify/require" ) type fakeOptions struct{} -func (f *fakeOptions) Get(string) interface{} { return nil } +func (f *fakeOptions) Get(key string) interface{} { + if key == "streamers.file.write_dir" { + return "data/file_streamer" + + } + return nil +} var ( mockOptions = new(fakeOptions) @@ -24,12 +36,12 @@ var ( ) func TestStreamingServiceConstructor(t *testing.T) { - _, err := NewServiceConstructor("unexpectedName") + _, err := streaming.NewServiceConstructor("unexpectedName") require.NotNil(t, err) - constructor, err := NewServiceConstructor("file") + constructor, err := streaming.NewServiceConstructor("file") require.Nil(t, err) - var expectedType ServiceConstructor + var expectedType streaming.ServiceConstructor require.IsType(t, expectedType, constructor) serv, err := constructor(mockOptions, mockKeys, testMarshaller) @@ -41,3 +53,55 @@ func TestStreamingServiceConstructor(t *testing.T) { require.True(t, ok) } } + +func TestLoadStreamingServices(t *testing.T) { + db := dbm.NewMemDB() + encCdc := simapp.MakeTestEncodingConfig() + keys := sdk.NewKVStoreKeys("mockKey1", "mockKey2") + bApp := baseapp.NewBaseApp("appName", log.NewNopLogger(), db, nil) + + testCases := map[string]struct { + appOpts serverTypes.AppOptions + activeStreamersLen int + }{ + "empty app options": { + appOpts: simapp.EmptyAppOptions{}, + }, + "all StoreKeys exposed": { + appOpts: streamingAppOptions{keys: []string{"*"}}, + activeStreamersLen: 1, + }, + "some StoreKey exposed": { + appOpts: streamingAppOptions{keys: []string{"mockKey1"}}, + activeStreamersLen: 1, + }, + "not exposing anything": { + appOpts: streamingAppOptions{keys: []string{"mockKey3"}}, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + activeStreamers, _, err := streaming.LoadStreamingServices(bApp, tc.appOpts, encCdc.Marshaler, keys) + require.NoError(t, err) + require.Equal(t, tc.activeStreamersLen, len(activeStreamers)) + }) + } +} + +type streamingAppOptions struct { + keys []string +} + +func (ao streamingAppOptions) Get(o string) interface{} { + switch o { + case "store.streamers": + return []string{"file"} + case "streamers.file.keys": + return ao.keys + case "streamers.file.write_dir": + return "data/file_streamer" + default: + return nil + } +} diff --git a/store/streaming/file/README.md b/store/streaming/file/README.md index 7243f15dd0bf..0c34de7f3bea 100644 --- a/store/streaming/file/README.md +++ b/store/streaming/file/README.md @@ -1,4 +1,5 @@ # File Streaming Service + This pkg contains an implementation of the [StreamingService](../../../baseapp/streaming.go) that writes the data stream out to files on the local filesystem. This process is performed synchronously with the message processing of the state machine. @@ -23,42 +24,68 @@ The `file.StreamingService` is configured from within an App using the `AppOptio We turn the service on by adding its name, "file", to `store.streamers`- the list of streaming services for this App to employ. In `streamers.file` we include three configuration parameters for the file streaming service: -1. `streamers.x.keys` contains the list of `StoreKey` names for the KVStores to expose using this service. -In order to expose *all* KVStores, we can include `*` in this list. An empty list is equivalent to turning the service off. + +1. `streamers.file.keys` contains the list of `StoreKey` names for the KVStores to expose using this service. + In order to expose *all* KVStores, we can include `*` in this list. An empty list is equivalent to turning the service off. 2. `streamers.file.write_dir` contains the path to the directory to write the files to. 3. `streamers.file.prefix` contains an optional prefix to prepend to the output files to prevent potential collisions -with other App `StreamingService` output files. - -##### Encoding - -For each pair of `BeginBlock` requests and responses, a file is created and named `block-{N}-begin`, where N is the block number. -At the head of this file the length-prefixed protobuf encoded `BeginBlock` request is written. -At the tail of this file the length-prefixed protobuf encoded `BeginBlock` response is written. -In between these two encoded messages, the state changes that occurred due to the `BeginBlock` request are written chronologically as -a series of length-prefixed protobuf encoded `StoreKVPair`s representing `Set` and `Delete` operations within the KVStores the service -is configured to listen to. - -For each pair of `DeliverTx` requests and responses, a file is created and named `block-{N}-tx-{M}` where N is the block number and M -is the tx number in the block (i.e. 0, 1, 2...). -At the head of this file the length-prefixed protobuf encoded `DeliverTx` request is written. -At the tail of this file the length-prefixed protobuf encoded `DeliverTx` response is written. -In between these two encoded messages, the state changes that occurred due to the `DeliverTx` request are written chronologically as -a series of length-prefixed protobuf encoded `StoreKVPair`s representing `Set` and `Delete` operations within the KVStores the service -is configured to listen to. - -For each pair of `EndBlock` requests and responses, a file is created and named `block-{N}-end`, where N is the block number. -At the head of this file the length-prefixed protobuf encoded `EndBlock` request is written. -At the tail of this file the length-prefixed protobuf encoded `EndBlock` response is written. -In between these two encoded messages, the state changes that occurred due to the `EndBlock` request are written chronologically as -a series of length-prefixed protobuf encoded `StoreKVPair`s representing `Set` and `Delete` operations within the KVStores the service -is configured to listen to. - -##### Decoding - -To decode the files written in the above format we read all the bytes from a given file into memory and segment them into proto -messages based on the length-prefixing of each message. Once segmented, it is known that the first message is the ABCI request, -the last message is the ABCI response, and that every message in between is a `StoreKVPair`. This enables us to decode each segment into -the appropriate message type. - -The type of ABCI req/res, the block height, and the transaction index (where relevant) is known -from the file name, and the KVStore each `StoreKVPair` originates from is known since the `StoreKey` is included as a field in the proto message. + with other App `StreamingService` output files. +4. `streamers.file.output-metadata` specifies if output the metadata file, otherwise only data file is outputted. +5. `streamers.file.stop-node-on-error` specifies if propagate the error to consensus state machine, it's nesserary for data integrity when node restarts. +6. `streamers.file.fsync` specifies if call fsync after writing the files, it's nesserary for data integrity when system crash, but slows down the commit time. + +### Encoding + +For each block, two files are created and names `block-{N}-meta` and `block-{N}-data`, where `N` is the block number. + +The meta file contains the protobuf encoded message `BlockMetadata` which contains the abci event requests and responses of the block: + +```protobuf +message BlockMetadata { + message DeliverTx { + tendermint.abci.RequestDeliverTx request = 1; + tendermint.abci.ResponseDeliverTx response = 2; + } + tendermint.abci.RequestBeginBlock request_begin_block = 1; + tendermint.abci.ResponseBeginBlock response_begin_block = 2; + repeated DeliverTx deliver_txs = 3; + tendermint.abci.RequestEndBlock request_end_block = 4; + tendermint.abci.ResponseEndBlock response_end_block = 5; + tendermint.abci.ResponseCommit response_commit = 6; +} +``` + +The data file contains a series of length-prefixed protobuf encoded `StoreKVPair`s representing `Set` and `Delete` operations within the KVStores during the execution of block. + +Both meta and data files are prefixed with the length of the data content for consumer to detect completeness of the file, the length is encoded as 8 bytes with big endianness. + +The files are written at abci commit event, by default the error happens will be propagated to interuppted consensus state machine, but fsync is not called, it'll have good performance but have the risk of lossing data in face of rare event of system crash. + +### Decoding + +The pseudo-code for decoding is like this: + +```python +def decode_meta_file(file): + bz = file.read(8) + if len(bz) < 8: + raise "incomplete file exception" + size = int.from_bytes(bz, 'big') + + if file.size != size + 8: + raise "incomplete file exception" + + return decode_protobuf_message(BlockMetadata, file) + +def decode_data_file(file): + bz = file.read(8) + if len(bz) < 8: + raise "incomplete file exception" + size = int.from_bytes(bz, 'big') + + if file.size != size + 8: + raise "incomplete file exception" + + while not file.eof(): + yield decode_length_prefixed_protobuf_message(StoreKVStore, file) +``` diff --git a/store/streaming/file/service.go b/store/streaming/file/service.go index 685ba7d9d770..97badfc40336 100644 --- a/store/streaming/file/service.go +++ b/store/streaming/file/service.go @@ -1,11 +1,13 @@ package file import ( - "errors" + "bytes" + "context" "fmt" + "io" "os" "path" - "path/filepath" + "sort" "sync" abci "github.com/tendermint/tendermint/abci/types" @@ -14,265 +16,228 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var _ baseapp.StreamingService = &StreamingService{} -// StreamingService is a concrete implementation of StreamingService that writes state changes out to files +// StreamingService is a concrete implementation of StreamingService that writes +// state changes out to files. type StreamingService struct { - listeners map[types.StoreKey][]types.WriteListener // the listeners that will be initialized with BaseApp - srcChan <-chan []byte // the channel that all the WriteListeners write their data out to - filePrefix string // optional prefix for each of the generated files - writeDir string // directory to write files into - codec codec.BinaryCodec // marshaller used for re-marshalling the ABCI messages to write them out to the destination files - stateCache [][]byte // cache the protobuf binary encoded StoreKVPairs in the order they are received - stateCacheLock *sync.Mutex // mutex for the state cache - currentBlockNumber int64 // the current block number - currentTxIndex int64 // the index of the current tx - quitChan chan struct{} // channel to synchronize closure -} + storeListeners []*types.MemoryListener // a series of KVStore listeners for each KVStore + filePrefix string // optional prefix for each of the generated files + writeDir string // directory to write files into + codec codec.BinaryCodec // marshaller used for re-marshalling the ABCI messages to write them out to the destination files -// IntermediateWriter is used so that we do not need to update the underlying io.Writer -// inside the StoreKVPairWriteListener everytime we begin writing to a new file -type IntermediateWriter struct { - outChan chan<- []byte -} + currentBlockNumber int64 + blockMetadata types.BlockMetadata -// NewIntermediateWriter create an instance of an intermediateWriter that sends to the provided channel -func NewIntermediateWriter(outChan chan<- []byte) *IntermediateWriter { - return &IntermediateWriter{ - outChan: outChan, - } -} + // outputMetadata, if true, writes additional metadata to file per block + outputMetadata bool -// Write satisfies io.Writer -func (iw *IntermediateWriter) Write(b []byte) (int, error) { - iw.outChan <- b - return len(b), nil + // stopNodeOnErr, if true, will panic and stop the node during ABCI Commit + // to ensure eventual consistency of the output, otherwise, any errors are + // logged and ignored which could yield data loss in streamed output. + stopNodeOnErr bool + + // fsync, if true, will execute file Sync to make sure the data is persisted + // onto disk, otherwise there is a risk of data loss during any crash. + fsync bool } -// NewStreamingService creates a new StreamingService for the provided writeDir, (optional) filePrefix, and storeKeys -func NewStreamingService(writeDir, filePrefix string, storeKeys []types.StoreKey, c codec.BinaryCodec) (*StreamingService, error) { - listenChan := make(chan []byte) - iw := NewIntermediateWriter(listenChan) - listener := types.NewStoreKVPairWriteListener(iw, c) - listeners := make(map[types.StoreKey][]types.WriteListener, len(storeKeys)) - // in this case, we are using the same listener for each Store - for _, key := range storeKeys { - listeners[key] = append(listeners[key], listener) - } - // check that the writeDir exists and is writeable so that we can catch the error here at initialization if it is not - // we don't open a dstFile until we receive our first ABCI message +func NewStreamingService( + writeDir, filePrefix string, + storeKeys []types.StoreKey, + cdc codec.BinaryCodec, + outputMetadata, stopNodeOnErr, fsync bool, +) (*StreamingService, error) { + // sort storeKeys for deterministic output + sort.SliceStable(storeKeys, func(i, j int) bool { + return storeKeys[i].Name() < storeKeys[j].Name() + }) + + // NOTE: We use the same listener for each store. + listeners := make([]*types.MemoryListener, len(storeKeys)) + for i, key := range storeKeys { + listeners[i] = types.NewMemoryListener(key) + } + + // Check that the writeDir exists and is writable so that we can catch the + // error here at initialization. If it is not we don't open a dstFile until we + // receive our first ABCI message. if err := isDirWriteable(writeDir); err != nil { return nil, err } + return &StreamingService{ - listeners: listeners, - srcChan: listenChan, + storeListeners: listeners, filePrefix: filePrefix, writeDir: writeDir, - codec: c, - stateCache: make([][]byte, 0), - stateCacheLock: new(sync.Mutex), + codec: cdc, + outputMetadata: outputMetadata, + stopNodeOnErr: stopNodeOnErr, + fsync: fsync, }, nil } -// Listeners satisfies the baseapp.StreamingService interface -// It returns the StreamingService's underlying WriteListeners -// Use for registering the underlying WriteListeners with the BaseApp +// Listeners satisfies the StreamingService interface. It returns the +// StreamingService's underlying WriteListeners. Use for registering the +// underlying WriteListeners with the BaseApp. func (fss *StreamingService) Listeners() map[types.StoreKey][]types.WriteListener { - return fss.listeners + listeners := make(map[types.StoreKey][]types.WriteListener, len(fss.storeListeners)) + for _, listener := range fss.storeListeners { + listeners[listener.StoreKey()] = []types.WriteListener{listener} + } + + return listeners } -// ListenBeginBlock satisfies the baseapp.ABCIListener interface -// It writes the received BeginBlock request and response and the resulting state changes -// out to a file as described in the above the naming schema -func (fss *StreamingService) ListenBeginBlock(ctx sdk.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) error { - // generate the new file - dstFile, err := fss.openBeginBlockFile(req) - if err != nil { - return err - } - // write req to file - lengthPrefixedReqBytes, err := fss.codec.MarshalLengthPrefixed(&req) - if err != nil { - return err - } - if _, err = dstFile.Write(lengthPrefixedReqBytes); err != nil { - return err - } - // write all state changes cached for this stage to file - fss.stateCacheLock.Lock() - for _, stateChange := range fss.stateCache { - if _, err = dstFile.Write(stateChange); err != nil { - fss.stateCache = nil - fss.stateCacheLock.Unlock() - return err - } - } - // reset cache - fss.stateCache = nil - fss.stateCacheLock.Unlock() - // write res to file - lengthPrefixedResBytes, err := fss.codec.MarshalLengthPrefixed(&res) - if err != nil { - return err - } - if _, err = dstFile.Write(lengthPrefixedResBytes); err != nil { - return err - } - // close file - return dstFile.Close() +// ListenBeginBlock satisfies the ABCIListener interface. It sets the received +// BeginBlock request, response and the current block number. Note, these are +// not written to file until ListenCommit is executed and outputMetadata is set, +// after which it will be reset again on the next block. +func (fss *StreamingService) ListenBeginBlock(ctx context.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) error { + fss.blockMetadata.RequestBeginBlock = &req + fss.blockMetadata.ResponseBeginBlock = &res + fss.currentBlockNumber = req.Header.Height + return nil } -func (fss *StreamingService) openBeginBlockFile(req abci.RequestBeginBlock) (*os.File, error) { - fss.currentBlockNumber = req.GetHeader().Height - fss.currentTxIndex = 0 - fileName := fmt.Sprintf("block-%d-begin", fss.currentBlockNumber) - if fss.filePrefix != "" { - fileName = fmt.Sprintf("%s-%s", fss.filePrefix, fileName) - } - return os.OpenFile(filepath.Join(fss.writeDir, fileName), os.O_CREATE|os.O_WRONLY, 0o600) +// ListenDeliverTx satisfies the ABCIListener interface. It appends the received +// DeliverTx request and response to a list of DeliverTxs objects. Note, these +// are not written to file until ListenCommit is executed and outputMetadata is +// set, after which it will be reset again on the next block. +func (fss *StreamingService) ListenDeliverTx(ctx context.Context, req abci.RequestDeliverTx, res abci.ResponseDeliverTx) error { + fss.blockMetadata.DeliverTxs = append(fss.blockMetadata.DeliverTxs, &types.BlockMetadata_DeliverTx{ + Request: &req, + Response: &res, + }) + + return nil } -// ListenDeliverTx satisfies the baseapp.ABCIListener interface -// It writes the received DeliverTx request and response and the resulting state changes -// out to a file as described in the above the naming schema -func (fss *StreamingService) ListenDeliverTx(ctx sdk.Context, req abci.RequestDeliverTx, res abci.ResponseDeliverTx) error { - // generate the new file - dstFile, err := fss.openDeliverTxFile() - if err != nil { - return err - } - // write req to file - lengthPrefixedReqBytes, err := fss.codec.MarshalLengthPrefixed(&req) - if err != nil { - return err - } - if _, err = dstFile.Write(lengthPrefixedReqBytes); err != nil { - return err - } - // write all state changes cached for this stage to file - fss.stateCacheLock.Lock() - for _, stateChange := range fss.stateCache { - if _, err = dstFile.Write(stateChange); err != nil { - fss.stateCache = nil - fss.stateCacheLock.Unlock() +// ListenEndBlock satisfies the ABCIListener interface. It sets the received +// EndBlock request, response and the current block number. Note, these are +// not written to file until ListenCommit is executed and outputMetadata is set, +// after which it will be reset again on the next block. +func (fss *StreamingService) ListenEndBlock(ctx context.Context, req abci.RequestEndBlock, res abci.ResponseEndBlock) error { + fss.blockMetadata.RequestEndBlock = &req + fss.blockMetadata.ResponseEndBlock = &res + return nil +} + +// ListenCommit satisfies the ABCIListener interface. It is executed during the +// ABCI Commit request and is responsible for writing all staged data to files. +// It will only return a non-nil error when stopNodeOnErr is set. +func (fss *StreamingService) ListenCommit(ctx context.Context, res abci.ResponseCommit) error { + if err := fss.doListenCommit(ctx, res); err != nil { + if fss.stopNodeOnErr { return err } } - // reset cache - fss.stateCache = nil - fss.stateCacheLock.Unlock() - // write res to file - lengthPrefixedResBytes, err := fss.codec.MarshalLengthPrefixed(&res) - if err != nil { - return err - } - if _, err = dstFile.Write(lengthPrefixedResBytes); err != nil { - return err - } - // close file - return dstFile.Close() + + return nil } -func (fss *StreamingService) openDeliverTxFile() (*os.File, error) { - fileName := fmt.Sprintf("block-%d-tx-%d", fss.currentBlockNumber, fss.currentTxIndex) +func (fss *StreamingService) doListenCommit(ctx context.Context, res abci.ResponseCommit) (err error) { + fss.blockMetadata.ResponseCommit = &res + + // Write to target files, the file size is written at the beginning, which can + // be used to detect completeness. + metaFileName := fmt.Sprintf("block-%d-meta", fss.currentBlockNumber) + dataFileName := fmt.Sprintf("block-%d-data", fss.currentBlockNumber) + if fss.filePrefix != "" { - fileName = fmt.Sprintf("%s-%s", fss.filePrefix, fileName) + metaFileName = fmt.Sprintf("%s-%s", fss.filePrefix, metaFileName) + dataFileName = fmt.Sprintf("%s-%s", fss.filePrefix, dataFileName) } - fss.currentTxIndex++ - return os.OpenFile(filepath.Join(fss.writeDir, fileName), os.O_CREATE|os.O_WRONLY, 0o600) -} -// ListenEndBlock satisfies the baseapp.ABCIListener interface -// It writes the received EndBlock request and response and the resulting state changes -// out to a file as described in the above the naming schema -func (fss *StreamingService) ListenEndBlock(ctx sdk.Context, req abci.RequestEndBlock, res abci.ResponseEndBlock) error { - // generate the new file - dstFile, err := fss.openEndBlockFile() - if err != nil { - return err - } - // write req to file - lengthPrefixedReqBytes, err := fss.codec.MarshalLengthPrefixed(&req) - if err != nil { - return err - } - if _, err = dstFile.Write(lengthPrefixedReqBytes); err != nil { - return err - } - // write all state changes cached for this stage to file - fss.stateCacheLock.Lock() - for _, stateChange := range fss.stateCache { - if _, err = dstFile.Write(stateChange); err != nil { - fss.stateCache = nil - fss.stateCacheLock.Unlock() + if fss.outputMetadata { + bz, err := fss.codec.Marshal(&fss.blockMetadata) + if err != nil { + return err + } + + if err := writeLengthPrefixedFile(path.Join(fss.writeDir, metaFileName), bz, fss.fsync); err != nil { return err } } - // reset cache - fss.stateCache = nil - fss.stateCacheLock.Unlock() - // write res to file - lengthPrefixedResBytes, err := fss.codec.MarshalLengthPrefixed(&res) - if err != nil { - return err - } - if _, err = dstFile.Write(lengthPrefixedResBytes); err != nil { + + var buf bytes.Buffer + if err := fss.writeBlockData(&buf); err != nil { return err } - // close file - return dstFile.Close() -} -func (fss *StreamingService) openEndBlockFile() (*os.File, error) { - fileName := fmt.Sprintf("block-%d-end", fss.currentBlockNumber) - if fss.filePrefix != "" { - fileName = fmt.Sprintf("%s-%s", fss.filePrefix, fileName) - } - return os.OpenFile(filepath.Join(fss.writeDir, fileName), os.O_CREATE|os.O_WRONLY, 0o600) + return writeLengthPrefixedFile(path.Join(fss.writeDir, dataFileName), buf.Bytes(), fss.fsync) } -// Stream satisfies the baseapp.StreamingService interface -// It spins up a goroutine select loop which awaits length-prefixed binary encoded KV pairs -// and caches them in the order they were received -// returns an error if it is called twice -func (fss *StreamingService) Stream(wg *sync.WaitGroup) error { - if fss.quitChan != nil { - return errors.New("`Stream` has already been called. The stream needs to be closed before it can be started again") - } - fss.quitChan = make(chan struct{}) - wg.Add(1) - go func() { - defer wg.Done() - for { - select { - case <-fss.quitChan: - fss.quitChan = nil - return - case by := <-fss.srcChan: - fss.stateCacheLock.Lock() - fss.stateCache = append(fss.stateCache, by) - fss.stateCacheLock.Unlock() +func (fss *StreamingService) writeBlockData(writer io.Writer) error { + for _, listener := range fss.storeListeners { + cache := listener.PopStateCache() + + for i := range cache { + bz, err := fss.codec.MarshalLengthPrefixed(&cache[i]) + if err != nil { + return err + } + + if _, err := writer.Write(bz); err != nil { + return err } } - }() - return nil -} + } -// Close satisfies the io.Closer interface, which satisfies the baseapp.StreamingService interface -func (fss *StreamingService) Close() error { - close(fss.quitChan) return nil } +// Stream satisfies the StreamingService interface. It performs a no-op. +func (fss *StreamingService) Stream(wg *sync.WaitGroup) error { return nil } + +// Close satisfies the StreamingService interface. It performs a no-op. +func (fss *StreamingService) Close() error { return nil } + // isDirWriteable checks if dir is writable by writing and removing a file -// to dir. It returns nil if dir is writable. +// to dir. It returns nil if dir is writable. We have to do this as there is no +// platform-independent way of determining if a directory is writeable. func isDirWriteable(dir string) error { f := path.Join(dir, ".touch") if err := os.WriteFile(f, []byte(""), 0o600); err != nil { return err } + return os.Remove(f) } + +func writeLengthPrefixedFile(path string, data []byte, fsync bool) (err error) { + var f *os.File + f, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600) + if err != nil { + return sdkerrors.Wrapf(err, "open file failed: %s", path) + } + + defer func() { + // avoid overriding the real error with file close error + if err1 := f.Close(); err1 != nil && err == nil { + err = sdkerrors.Wrapf(err, "close file failed: %s", path) + } + }() + + _, err = f.Write(sdk.Uint64ToBigEndian(uint64(len(data)))) + if err != nil { + return sdkerrors.Wrapf(err, "write length prefix failed: %s", path) + } + + _, err = f.Write(data) + if err != nil { + return sdkerrors.Wrapf(err, "write block data failed: %s", path) + } + + if fsync { + err = f.Sync() + if err != nil { + return sdkerrors.Wrapf(err, "fsync failed: %s", path) + } + } + + return err +} diff --git a/store/streaming/file/service_test.go b/store/streaming/file/service_test.go index 6ecad254b5ce..1136143e4494 100644 --- a/store/streaming/file/service_test.go +++ b/store/streaming/file/service_test.go @@ -2,20 +2,21 @@ package file import ( "encoding/binary" + "errors" "fmt" "os" "path/filepath" "sync" "testing" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + types1 "github.com/tendermint/tendermint/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/codec" codecTypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - types1 "github.com/tendermint/tendermint/proto/tendermint/types" ) var ( @@ -23,7 +24,8 @@ var ( testMarshaller = codec.NewProtoCodec(interfaceRegistry) testStreamingService *StreamingService testListener1, testListener2 types.WriteListener - emptyContext = sdk.Context{} + emptyContext = sdk.NewContext(nil, types1.Header{}, false, nil) + emptyContextWrap = sdk.WrapSDKContext(emptyContext) // test abci message types mockHash = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9} @@ -56,6 +58,10 @@ var ( ConsensusParamUpdates: &abci.ConsensusParams{}, ValidatorUpdates: []abci.ValidatorUpdate{}, } + testCommitRes = abci.ResponseCommit{ + Data: []byte{1}, + RetainHeight: 0, + } mockTxBytes1 = []byte{9, 8, 7, 6, 5, 4, 3, 2, 1} testDeliverTxReq1 = abci.RequestDeliverTx{ Tx: mockTxBytes1, @@ -104,57 +110,39 @@ var ( mockValue3 = []byte{5, 4, 3} ) -func TestIntermediateWriter(t *testing.T) { - outChan := make(chan []byte, 0) - iw := NewIntermediateWriter(outChan) - require.IsType(t, &IntermediateWriter{}, iw) - testBytes := []byte{1, 2, 3, 4, 5} - var length int - var err error - waitChan := make(chan struct{}, 0) - go func() { - length, err = iw.Write(testBytes) - waitChan <- struct{}{} - }() - receivedBytes := <-outChan - <-waitChan - require.Equal(t, len(testBytes), length) - require.Equal(t, testBytes, receivedBytes) - require.Nil(t, err) -} - func TestFileStreamingService(t *testing.T) { if os.Getenv("CI") != "" { t.Skip("Skipping TestFileStreamingService in CI environment") } - err := os.Mkdir(testDir, 0o700) - require.Nil(t, err) + + require.Nil(t, os.Mkdir(testDir, 0o700)) defer os.RemoveAll(testDir) testKeys := []types.StoreKey{mockStoreKey1, mockStoreKey2} - testStreamingService, err = NewStreamingService(testDir, testPrefix, testKeys, testMarshaller) + var err error + testStreamingService, err = NewStreamingService(testDir, testPrefix, testKeys, testMarshaller, true, false, false) require.Nil(t, err) require.IsType(t, &StreamingService{}, testStreamingService) require.Equal(t, testPrefix, testStreamingService.filePrefix) require.Equal(t, testDir, testStreamingService.writeDir) require.Equal(t, testMarshaller, testStreamingService.codec) - testListener1 = testStreamingService.listeners[mockStoreKey1][0] - testListener2 = testStreamingService.listeners[mockStoreKey2][0] + + testListener1 = testStreamingService.storeListeners[0] + testListener2 = testStreamingService.storeListeners[1] + wg := new(sync.WaitGroup) + testStreamingService.Stream(wg) - testListenBeginBlock(t) - testListenDeliverTx1(t) - testListenDeliverTx2(t) - testListenEndBlock(t) + testListenBlock(t) testStreamingService.Close() wg.Wait() } -func testListenBeginBlock(t *testing.T) { - expectedBeginBlockReqBytes, err := testMarshaller.Marshal(&testBeginBlockReq) - require.Nil(t, err) - expectedBeginBlockResBytes, err := testMarshaller.Marshal(&testBeginBlockRes) - require.Nil(t, err) +func testListenBlock(t *testing.T) { + var ( + expectKVPairsStore1 [][]byte + expectKVPairsStore2 [][]byte + ) // write state changes testListener1.OnWrite(mockStoreKey1, mockKey1, mockValue1, false) @@ -169,6 +157,7 @@ func testListenBeginBlock(t *testing.T) { Delete: false, }) require.Nil(t, err) + expectedKVPair2, err := testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey2.Name(), Key: mockKey2, @@ -176,6 +165,7 @@ func testListenBeginBlock(t *testing.T) { Delete: false, }) require.Nil(t, err) + expectedKVPair3, err := testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey1.Name(), Key: mockKey3, @@ -184,53 +174,36 @@ func testListenBeginBlock(t *testing.T) { }) require.Nil(t, err) - // send the ABCI messages - err = testStreamingService.ListenBeginBlock(emptyContext, testBeginBlockReq, testBeginBlockRes) - require.Nil(t, err) - - // load the file, checking that it was created with the expected name - fileName := fmt.Sprintf("%s-block-%d-begin", testPrefix, testBeginBlockReq.GetHeader().Height) - fileBytes, err := readInFile(fileName) - require.Nil(t, err) + expectKVPairsStore1 = append(expectKVPairsStore1, expectedKVPair1, expectedKVPair3) + expectKVPairsStore2 = append(expectKVPairsStore2, expectedKVPair2) - // segment the file into the separate gRPC messages and check the correctness of each - segments, err := segmentBytes(fileBytes) - require.Nil(t, err) - require.Equal(t, 5, len(segments)) - require.Equal(t, expectedBeginBlockReqBytes, segments[0]) - require.Equal(t, expectedKVPair1, segments[1]) - require.Equal(t, expectedKVPair2, segments[2]) - require.Equal(t, expectedKVPair3, segments[3]) - require.Equal(t, expectedBeginBlockResBytes, segments[4]) -} - -func testListenDeliverTx1(t *testing.T) { - expectedDeliverTxReq1Bytes, err := testMarshaller.Marshal(&testDeliverTxReq1) - require.Nil(t, err) - expectedDeliverTxRes1Bytes, err := testMarshaller.Marshal(&testDeliverTxRes1) + // send the ABCI messages + err = testStreamingService.ListenBeginBlock(emptyContextWrap, testBeginBlockReq, testBeginBlockRes) require.Nil(t, err) // write state changes testListener1.OnWrite(mockStoreKey1, mockKey1, mockValue1, false) testListener2.OnWrite(mockStoreKey2, mockKey2, mockValue2, false) - testListener1.OnWrite(mockStoreKey2, mockKey3, mockValue3, false) + testListener2.OnWrite(mockStoreKey2, mockKey3, mockValue3, false) // expected KV pairs - expectedKVPair1, err := testMarshaller.Marshal(&types.StoreKVPair{ + expectedKVPair1, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey1.Name(), Key: mockKey1, Value: mockValue1, Delete: false, }) require.Nil(t, err) - expectedKVPair2, err := testMarshaller.Marshal(&types.StoreKVPair{ + + expectedKVPair2, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey2.Name(), Key: mockKey2, Value: mockValue2, Delete: false, }) require.Nil(t, err) - expectedKVPair3, err := testMarshaller.Marshal(&types.StoreKVPair{ + + expectedKVPair3, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey2.Name(), Key: mockKey3, Value: mockValue3, @@ -238,53 +211,36 @@ func testListenDeliverTx1(t *testing.T) { }) require.Nil(t, err) - // send the ABCI messages - err = testStreamingService.ListenDeliverTx(emptyContext, testDeliverTxReq1, testDeliverTxRes1) - require.Nil(t, err) - - // load the file, checking that it was created with the expected name - fileName := fmt.Sprintf("%s-block-%d-tx-%d", testPrefix, testBeginBlockReq.GetHeader().Height, 0) - fileBytes, err := readInFile(fileName) - require.Nil(t, err) - - // segment the file into the separate gRPC messages and check the correctness of each - segments, err := segmentBytes(fileBytes) - require.Nil(t, err) - require.Equal(t, 5, len(segments)) - require.Equal(t, expectedDeliverTxReq1Bytes, segments[0]) - require.Equal(t, expectedKVPair1, segments[1]) - require.Equal(t, expectedKVPair2, segments[2]) - require.Equal(t, expectedKVPair3, segments[3]) - require.Equal(t, expectedDeliverTxRes1Bytes, segments[4]) -} + expectKVPairsStore1 = append(expectKVPairsStore1, expectedKVPair1) + expectKVPairsStore2 = append(expectKVPairsStore2, expectedKVPair2, expectedKVPair3) -func testListenDeliverTx2(t *testing.T) { - expectedDeliverTxReq2Bytes, err := testMarshaller.Marshal(&testDeliverTxReq2) - require.Nil(t, err) - expectedDeliverTxRes2Bytes, err := testMarshaller.Marshal(&testDeliverTxRes2) + // send the ABCI messages + err = testStreamingService.ListenDeliverTx(emptyContextWrap, testDeliverTxReq1, testDeliverTxRes1) require.Nil(t, err) // write state changes - testListener1.OnWrite(mockStoreKey2, mockKey1, mockValue1, false) - testListener2.OnWrite(mockStoreKey1, mockKey2, mockValue2, false) - testListener1.OnWrite(mockStoreKey2, mockKey3, mockValue3, false) + testListener2.OnWrite(mockStoreKey2, mockKey1, mockValue1, false) + testListener1.OnWrite(mockStoreKey1, mockKey2, mockValue2, false) + testListener2.OnWrite(mockStoreKey2, mockKey3, mockValue3, false) // expected KV pairs - expectedKVPair1, err := testMarshaller.Marshal(&types.StoreKVPair{ + expectedKVPair1, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey2.Name(), Key: mockKey1, Value: mockValue1, Delete: false, }) require.Nil(t, err) - expectedKVPair2, err := testMarshaller.Marshal(&types.StoreKVPair{ + + expectedKVPair2, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey1.Name(), Key: mockKey2, Value: mockValue2, Delete: false, }) require.Nil(t, err) - expectedKVPair3, err := testMarshaller.Marshal(&types.StoreKVPair{ + + expectedKVPair3, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey2.Name(), Key: mockKey3, Value: mockValue3, @@ -292,53 +248,36 @@ func testListenDeliverTx2(t *testing.T) { }) require.Nil(t, err) - // send the ABCI messages - err = testStreamingService.ListenDeliverTx(emptyContext, testDeliverTxReq2, testDeliverTxRes2) - require.Nil(t, err) - - // load the file, checking that it was created with the expected name - fileName := fmt.Sprintf("%s-block-%d-tx-%d", testPrefix, testBeginBlockReq.GetHeader().Height, 1) - fileBytes, err := readInFile(fileName) - require.Nil(t, err) + expectKVPairsStore1 = append(expectKVPairsStore1, expectedKVPair2) + expectKVPairsStore2 = append(expectKVPairsStore2, expectedKVPair1, expectedKVPair3) - // segment the file into the separate gRPC messages and check the correctness of each - segments, err := segmentBytes(fileBytes) - require.Nil(t, err) - require.Equal(t, 5, len(segments)) - require.Equal(t, expectedDeliverTxReq2Bytes, segments[0]) - require.Equal(t, expectedKVPair1, segments[1]) - require.Equal(t, expectedKVPair2, segments[2]) - require.Equal(t, expectedKVPair3, segments[3]) - require.Equal(t, expectedDeliverTxRes2Bytes, segments[4]) -} - -func testListenEndBlock(t *testing.T) { - expectedEndBlockReqBytes, err := testMarshaller.Marshal(&testEndBlockReq) - require.Nil(t, err) - expectedEndBlockResBytes, err := testMarshaller.Marshal(&testEndBlockRes) + // send the ABCI messages + err = testStreamingService.ListenDeliverTx(emptyContextWrap, testDeliverTxReq2, testDeliverTxRes2) require.Nil(t, err) // write state changes testListener1.OnWrite(mockStoreKey1, mockKey1, mockValue1, false) - testListener2.OnWrite(mockStoreKey1, mockKey2, mockValue2, false) - testListener1.OnWrite(mockStoreKey2, mockKey3, mockValue3, false) + testListener1.OnWrite(mockStoreKey1, mockKey2, mockValue2, false) + testListener2.OnWrite(mockStoreKey2, mockKey3, mockValue3, false) // expected KV pairs - expectedKVPair1, err := testMarshaller.Marshal(&types.StoreKVPair{ + expectedKVPair1, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey1.Name(), Key: mockKey1, Value: mockValue1, Delete: false, }) require.Nil(t, err) - expectedKVPair2, err := testMarshaller.Marshal(&types.StoreKVPair{ + + expectedKVPair2, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey1.Name(), Key: mockKey2, Value: mockValue2, Delete: false, }) require.Nil(t, err) - expectedKVPair3, err := testMarshaller.Marshal(&types.StoreKVPair{ + + expectedKVPair3, err = testMarshaller.Marshal(&types.StoreKVPair{ StoreKey: mockStoreKey2.Name(), Key: mockKey3, Value: mockValue3, @@ -346,55 +285,92 @@ func testListenEndBlock(t *testing.T) { }) require.Nil(t, err) + expectKVPairsStore1 = append(expectKVPairsStore1, expectedKVPair1, expectedKVPair2) + expectKVPairsStore2 = append(expectKVPairsStore2, expectedKVPair3) + // send the ABCI messages - err = testStreamingService.ListenEndBlock(emptyContext, testEndBlockReq, testEndBlockRes) + err = testStreamingService.ListenEndBlock(emptyContextWrap, testEndBlockReq, testEndBlockRes) + require.Nil(t, err) + + err = testStreamingService.ListenCommit(emptyContextWrap, testCommitRes) require.Nil(t, err) // load the file, checking that it was created with the expected name - fileName := fmt.Sprintf("%s-block-%d-end", testPrefix, testEndBlockReq.Height) - fileBytes, err := readInFile(fileName) + metaFileName := fmt.Sprintf("%s-block-%d-meta", testPrefix, testBeginBlockReq.GetHeader().Height) + dataFileName := fmt.Sprintf("%s-block-%d-data", testPrefix, testBeginBlockReq.GetHeader().Height) + metaFileBytes, err := readInFile(metaFileName) + dataFileBytes, err := readInFile(dataFileName) + require.Nil(t, err) + + metadata := types.BlockMetadata{ + RequestBeginBlock: &testBeginBlockReq, + ResponseBeginBlock: &testBeginBlockRes, + RequestEndBlock: &testEndBlockReq, + ResponseEndBlock: &testEndBlockRes, + ResponseCommit: &testCommitRes, + DeliverTxs: []*types.BlockMetadata_DeliverTx{ + {Request: &testDeliverTxReq1, Response: &testDeliverTxRes1}, + {Request: &testDeliverTxReq2, Response: &testDeliverTxRes2}, + }, + } + expectedMetadataBytes, err := testMarshaller.Marshal(&metadata) require.Nil(t, err) + require.Equal(t, expectedMetadataBytes, metaFileBytes) // segment the file into the separate gRPC messages and check the correctness of each - segments, err := segmentBytes(fileBytes) + segments, err := segmentBytes(dataFileBytes) require.Nil(t, err) - require.Equal(t, 5, len(segments)) - require.Equal(t, expectedEndBlockReqBytes, segments[0]) - require.Equal(t, expectedKVPair1, segments[1]) - require.Equal(t, expectedKVPair2, segments[2]) - require.Equal(t, expectedKVPair3, segments[3]) - require.Equal(t, expectedEndBlockResBytes, segments[4]) + require.Equal(t, len(expectKVPairsStore1)+len(expectKVPairsStore2), len(segments)) + require.Equal(t, expectKVPairsStore1, segments[:len(expectKVPairsStore1)]) + require.Equal(t, expectKVPairsStore2, segments[len(expectKVPairsStore1):]) } func readInFile(name string) ([]byte, error) { path := filepath.Join(testDir, name) - return os.ReadFile(path) + bz, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + size := sdk.BigEndianToUint64(bz[:8]) + if len(bz) != int(size)+8 { + return nil, errors.New("incomplete file ") + } + + return bz[8:], nil } -// Returns all of the protobuf messages contained in the byte array as an array of byte arrays -// The messages have their length prefix removed +// segmentBytes returns all of the protobuf messages contained in the byte array +// as an array of byte arrays. The messages have their length prefix removed. func segmentBytes(bz []byte) ([][]byte, error) { var err error + segments := make([][]byte, 0) for len(bz) > 0 { var segment []byte + segment, bz, err = getHeadSegment(bz) if err != nil { return nil, err } + segments = append(segments, segment) } + return segments, nil } -// Returns the bytes for the leading protobuf object in the byte array (removing the length prefix) and returns the remainder of the byte array +// getHeadSegment returns the bytes for the leading protobuf object in the byte +// array (removing the length prefix) and returns the remainder of the byte array. func getHeadSegment(bz []byte) ([]byte, []byte, error) { size, prefixSize := binary.Uvarint(bz) if prefixSize < 0 { return nil, nil, fmt.Errorf("invalid number of bytes read from length-prefixed encoding: %d", prefixSize) } + if size > uint64(len(bz)-prefixSize) { return nil, nil, fmt.Errorf("not enough bytes to read; want: %v, got: %v", size, len(bz)-prefixSize) } + return bz[prefixSize:(uint64(prefixSize) + size)], bz[uint64(prefixSize)+size:], nil } diff --git a/store/tracekv/store.go b/store/tracekv/store.go index a454edc7dd5f..247bc0030cfd 100644 --- a/store/tracekv/store.go +++ b/store/tracekv/store.go @@ -173,11 +173,6 @@ func (tkv *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Ca panic("cannot CacheWrapWithTrace a TraceKVStore") } -// CacheWrapWithListeners implements the CacheWrapper interface. -func (tkv *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { - panic("cannot CacheWrapWithListeners a TraceKVStore") -} - // writeOperation writes a KVStore operation to the underlying io.Writer as // JSON-encoded data where the key/value pair is base64 encoded. func writeOperation(w io.Writer, op operation, tc types.TraceContext, key, value []byte) { diff --git a/store/tracekv/store_test.go b/store/tracekv/store_test.go index 1b81e89bafd2..b7a3b13ea964 100644 --- a/store/tracekv/store_test.go +++ b/store/tracekv/store_test.go @@ -290,8 +290,3 @@ func TestTraceKVStoreCacheWrapWithTrace(t *testing.T) { store := newEmptyTraceKVStore(nil) require.Panics(t, func() { store.CacheWrapWithTrace(nil, nil) }) } - -func TestTraceKVStoreCacheWrapWithListeners(t *testing.T) { - store := newEmptyTraceKVStore(nil) - require.Panics(t, func() { store.CacheWrapWithListeners(nil, nil) }) -} diff --git a/store/types/listening.go b/store/types/listening.go index 2294a5ada531..6b2ec68d603d 100644 --- a/store/types/listening.go +++ b/store/types/listening.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -// WriteListener interface for streaming data out from a listenkv.Store +// WriteListener interface for streaming data out from a KVStore type WriteListener interface { // if value is nil then it was deleted // storeKey indicates the source KVStore, to facilitate using the the same WriteListener across separate KVStores @@ -14,14 +14,16 @@ type WriteListener interface { OnWrite(storeKey StoreKey, key []byte, value []byte, delete bool) error } -// StoreKVPairWriteListener is used to configure listening to a KVStore by writing out length-prefixed -// protobuf encoded StoreKVPairs to an underlying io.Writer +// StoreKVPairWriteListener is used to configure listening to a KVStore by +// writing out length-prefixed Protobuf encoded StoreKVPairs to an underlying +// io.Writer object. type StoreKVPairWriteListener struct { writer io.Writer marshaller codec.BinaryCodec } -// NewStoreKVPairWriteListener wraps creates a StoreKVPairWriteListener with a provdied io.Writer and codec.BinaryCodec +// NewStoreKVPairWriteListener wraps creates a StoreKVPairWriteListener with a +// provided io.Writer and codec.BinaryCodec. func NewStoreKVPairWriteListener(w io.Writer, m codec.BinaryCodec) *StoreKVPairWriteListener { return &StoreKVPairWriteListener{ writer: w, @@ -29,19 +31,60 @@ func NewStoreKVPairWriteListener(w io.Writer, m codec.BinaryCodec) *StoreKVPairW } } -// OnWrite satisfies the WriteListener interface by writing length-prefixed protobuf encoded StoreKVPairs +// OnWrite satisfies the WriteListener interface by writing length-prefixed +// Protobuf encoded StoreKVPairs. func (wl *StoreKVPairWriteListener) OnWrite(storeKey StoreKey, key []byte, value []byte, delete bool) error { - kvPair := new(StoreKVPair) - kvPair.StoreKey = storeKey.Name() - kvPair.Delete = delete - kvPair.Key = key - kvPair.Value = value + kvPair := &StoreKVPair{ + StoreKey: storeKey.Name(), + Key: key, + Value: value, + Delete: delete, + } + by, err := wl.marshaller.MarshalLengthPrefixed(kvPair) if err != nil { return err } + if _, err := wl.writer.Write(by); err != nil { return err } + return nil } + +// MemoryListener listens to the state writes and accumulate the records in memory. +type MemoryListener struct { + key StoreKey + stateCache []StoreKVPair +} + +// NewMemoryListener creates a listener that accumulate the state writes in memory. +func NewMemoryListener(key StoreKey) *MemoryListener { + return &MemoryListener{key: key} +} + +// OnWrite implements WriteListener interface. +func (fl *MemoryListener) OnWrite(storeKey StoreKey, key []byte, value []byte, delete bool) error { + fl.stateCache = append(fl.stateCache, StoreKVPair{ + StoreKey: storeKey.Name(), + Delete: delete, + Key: key, + Value: value, + }) + + return nil +} + +// PopStateCache returns the current state caches and set to nil. +func (fl *MemoryListener) PopStateCache() []StoreKVPair { + res := fl.stateCache + fl.stateCache = nil + + return res +} + +// StoreKey returns the storeKey it listens to. +func (fl *MemoryListener) StoreKey() StoreKey { + return fl.key +} diff --git a/store/types/listening.pb.go b/store/types/listening.pb.go index 47d5a23a8367..4505b11f1b69 100644 --- a/store/types/listening.pb.go +++ b/store/types/listening.pb.go @@ -6,6 +6,7 @@ package types import ( fmt "fmt" proto "github.com/gogo/protobuf/proto" + types "github.com/tendermint/tendermint/abci/types" io "io" math "math" math_bits "math/bits" @@ -95,8 +96,149 @@ func (m *StoreKVPair) GetValue() []byte { return nil } +// BlockMetadata contains all the abci event data of a block +// the file streamer dump them into files together with the state changes. +type BlockMetadata struct { + RequestBeginBlock *types.RequestBeginBlock `protobuf:"bytes,1,opt,name=request_begin_block,json=requestBeginBlock,proto3" json:"request_begin_block,omitempty"` + ResponseBeginBlock *types.ResponseBeginBlock `protobuf:"bytes,2,opt,name=response_begin_block,json=responseBeginBlock,proto3" json:"response_begin_block,omitempty"` + DeliverTxs []*BlockMetadata_DeliverTx `protobuf:"bytes,3,rep,name=deliver_txs,json=deliverTxs,proto3" json:"deliver_txs,omitempty"` + RequestEndBlock *types.RequestEndBlock `protobuf:"bytes,4,opt,name=request_end_block,json=requestEndBlock,proto3" json:"request_end_block,omitempty"` + ResponseEndBlock *types.ResponseEndBlock `protobuf:"bytes,5,opt,name=response_end_block,json=responseEndBlock,proto3" json:"response_end_block,omitempty"` + ResponseCommit *types.ResponseCommit `protobuf:"bytes,6,opt,name=response_commit,json=responseCommit,proto3" json:"response_commit,omitempty"` +} + +func (m *BlockMetadata) Reset() { *m = BlockMetadata{} } +func (m *BlockMetadata) String() string { return proto.CompactTextString(m) } +func (*BlockMetadata) ProtoMessage() {} +func (*BlockMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_a5d350879fe4fecd, []int{1} +} +func (m *BlockMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlockMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlockMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlockMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockMetadata.Merge(m, src) +} +func (m *BlockMetadata) XXX_Size() int { + return m.Size() +} +func (m *BlockMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_BlockMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockMetadata proto.InternalMessageInfo + +func (m *BlockMetadata) GetRequestBeginBlock() *types.RequestBeginBlock { + if m != nil { + return m.RequestBeginBlock + } + return nil +} + +func (m *BlockMetadata) GetResponseBeginBlock() *types.ResponseBeginBlock { + if m != nil { + return m.ResponseBeginBlock + } + return nil +} + +func (m *BlockMetadata) GetDeliverTxs() []*BlockMetadata_DeliverTx { + if m != nil { + return m.DeliverTxs + } + return nil +} + +func (m *BlockMetadata) GetRequestEndBlock() *types.RequestEndBlock { + if m != nil { + return m.RequestEndBlock + } + return nil +} + +func (m *BlockMetadata) GetResponseEndBlock() *types.ResponseEndBlock { + if m != nil { + return m.ResponseEndBlock + } + return nil +} + +func (m *BlockMetadata) GetResponseCommit() *types.ResponseCommit { + if m != nil { + return m.ResponseCommit + } + return nil +} + +// DeliverTx encapulate deliver tx request and response. +type BlockMetadata_DeliverTx struct { + Request *types.RequestDeliverTx `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"` + Response *types.ResponseDeliverTx `protobuf:"bytes,2,opt,name=response,proto3" json:"response,omitempty"` +} + +func (m *BlockMetadata_DeliverTx) Reset() { *m = BlockMetadata_DeliverTx{} } +func (m *BlockMetadata_DeliverTx) String() string { return proto.CompactTextString(m) } +func (*BlockMetadata_DeliverTx) ProtoMessage() {} +func (*BlockMetadata_DeliverTx) Descriptor() ([]byte, []int) { + return fileDescriptor_a5d350879fe4fecd, []int{1, 0} +} +func (m *BlockMetadata_DeliverTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlockMetadata_DeliverTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlockMetadata_DeliverTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlockMetadata_DeliverTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockMetadata_DeliverTx.Merge(m, src) +} +func (m *BlockMetadata_DeliverTx) XXX_Size() int { + return m.Size() +} +func (m *BlockMetadata_DeliverTx) XXX_DiscardUnknown() { + xxx_messageInfo_BlockMetadata_DeliverTx.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockMetadata_DeliverTx proto.InternalMessageInfo + +func (m *BlockMetadata_DeliverTx) GetRequest() *types.RequestDeliverTx { + if m != nil { + return m.Request + } + return nil +} + +func (m *BlockMetadata_DeliverTx) GetResponse() *types.ResponseDeliverTx { + if m != nil { + return m.Response + } + return nil +} + func init() { proto.RegisterType((*StoreKVPair)(nil), "cosmos.base.store.v1beta1.StoreKVPair") + proto.RegisterType((*BlockMetadata)(nil), "cosmos.base.store.v1beta1.BlockMetadata") + proto.RegisterType((*BlockMetadata_DeliverTx)(nil), "cosmos.base.store.v1beta1.BlockMetadata.DeliverTx") } func init() { @@ -104,21 +246,37 @@ func init() { } var fileDescriptor_a5d350879fe4fecd = []byte{ - // 224 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4c, 0xce, 0x2f, 0xce, - 0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0x2c, 0x4e, 0xd5, 0x2f, 0x2e, 0xc9, 0x2f, 0x4a, 0xd5, 0x2f, 0x33, - 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0xcf, 0xc9, 0x2c, 0x2e, 0x49, 0xcd, 0xcb, 0xcc, 0x4b, 0xd7, - 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x84, 0x28, 0xd5, 0x03, 0x29, 0xd5, 0x03, 0x2b, 0xd5, - 0x83, 0x2a, 0x55, 0xca, 0xe2, 0xe2, 0x0e, 0x06, 0x09, 0x78, 0x87, 0x05, 0x24, 0x66, 0x16, 0x09, - 0x49, 0x73, 0x71, 0x82, 0xe5, 0xe3, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, - 0x38, 0xc0, 0x02, 0xde, 0xa9, 0x95, 0x42, 0x62, 0x5c, 0x6c, 0x29, 0xa9, 0x39, 0xa9, 0x25, 0xa9, - 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x1c, 0x41, 0x50, 0x9e, 0x90, 0x00, 0x17, 0x33, 0x48, 0x39, 0xb3, - 0x02, 0xa3, 0x06, 0x4f, 0x10, 0x88, 0x29, 0x24, 0xc2, 0xc5, 0x5a, 0x96, 0x98, 0x53, 0x9a, 0x2a, - 0xc1, 0x02, 0x16, 0x83, 0x70, 0x9c, 0x9c, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, - 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, - 0x21, 0x4a, 0x23, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x1f, 0xea, 0x2d, - 0x08, 0xa5, 0x5b, 0x9c, 0x92, 0x0d, 0xf5, 0x5c, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, - 0x47, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2b, 0xe0, 0xb3, 0x51, 0xfe, 0x00, 0x00, 0x00, + // 473 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0x4f, 0x6f, 0xd3, 0x40, + 0x10, 0xc5, 0xe3, 0xa6, 0x09, 0xc9, 0x04, 0x68, 0x59, 0x2a, 0x64, 0x5a, 0xc9, 0xb8, 0xe1, 0x62, + 0x0e, 0xac, 0xd5, 0x70, 0x44, 0xe2, 0x10, 0x40, 0x42, 0x2a, 0x08, 0xe4, 0x02, 0x07, 0x2e, 0x96, + 0xff, 0x8c, 0xc2, 0x12, 0xdb, 0x1b, 0x76, 0x37, 0x51, 0x73, 0xe6, 0xc2, 0x91, 0x8f, 0xc5, 0xb1, + 0x47, 0x8e, 0x28, 0xf9, 0x22, 0xc8, 0x6b, 0xc7, 0xa9, 0x43, 0x7d, 0xca, 0xee, 0xe4, 0xbd, 0x9f, + 0xdf, 0xcc, 0x6a, 0xe0, 0x49, 0xc4, 0x65, 0xca, 0xa5, 0x1b, 0x06, 0x12, 0x5d, 0xa9, 0xb8, 0x40, + 0x77, 0x71, 0x16, 0xa2, 0x0a, 0xce, 0xdc, 0x84, 0x49, 0x85, 0x19, 0xcb, 0x26, 0x74, 0x26, 0xb8, + 0xe2, 0xe4, 0x61, 0x21, 0xa5, 0xb9, 0x94, 0x6a, 0x29, 0x2d, 0xa5, 0xc7, 0x27, 0x0a, 0xb3, 0x18, + 0x45, 0xca, 0x32, 0xe5, 0x06, 0x61, 0xc4, 0x5c, 0xb5, 0x9c, 0xa1, 0x2c, 0x7c, 0xc3, 0x6f, 0x30, + 0xb8, 0xc8, 0xd5, 0xe7, 0x9f, 0x3f, 0x04, 0x4c, 0x90, 0x13, 0xe8, 0x6b, 0xb3, 0x3f, 0xc5, 0xa5, + 0x69, 0xd8, 0x86, 0xd3, 0xf7, 0x7a, 0xba, 0x70, 0x8e, 0x4b, 0xf2, 0x00, 0xba, 0x31, 0x26, 0xa8, + 0xd0, 0xdc, 0xb3, 0x0d, 0xa7, 0xe7, 0x95, 0x37, 0x72, 0x08, 0xed, 0x5c, 0xde, 0xb6, 0x0d, 0xe7, + 0xb6, 0x97, 0x1f, 0xc9, 0x11, 0x74, 0x16, 0x41, 0x32, 0x47, 0x73, 0x5f, 0xd7, 0x8a, 0xcb, 0xf0, + 0x47, 0x07, 0xee, 0x8c, 0x13, 0x1e, 0x4d, 0xdf, 0xa1, 0x0a, 0xe2, 0x40, 0x05, 0xc4, 0x83, 0xfb, + 0x02, 0xbf, 0xcf, 0x51, 0x2a, 0x3f, 0xc4, 0x09, 0xcb, 0xfc, 0x30, 0xff, 0x5b, 0x7f, 0x78, 0x30, + 0x1a, 0xd2, 0x6d, 0x70, 0x9a, 0x07, 0xa7, 0x5e, 0xa1, 0x1d, 0xe7, 0x52, 0x0d, 0xf2, 0xee, 0x89, + 0xdd, 0x12, 0xf9, 0x04, 0x47, 0x02, 0xe5, 0x8c, 0x67, 0x12, 0x6b, 0xd0, 0x3d, 0x0d, 0x7d, 0x7c, + 0x03, 0xb4, 0x10, 0x5f, 0xa3, 0x12, 0xf1, 0x5f, 0x8d, 0x5c, 0xc0, 0x20, 0xc6, 0x84, 0x2d, 0x50, + 0xf8, 0xea, 0x52, 0x9a, 0x6d, 0xbb, 0xed, 0x0c, 0x46, 0x23, 0xda, 0x38, 0x76, 0x5a, 0xeb, 0x94, + 0xbe, 0x2a, 0xbc, 0x1f, 0x2f, 0x3d, 0x88, 0x37, 0x47, 0x49, 0xde, 0xc2, 0xa6, 0x01, 0x1f, 0xb3, + 0xb8, 0x0c, 0xba, 0xaf, 0x83, 0xda, 0x4d, 0xdd, 0xbf, 0xce, 0xe2, 0x22, 0xe5, 0x81, 0xa8, 0x17, + 0xc8, 0x7b, 0xa8, 0x82, 0x5f, 0xc3, 0x75, 0x34, 0xee, 0xb4, 0xb1, 0xef, 0x8a, 0x77, 0x28, 0x76, + 0x2a, 0xe4, 0x0d, 0x1c, 0x54, 0xc0, 0x88, 0xa7, 0x29, 0x53, 0x66, 0x57, 0xd3, 0x1e, 0x35, 0xd2, + 0x5e, 0x6a, 0x99, 0x77, 0x57, 0xd4, 0xee, 0xc7, 0x3f, 0x0d, 0xe8, 0x57, 0x23, 0x20, 0xcf, 0xe1, + 0x56, 0x99, 0xbd, 0x7c, 0xea, 0xd3, 0xa6, 0x66, 0xb7, 0x63, 0xdb, 0x38, 0xc8, 0x0b, 0xe8, 0x6d, + 0xe0, 0xe5, 0x9b, 0x0e, 0x1b, 0xd3, 0x6c, 0xed, 0x95, 0x67, 0x3c, 0xfe, 0xbd, 0xb2, 0x8c, 0xab, + 0x95, 0x65, 0xfc, 0x5d, 0x59, 0xc6, 0xaf, 0xb5, 0xd5, 0xba, 0x5a, 0x5b, 0xad, 0x3f, 0x6b, 0xab, + 0xf5, 0xc5, 0x99, 0x30, 0xf5, 0x75, 0x1e, 0xd2, 0x88, 0xa7, 0x6e, 0xb9, 0x79, 0xc5, 0xcf, 0x53, + 0x19, 0x4f, 0xcb, 0xfd, 0xd3, 0xbb, 0x13, 0x76, 0xf5, 0xf2, 0x3c, 0xfb, 0x17, 0x00, 0x00, 0xff, + 0xff, 0x69, 0x5c, 0x8f, 0x23, 0xa1, 0x03, 0x00, 0x00, } func (m *StoreKVPair) Marshal() (dAtA []byte, err error) { @@ -175,6 +333,150 @@ func (m *StoreKVPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *BlockMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ResponseCommit != nil { + { + size, err := m.ResponseCommit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintListening(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if m.ResponseEndBlock != nil { + { + size, err := m.ResponseEndBlock.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintListening(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if m.RequestEndBlock != nil { + { + size, err := m.RequestEndBlock.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintListening(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.DeliverTxs) > 0 { + for iNdEx := len(m.DeliverTxs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DeliverTxs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintListening(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.ResponseBeginBlock != nil { + { + size, err := m.ResponseBeginBlock.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintListening(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.RequestBeginBlock != nil { + { + size, err := m.RequestBeginBlock.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintListening(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *BlockMetadata_DeliverTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockMetadata_DeliverTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockMetadata_DeliverTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Response != nil { + { + size, err := m.Response.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintListening(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Request != nil { + { + size, err := m.Request.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintListening(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintListening(dAtA []byte, offset int, v uint64) int { offset -= sovListening(v) base := offset @@ -210,6 +512,58 @@ func (m *StoreKVPair) Size() (n int) { return n } +func (m *BlockMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.RequestBeginBlock != nil { + l = m.RequestBeginBlock.Size() + n += 1 + l + sovListening(uint64(l)) + } + if m.ResponseBeginBlock != nil { + l = m.ResponseBeginBlock.Size() + n += 1 + l + sovListening(uint64(l)) + } + if len(m.DeliverTxs) > 0 { + for _, e := range m.DeliverTxs { + l = e.Size() + n += 1 + l + sovListening(uint64(l)) + } + } + if m.RequestEndBlock != nil { + l = m.RequestEndBlock.Size() + n += 1 + l + sovListening(uint64(l)) + } + if m.ResponseEndBlock != nil { + l = m.ResponseEndBlock.Size() + n += 1 + l + sovListening(uint64(l)) + } + if m.ResponseCommit != nil { + l = m.ResponseCommit.Size() + n += 1 + l + sovListening(uint64(l)) + } + return n +} + +func (m *BlockMetadata_DeliverTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Request != nil { + l = m.Request.Size() + n += 1 + l + sovListening(uint64(l)) + } + if m.Response != nil { + l = m.Response.Size() + n += 1 + l + sovListening(uint64(l)) + } + return n +} + func sovListening(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -386,6 +740,392 @@ func (m *StoreKVPair) Unmarshal(dAtA []byte) error { } return nil } +func (m *BlockMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestBeginBlock", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RequestBeginBlock == nil { + m.RequestBeginBlock = &types.RequestBeginBlock{} + } + if err := m.RequestBeginBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ResponseBeginBlock", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ResponseBeginBlock == nil { + m.ResponseBeginBlock = &types.ResponseBeginBlock{} + } + if err := m.ResponseBeginBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DeliverTxs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DeliverTxs = append(m.DeliverTxs, &BlockMetadata_DeliverTx{}) + if err := m.DeliverTxs[len(m.DeliverTxs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestEndBlock", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RequestEndBlock == nil { + m.RequestEndBlock = &types.RequestEndBlock{} + } + if err := m.RequestEndBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ResponseEndBlock", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ResponseEndBlock == nil { + m.ResponseEndBlock = &types.ResponseEndBlock{} + } + if err := m.ResponseEndBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ResponseCommit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ResponseCommit == nil { + m.ResponseCommit = &types.ResponseCommit{} + } + if err := m.ResponseCommit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipListening(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthListening + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlockMetadata_DeliverTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeliverTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeliverTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Request", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Request == nil { + m.Request = &types.RequestDeliverTx{} + } + if err := m.Request.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Response", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Response == nil { + m.Response = &types.ResponseDeliverTx{} + } + if err := m.Response.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipListening(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthListening + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipListening(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/store/types/store.go b/store/types/store.go index 8bb7037ea9f0..71ed9f2e60ca 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -129,13 +129,6 @@ type MultiStore interface { // implied that the caller should update the context when necessary between // tracing operations. The modified MultiStore is returned. SetTracingContext(TraceContext) MultiStore - - // ListeningEnabled returns if listening is enabled for the KVStore belonging the provided StoreKey - ListeningEnabled(key StoreKey) bool - - // AddListeners adds WriteListeners for the KVStore belonging to the provided StoreKey - // It appends the listeners to a current set, if one already exists - AddListeners(key StoreKey, listeners []WriteListener) } // From MultiStore.CacheMultiStore().... @@ -196,6 +189,13 @@ type CommitMultiStore interface { // RollbackToVersion rollback the db to specific version(height). RollbackToVersion(version int64) error + + // ListeningEnabled returns if listening is enabled for the KVStore belonging the provided StoreKey + ListeningEnabled(key StoreKey) bool + + // AddListeners adds WriteListeners for the KVStore belonging to the provided StoreKey + // It appends the listeners to a current set, if one already exists + AddListeners(key StoreKey, listeners []WriteListener) } //---------subsp------------------------------- @@ -268,9 +268,6 @@ type CacheWrap interface { // CacheWrapWithTrace recursively wraps again with tracing enabled. CacheWrapWithTrace(w io.Writer, tc TraceContext) CacheWrap - - // CacheWrapWithListeners recursively wraps again with listening enabled - CacheWrapWithListeners(storeKey StoreKey, listeners []WriteListener) CacheWrap } type CacheWrapper interface { @@ -279,9 +276,6 @@ type CacheWrapper interface { // CacheWrapWithTrace branches a store with tracing enabled. CacheWrapWithTrace(w io.Writer, tc TraceContext) CacheWrap - - // CacheWrapWithListeners recursively wraps again with listening enabled - CacheWrapWithListeners(storeKey StoreKey, listeners []WriteListener) CacheWrap } func (cid CommitID) IsZero() bool { @@ -418,6 +412,29 @@ type KVPair kv.Pair // every trace operation. type TraceContext map[string]interface{} +// Clone clones tc into another instance of TraceContext. +func (tc TraceContext) Clone() TraceContext { + ret := TraceContext{} + for k, v := range tc { + ret[k] = v + } + + return ret +} + +// Merge merges value of newTc into tc. +func (tc TraceContext) Merge(newTc TraceContext) TraceContext { + if tc == nil { + tc = TraceContext{} + } + + for k, v := range newTc { + tc[k] = v + } + + return tc +} + // MultiStorePersistentCache defines an interface which provides inter-block // (persistent) caching capabilities for multiple CommitKVStores based on StoreKeys. type MultiStorePersistentCache interface { diff --git a/store/types/store_test.go b/store/types/store_test.go index f86144af7fbd..39087cd6a820 100644 --- a/store/types/store_test.go +++ b/store/types/store_test.go @@ -90,3 +90,120 @@ func TestTransientStoreKey(t *testing.T) { require.Equal(t, key.name, key.Name()) require.Equal(t, fmt.Sprintf("TransientStoreKey{%p, test}", key), key.String()) } + +func TestTraceContext_Clone(t *testing.T) { + tests := []struct { + name string + tc TraceContext + want TraceContext + }{ + { + "nil TraceContext yields empty TraceContext", + nil, + TraceContext{}, + }, + { + "non-nil TraceContext yields equal TraceContext", + TraceContext{ + "value": 42, + }, + TraceContext{ + "value": 42, + }, + }, + { + "non-nil TraceContext yields equal TraceContext, for more than one key", + TraceContext{ + "value": 42, + "another": 24, + "weird": "string", + }, + TraceContext{ + "value": 42, + "another": 24, + "weird": "string", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.want, tt.tc.Clone()) + }) + } +} + +func TestTraceContext_Clone_is_deep(t *testing.T) { + original := TraceContext{ + "value": 42, + "another": 24, + "weird": "string", + } + + clone := original.Clone() + + clone["other"] = true + + require.NotEqual(t, original, clone) +} + +func TestTraceContext_Merge(t *testing.T) { + tests := []struct { + name string + tc TraceContext + other TraceContext + want TraceContext + }{ + { + "tc is nil, other is empty, yields an empty TraceContext", + nil, + TraceContext{}, + TraceContext{}, + }, + { + "tc is nil, other is nil, yields an empty TraceContext", + nil, + nil, + TraceContext{}, + }, + { + "tc is not nil, other is nil, yields tc", + TraceContext{ + "data": 42, + }, + nil, + TraceContext{ + "data": 42, + }, + }, + { + "tc is not nil, other is not nil, yields tc + other", + TraceContext{ + "data": 42, + }, + TraceContext{ + "data2": 42, + }, + TraceContext{ + "data": 42, + "data2": 42, + }, + }, + { + "tc is not nil, other is not nil, other updates value in tc, yields tc updated with value from other", + TraceContext{ + "data": 42, + }, + TraceContext{ + "data": 24, + }, + TraceContext{ + "data": 24, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.want, tt.tc.Merge(tt.other)) + }) + } +} diff --git a/types/utils.go b/types/utils.go index cca98edf0ab7..cc46f284ae31 100644 --- a/types/utils.go +++ b/types/utils.go @@ -104,3 +104,15 @@ func CopyBytes(bz []byte) (ret []byte) { copy(ret, bz) return ret } + +// SliceContains implements a generic function for checking if a slice contains +// a certain value. +func SliceContains[T comparable](elements []T, v T) bool { + for _, s := range elements { + if v == s { + return true + } + } + + return false +} diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index 09be9bbb589d..fa5e233d961b 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -99,7 +99,7 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { } if ms == "" { from, _ := cmd.Flags().GetString(flags.FlagFrom) - _, fromName, _, err := client.GetFromFields(txFactory.Keybase(), from, clientCtx.GenerateOnly) + _, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from) if err != nil { return fmt.Errorf("error getting account from keybase: %w", err) } @@ -108,7 +108,7 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { return err } } else { - multisigAddr, _, _, err := client.GetFromFields(txFactory.Keybase(), ms, clientCtx.GenerateOnly) + multisigAddr, _, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), ms) if err != nil { return fmt.Errorf("error getting account from keybase: %w", err) } @@ -228,7 +228,7 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error { return err } from, _ := cmd.Flags().GetString(flags.FlagFrom) - _, fromName, _, err := client.GetFromFields(txF.Keybase(), from, clientCtx.GenerateOnly) + _, fromName, _, err := client.GetFromFields(clientCtx, txF.Keybase(), from) if err != nil { return fmt.Errorf("error getting account from keybase: %w", err) } @@ -238,7 +238,7 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error { multisigAddr, err := sdk.AccAddressFromBech32(multisig) if err != nil { // Bech32 decode error, maybe it's a name, we try to fetch from keyring - multisigAddr, _, _, err = client.GetFromFields(txFactory.Keybase(), multisig, clientCtx.GenerateOnly) + multisigAddr, _, _, err = client.GetFromFields(clientCtx, txFactory.Keybase(), multisig) if err != nil { return fmt.Errorf("error getting account from keybase: %w", err) } diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 6d2f51d486c3..f9805d2e4252 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -29,8 +29,9 @@ func NewTxCmd() *cobra.Command { func NewSendTxCmd() *cobra.Command { cmd := &cobra.Command{ Use: "send [from_key_or_address] [to_address] [amount]", - Short: `Send funds from one account to another. Note, the'--from' flag is -ignored as it is implied from [from_key_or_address].`, + Short: `Send funds from one account to another. + Note, the'--from' flag is ignored as it is implied from [from_key_or_address]. + When using '--dry-run' a key name cannot be used, only a bech32 address.`, Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { cmd.Flags().Set(flags.FlagFrom, args[0]) diff --git a/x/feegrant/client/testutil/suite.go b/x/feegrant/client/testutil/suite.go index 781bc017b043..fff5475170dc 100644 --- a/x/feegrant/client/testutil/suite.go +++ b/x/feegrant/client/testutil/suite.go @@ -313,7 +313,7 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() { alreadyExistedGrantee := s.addedGrantee clientCtx := val.ClientCtx - fromAddr, fromName, _, err := client.GetFromFields(clientCtx.Keyring, granter.String(), clientCtx.GenerateOnly) + fromAddr, fromName, _, err := client.GetFromFields(clientCtx, clientCtx.Keyring, granter.String()) s.Require().Equal(fromAddr, granter) s.Require().NoError(err)