diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 61fe636ac..462fdcd7c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,7 @@ on: push: branches: - main + - occ-main # TODO: remove after occ work is done permissions: contents: read @@ -22,7 +23,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' - name: Create a file with all core Cosmos SDK pkgs run: go list ./... > pkgs.txt - name: Split pkgs into 10 files @@ -81,7 +82,7 @@ jobs: - uses: actions/setup-python@v3 - uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' - uses: technote-space/get-diff-action@v6.1.0 with: PATTERNS: | @@ -116,7 +117,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' # Download all coverage reports from the 'tests' job - name: Download coverage reports diff --git a/baseapp/abci.go b/baseapp/abci.go index 0dc731ad2..f451e8610 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -12,6 +12,8 @@ import ( "syscall" "time" + "github.com/cosmos/cosmos-sdk/tasks" + "github.com/armon/go-metrics" "github.com/gogo/protobuf/proto" abci "github.com/tendermint/tendermint/abci/types" @@ -25,6 +27,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/legacytm" + "github.com/cosmos/cosmos-sdk/utils" ) // InitChain implements the ABCI interface. It runs the initialization logic @@ -68,11 +71,6 @@ func (app *BaseApp) InitChain(ctx context.Context, req *abci.RequestInitChain) ( return } - // add block gas meter for any genesis transactions (allow infinite gas) - app.deliverState.ctx = app.deliverState.ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) - app.prepareProposalState.ctx = app.prepareProposalState.ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) - app.processProposalState.ctx = app.processProposalState.ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) - resp := app.initChainer(app.deliverState.ctx, *req) app.initChainer(app.prepareProposalState.ctx, *req) app.initChainer(app.processProposalState.ctx, *req) @@ -234,11 +232,31 @@ func (app *BaseApp) CheckTx(ctx context.Context, req *abci.RequestCheckTx) (*abc }, nil } +// DeliverTxBatch executes multiple txs +func (app *BaseApp) DeliverTxBatch(ctx sdk.Context, req sdk.DeliverTxBatchRequest) (res sdk.DeliverTxBatchResponse) { + scheduler := tasks.NewScheduler(app.concurrencyWorkers, app.TracingInfo, app.DeliverTx) + // This will basically no-op the actual prefill if the metadata for the txs is empty + + // process all txs, this will also initializes the MVS if prefill estimates was disabled + txRes, err := scheduler.ProcessAll(ctx, req.TxEntries) + if err != nil { + // TODO: handle error + } + + responses := make([]*sdk.DeliverTxResult, 0, len(req.TxEntries)) + for _, tx := range txRes { + responses = append(responses, &sdk.DeliverTxResult{Response: tx}) + } + return sdk.DeliverTxBatchResponse{Results: responses} +} + // DeliverTx implements the ABCI interface and executes a tx in DeliverTx mode. // State only gets persisted if all messages are valid and get executed successfully. -// Otherwise, the ResponseDeliverTx will contain releveant error information. +// Otherwise, the ResponseDeliverTx will contain relevant error information. // Regardless of tx execution outcome, the ResponseDeliverTx will contain relevant // gas execution context. +// TODO: (occ) this is the function called from sei-chain to perform execution of a transaction. +// We'd likely replace this with an execution tasks that is scheduled by the OCC scheduler func (app *BaseApp) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTx) (res abci.ResponseDeliverTx) { defer telemetry.MeasureSince(time.Now(), "abci", "deliver_tx") defer func() { @@ -344,15 +362,19 @@ func (app *BaseApp) Commit(ctx context.Context) (res *abci.ResponseCommit, err e app.halt() } - if app.snapshotInterval > 0 && uint64(header.Height)%app.snapshotInterval == 0 { - go app.snapshot(header.Height) - } + app.SnapshotIfApplicable(uint64(header.Height)) return &abci.ResponseCommit{ RetainHeight: retainHeight, }, nil } +func (app *BaseApp) SnapshotIfApplicable(height uint64) { + if app.snapshotInterval > 0 && height%app.snapshotInterval == 0 { + go app.Snapshot(int64(height)) + } +} + // halt attempts to gracefully shutdown the node via SIGINT and SIGTERM falling // back on os.Exit if both fail. func (app *BaseApp) halt() { @@ -375,8 +397,8 @@ func (app *BaseApp) halt() { os.Exit(0) } -// snapshot takes a snapshot of the current state and prunes any old snapshottypes. -func (app *BaseApp) snapshot(height int64) { +// Snapshot takes a snapshot of the current state and prunes any old snapshottypes. +func (app *BaseApp) Snapshot(height int64) { if app.snapshotManager == nil { app.logger.Info("snapshot manager not configured") return @@ -908,7 +930,7 @@ func splitPath(requestPath string) (path []string) { } // ABCI++ -func (app *BaseApp) PrepareProposal(ctx context.Context, req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) { +func (app *BaseApp) PrepareProposal(ctx context.Context, req *abci.RequestPrepareProposal) (resp *abci.ResponsePrepareProposal, err error) { defer telemetry.MeasureSince(time.Now(), "abci", "prepare_proposal") header := tmproto.Header{ @@ -942,21 +964,40 @@ func (app *BaseApp) PrepareProposal(ctx context.Context, req *abci.RequestPrepar app.preparePrepareProposalState() + defer func() { + if err := recover(); err != nil { + app.logger.Error( + "panic recovered in PrepareProposal", + "height", req.Height, + "time", req.Time, + "panic", err, + ) + + resp = &abci.ResponsePrepareProposal{ + TxRecords: utils.Map(req.Txs, func(tx []byte) *abci.TxRecord { + return &abci.TxRecord{Action: abci.TxRecord_UNMODIFIED, Tx: tx} + }), + } + } + }() + if app.prepareProposalHandler != nil { - res, err := app.prepareProposalHandler(app.prepareProposalState.ctx, req) + resp, err = app.prepareProposalHandler(app.prepareProposalState.ctx, req) if err != nil { return nil, err } + if cp := app.GetConsensusParams(app.prepareProposalState.ctx); cp != nil { - res.ConsensusParamUpdates = cp + resp.ConsensusParamUpdates = cp } - return res, nil - } else { - return nil, errors.New("no prepare proposal handler") + + return resp, nil } + + return nil, errors.New("no prepare proposal handler") } -func (app *BaseApp) ProcessProposal(ctx context.Context, req *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) { +func (app *BaseApp) ProcessProposal(ctx context.Context, req *abci.RequestProcessProposal) (resp *abci.ResponseProcessProposal, err error) { defer telemetry.MeasureSince(time.Now(), "abci", "process_proposal") header := tmproto.Header{ @@ -988,30 +1029,38 @@ func (app *BaseApp) ProcessProposal(ctx context.Context, req *abci.RequestProces app.setProcessProposalHeader(header) } - // add block gas meter - var gasMeter sdk.GasMeter - if maxGas := app.getMaximumBlockGas(app.processProposalState.ctx); maxGas > 0 { - gasMeter = sdk.NewGasMeter(maxGas) - } else { - gasMeter = sdk.NewInfiniteGasMeter() - } - // NOTE: header hash is not set in NewContext, so we manually set it here - app.prepareProcessProposalState(gasMeter, req.Hash) + app.prepareProcessProposalState(req.Hash) + + defer func() { + if err := recover(); err != nil { + app.logger.Error( + "panic recovered in ProcessProposal", + "height", req.Height, + "time", req.Time, + "hash", fmt.Sprintf("%X", req.Hash), + "panic", err, + ) + + resp = &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + }() if app.processProposalHandler != nil { - res, err := app.processProposalHandler(app.processProposalState.ctx, req) + resp, err = app.processProposalHandler(app.processProposalState.ctx, req) if err != nil { return nil, err } + if cp := app.GetConsensusParams(app.processProposalState.ctx); cp != nil { - res.ConsensusParamUpdates = cp + resp.ConsensusParamUpdates = cp } - return res, nil - } else { - return nil, errors.New("no process proposal handler") + + return resp, nil } + + return nil, errors.New("no process proposal handler") } func (app *BaseApp) FinalizeBlock(ctx context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { @@ -1055,22 +1104,14 @@ func (app *BaseApp) FinalizeBlock(ctx context.Context, req *abci.RequestFinalize app.setDeliverStateHeader(header) } - // add block gas meter - var gasMeter sdk.GasMeter - if maxGas := app.getMaximumBlockGas(app.deliverState.ctx); maxGas > 0 { - gasMeter = sdk.NewGasMeter(maxGas) - } else { - gasMeter = sdk.NewInfiniteGasMeter() - } - // NOTE: header hash is not set in NewContext, so we manually set it here - app.prepareDeliverState(gasMeter, req.Hash) + app.prepareDeliverState(req.Hash) // we also set block gas meter to checkState in case the application needs to // verify gas consumption during (Re)CheckTx if app.checkState != nil { - app.checkState.SetContext(app.checkState.ctx.WithBlockGasMeter(gasMeter).WithHeaderHash(req.Hash)) + app.checkState.SetContext(app.checkState.ctx.WithHeaderHash(req.Hash)) } if app.finalizeBlocker != nil { diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 174924baf..51e235594 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -3,19 +3,24 @@ package baseapp import ( "context" "crypto/sha256" - "errors" "fmt" "reflect" "strings" "sync" "time" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" - "github.com/armon/go-metrics" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/snapshots" + "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + acltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/utils/tracing" + "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" "github.com/gogo/protobuf/proto" sdbm "github.com/sei-protocol/sei-tm-db/backends" "github.com/spf13/cast" @@ -25,18 +30,9 @@ import ( "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec/types" - servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/rootmulti" - "github.com/cosmos/cosmos-sdk/telemetry" - sdk "github.com/cosmos/cosmos-sdk/types" - acltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" - "github.com/cosmos/iavl" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) const ( @@ -60,7 +56,9 @@ const ( FlagArchivalArweaveIndexDBFullPath = "archival-arweave-index-db-full-path" FlagArchivalArweaveNodeURL = "archival-arweave-node-url" - FlagChainID = "chain-id" + FlagChainID = "chain-id" + FlagConcurrencyWorkers = "concurrency-workers" + FlagOccEnabled = "occ-enabled" ) var ( @@ -163,11 +161,12 @@ type BaseApp struct { //nolint: maligned compactionInterval uint64 - orphanConfig *iavl.Options - TmConfig *tmcfg.Config TracingInfo *tracing.Info + + concurrencyWorkers int + occEnabled bool } type appStore struct { @@ -290,8 +289,15 @@ func NewBaseApp( panic("must pass --chain-id when calling 'seid start' or set in ~/.sei/config/client.toml") } app.startCompactionRoutine(db) - if app.orphanConfig != nil { - app.cms.(*rootmulti.Store).SetOrphanConfig(app.orphanConfig) + + // if no option overrode already, initialize to the flags value + // this avoids forcing every implementation to pass an option, but allows it + if app.concurrencyWorkers == 0 { + app.concurrencyWorkers = cast.ToInt(appOpts.Get(FlagConcurrencyWorkers)) + } + // safely default this to the default value if 0 + if app.concurrencyWorkers == 0 { + app.concurrencyWorkers = config.DefaultConcurrencyWorkers } return app @@ -307,6 +313,16 @@ func (app *BaseApp) AppVersion() uint64 { return app.appVersion } +// ConcurrencyWorkers returns the number of concurrent workers for the BaseApp. +func (app *BaseApp) ConcurrencyWorkers() int { + return app.concurrencyWorkers +} + +// OccEnabled returns the whether OCC is enabled for the BaseApp. +func (app *BaseApp) OccEnabled() bool { + return app.occEnabled +} + // Version returns the application's version string. func (app *BaseApp) Version() string { return app.version @@ -443,20 +459,6 @@ func (app *BaseApp) init() error { app.setCheckState(tmproto.Header{}) app.Seal() - // make sure the snapshot interval is a multiple of the pruning KeepEvery interval - if app.snapshotManager != nil && app.snapshotInterval > 0 { - rms, ok := app.cms.(*rootmulti.Store) - if !ok { - return errors.New("state sync snapshots require a rootmulti store") - } - pruningOpts := rms.GetPruning() - if pruningOpts.KeepEvery > 0 && app.snapshotInterval%pruningOpts.KeepEvery != 0 { - return fmt.Errorf( - "state sync snapshot interval %v must be a multiple of pruning keep every interval %v", - app.snapshotInterval, pruningOpts.KeepEvery) - } - } - return nil } @@ -472,10 +474,6 @@ func (app *BaseApp) setHaltTime(haltTime uint64) { app.haltTime = haltTime } -func (app *BaseApp) setOrphanConfig(opts *iavl.Options) { - app.orphanConfig = opts -} - func (app *BaseApp) setMinRetainBlocks(minRetainBlocks uint64) { app.minRetainBlocks = minRetainBlocks } @@ -613,8 +611,8 @@ func (app *BaseApp) preparePrepareProposalState() { } } -func (app *BaseApp) prepareProcessProposalState(gasMeter sdk.GasMeter, headerHash []byte) { - app.processProposalState.SetContext(app.processProposalState.Context().WithBlockGasMeter(gasMeter). +func (app *BaseApp) prepareProcessProposalState(headerHash []byte) { + app.processProposalState.SetContext(app.processProposalState.Context(). WithHeaderHash(headerHash). WithConsensusParams(app.GetConsensusParams(app.processProposalState.Context()))) @@ -623,9 +621,8 @@ func (app *BaseApp) prepareProcessProposalState(gasMeter sdk.GasMeter, headerHas } } -func (app *BaseApp) prepareDeliverState(gasMeter sdk.GasMeter, headerHash []byte) { +func (app *BaseApp) prepareDeliverState(headerHash []byte) { app.deliverState.SetContext(app.deliverState.Context(). - WithBlockGasMeter(gasMeter). WithHeaderHash(headerHash). WithConsensusParams(app.GetConsensusParams(app.deliverState.Context()))) } @@ -724,27 +721,6 @@ func (app *BaseApp) StoreConsensusParams(ctx sdk.Context, cp *tmproto.ConsensusP app.paramStore.Set(ctx, ParamStoreKeyABCIParams, cp.Abci) } -// getMaximumBlockGas gets the maximum gas from the consensus params. It panics -// if maximum block gas is less than negative one and returns zero if negative -// one. -func (app *BaseApp) getMaximumBlockGas(ctx sdk.Context) uint64 { - cp := app.GetConsensusParams(ctx) - if cp == nil || cp.Block == nil { - return 0 - } - - maxGas := cp.Block.MaxGas - - // TODO::: This is a temporary fix, max gas causes non-deterministic behavior - // with parallel TX - switch { - case maxGas < -1: - panic(fmt.Sprintf("invalid maximum block gas: %d", maxGas)) - default: - return 0 - } -} - func (app *BaseApp) validateHeight(req abci.RequestBeginBlock) error { if req.Header.Height < 1 { return fmt.Errorf("invalid height: %d", req.Header.Height) @@ -821,6 +797,7 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) sdk.Context // cacheTxContext returns a new context based off of the provided context with // a branched multi-store. +// TODO: (occ) This is an example of where we wrap the multistore with a cache multistore, and then return a modified context using that multistore func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context, sdk.CacheMultiStore) { ms := ctx.MultiStore() // TODO: https://github.com/cosmos/cosmos-sdk/issues/2824 @@ -847,13 +824,13 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context // and execute successfully. An error is returned otherwise. func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, priority int64, err error) { - defer telemetry.MeasureThroughputSinceWithLabels( - telemetry.TxCount, - []metrics.Label{ - telemetry.NewLabel("mode", modeKeyToString[mode]), - }, - time.Now(), - ) + // defer telemetry.MeasureThroughputSinceWithLabels( + // telemetry.TxCount, + // []metrics.Label{ + // telemetry.NewLabel("mode", modeKeyToString[mode]), + // }, + // time.Now(), + // ) // Reset events after each checkTx or simulateTx or recheckTx // DeliverTx is garbage collected after FinalizeBlocker @@ -878,11 +855,6 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf ms := ctx.MultiStore() - // only run the tx if there is block gas remaining - if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() { - return gInfo, nil, nil, -1, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") - } - defer func() { if r := recover(); r != nil { acltypes.SendAllSignalsForTx(ctx.TxCompletionChannels()) @@ -895,27 +867,6 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf gInfo = sdk.GasInfo{GasWanted: gasWanted, GasUsed: ctx.GasMeter().GasConsumed()} }() - blockGasConsumed := false - // consumeBlockGas makes sure block gas is consumed at most once. It must happen after - // tx processing, and must be execute even if tx processing fails. Hence we use trick with `defer` - consumeBlockGas := func() { - if !blockGasConsumed { - blockGasConsumed = true - ctx.BlockGasMeter().ConsumeGas( - ctx.GasMeter().GasConsumedToLimit(), "block gas meter", - ) - } - } - - // If BlockGasMeter() panics it will be caught by the above recover and will - // return an error - in any case BlockGasMeter will consume gas past the limit. - // - // NOTE: This must exist in a separate defer function for the above recovery - // to recover from this one. - if mode == runTxModeDeliver { - defer consumeBlockGas() - } - tx, err := app.txDecoder(txBytes) if err != nil { return sdk.GasInfo{}, nil, nil, 0, err @@ -974,6 +925,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf storeAccessOpEvents := msCache.GetEvents() accessOps := ctx.TxMsgAccessOps()[acltypes.ANTE_MSG_INDEX] + // TODO: (occ) This is an example of where we do our current validation. Note that this validation operates on the declared dependencies for a TX / antehandler + the utilized dependencies, whereas the validation missingAccessOps := ctx.MsgValidator().ValidateAccessOperations(accessOps, storeAccessOpEvents) if len(missingAccessOps) != 0 { for op := range missingAccessOps { @@ -1002,9 +954,6 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf result, err = app.runMsgs(runMsgCtx, msgs, mode) if err == nil && mode == runTxModeDeliver { - // When block gas exceeds, it'll panic and won't commit the cached store. - consumeBlockGas() - msCache.Write() } // we do this since we will only be looking at result in DeliverTx @@ -1118,6 +1067,8 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s storeAccessOpEvents := msgMsCache.GetEvents() accessOps := ctx.TxMsgAccessOps()[i] missingAccessOps := ctx.MsgValidator().ValidateAccessOperations(accessOps, storeAccessOpEvents) + // TODO: (occ) This is where we are currently validating our per message dependencies, + // whereas validation will be done holistically based on the mvkv for OCC approach if len(missingAccessOps) != 0 { for op := range missingAccessOps { ctx.Logger().Info((fmt.Sprintf("eventMsgName=%s Missing Access Operation:%s ", eventMsgName, op.String()))) @@ -1174,6 +1125,10 @@ func (app *BaseApp) Close() error { if err := app.appStore.db.Close(); err != nil { return err } + // close the underline database for storeV2 + if err := app.cms.Close(); err != nil { + return err + } return app.snapshotManager.Close() } diff --git a/baseapp/block_gas_test.go b/baseapp/block_gas_test.go index 7d9e02c7b..2d154709c 100644 --- a/baseapp/block_gas_test.go +++ b/baseapp/block_gas_test.go @@ -125,7 +125,7 @@ func TestBaseApp_BlockGas(t *testing.T) { } // check block gas is always consumed - this value may change if we update the logic for // how gas is consumed - baseGas := uint64(58406) // baseGas is the gas consumed before tx msg + baseGas := uint64(62766) // baseGas is the gas consumed before tx msg expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas) if expGasConsumed > txtypes.MaxGasWanted { // capped by gasLimit diff --git a/baseapp/deliver_tx_batch_test.go b/baseapp/deliver_tx_batch_test.go new file mode 100644 index 000000000..c8a29b8b7 --- /dev/null +++ b/baseapp/deliver_tx_batch_test.go @@ -0,0 +1,145 @@ +package baseapp + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +func anteHandler(capKey sdk.StoreKey, storeKey []byte) sdk.AnteHandler { + return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { + store := ctx.KVStore(capKey) + txTest := tx.(txTest) + + if txTest.FailOnAnte { + return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure") + } + + val := getIntFromStore(store, storeKey) + setIntOnStore(store, storeKey, val+1) + + ctx.EventManager().EmitEvents( + counterEvent("ante-val", val+1), + ) + + return ctx, nil + } +} + +func handlerKVStore(capKey sdk.StoreKey) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + res := &sdk.Result{} + + // Extract the unique ID from the message (assuming you have added this) + txIndex := ctx.TxIndex() + + // Use the unique ID to get a specific key for this transaction + sharedKey := []byte(fmt.Sprintf("shared")) + txKey := []byte(fmt.Sprintf("tx-%d", txIndex)) + + // Similar steps as before: Get the store, retrieve a value, increment it, store back, emit an event + // Get the store + store := ctx.KVStore(capKey) + + // increment per-tx key (no conflict) + val := getIntFromStore(store, txKey) + setIntOnStore(store, txKey, val+1) + + // increment shared key + sharedVal := getIntFromStore(store, sharedKey) + setIntOnStore(store, sharedKey, sharedVal+1) + + // Emit an event with the incremented value and the unique ID + ctx.EventManager().EmitEvent( + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute("shared-val", fmt.Sprintf("%d", sharedVal+1)), + sdk.NewAttribute("tx-val", fmt.Sprintf("%d", val+1)), + sdk.NewAttribute("tx-id", fmt.Sprintf("%d", txIndex)), + ), + ) + + res.Events = ctx.EventManager().Events().ToABCIEvents() + return res, nil + } +} + +func requireAttribute(t *testing.T, evts []abci.Event, name string, val string) { + for _, evt := range evts { + for _, att := range evt.Attributes { + if string(att.Key) == name { + require.Equal(t, val, string(att.Value)) + return + } + } + } + require.Fail(t, fmt.Sprintf("attribute %s not found via value %s", name, val)) +} + +func TestDeliverTxBatch(t *testing.T) { + // test increments in the ante + anteKey := []byte("ante-key") + + anteOpt := func(bapp *BaseApp) { + bapp.SetAnteHandler(anteHandler(capKey1, anteKey)) + } + + // test increments in the handler + routerOpt := func(bapp *BaseApp) { + r := sdk.NewRoute(routeMsgCounter, handlerKVStore(capKey1)) + bapp.Router().AddRoute(r) + } + + app := setupBaseApp(t, anteOpt, routerOpt) + app.InitChain(context.Background(), &abci.RequestInitChain{}) + + // Create same codec used in txDecoder + codec := codec.NewLegacyAmino() + registerTestCodec(codec) + + nBlocks := 3 + txPerHeight := 5 + + for blockN := 0; blockN < nBlocks; blockN++ { + header := tmproto.Header{Height: int64(blockN) + 1} + app.setDeliverState(header) + app.deliverState.ctx = app.deliverState.ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) + app.BeginBlock(app.deliverState.ctx, abci.RequestBeginBlock{Header: header}) + + var requests []*sdk.DeliverTxEntry + for i := 0; i < txPerHeight; i++ { + counter := int64(blockN*txPerHeight + i) + tx := newTxCounter(counter, counter) + + txBytes, err := codec.Marshal(tx) + require.NoError(t, err) + requests = append(requests, &sdk.DeliverTxEntry{ + Request: abci.RequestDeliverTx{Tx: txBytes}, + }) + } + + responses := app.DeliverTxBatch(app.deliverState.ctx, sdk.DeliverTxBatchRequest{TxEntries: requests}) + require.Len(t, responses.Results, txPerHeight) + + for idx, deliverTxRes := range responses.Results { + res := deliverTxRes.Response + require.Equal(t, abci.CodeTypeOK, res.Code) + requireAttribute(t, res.Events, "tx-id", fmt.Sprintf("%d", idx)) + requireAttribute(t, res.Events, "tx-val", fmt.Sprintf("%d", blockN+1)) + requireAttribute(t, res.Events, "shared-val", fmt.Sprintf("%d", blockN*txPerHeight+idx+1)) + } + + app.EndBlock(app.deliverState.ctx, abci.RequestEndBlock{}) + require.Empty(t, app.deliverState.ctx.MultiStore().GetEvents()) + app.SetDeliverStateToCommit() + app.Commit(context.Background()) + } +} diff --git a/baseapp/options.go b/baseapp/options.go index 3eac7f812..165a17e91 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -4,13 +4,11 @@ import ( "fmt" "io" - dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/iavl" + dbm "github.com/tendermint/tm-db" ) // File for storing in-package BaseApp optional functions, @@ -41,10 +39,6 @@ func SetHaltTime(haltTime uint64) func(*BaseApp) { return func(bapp *BaseApp) { bapp.setHaltTime(haltTime) } } -func SetOrphanConfig(opts *iavl.Options) func(*BaseApp) { - return func(bapp *BaseApp) { bapp.setOrphanConfig(opts) } -} - // SetMinRetainBlocks returns a BaseApp option function that sets the minimum // block retention height value when determining which heights to prune during // ABCI Commit. @@ -87,6 +81,10 @@ func SetSnapshotInterval(interval uint64) func(*BaseApp) { return func(app *BaseApp) { app.SetSnapshotInterval(interval) } } +func SetConcurrencyWorkers(workers int) func(*BaseApp) { + return func(app *BaseApp) { app.SetConcurrencyWorkers(workers) } +} + // SetSnapshotKeepRecent sets the recent snapshots to keep. func SetSnapshotKeepRecent(keepRecent uint32) func(*BaseApp) { return func(app *BaseApp) { app.SetSnapshotKeepRecent(keepRecent) } @@ -284,7 +282,7 @@ func (app *BaseApp) SetSnapshotStore(snapshotStore *snapshots.Store) { app.snapshotManager = nil return } - app.snapshotManager = snapshots.NewManager(snapshotStore, app.cms) + app.snapshotManager = snapshots.NewManager(snapshotStore, app.cms, app.logger) } // SetSnapshotInterval sets the snapshot interval. @@ -295,6 +293,13 @@ func (app *BaseApp) SetSnapshotInterval(snapshotInterval uint64) { app.snapshotInterval = snapshotInterval } +func (app *BaseApp) SetConcurrencyWorkers(workers int) { + if app.sealed { + panic("SetConcurrencyWorkers() on sealed BaseApp") + } + app.SetConcurrencyWorkers(workers) +} + // SetSnapshotKeepRecent sets the number of recent snapshots to keep. func (app *BaseApp) SetSnapshotKeepRecent(snapshotKeepRecent uint32) { if app.sealed { diff --git a/go.mod b/go.mod index ab7ccd3cd..0f99404d0 100644 --- a/go.mod +++ b/go.mod @@ -1,47 +1,50 @@ -go 1.18 +go 1.21 module github.com/cosmos/cosmos-sdk require ( - github.com/99designs/keyring v1.1.6 - github.com/armon/go-metrics v0.3.10 + cosmossdk.io/errors v1.0.0 + github.com/99designs/keyring v1.2.1 + github.com/armon/go-metrics v0.4.1 github.com/bgentry/speakeasy v0.1.0 github.com/btcsuite/btcd v0.22.1 github.com/coinbase/rosetta-sdk-go v0.7.0 - github.com/confio/ics23/go v0.7.0 - github.com/cosmos/btcutil v1.0.4 + github.com/confio/ics23/go v0.9.0 + github.com/cosmos/btcutil v1.0.5 github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/iavl v0.19.4 - github.com/cosmos/ledger-cosmos-go v0.11.1 + github.com/cosmos/iavl v0.21.0-alpha.1.0.20230904092046-df3db2d96583 + github.com/cosmos/ledger-cosmos-go v0.12.2 github.com/deckarep/golang-set v1.8.0 github.com/gogo/gateway v1.1.0 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 - github.com/golang/protobuf v1.5.2 + github.com/golang/protobuf v1.5.3 + github.com/google/btree v1.1.2 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/golang-lru/v2 v2.0.1 - github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 + github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 github.com/improbable-eng/grpc-web v0.14.1 github.com/jhump/protoreflect v1.12.1-0.20220417024638-438db461d753 github.com/magiconair/properties v1.8.6 - github.com/mattn/go-isatty v0.0.16 + github.com/mattn/go-isatty v0.0.19 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.2 - github.com/prometheus/common v0.34.0 + github.com/prometheus/client_golang v1.14.0 + github.com/prometheus/common v0.42.0 github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.3.1 - github.com/rs/zerolog v1.27.0 + github.com/rs/zerolog v1.30.0 github.com/savaki/jq v0.0.0-20161209013833-0e6baecebbf8 + github.com/sei-protocol/sei-db v0.0.22 github.com/sei-protocol/sei-tm-db v0.0.5 github.com/spf13/cast v1.5.0 - github.com/spf13/cobra v1.4.0 + github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.12.0 - github.com/stretchr/testify v1.8.1 - github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + github.com/spf13/viper v1.13.0 + github.com/stretchr/testify v1.8.4 + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.16.0 @@ -52,102 +55,134 @@ require ( go.opentelemetry.io/otel/exporters/jaeger v1.9.0 go.opentelemetry.io/otel/sdk v1.9.0 go.opentelemetry.io/otel/trace v1.9.0 - golang.org/x/crypto v0.1.0 - golang.org/x/exp v0.0.0-20221026153819-32f3d567a233 - google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a - google.golang.org/grpc v1.50.1 - google.golang.org/protobuf v1.28.1 + golang.org/x/crypto v0.14.0 + golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb + google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13 + google.golang.org/grpc v1.58.3 + google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 gotest.tools v2.2.0+incompatible ) require ( - filippo.io/edwards25519 v1.0.0-beta.2 // indirect + filippo.io/edwards25519 v1.0.0-rc.1 // indirect + github.com/DataDog/zstd v1.4.5 // indirect + github.com/alitto/pond v1.8.3 // 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/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cockroachdb/errors v1.8.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect + github.com/cockroachdb/pebble v0.0.0-20230819001538-1798fbf5956c // indirect + github.com/cockroachdb/redact v1.0.8 // indirect + github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cosmos/gorocksdb v1.2.0 // 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/davecgh/go-spew v1.1.1 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v3 v3.2103.2 // indirect - github.com/dgraph-io/ristretto v0.1.0 // indirect - github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/gin-gonic/gin v1.7.7 // 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.0 // indirect + github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect - github.com/golang/glog v1.0.0 // indirect + github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect github.com/google/flatbuffers v1.12.1 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/google/gofuzz v1.2.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jmhodges/levigo v1.0.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // 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.16.3 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/ledgerwatch/erigon-lib v0.0.0-20230210071639-db0e7ed11263 // indirect github.com/lib/pq v1.10.6 // indirect github.com/libp2p/go-buffer-pool v0.0.2 // indirect + github.com/linxGnu/grocksdb v1.8.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20210609091139-0a56a4bca00b // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.2 // indirect - github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // 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/client_model v0.3.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rogpeppe/go-internal v1.11.0 // 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/jwalterweatherman v1.1.0 // indirect - github.com/subosito/gotenv v1.4.0 // indirect - github.com/zondax/hid v0.9.0 // indirect - go.etcd.io/bbolt v1.3.6 // indirect + github.com/subosito/gotenv v1.4.1 // indirect + github.com/tidwall/gjson v1.10.2 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/tinylru v1.1.0 // indirect + github.com/tidwall/wal v1.1.7 // indirect + github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d // indirect + github.com/zondax/hid v0.9.1 // indirect + github.com/zondax/ledger-go v0.14.1 // indirect + go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.23.0 // indirect - golang.org/x/net v0.2.0 // indirect - golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // 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.66.6 // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.6.0 // indirect + google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + lukechampine.com/uint128 v1.2.0 // indirect + modernc.org/cc/v3 v3.40.0 // indirect + modernc.org/ccgo/v3 v3.16.13 // indirect + modernc.org/libc v1.24.1 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.6.0 // indirect + modernc.org/opt v0.1.3 // indirect + modernc.org/sqlite v1.26.0 // indirect + modernc.org/strutil v1.1.3 // indirect + modernc.org/token v1.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 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - - github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.7 - + github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.7-seidb-1 // 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/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.2.28 - + github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.30 + // Latest goleveldb is broken, we have to stick to this version + github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.2.37 // latest grpc doesn't work with with our modified proto compiler, so we need to enforce // the following version across all dependencies. google.golang.org/grpc => google.golang.org/grpc v1.33.2 diff --git a/go.sum b/go.sum index d05543504..9fff364a5 100644 --- a/go.sum +++ b/go.sum @@ -34,13 +34,17 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04= +cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= 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= +filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= 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= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= @@ -53,14 +57,22 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= @@ -69,13 +81,17 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrd github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= github.com/adlio/schema v1.3.0 h1:eSVYLxYWbm/6ReZBCkLw4Fz7uqC+ZNoPvA39bOwi52A= +github.com/adlio/schema v1.3.0/go.mod h1:51QzxkpeFs6lRY11kPye26IaFPOV+HqEj01t5aXXKfs= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs= +github.com/alitto/pond v1.8.3/go.mod h1:CmvIIGd5jKLasGI3D87qDkQxjzChdKMmnXMg3fG6M6Q= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -84,14 +100,15 @@ 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.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/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= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -99,19 +116,21 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/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/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= +github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-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= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= @@ -127,8 +146,8 @@ github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -138,18 +157,36 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4 github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= +github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/pebble v0.0.0-20230819001538-1798fbf5956c h1:aDetJlMe4qJxWAwu+/bzTs2/b1EW9ecVyawpRD7N/tE= +github.com/cockroachdb/pebble v0.0.0-20230819001538-1798fbf5956c/go.mod h1:EDjiaAXc0FXiRmxDzcu1wIEJ093ohHMUWxrI6iku0XA= +github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= 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/containerd/continuity v0.2.1 h1:/EeEo2EtN3umhbbgCveyjifoMYg0pS+nMMEemaYw634= +github.com/containerd/continuity v0.2.1/go.mod h1:wCYX+dRqZdImhGucXOqTQn05AhX6EUDaGEMUzTFFpLg= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= -github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= +github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= +github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 h1:iKclrn3YEOwk4jQHT2ulgzuXyxmzmPczUalMwW4XH9k= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= @@ -158,16 +195,15 @@ github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4 github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= 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/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.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -177,16 +213,20 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= 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= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/badger/v3 v3.2103.2 h1:dpyM5eCJAtQCBcMCZcT4UBZchuTJgCywerHHgmxfxM8= github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= 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/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= 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= @@ -195,12 +235,14 @@ 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-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 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/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac h1:opbrjaN/L8gg6Xh5D04Tem+8xVcz6ajZlGCs49mQgyg= -github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 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/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= @@ -209,32 +251,46 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -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/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= 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/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -243,9 +299,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -256,6 +311,7 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= 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= @@ -278,9 +334,11 @@ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6 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/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -311,14 +369,15 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= @@ -338,11 +397,11 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 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= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -358,6 +417,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -376,6 +437,7 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -414,8 +476,9 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4= github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -424,21 +487,28 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= -github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= +github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSVUgRRRtOrZOC1fYmY9gV0e9z/Iu+xNVSASWjsuyGU= +github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3/go.mod h1:5PC6ZNPde8bBqU/ewGZig35+UIZtw9Ytxez8/q5ZyFE= github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/improbable-eng/grpc-web v0.14.1 h1:NrN4PY71A6tAz2sKDvC5JCauENWp0ykG8Oq1H3cpFvw= github.com/improbable-eng/grpc-web v0.14.1/go.mod h1:zEjGHa8DAlkoOXmswrNvhUGEYQA9UI7DhrGeHR1DMGU= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +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/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/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= @@ -460,37 +530,55 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 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/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/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.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -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.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 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.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +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/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/ledgerwatch/erigon-lib v0.0.0-20230210071639-db0e7ed11263 h1:LGEzZvf33Y1NhuP5+jI/ni9l1TFS6oYPDilgy74NusM= +github.com/ledgerwatch/erigon-lib v0.0.0-20230210071639-db0e7ed11263/go.mod h1:OXgMDuUo2lZ3NpH29ZvMYbk+LxFd5ffDl2Z2mGMuY/I= 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/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= @@ -499,12 +587,15 @@ github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOS github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/linxGnu/grocksdb v1.8.4 h1:ZMsBpPpJNtRLHiKKp0mI7gW+NT4s7UgfD5xHxx1jVRo= +github.com/linxGnu/grocksdb v1.8.4/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -514,16 +605,25 @@ github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HN github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -543,6 +643,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -554,7 +655,9 @@ github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 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= @@ -572,17 +675,22 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= +github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= 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/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v1.0.3 h1:1hbqejyQWCJBvtKAfdO0b1FmaEf2z/bxnjqbARass5k= +github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= 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= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -592,6 +700,7 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -601,14 +710,18 @@ 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.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= -github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= +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= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= +github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= 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/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +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= @@ -624,17 +737,16 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -642,19 +754,16 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE= -github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.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.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= 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= @@ -663,36 +772,46 @@ github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzy github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= 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.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors 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= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= -github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= -github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/savaki/jq v0.0.0-20161209013833-0e6baecebbf8 h1:ajJQhvqPSQFJJ4aV5mDAMx8F7iFi6Dxfo6y62wymLNs= github.com/savaki/jq v0.0.0-20161209013833-0e6baecebbf8/go.mod h1:Nw/CCOXNyF5JDd6UpYxBwG5WWZ2FOJ/d5QnXL4KQ6vY= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= -github.com/sei-protocol/sei-iavl v0.1.7 h1:cUdHDBkxs0FF/kOt1qCVLm0K+Bqaw92/dbZSgn4kxiA= -github.com/sei-protocol/sei-iavl v0.1.7/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= -github.com/sei-protocol/sei-tendermint v0.2.28 h1:5PB1a/zu6H2iDbxIMnXgDtB4QwV5PZRikguX8gASLGI= -github.com/sei-protocol/sei-tendermint v0.2.28/go.mod h1:+BtDvAwTkE64BlxzpH9ZP7S6vUYT9wRXiZa/WW8/o4g= +github.com/sei-protocol/sei-db v0.0.30 h1:dlAOTE+7nByzzAD9cb1/DxaHWbxXOHFh58a2ImvcoYs= +github.com/sei-protocol/sei-db v0.0.30/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= +github.com/sei-protocol/sei-iavl v0.1.7-seidb-1 h1:Acsjnanr8vhRZ5Dbv5sYnxDa8ibheXrlqLtbsUmLGEo= +github.com/sei-protocol/sei-iavl v0.1.7-seidb-1/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= +github.com/sei-protocol/sei-tendermint v0.2.37 h1:rCVsvngDNKtN8A48zWEn083Sq/TZ/C6qm/PSN4xSxQI= +github.com/sei-protocol/sei-tendermint v0.2.37/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -700,6 +819,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -715,8 +835,8 @@ 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.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/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= @@ -725,8 +845,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.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +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/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= @@ -746,13 +866,11 @@ 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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs= -github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/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/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= @@ -763,10 +881,22 @@ github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2l github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/tm-db v0.6.8-0.20220519162814-e24b96538a12 h1:unOeFDC/TV4Oh371XZGmZyfeIzeGfK/JINb0T+6C+QY= github.com/tendermint/tm-db v0.6.8-0.20220519162814-e24b96538a12/go.mod h1:PWsIWOTwdwC7Ow/GUvx8HgUJTO691pBuorIQD8JvwAs= +github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= +github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo= +github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= +github.com/tidwall/tinylru v1.1.0 h1:XY6IUfzVTU9rpwdhKUF6nQdChgCdGjkMfLzbWyiau6I= +github.com/tidwall/tinylru v1.1.0/go.mod h1:3+bX+TJ2baOLMWTnlyNWHh4QMnFyARg2TLTQ6OFbzw8= +github.com/tidwall/wal v1.1.7 h1:emc1TRjIVsdKKSnpwGBAcsAGg0767SvUk8+ygx7Bb+4= +github.com/tidwall/wal v1.1.7/go.mod h1:r6lR1j27W9EPalgHiB7zLJDYu3mzW5BQP5KrzBpYY/E= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 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= @@ -778,24 +908,40 @@ 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/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= github.com/yourbasic/graph v0.0.0-20210606180040-8ecfec1c2869 h1:7v7L5lsfw4w8iqBBXETukHo4IPltmD+mWoLRYUmeGN8= github.com/yourbasic/graph v0.0.0-20210606180040-8ecfec1c2869/go.mod h1:Rfzr+sqaDreiCaoQbFCu3sTXxeFq/9kXRuyOoSlGQHE= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= -github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d h1:XQyeLr7N9iY9mi+TGgsBFkj54+j3fdoo8e2u6zrGP5A= +github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d/go.mod h1:hoMeDjlNXTNqVwrCk8YDyaBS2g5vFfEX2ezMi4vb6CY= +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= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -842,8 +988,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 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= @@ -856,8 +1002,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20221026153819-32f3d567a233 h1:9bNbSKT4RPLEzne0Xh1v3NaNecsa1DKjkOuTbY6V9rI= -golang.org/x/exp v0.0.0-20221026153819-32f3d567a233/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= +golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -883,6 +1029,8 @@ 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.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -895,6 +1043,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -904,6 +1053,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -929,11 +1079,8 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -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.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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= @@ -943,8 +1090,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -956,8 +1101,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -967,6 +1112,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -977,6 +1123,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w 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-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1009,7 +1156,6 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1018,24 +1164,21 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-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-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.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -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/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 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= @@ -1043,19 +1186,19 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/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/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1105,11 +1248,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.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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= 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= @@ -1137,6 +1281,7 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1179,8 +1324,12 @@ 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-20221014213838-99cd37c6964a h1:GH6UPn3ixhWcKDhpnEC55S75cerLPdpp3hrhfKYjZgw= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= +google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13 h1:U7+wNaVuSTaUqNvK2+osJ9ejEZxbjHHk8F2b6Hpx0AE= +google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b h1:tdhlmiMZNpc5p2W5qqKgRrOubaMZ3c85uG/GJtGgL98= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= 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= @@ -1195,19 +1344,21 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-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= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= -gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -1238,9 +1389,38 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= +modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= +modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= +modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= +modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= +modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= +modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= +modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= +pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/proto/cosmos/accesscontrol/constants.proto b/proto/cosmos/accesscontrol/constants.proto index 889916568..3c214d912 100644 --- a/proto/cosmos/accesscontrol/constants.proto +++ b/proto/cosmos/accesscontrol/constants.proto @@ -130,6 +130,7 @@ enum ResourceType { KV_DEX_SHORT_ORDER_COUNT = 92; // child of KV_DEX KV_BANK_DEFERRED = 93; // child of KV + reserved 94; KV_BANK_DEFERRED_MODULE_TX_INDEX = 95; // child of KV_BANK_DEFERRED KV_EVM = 96; // child of KV diff --git a/proto/cosmos/auth/v1beta1/auth.proto b/proto/cosmos/auth/v1beta1/auth.proto index 72e1d9ec2..6c7e863b7 100644 --- a/proto/cosmos/auth/v1beta1/auth.proto +++ b/proto/cosmos/auth/v1beta1/auth.proto @@ -47,4 +47,5 @@ message Params { [(gogoproto.customname) = "SigVerifyCostED25519", (gogoproto.moretags) = "yaml:\"sig_verify_cost_ed25519\""]; uint64 sig_verify_cost_secp256k1 = 5 [(gogoproto.customname) = "SigVerifyCostSecp256k1", (gogoproto.moretags) = "yaml:\"sig_verify_cost_secp256k1\""]; + bool disable_seqno_check = 6; } diff --git a/server/config/config.go b/server/config/config.go index 9a794cd08..7c1be525d 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -4,12 +4,12 @@ import ( "fmt" "strings" - "github.com/spf13/viper" - storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/sei-protocol/sei-db/config" + "github.com/spf13/viper" tmcfg "github.com/tendermint/tendermint/config" ) @@ -21,6 +21,9 @@ const ( // DefaultGRPCWebAddress defines the default address to bind the gRPC-web server to. DefaultGRPCWebAddress = "0.0.0.0:9091" + + // DefaultConcurrencyWorkers defines the default workers to use for concurrent transactions + DefaultConcurrencyWorkers = 100 ) // BaseConfig defines the server's basic configuration @@ -88,6 +91,10 @@ type BaseConfig struct { SeparateOrphanVersionsToKeep int64 `mapstructure:"separate-orphan-versions-to-keep"` NumOrphanPerFile int `mapstructure:"num-orphan-per-file"` OrphanDirectory string `mapstructure:"orphan-dir"` + + // ConcurrencyWorkers defines the number of workers to use for concurrent + // transaction execution. A value of -1 means unlimited workers. Default value is 10. + ConcurrencyWorkers int `mapstructure:"concurrency-workers"` } // APIConfig defines the API listener configuration. @@ -185,12 +192,15 @@ type Config struct { BaseConfig `mapstructure:",squash"` // Telemetry defines the application telemetry configuration - Telemetry telemetry.Config `mapstructure:"telemetry"` - API APIConfig `mapstructure:"api"` - GRPC GRPCConfig `mapstructure:"grpc"` - Rosetta RosettaConfig `mapstructure:"rosetta"` - GRPCWeb GRPCWebConfig `mapstructure:"grpc-web"` - StateSync StateSyncConfig `mapstructure:"state-sync"` + + Telemetry telemetry.Config `mapstructure:"telemetry"` + API APIConfig `mapstructure:"api"` + GRPC GRPCConfig `mapstructure:"grpc"` + Rosetta RosettaConfig `mapstructure:"rosetta"` + GRPCWeb GRPCWebConfig `mapstructure:"grpc-web"` + StateSync StateSyncConfig `mapstructure:"state-sync"` + StateCommit config.StateCommitConfig `mapstructure:"state-commit"` + StateStore config.StateStoreConfig `mapstructure:"state-store"` } // SetMinGasPrices sets the validator's minimum gas prices. @@ -236,6 +246,7 @@ func DefaultConfig() *Config { IAVLDisableFastNode: true, CompactionInterval: 0, NoVersioning: false, + ConcurrencyWorkers: DefaultConcurrencyWorkers, }, Telemetry: telemetry.Config{ Enabled: false, @@ -270,6 +281,9 @@ func DefaultConfig() *Config { SnapshotKeepRecent: 2, SnapshotDirectory: "", }, + + StateCommit: config.DefaultStateCommitConfig(), + StateStore: config.DefaultStateStoreConfig(), } } @@ -310,6 +324,7 @@ func GetConfig(v *viper.Viper) (Config, error) { SeparateOrphanVersionsToKeep: v.GetInt64("separate-orphan-versions-to-keep"), NumOrphanPerFile: v.GetInt("num-orphan-per-file"), OrphanDirectory: v.GetString("orphan-dir"), + ConcurrencyWorkers: v.GetInt("concurrency-workers"), }, Telemetry: telemetry.Config{ ServiceName: v.GetString("telemetry.service-name"), @@ -352,6 +367,25 @@ func GetConfig(v *viper.Viper) (Config, error) { SnapshotKeepRecent: v.GetUint32("state-sync.snapshot-keep-recent"), SnapshotDirectory: v.GetString("state-sync.snapshot-directory"), }, + StateCommit: config.StateCommitConfig{ + Enable: v.GetBool("state-commit.enable"), + Directory: v.GetString("state-commit.directory"), + ZeroCopy: v.GetBool("state-commit.zero-copy"), + AsyncCommitBuffer: v.GetInt("state-commit.async-commit-buffer"), + SnapshotKeepRecent: v.GetUint32("state-commit.snapshot-keep-recent"), + SnapshotInterval: v.GetUint32("state-commit.snapshot-interval"), + SnapshotWriterLimit: v.GetInt("state-commit.snapshot-writer-limit"), + CacheSize: v.GetInt("state-commit.cache-size"), + }, + StateStore: config.StateStoreConfig{ + Enable: v.GetBool("state-store.enable"), + DBDirectory: v.GetString("state-store.db-directory"), + Backend: v.GetString("state-store.backend"), + AsyncWriteBuffer: v.GetInt("state-store.async-write-buffer"), + KeepRecent: v.GetInt("state-store.keep-recent"), + PruneIntervalSeconds: v.GetInt("state-store.prune-interval-seconds"), + ImportNumWorkers: v.GetInt("state-store.import-num-workers"), + }, }, nil } diff --git a/server/config/config_test.go b/server/config/config_test.go index ce733c346..040bfa788 100644 --- a/server/config/config_test.go +++ b/server/config/config_test.go @@ -23,3 +23,8 @@ func TestSetSnapshotDirectory(t *testing.T) { cfg := DefaultConfig() require.Equal(t, "", cfg.StateSync.SnapshotDirectory) } + +func TestSetConcurrencyWorkers(t *testing.T) { + cfg := DefaultConfig() + require.Equal(t, DefaultConcurrencyWorkers, cfg.ConcurrencyWorkers) +} diff --git a/server/config/toml.go b/server/config/toml.go index 47571fdff..c5bd7e400 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -7,6 +7,7 @@ import ( "os" "text/template" + "github.com/sei-protocol/sei-db/config" "github.com/spf13/viper" ) @@ -22,15 +23,27 @@ const DefaultConfigTemplate = `# This is a TOML config file. # specified in this config (e.g. 0.25token1;0.0001token2). minimum-gas-prices = "{{ .BaseConfig.MinGasPrices }}" -# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals +# default: Keep the recent 362880 blocks and prune is triggered every 10 blocks # nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) -# everything: all saved states will be deleted, storing only the current and previous state; pruning at 10 block intervals -# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval' +# everything: all saved states will be deleted, storing only the recent 2 blocks; pruning at every block +# custom: allow pruning options to be manually specified through 'pruning-keep-recent' and 'pruning-interval' +# When seiDB is enabled, pruning will be applied for state store. + +# Pruning Strategies: +# - default: Keep the recent 362880 blocks and prune is triggered every 10 blocks +# - nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) +# - everything: all saved states will be deleted, storing only the recent 2 blocks; pruning at every block +# - custom: allow pruning options to be manually specified through 'pruning-keep-recent' and 'pruning-interval' +# Pruning strategy is completely ignored when seidb is enabled pruning = "{{ .BaseConfig.Pruning }}" -# These are applied if and only if the pruning strategy is custom. +# These are applied if and only if the pruning strategy is custom, and seidb is not enabled pruning-keep-recent = "{{ .BaseConfig.PruningKeepRecent }}" + +# Deprecated: this will not take effect any more with seiDB enabled. pruning-keep-every = "{{ .BaseConfig.PruningKeepEvery }}" + +# How often prune is triggered for SS store pruning-interval = "{{ .BaseConfig.PruningInterval }}" # HaltHeight contains a non-zero block height at which a node will gracefully @@ -72,11 +85,11 @@ inter-block-cache = {{ .BaseConfig.InterBlockCache }} # ["message.sender", "message.recipient"] index-events = {{ .BaseConfig.IndexEvents }} -# IavlCacheSize set the size of the iavl tree cache. +# IavlCacheSize set the size of the iavl tree cache. # Default cache size is 50mb. iavl-cache-size = {{ .BaseConfig.IAVLCacheSize }} -# IAVLDisableFastNode enables or disables the fast node feature of IAVL. +# IAVLDisableFastNode enables or disables the fast node feature of IAVL. # Default is true. iavl-disable-fastnode = {{ .BaseConfig.IAVLDisableFastNode }} @@ -101,6 +114,9 @@ num-orphan-per-file = {{ .BaseConfig.NumOrphanPerFile }} # if separate-orphan-storage is true, where to store orphan data orphan-dir = "{{ .BaseConfig.OrphanDirectory }}" +# concurrency-workers defines how many workers to run for concurrent transaction execution +# concurrency-workers = {{ .BaseConfig.ConcurrencyWorkers }} + ############################################################################### ### Telemetry Configuration ### ############################################################################### @@ -237,7 +253,7 @@ snapshot-keep-recent = {{ .StateSync.SnapshotKeepRecent }} # default is emtpy which will then store under the app home directory same as before. snapshot-directory = "{{ .StateSync.SnapshotDirectory }}" -` +` + config.DefaultConfigTemplate var configTemplate *template.Template diff --git a/server/mock/store.go b/server/mock/store.go index a4ebbcb37..c7461e54c 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -229,3 +229,19 @@ func (kv kvStore) ReverseSubspaceIterator(prefix []byte) sdk.Iterator { func NewCommitMultiStore() sdk.CommitMultiStore { return multiStore{kv: make(map[sdk.StoreKey]kvStore)} } + +func (ms multiStore) LatestVersion() int64 { + panic("not implemented") +} + +func (ms multiStore) SetKVStores(handler func(key store.StoreKey, s sdk.KVStore) store.CacheWrap) store.MultiStore { + panic("not implemented") +} + +func (ms multiStore) StoreKeys() []sdk.StoreKey { + panic("not implemented") +} + +func (ms multiStore) Close() error { + return nil +} diff --git a/server/start.go b/server/start.go index 14f4e9770..aedc274e4 100644 --- a/server/start.go +++ b/server/start.go @@ -70,6 +70,7 @@ const ( FlagSeparateOrphanVersionsToKeep = "separate-orphan-versions-to-keep" FlagNumOrphanPerFile = "num-orphan-per-file" FlagOrphanDirectory = "orphan-dir" + FlagConcurrencyWorkers = "concurrency-workers" // state sync-related flags FlagStateSyncSnapshotInterval = "state-sync.snapshot-interval" @@ -252,6 +253,7 @@ is performed. Note, when enabled, gRPC will also be automatically enabled. cmd.Flags().Int64(FlagSeparateOrphanVersionsToKeep, 2, "Number of versions to keep if storing orphans separately") cmd.Flags().Int(FlagNumOrphanPerFile, 100000, "Number of orphans to store on each file if storing orphans separately") cmd.Flags().String(FlagOrphanDirectory, path.Join(defaultNodeHome, "orphans"), "Directory to store orphan files if storing orphans separately") + cmd.Flags().Int(FlagConcurrencyWorkers, config.DefaultConcurrencyWorkers, "Number of workers to process concurrent transactions") cmd.Flags().Bool(flagGRPCOnly, false, "Start the node in gRPC query only mode (no Tendermint process is started)") cmd.Flags().Bool(flagGRPCEnable, true, "Define if the gRPC server should be enabled") diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 7912766cc..c84c0e835 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -7,7 +7,6 @@ import ( "path/filepath" serverconfig "github.com/cosmos/cosmos-sdk/server/config" - "github.com/cosmos/iavl" "github.com/spf13/cast" "github.com/spf13/cobra" tmmain "github.com/tendermint/tendermint/cmd/tendermint/commands" @@ -306,12 +305,6 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, t baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagIAVLFastNode))), baseapp.SetCompactionInterval(cast.ToUint64(appOpts.Get(server.FlagCompactionInterval))), - baseapp.SetOrphanConfig(&iavl.Options{ - SeparateOrphanStorage: cast.ToBool(appOpts.Get(server.FlagSeparateOrphanStorage)), - SeparateOphanVersionsToKeep: cast.ToInt64(appOpts.Get(server.FlagSeparateOrphanVersionsToKeep)), - NumOrphansPerFile: cast.ToInt(appOpts.Get(server.FlagNumOrphanPerFile)), - OrphanDirectory: cast.ToString(appOpts.Get(server.FlagOrphanDirectory)), - }), ) } diff --git a/snapshots/chunk.go b/snapshots/chunk.go index 674bd49d9..119ff49fe 100644 --- a/snapshots/chunk.go +++ b/snapshots/chunk.go @@ -56,10 +56,14 @@ func (w *ChunkWriter) Close() error { // CloseWithError closes the writer and sends an error to the reader. func (w *ChunkWriter) CloseWithError(err error) { if !w.closed { + if w.pipe == nil { + // create a dummy pipe just to propagate the error to the reader, it always returns nil + _ = w.chunk() + } w.closed = true close(w.ch) if w.pipe != nil { - w.pipe.CloseWithError(err) + _ = w.pipe.CloseWithError(err) } } } diff --git a/snapshots/helpers_test.go b/snapshots/helpers_test.go index 8c9a67b1b..84f43b8f4 100644 --- a/snapshots/helpers_test.go +++ b/snapshots/helpers_test.go @@ -6,20 +6,20 @@ import ( "compress/zlib" "crypto/sha256" "errors" + "github.com/tendermint/tendermint/libs/log" "io" "io/ioutil" "os" "testing" "time" - protoio "github.com/gogo/protobuf/io" - "github.com/stretchr/testify/require" - db "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/snapshots/types" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + protoio "github.com/gogo/protobuf/io" + "github.com/stretchr/testify/require" + db "github.com/tendermint/tm-db" ) func checksums(slice [][]byte) [][]byte { @@ -156,7 +156,7 @@ func setupBusyManager(t *testing.T) *snapshots.Manager { store, err := snapshots.NewStore(db.NewMemDB(), tempdir) require.NoError(t, err) hung := newHungSnapshotter() - mgr := snapshots.NewManager(store, hung) + mgr := snapshots.NewManager(store, hung, log.NewNopLogger()) go func() { _, err := mgr.Create(1) diff --git a/snapshots/manager.go b/snapshots/manager.go index c12045f6a..e086f9024 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -9,9 +9,11 @@ import ( "math" "sort" "sync" + "time" "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/tendermint/tendermint/libs/log" ) const ( @@ -49,6 +51,7 @@ type restoreDone struct { // errors via io.Pipe.CloseWithError(). type Manager struct { store *Store + logger log.Logger multistore types.Snapshotter extensions map[string]types.ExtensionSnapshotter @@ -61,8 +64,9 @@ type Manager struct { } // NewManager creates a new manager. -func NewManager(store *Store, multistore types.Snapshotter) *Manager { +func NewManager(store *Store, multistore types.Snapshotter, logger log.Logger) *Manager { return &Manager{ + logger: logger, store: store, multistore: multistore, extensions: make(map[string]types.ExtensionSnapshotter), @@ -186,6 +190,7 @@ func (m *Manager) createSnapshot(height uint64, ch chan<- io.ReadCloser) { } defer streamWriter.Close() if err := m.multistore.Snapshot(height, streamWriter); err != nil { + m.logger.Error("Snapshot creation failed", "err", err) streamWriter.CloseWithError(err) return } @@ -277,12 +282,14 @@ func (m *Manager) Restore(snapshot types.Snapshot) error { chDone := make(chan restoreDone, 1) go func() { + startTime := time.Now() err := m.restoreSnapshot(snapshot, chChunks) chDone <- restoreDone{ complete: err == nil, err: err, } close(chDone) + m.logger.Info(fmt.Sprintf("Restoring snapshot for version %d took %s", snapshot.Height, time.Since(startTime))) }() m.chRestore = chChunks diff --git a/snapshots/manager_test.go b/snapshots/manager_test.go index 599d980c1..07c46e15b 100644 --- a/snapshots/manager_test.go +++ b/snapshots/manager_test.go @@ -4,16 +4,16 @@ import ( "errors" "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" ) func TestManager_List(t *testing.T) { store := setupStore(t) - manager := snapshots.NewManager(store, nil) + manager := snapshots.NewManager(store, nil, log.NewNopLogger()) mgrList, err := manager.List() require.NoError(t, err) @@ -32,7 +32,7 @@ func TestManager_List(t *testing.T) { func TestManager_LoadChunk(t *testing.T) { store := setupStore(t) - manager := snapshots.NewManager(store, nil) + manager := snapshots.NewManager(store, nil, log.NewNopLogger()) // Existing chunk should return body chunk, err := manager.LoadChunk(2, 1, 1) @@ -62,7 +62,7 @@ func TestManager_Take(t *testing.T) { items: items, } expectChunks := snapshotItems(items) - manager := snapshots.NewManager(store, snapshotter) + manager := snapshots.NewManager(store, snapshotter, log.NewNopLogger()) // nil manager should return error _, err := (*snapshots.Manager)(nil).Create(1) @@ -98,7 +98,7 @@ func TestManager_Take(t *testing.T) { func TestManager_Prune(t *testing.T) { store := setupStore(t) - manager := snapshots.NewManager(store, nil) + manager := snapshots.NewManager(store, nil, log.NewNopLogger()) pruned, err := manager.Prune(2) require.NoError(t, err) @@ -117,7 +117,7 @@ func TestManager_Prune(t *testing.T) { func TestManager_Restore(t *testing.T) { store := setupStore(t) target := &mockSnapshotter{} - manager := snapshots.NewManager(store, target) + manager := snapshots.NewManager(store, target, log.NewNopLogger()) expectItems := [][]byte{ {1, 2, 3}, diff --git a/snapshots/store.go b/snapshots/store.go index 77ff58e22..21f0c9816 100644 --- a/snapshots/store.go +++ b/snapshots/store.go @@ -10,11 +10,10 @@ import ( "strconv" "sync" - "github.com/gogo/protobuf/proto" - db "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/gogo/protobuf/proto" + db "github.com/tendermint/tm-db" ) const ( @@ -275,14 +274,17 @@ func (s *Store) Save( chunkHasher.Reset() _, err = io.Copy(io.MultiWriter(file, chunkHasher, snapshotHasher), chunkBody) if err != nil { + _ = os.RemoveAll(s.pathHeight(height)) return nil, sdkerrors.Wrapf(err, "failed to generate snapshot chunk %v", index) } err = file.Close() if err != nil { + _ = os.RemoveAll(s.pathHeight(height)) return nil, sdkerrors.Wrapf(err, "failed to close snapshot chunk %v", index) } err = chunkBody.Close() if err != nil { + _ = os.RemoveAll(s.pathHeight(height)) return nil, sdkerrors.Wrapf(err, "failed to close snapshot chunk %v", index) } snapshot.Metadata.ChunkHashes = append(snapshot.Metadata.ChunkHashes, chunkHasher.Sum(nil)) diff --git a/store/cache/cache.go b/store/cache/cache.go index cbaeaeb86..1d4054653 100644 --- a/store/cache/cache.go +++ b/store/cache/cache.go @@ -33,7 +33,7 @@ type ( // the same CommitKVStoreCache may be accessed concurrently by multiple // goroutines due to transaction parallelization - mtx sync.Mutex + mtx sync.RWMutex } // CommitKVStoreCacheManager maintains a mapping from a StoreKey to a @@ -102,27 +102,34 @@ func (ckv *CommitKVStoreCache) CacheWrap(storeKey types.StoreKey) types.CacheWra return cachekv.NewStore(ckv, storeKey, ckv.cacheKVSize) } +// getFromCache queries the write-through cache for a value by key. +func (ckv *CommitKVStoreCache) getFromCache(key []byte) ([]byte, bool) { + ckv.mtx.RLock() + defer ckv.mtx.RUnlock() + return ckv.cache.Get(string(key)) +} + +// getAndWriteToCache queries the underlying CommitKVStore and writes the result +func (ckv *CommitKVStoreCache) getAndWriteToCache(key []byte) []byte { + ckv.mtx.RLock() + defer ckv.mtx.RUnlock() + value := ckv.CommitKVStore.Get(key) + ckv.cache.Add(string(key), value) + return value +} + // Get retrieves a value by key. It will first look in the write-through cache. // If the value doesn't exist in the write-through cache, the query is delegated // to the underlying CommitKVStore. func (ckv *CommitKVStoreCache) Get(key []byte) []byte { - ckv.mtx.Lock() - defer ckv.mtx.Unlock() - types.AssertValidKey(key) - keyStr := string(key) - value, ok := ckv.cache.Get(keyStr) - if ok { - // cache hit + if value, ok := ckv.getFromCache(key); ok { return value } - // cache miss; write to cache - value = ckv.CommitKVStore.Get(key) - ckv.cache.Add(keyStr, value) - - return value + // if not found in the cache, query the underlying CommitKVStore and init cache value + return ckv.getAndWriteToCache(key) } // Set inserts a key/value pair into both the write-through cache and the diff --git a/store/cachekv/store.go b/store/cachekv/store.go index 59cb434b4..4e9a22d09 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -5,61 +5,23 @@ import ( "io" "sort" "sync" - "time" "github.com/cosmos/cosmos-sdk/internal/conv" "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" sdktypes "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/kv" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/math" dbm "github.com/tendermint/tm-db" ) -type mapCacheBackend struct { - m map[string]*types.CValue -} - -func (b mapCacheBackend) Get(key string) (val *types.CValue, ok bool) { - val, ok = b.m[key] - return -} - -func (b mapCacheBackend) Set(key string, val *types.CValue) { - b.m[key] = val -} - -func (b mapCacheBackend) Len() int { - return len(b.m) -} - -func (b mapCacheBackend) Delete(key string) { - delete(b.m, key) -} - -func (b mapCacheBackend) Range(f func(string, *types.CValue) bool) { - // this is always called within a mutex so all operations below are atomic - keys := []string{} - for k := range b.m { - keys = append(keys, k) - } - for _, key := range keys { - val, _ := b.Get(key) - if !f(key, val) { - break - } - } -} - // Store wraps an in-memory cache around an underlying types.KVStore. type Store struct { - mtx sync.Mutex - cache *types.BoundedCache + mtx sync.RWMutex + cache *sync.Map deleted *sync.Map - unsortedCache map[string]struct{} + unsortedCache *sync.Map sortedCache *dbm.MemDB // always ascending sorted parent types.KVStore eventManager *sdktypes.EventManager @@ -72,9 +34,9 @@ var _ types.CacheKVStore = (*Store)(nil) // NewStore creates a new Store object func NewStore(parent types.KVStore, storeKey types.StoreKey, cacheSize int) *Store { return &Store{ - cache: types.NewBoundedCache(mapCacheBackend{make(map[string]*types.CValue)}, cacheSize), + cache: &sync.Map{}, deleted: &sync.Map{}, - unsortedCache: make(map[string]struct{}), + unsortedCache: &sync.Map{}, sortedCache: dbm.NewMemDB(), parent: parent, eventManager: sdktypes.NewEventManager(), @@ -94,8 +56,6 @@ func (store *Store) GetEvents() []abci.Event { // Implements Store func (store *Store) ResetEvents() { - store.mtx.Lock() - defer store.mtx.Unlock() store.eventManager = sdktypes.NewEventManager() } @@ -104,76 +64,65 @@ func (store *Store) GetStoreType() types.StoreType { return store.parent.GetStoreType() } -// Get implements types.KVStore. -func (store *Store) Get(key []byte) (value []byte) { - store.mtx.Lock() - defer store.mtx.Unlock() - - types.AssertValidKey(key) - - cacheValue, ok := store.cache.Get(conv.UnsafeBytesToStr(key)) - if !ok { - value = store.parent.Get(key) - store.setCacheValue(key, value, false, false) +// getFromCache queries the write-through cache for a value by key. +func (store *Store) getFromCache(key []byte) []byte { + if cv, ok := store.cache.Load(conv.UnsafeBytesToStr(key)); ok { + return cv.(*types.CValue).Value() } else { - value = cacheValue.Value() + return store.parent.Get(key) } - store.eventManager.EmitResourceAccessReadEvent("get", store.storeKey, key, value) +} +// getAndWriteToCache queries the underlying CommitKVStore and writes the result +func (store *Store) getAndWriteToCache(key []byte) []byte { + store.mtx.Lock() + defer store.mtx.Unlock() + value := store.parent.Get(key) + store.setCacheValue(key, value, false, false) return value } +// Get implements types.KVStore. +func (store *Store) Get(key []byte) (value []byte) { + types.AssertValidKey(key) + return store.getFromCache(key) +} + // Set implements types.KVStore. func (store *Store) Set(key []byte, value []byte) { - store.mtx.Lock() - defer store.mtx.Unlock() - types.AssertValidKey(key) types.AssertValidValue(value) - store.setCacheValue(key, value, false, true) - store.eventManager.EmitResourceAccessWriteEvent("set", store.storeKey, key, value) } // Has implements types.KVStore. func (store *Store) Has(key []byte) bool { value := store.Get(key) - store.mtx.Lock() - defer store.mtx.Unlock() - store.eventManager.EmitResourceAccessReadEvent("has", store.storeKey, key, value) return value != nil } // Delete implements types.KVStore. func (store *Store) Delete(key []byte) { - store.mtx.Lock() - defer store.mtx.Unlock() - defer telemetry.MeasureSince(time.Now(), "store", "cachekv", "delete") - types.AssertValidKey(key) store.setCacheValue(key, nil, true, true) - store.eventManager.EmitResourceAccessWriteEvent("delete", store.storeKey, key, []byte{}) } // Implements Cachetypes.KVStore. func (store *Store) Write() { store.mtx.Lock() defer store.mtx.Unlock() - defer telemetry.MeasureSince(time.Now(), "store", "cachekv", "write") // We need a copy of all of the keys. // Not the best, but probably not a bottleneck depending. - keys := make([]string, 0, store.cache.Len()) + keys := []string{} - store.cache.Range(func(key string, dbValue *types.CValue) bool { - if dbValue.Dirty() { - keys = append(keys, key) + store.cache.Range(func(key, value any) bool { + if value.(*types.CValue).Dirty() { + keys = append(keys, key.(string)) } return true }) - sort.Strings(keys) - // TODO: Consider allowing usage of Batch, which would allow the write to // at least happen atomically. for _, key := range keys { @@ -186,24 +135,28 @@ func (store *Store) Write() { continue } - cacheValue, _ := store.cache.Get(key) - if cacheValue.Value() != nil { + cacheValue, _ := store.cache.Load(key) + if cacheValue.(*types.CValue).Value() != nil { // It already exists in the parent, hence delete it. - store.parent.Set([]byte(key), cacheValue.Value()) + store.parent.Set([]byte(key), cacheValue.(*types.CValue).Value()) } } // Clear the cache using the map clearing idiom // and not allocating fresh objects. // Please see https://bencher.orijtech.com/perfclinic/mapclearing/ - store.cache.DeleteAll() + store.cache.Range(func(key, value any) bool { + store.cache.Delete(key) + return true + }) store.deleted.Range(func(key, value any) bool { store.deleted.Delete(key) return true }) - for key := range store.unsortedCache { - delete(store.unsortedCache, key) - } + store.unsortedCache.Range(func(key, value any) bool { + store.deleted.Delete(key) + return true + }) store.sortedCache = dbm.NewMemDB() } @@ -238,6 +191,7 @@ func (store *Store) ReverseIterator(start, end []byte) types.Iterator { func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator { store.mtx.Lock() defer store.mtx.Unlock() + // TODO: (occ) Note that for iterators, we'll need to have special handling (discussed in RFC) to ensure proper validation var parent, cache types.Iterator @@ -350,7 +304,6 @@ func (store *Store) dirtyItems(start, end []byte) { return } - n := len(store.unsortedCache) unsorted := make([]*kv.Pair, 0) // If the unsortedCache is too big, its costs too much to determine // whats in the subset we are concerned about. @@ -358,54 +311,22 @@ func (store *Store) dirtyItems(start, end []byte) { // O(N^2) overhead. // Even without that, too many range checks eventually becomes more expensive // than just not having the cache. - store.emitUnsortedCacheSizeMetric() - if n < minSortSize { - for key := range store.unsortedCache { - if dbm.IsKeyInDomain(conv.UnsafeStrToBytes(key), start, end) { - cacheValue, _ := store.cache.Get(key) - unsorted = append(unsorted, &kv.Pair{Key: []byte(key), Value: cacheValue.Value()}) - } + // store.emitUnsortedCacheSizeMetric() + store.unsortedCache.Range(func(key, value any) bool { + cKey := key.(string) + if dbm.IsKeyInDomain(conv.UnsafeStrToBytes(cKey), start, end) { + cacheValue, _ := store.cache.Load(key) + unsorted = append(unsorted, &kv.Pair{Key: []byte(cKey), Value: cacheValue.(*types.CValue).Value()}) } - store.clearUnsortedCacheSubset(unsorted, stateUnsorted) - return - } - - // Otherwise it is large so perform a modified binary search to find - // the target ranges for the keys that we should be looking for. - strL := make([]string, 0, n) - for key := range store.unsortedCache { - strL = append(strL, key) - } - sort.Strings(strL) - - startIndex, endIndex := findStartEndIndex(strL, startStr, endStr) - - // 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 - // if below minSortSize, expand it to cover additional values - // this amortizes the cost of processing elements across multiple calls - if endIndex-startIndex < minSortSize { - endIndex = math.MinInt(startIndex+minSortSize, len(strL)-1) - if endIndex-startIndex < minSortSize { - startIndex = math.MaxInt(endIndex-minSortSize, 0) - } - } - - kvL := make([]*kv.Pair, 0, 1+endIndex-startIndex) - for i := startIndex; i <= endIndex; i++ { - key := strL[i] - cacheValue, _ := store.cache.Get(key) - kvL = append(kvL, &kv.Pair{Key: []byte(key), Value: cacheValue.Value()}) - } - - // kvL was already sorted so pass it in as is. - store.clearUnsortedCacheSubset(kvL, stateAlreadySorted) - store.emitUnsortedCacheSizeMetric() + return true + }) + store.clearUnsortedCacheSubset(unsorted, stateUnsorted) + return } func (store *Store) emitUnsortedCacheSizeMetric() { - n := len(store.unsortedCache) - telemetry.SetGauge(float32(n), "sei", "cosmos", "unsorted", "cache", "size") + // n := len(store.unsortedCache) + // telemetry.SetGauge(float32(n), "sei", "cosmos", "unsorted", "cache", "size") } func findStartEndIndex(strL []string, startStr, endStr string) (int, int) { @@ -449,18 +370,10 @@ func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair, sortState sort } func (store *Store) deleteKeysFromUnsortedCache(unsorted []*kv.Pair) { - n := len(store.unsortedCache) - store.emitUnsortedCacheSizeMetric() - if len(unsorted) == n { // This pattern allows the Go compiler to emit the map clearing idiom for the entire map. - for key := range store.unsortedCache { - delete(store.unsortedCache, key) - } - } else { // Otherwise, normally delete the unsorted keys from the map. - for _, kv := range unsorted { - delete(store.unsortedCache, conv.UnsafeBytesToStr(kv.Key)) - } + for _, kv := range unsorted { + keyStr := conv.UnsafeBytesToStr(kv.Key) + store.unsortedCache.Delete(keyStr) } - defer store.emitUnsortedCacheSizeMetric() } //---------------------------------------- @@ -471,14 +384,14 @@ func (store *Store) setCacheValue(key, value []byte, deleted bool, dirty bool) { types.AssertValidKey(key) keyStr := conv.UnsafeBytesToStr(key) - store.cache.Set(keyStr, types.NewCValue(value, dirty)) + store.cache.Store(keyStr, types.NewCValue(value, dirty)) if deleted { store.deleted.Store(keyStr, struct{}{}) } else { store.deleted.Delete(keyStr) } if dirty { - store.unsortedCache[keyStr] = struct{}{} + store.unsortedCache.Store(keyStr, struct{}{}) } } diff --git a/store/cachemulti/store.go b/store/cachemulti/store.go index 43e00c32b..434e23b16 100644 --- a/store/cachemulti/store.go +++ b/store/cachemulti/store.go @@ -208,3 +208,25 @@ func (cms Store) GetKVStore(key types.StoreKey) types.KVStore { func (cms Store) GetWorkingHash() ([]byte, error) { panic("should never attempt to get working hash from cache multi store") } + +// LatestVersion returns the branch version of the store +func (cms Store) LatestVersion() int64 { + panic("cannot get latest version from branch cached multi-store") +} + +// StoreKeys returns a list of all store keys +func (cms Store) StoreKeys() []types.StoreKey { + keys := make([]types.StoreKey, 0, len(cms.stores)) + for _, key := range cms.keys { + keys = append(keys, key) + } + return keys +} + +// SetKVStores sets the underlying KVStores via a handler for each key +func (cms Store) SetKVStores(handler func(sk types.StoreKey, s types.KVStore) types.CacheWrap) types.MultiStore { + for k, s := range cms.stores { + cms.stores[k] = handler(k, s.(types.KVStore)) + } + return cms +} diff --git a/store/multiversion/data_structures.go b/store/multiversion/data_structures.go new file mode 100644 index 000000000..cba10d0f4 --- /dev/null +++ b/store/multiversion/data_structures.go @@ -0,0 +1,200 @@ +package multiversion + +import ( + "sync" + + "github.com/cosmos/cosmos-sdk/store/types" + "github.com/google/btree" +) + +const ( + // The approximate number of items and children per B-tree node. Tuned with benchmarks. + multiVersionBTreeDegree = 2 // should be equivalent to a binary search tree TODO: benchmark this +) + +type MultiVersionValue interface { + GetLatest() (value MultiVersionValueItem, found bool) + GetLatestNonEstimate() (value MultiVersionValueItem, found bool) + GetLatestBeforeIndex(index int) (value MultiVersionValueItem, found bool) + Set(index int, incarnation int, value []byte) + SetEstimate(index int, incarnation int) + Delete(index int, incarnation int) + Remove(index int) +} + +type MultiVersionValueItem interface { + IsDeleted() bool + IsEstimate() bool + Value() []byte + Incarnation() int + Index() int +} + +type multiVersionItem struct { + valueTree *btree.BTree // contains versions values written to this key + mtx sync.RWMutex // manages read + write accesses +} + +var _ MultiVersionValue = (*multiVersionItem)(nil) + +func NewMultiVersionItem() *multiVersionItem { + return &multiVersionItem{ + valueTree: btree.New(multiVersionBTreeDegree), + } +} + +// GetLatest returns the latest written value to the btree, and returns a boolean indicating whether it was found. +func (item *multiVersionItem) GetLatest() (MultiVersionValueItem, bool) { + item.mtx.RLock() + defer item.mtx.RUnlock() + + bTreeItem := item.valueTree.Max() + if bTreeItem == nil { + return nil, false + } + valueItem := bTreeItem.(*valueItem) + return valueItem, true +} + +// GetLatestNonEstimate returns the latest written value that isn't an ESTIMATE and returns a boolean indicating whether it was found. +// This can be used when we want to write finalized values, since ESTIMATEs can be considered to be irrelevant at that point +func (item *multiVersionItem) GetLatestNonEstimate() (MultiVersionValueItem, bool) { + item.mtx.RLock() + defer item.mtx.RUnlock() + + var vItem *valueItem + var found bool + item.valueTree.Descend(func(bTreeItem btree.Item) bool { + // only return if non-estimate + item := bTreeItem.(*valueItem) + if item.IsEstimate() { + // if estimate, continue + return true + } + // else we want to return + vItem = item + found = true + return false + }) + return vItem, found +} + +// GetLatest returns the latest written value to the btree prior to the index passed in, and returns a boolean indicating whether it was found. +// +// A `nil` value along with `found=true` indicates a deletion that has occurred and the underlying parent store doesn't need to be hit. +func (item *multiVersionItem) GetLatestBeforeIndex(index int) (MultiVersionValueItem, bool) { + item.mtx.RLock() + defer item.mtx.RUnlock() + + // we want to find the value at the index that is LESS than the current index + pivot := &valueItem{index: index - 1} + + var vItem *valueItem + var found bool + // start from pivot which contains our current index, and return on first item we hit. + // This will ensure we get the latest indexed value relative to our current index + item.valueTree.DescendLessOrEqual(pivot, func(bTreeItem btree.Item) bool { + vItem = bTreeItem.(*valueItem) + found = true + return false + }) + return vItem, found +} + +func (item *multiVersionItem) Set(index int, incarnation int, value []byte) { + types.AssertValidValue(value) + item.mtx.Lock() + defer item.mtx.Unlock() + + valueItem := NewValueItem(index, incarnation, value) + item.valueTree.ReplaceOrInsert(valueItem) +} + +func (item *multiVersionItem) Delete(index int, incarnation int) { + item.mtx.Lock() + defer item.mtx.Unlock() + + deletedItem := NewDeletedItem(index, incarnation) + item.valueTree.ReplaceOrInsert(deletedItem) +} + +func (item *multiVersionItem) Remove(index int) { + item.mtx.Lock() + defer item.mtx.Unlock() + + item.valueTree.Delete(&valueItem{index: index}) +} + +func (item *multiVersionItem) SetEstimate(index int, incarnation int) { + item.mtx.Lock() + defer item.mtx.Unlock() + + estimateItem := NewEstimateItem(index, incarnation) + item.valueTree.ReplaceOrInsert(estimateItem) +} + +type valueItem struct { + index int + incarnation int + value []byte + estimate bool +} + +var _ MultiVersionValueItem = (*valueItem)(nil) + +// Index implements MultiVersionValueItem. +func (v *valueItem) Index() int { + return v.index +} + +// Incarnation implements MultiVersionValueItem. +func (v *valueItem) Incarnation() int { + return v.incarnation +} + +// IsDeleted implements MultiVersionValueItem. +func (v *valueItem) IsDeleted() bool { + return v.value == nil && !v.estimate +} + +// IsEstimate implements MultiVersionValueItem. +func (v *valueItem) IsEstimate() bool { + return v.estimate +} + +// Value implements MultiVersionValueItem. +func (v *valueItem) Value() []byte { + return v.value +} + +// implement Less for btree.Item for valueItem +func (i *valueItem) Less(other btree.Item) bool { + return i.index < other.(*valueItem).index +} + +func NewValueItem(index int, incarnation int, value []byte) *valueItem { + return &valueItem{ + index: index, + incarnation: incarnation, + value: value, + estimate: false, + } +} + +func NewEstimateItem(index int, incarnation int) *valueItem { + return &valueItem{ + index: index, + incarnation: incarnation, + value: nil, + estimate: true, + } +} + +func NewDeletedItem(index int, incarnation int) *valueItem { + return &valueItem{ + index: index, + incarnation: incarnation, + value: nil, + estimate: false, + } +} diff --git a/store/multiversion/data_structures_test.go b/store/multiversion/data_structures_test.go new file mode 100644 index 000000000..fccc26a8b --- /dev/null +++ b/store/multiversion/data_structures_test.go @@ -0,0 +1,228 @@ +package multiversion_test + +import ( + "testing" + + mv "github.com/cosmos/cosmos-sdk/store/multiversion" + "github.com/stretchr/testify/require" +) + +func TestMultiversionItemGetLatest(t *testing.T) { + mvItem := mv.NewMultiVersionItem() + // We have no value, should get found == false and a nil value + value, found := mvItem.GetLatest() + require.False(t, found) + require.Nil(t, value) + + // assert that we find a value after it's set + one := []byte("one") + mvItem.Set(1, 0, one) + value, found = mvItem.GetLatest() + require.True(t, found) + require.Equal(t, one, value.Value()) + + // assert that we STILL get the "one" value since it is the latest + zero := []byte("zero") + mvItem.Set(0, 0, zero) + value, found = mvItem.GetLatest() + require.True(t, found) + require.Equal(t, one, value.Value()) + require.Equal(t, 1, value.Index()) + require.Equal(t, 0, value.Incarnation()) + + // we should see a deletion as the latest now, aka nil value and found == true + mvItem.Delete(2, 0) + value, found = mvItem.GetLatest() + require.True(t, found) + require.True(t, value.IsDeleted()) + require.Nil(t, value.Value()) + + // Overwrite the deleted value with some data + two := []byte("two") + mvItem.Set(2, 3, two) + value, found = mvItem.GetLatest() + require.True(t, found) + require.Equal(t, two, value.Value()) + require.Equal(t, 2, value.Index()) + require.Equal(t, 3, value.Incarnation()) +} + +func TestMultiversionItemGetByIndex(t *testing.T) { + mvItem := mv.NewMultiVersionItem() + // We have no value, should get found == false and a nil value + value, found := mvItem.GetLatestBeforeIndex(9) + require.False(t, found) + require.Nil(t, value) + + // assert that we find a value after it's set + one := []byte("one") + mvItem.Set(1, 0, one) + // should not be found because we specifically search "LESS THAN" + value, found = mvItem.GetLatestBeforeIndex(1) + require.False(t, found) + require.Nil(t, value) + // querying from "two" should be found + value, found = mvItem.GetLatestBeforeIndex(2) + require.True(t, found) + require.Equal(t, one, value.Value()) + + // verify that querying for an earlier index returns nil + value, found = mvItem.GetLatestBeforeIndex(0) + require.False(t, found) + require.Nil(t, value) + + // assert that we STILL get the "one" value when querying with a later index + zero := []byte("zero") + mvItem.Set(0, 0, zero) + // verify that querying for zero should ALWAYS return nil + value, found = mvItem.GetLatestBeforeIndex(0) + require.False(t, found) + require.Nil(t, value) + + value, found = mvItem.GetLatestBeforeIndex(2) + require.True(t, found) + require.Equal(t, one, value.Value()) + // verify we get zero when querying with index 1 + value, found = mvItem.GetLatestBeforeIndex(1) + require.True(t, found) + require.Equal(t, zero, value.Value()) + + // we should see a deletion as the latest now, aka nil value and found == true, but index 4 still returns `one` + mvItem.Delete(4, 0) + value, found = mvItem.GetLatestBeforeIndex(4) + require.True(t, found) + require.Equal(t, one, value.Value()) + // should get deletion item for a later index + value, found = mvItem.GetLatestBeforeIndex(5) + require.True(t, found) + require.True(t, value.IsDeleted()) + + // verify that we still read the proper underlying item for an older index + value, found = mvItem.GetLatestBeforeIndex(3) + require.True(t, found) + require.Equal(t, one, value.Value()) + + // Overwrite the deleted value with some data and verify we read it properly + four := []byte("four") + mvItem.Set(4, 0, four) + // also reads the four + value, found = mvItem.GetLatestBeforeIndex(6) + require.True(t, found) + require.Equal(t, four, value.Value()) + // still reads the `one` + value, found = mvItem.GetLatestBeforeIndex(4) + require.True(t, found) + require.Equal(t, one, value.Value()) +} + +func TestMultiversionItemEstimate(t *testing.T) { + mvItem := mv.NewMultiVersionItem() + // We have no value, should get found == false and a nil value + value, found := mvItem.GetLatestBeforeIndex(9) + require.False(t, found) + require.Nil(t, value) + + // assert that we find a value after it's set + one := []byte("one") + mvItem.Set(1, 0, one) + // should not be found because we specifically search "LESS THAN" + value, found = mvItem.GetLatestBeforeIndex(1) + require.False(t, found) + require.Nil(t, value) + // querying from "two" should be found + value, found = mvItem.GetLatestBeforeIndex(2) + require.True(t, found) + require.False(t, value.IsEstimate()) + require.Equal(t, one, value.Value()) + // set as estimate + mvItem.SetEstimate(1, 2) + // should not be found because we specifically search "LESS THAN" + value, found = mvItem.GetLatestBeforeIndex(1) + require.False(t, found) + require.Nil(t, value) + // querying from "two" should be found as ESTIMATE + value, found = mvItem.GetLatestBeforeIndex(2) + require.True(t, found) + require.True(t, value.IsEstimate()) + require.Equal(t, 1, value.Index()) + require.Equal(t, 2, value.Incarnation()) + + // verify that querying for an earlier index returns nil + value, found = mvItem.GetLatestBeforeIndex(0) + require.False(t, found) + require.Nil(t, value) + + // assert that we STILL get the "one" value when querying with a later index + zero := []byte("zero") + mvItem.Set(0, 0, zero) + // verify that querying for zero should ALWAYS return nil + value, found = mvItem.GetLatestBeforeIndex(0) + require.False(t, found) + require.Nil(t, value) + + value, found = mvItem.GetLatestBeforeIndex(2) + require.True(t, found) + require.True(t, value.IsEstimate()) + // verify we get zero when querying with index 1 + value, found = mvItem.GetLatestBeforeIndex(1) + require.True(t, found) + require.Equal(t, zero, value.Value()) + // reset one to no longer be an estiamte + mvItem.Set(1, 0, one) + // we should see a deletion as the latest now, aka nil value and found == true, but index 4 still returns `one` + mvItem.Delete(4, 1) + value, found = mvItem.GetLatestBeforeIndex(4) + require.True(t, found) + require.Equal(t, one, value.Value()) + // should get deletion item for a later index + value, found = mvItem.GetLatestBeforeIndex(5) + require.True(t, found) + require.True(t, value.IsDeleted()) + require.Equal(t, 4, value.Index()) + require.Equal(t, 1, value.Incarnation()) + + // verify that we still read the proper underlying item for an older index + value, found = mvItem.GetLatestBeforeIndex(3) + require.True(t, found) + require.Equal(t, one, value.Value()) + + // Overwrite the deleted value with an estimate and verify we read it properly + mvItem.SetEstimate(4, 0) + // also reads the four + value, found = mvItem.GetLatestBeforeIndex(6) + require.True(t, found) + require.True(t, value.IsEstimate()) + require.False(t, value.IsDeleted()) + // still reads the `one` + value, found = mvItem.GetLatestBeforeIndex(4) + require.True(t, found) + require.Equal(t, one, value.Value()) +} + +func TestMultiversionItemRemove(t *testing.T) { + mvItem := mv.NewMultiVersionItem() + + mvItem.Set(1, 0, []byte("one")) + mvItem.Set(2, 0, []byte("two")) + + mvItem.Remove(2) + value, found := mvItem.GetLatest() + require.True(t, found) + require.Equal(t, []byte("one"), value.Value()) +} + +func TestMultiversionItemGetLatestNonEstimate(t *testing.T) { + mvItem := mv.NewMultiVersionItem() + + mvItem.SetEstimate(3, 0) + + value, found := mvItem.GetLatestNonEstimate() + require.False(t, found) + require.Nil(t, value) + + mvItem.Set(1, 0, []byte("one")) + value, found = mvItem.GetLatestNonEstimate() + require.True(t, found) + require.Equal(t, []byte("one"), value.Value()) + +} diff --git a/store/multiversion/memiterator.go b/store/multiversion/memiterator.go new file mode 100644 index 000000000..43e8e306b --- /dev/null +++ b/store/multiversion/memiterator.go @@ -0,0 +1,114 @@ +package multiversion + +import ( + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/store/types" + occtypes "github.com/cosmos/cosmos-sdk/types/occ" +) + +// Iterates over iterKVCache items. +// if key is nil, means it was deleted. +// Implements Iterator. +type memIterator struct { + types.Iterator + + mvStore MultiVersionStore + writeset WriteSet + index int + abortChannel chan occtypes.Abort + ReadsetHandler +} + +func (store *VersionIndexedStore) newMemIterator( + start, end []byte, + items *dbm.MemDB, + ascending bool, + readsetHandler ReadsetHandler, +) *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 { + if iter != nil { + iter.Close() + } + panic(err) + } + + return &memIterator{ + Iterator: iter, + mvStore: store.multiVersionStore, + index: store.transactionIndex, + abortChannel: store.abortChannel, + writeset: store.GetWriteset(), + ReadsetHandler: readsetHandler, + } +} + +// try to get value from the writeset, otherwise try to get from multiversion store, otherwise try to get from parent iterator +func (mi *memIterator) Value() []byte { + key := mi.Iterator.Key() + + // try fetch from writeset - return if exists + if val, ok := mi.writeset[string(key)]; ok { + return val + } + + // get the value from the multiversion store + val := mi.mvStore.GetLatestBeforeIndex(mi.index, key) + + // if we have an estiamte, write to abort channel + if val.IsEstimate() { + mi.abortChannel <- occtypes.NewEstimateAbort(val.Index()) + } + + // need to update readset + // if we have a deleted value, return nil + if val.IsDeleted() { + defer mi.ReadsetHandler.UpdateReadSet(key, nil) + return nil + } + defer mi.ReadsetHandler.UpdateReadSet(key, val.Value()) + return val.Value() +} + +func (store *Store) newMVSValidationIterator( + index int, + start, end []byte, + items *dbm.MemDB, + ascending bool, + writeset WriteSet, + abortChannel chan occtypes.Abort, +) *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 { + if iter != nil { + iter.Close() + } + panic(err) + } + + return &memIterator{ + Iterator: iter, + mvStore: store, + index: index, + abortChannel: abortChannel, + ReadsetHandler: NoOpHandler{}, + writeset: writeset, + } +} diff --git a/store/multiversion/mergeiterator.go b/store/multiversion/mergeiterator.go new file mode 100644 index 000000000..3b5cee741 --- /dev/null +++ b/store/multiversion/mergeiterator.go @@ -0,0 +1,259 @@ +package multiversion + +import ( + "bytes" + "errors" + + "github.com/cosmos/cosmos-sdk/store/types" +) + +// mvsMergeIterator merges a parent Iterator and a cache Iterator. +// The cache iterator may return nil keys to signal that an item +// had been deleted (but not deleted in the parent). +// If the cache iterator has the same key as the parent, the +// cache shadows (overrides) the parent. +type mvsMergeIterator struct { + parent types.Iterator + cache types.Iterator + ascending bool + ReadsetHandler +} + +var _ types.Iterator = (*mvsMergeIterator)(nil) + +func NewMVSMergeIterator( + parent, cache types.Iterator, + ascending bool, + readsetHandler ReadsetHandler, +) *mvsMergeIterator { + iter := &mvsMergeIterator{ + parent: parent, + cache: cache, + ascending: ascending, + ReadsetHandler: readsetHandler, + } + + return iter +} + +// Domain implements Iterator. +// It returns the union of the iter.Parent doman, and the iter.Cache domain. +// If the domains are disjoint, this includes the domain in between them as well. +func (iter *mvsMergeIterator) Domain() (start, end []byte) { + startP, endP := iter.parent.Domain() + startC, endC := iter.cache.Domain() + + if iter.compare(startP, startC) < 0 { + start = startP + } else { + start = startC + } + + if iter.compare(endP, endC) < 0 { + end = endC + } else { + end = endP + } + + return start, end +} + +// Valid implements Iterator. +func (iter *mvsMergeIterator) Valid() bool { + return iter.skipUntilExistsOrInvalid() +} + +// Next implements Iterator +func (iter *mvsMergeIterator) Next() { + iter.skipUntilExistsOrInvalid() + iter.assertValid() + + // If parent is invalid, get the next cache item. + if !iter.parent.Valid() { + iter.cache.Next() + return + } + + // If cache is invalid, get the next parent item. + if !iter.cache.Valid() { + 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() + } +} + +// Key implements Iterator +func (iter *mvsMergeIterator) Key() []byte { + iter.skipUntilExistsOrInvalid() + iter.assertValid() + + // If parent is invalid, get the cache key. + if !iter.parent.Valid() { + return iter.cache.Key() + } + + // If cache is invalid, get the parent key. + if !iter.cache.Valid() { + return iter.parent.Key() + } + + // Both are valid. Compare keys. + keyP, keyC := iter.parent.Key(), iter.cache.Key() + + cmp := iter.compare(keyP, keyC) + switch cmp { + case -1: // parent < cache + return keyP + case 0: // parent == cache + return keyP + case 1: // parent > cache + return keyC + default: + panic("invalid compare result") + } +} + +// Value implements Iterator +func (iter *mvsMergeIterator) Value() []byte { + iter.skipUntilExistsOrInvalid() + iter.assertValid() + + // If parent is invalid, get the cache value. + if !iter.parent.Valid() { + value := iter.cache.Value() + return value + } + + // If cache is invalid, get the parent value. + if !iter.cache.Valid() { + value := iter.parent.Value() + return value + } + + // Both are valid. Compare keys. + keyP, keyC := iter.parent.Key(), iter.cache.Key() + + cmp := iter.compare(keyP, keyC) + switch cmp { + case -1: // parent < cache + value := iter.parent.Value() + return value + case 0, 1: // parent >= cache + value := iter.cache.Value() + return value + default: + panic("invalid comparison result") + } +} + +// Close implements Iterator +func (iter *mvsMergeIterator) Close() error { + if err := iter.parent.Close(); err != nil { + // still want to close cache iterator regardless + iter.cache.Close() + return err + } + + return iter.cache.Close() +} + +// Error returns an error if the mvsMergeIterator is invalid defined by the +// Valid method. +func (iter *mvsMergeIterator) Error() error { + if !iter.Valid() { + return errors.New("invalid mvsMergeIterator") + } + + return nil +} + +// If not valid, panics. +// NOTE: May have side-effect of iterating over cache. +func (iter *mvsMergeIterator) assertValid() { + if err := iter.Error(); err != nil { + panic(err) + } +} + +// Like bytes.Compare but opposite if not ascending. +func (iter *mvsMergeIterator) compare(a, b []byte) int { + if iter.ascending { + return bytes.Compare(a, b) + } + + return bytes.Compare(a, b) * -1 +} + +// Skip all delete-items from the cache w/ `key < until`. After this function, +// current cache item is a non-delete-item, or `until <= key`. +// If the current cache item is not a delete item, does nothing. +// If `until` is nil, there is no limit, and cache may end up invalid. +// CONTRACT: cache is valid. +func (iter *mvsMergeIterator) skipCacheDeletes(until []byte) { + for iter.cache.Valid() && + iter.cache.Value() == nil && + (until == nil || iter.compare(iter.cache.Key(), until) < 0) { + iter.cache.Next() + } +} + +// Fast forwards cache (or parent+cache in case of deleted items) until current +// item exists, or until iterator becomes invalid. +// Returns whether the iterator is valid. +func (iter *mvsMergeIterator) skipUntilExistsOrInvalid() bool { + for { + // If parent is invalid, fast-forward cache. + if !iter.parent.Valid() { + iter.skipCacheDeletes(nil) + return iter.cache.Valid() + } + // Parent is valid. + if !iter.cache.Valid() { + return true + } + // Parent is valid, cache is valid. + + // Compare parent and cache. + keyP := iter.parent.Key() + keyC := iter.cache.Key() + + switch iter.compare(keyP, keyC) { + case -1: // parent < cache. + return true + + case 0: // parent == cache. + // Skip over if cache item is a delete. + valueC := iter.cache.Value() + if valueC == nil { + iter.parent.Next() + iter.cache.Next() + + continue + } + // Cache is not a delete. + + return true // cache exists. + case 1: // cache < parent + // Skip over if cache item is a delete. + valueC := iter.cache.Value() + if valueC == nil { + iter.skipCacheDeletes(keyP) + continue + } + // Cache is not a delete. + + return true // cache exists. + } + } +} diff --git a/store/multiversion/mvkv.go b/store/multiversion/mvkv.go new file mode 100644 index 000000000..1e8437ad7 --- /dev/null +++ b/store/multiversion/mvkv.go @@ -0,0 +1,384 @@ +package multiversion + +import ( + "io" + "sort" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/store/types" + scheduler "github.com/cosmos/cosmos-sdk/types/occ" + dbm "github.com/tendermint/tm-db" +) + +// exposes a handler for adding items to readset, useful for iterators +type ReadsetHandler interface { + UpdateReadSet(key []byte, value []byte) +} + +type NoOpHandler struct{} + +func (NoOpHandler) UpdateReadSet(key []byte, value []byte) {} + +// exposes a handler for adding items to iterateset, to be called upon iterator close +type IterateSetHandler interface { + UpdateIterateSet(iterationTracker) +} + +type iterationTracker struct { + startKey []byte // start of the iteration range + endKey []byte // end of the iteration range + earlyStopKey []byte // key that caused early stop + iteratedKeys map[string]struct{} // TODO: is a map okay because the ordering will be enforced when we replay the iterator? + ascending bool + + writeset WriteSet + + // TODO: is it possible that terimation is affected by keys later in iteration that weren't reached? eg. number of keys affecting iteration? + // TODO: i believe to get number of keys the iteration would need to be done fully so its not a concern? + + // TODO: maybe we need to store keys served from writeset for the transaction? that way if theres OTHER keys within the writeset and the iteration range, and were written to the writeset later, we can discriminate between the groups? + // keysServedFromWriteset map[string]struct{} + + // actually its simpler to just store a copy of the writeset at the time of iterator creation +} + +func NewIterationTracker(startKey, endKey []byte, ascending bool, writeset WriteSet) iterationTracker { + copyWriteset := make(WriteSet, len(writeset)) + + for key, value := range writeset { + copyWriteset[key] = value + } + + return iterationTracker{ + startKey: startKey, + endKey: endKey, + iteratedKeys: make(map[string]struct{}), + ascending: ascending, + writeset: copyWriteset, + } +} + +func (item *iterationTracker) AddKey(key []byte) { + item.iteratedKeys[string(key)] = struct{}{} +} + +func (item *iterationTracker) SetEarlyStopKey(key []byte) { + item.earlyStopKey = key +} + +// Version Indexed Store wraps the multiversion store in a way that implements the KVStore interface, but also stores the index of the transaction, and so store actions are applied to the multiversion store using that index +type VersionIndexedStore struct { + // TODO: this shouldnt NEED a mutex because its used within single transaction execution, therefore no concurrency + // mtx sync.Mutex + // used for tracking reads and writes for eventual validation + persistence into multi-version store + // TODO: does this need sync.Map? + readset map[string][]byte // contains the key -> value mapping for all keys read from the store (not mvkv, underlying store) + writeset map[string][]byte // contains the key -> value mapping for all keys written to the store + iterateset Iterateset + // TODO: need to add iterateset here as well + + // dirty keys that haven't been sorted yet for iteration + dirtySet map[string]struct{} + // used for iterators - populated at the time of iterator instantiation + // TODO: when we want to perform iteration, we need to move all the dirty keys (writeset and readset) into the sortedTree and then combine with the iterators for the underlying stores + sortedStore *dbm.MemDB // always ascending sorted + // parent stores (both multiversion and underlying parent store) + multiVersionStore MultiVersionStore + parent types.KVStore + // transaction metadata for versioned operations + transactionIndex int + incarnation int + // have abort channel here for aborting transactions + abortChannel chan scheduler.Abort +} + +var _ types.KVStore = (*VersionIndexedStore)(nil) +var _ ReadsetHandler = (*VersionIndexedStore)(nil) +var _ IterateSetHandler = (*VersionIndexedStore)(nil) + +func NewVersionIndexedStore(parent types.KVStore, multiVersionStore MultiVersionStore, transactionIndex, incarnation int, abortChannel chan scheduler.Abort) *VersionIndexedStore { + return &VersionIndexedStore{ + readset: make(map[string][]byte), + writeset: make(map[string][]byte), + iterateset: []iterationTracker{}, + dirtySet: make(map[string]struct{}), + sortedStore: dbm.NewMemDB(), + parent: parent, + multiVersionStore: multiVersionStore, + transactionIndex: transactionIndex, + incarnation: incarnation, + abortChannel: abortChannel, + } +} + +// GetReadset returns the readset +func (store *VersionIndexedStore) GetReadset() map[string][]byte { + return store.readset +} + +// GetWriteset returns the writeset +func (store *VersionIndexedStore) GetWriteset() map[string][]byte { + return store.writeset +} + +// Get implements types.KVStore. +func (store *VersionIndexedStore) Get(key []byte) []byte { + // first try to get from writeset cache, if cache miss, then try to get from multiversion store, if that misses, then get from parent store + // if the key is in the cache, return it + + // don't have RW mutex because we have to update readset + // TODO: remove? + // store.mtx.Lock() + // defer store.mtx.Unlock() + // defer telemetry.MeasureSince(time.Now(), "store", "mvkv", "get") + + types.AssertValidKey(key) + strKey := string(key) + // first check the MVKV writeset, and return that value if present + cacheValue, ok := store.writeset[strKey] + if ok { + // return the value from the cache, no need to update any readset stuff + return cacheValue + } + // read the readset to see if the value exists - and return if applicable + if readsetVal, ok := store.readset[strKey]; ok { + return readsetVal + } + + // if we didn't find it, then we want to check the multivalue store + add to readset if applicable + mvsValue := store.multiVersionStore.GetLatestBeforeIndex(store.transactionIndex, key) + if mvsValue != nil { + if mvsValue.IsEstimate() { + store.abortChannel <- scheduler.NewEstimateAbort(mvsValue.Index()) + return nil + } else { + // This handles both detecting readset conflicts and updating readset if applicable + return store.parseValueAndUpdateReadset(strKey, mvsValue) + } + } + // if we didn't find it in the multiversion store, then we want to check the parent store + add to readset + parentValue := store.parent.Get(key) + store.UpdateReadSet(key, parentValue) + return parentValue +} + +// This functions handles reads with deleted items and values and verifies that the data is consistent to what we currently have in the readset (IF we have a readset value for that key) +func (store *VersionIndexedStore) parseValueAndUpdateReadset(strKey string, mvsValue MultiVersionValueItem) []byte { + value := mvsValue.Value() + if mvsValue.IsDeleted() { + value = nil + } + store.UpdateReadSet([]byte(strKey), value) + return value +} + +// This function iterates over the readset, validating that the values in the readset are consistent with the values in the multiversion store and underlying parent store, and returns a boolean indicating validity +func (store *VersionIndexedStore) ValidateReadset() bool { + // TODO: remove? + // store.mtx.Lock() + // defer store.mtx.Unlock() + // defer telemetry.MeasureSince(time.Now(), "store", "mvkv", "validate_readset") + + // sort the readset keys - this is so we have consistent behavior when theres varying conflicts within the readset (eg. read conflict vs estimate) + readsetKeys := make([]string, 0, len(store.readset)) + for key := range store.readset { + readsetKeys = append(readsetKeys, key) + } + sort.Strings(readsetKeys) + + // iterate over readset keys and values + for _, strKey := range readsetKeys { + key := []byte(strKey) + value := store.readset[strKey] + mvsValue := store.multiVersionStore.GetLatestBeforeIndex(store.transactionIndex, key) + if mvsValue != nil { + if mvsValue.IsEstimate() { + // if we see an estimate, that means that we need to abort and rerun + store.abortChannel <- scheduler.NewEstimateAbort(mvsValue.Index()) + return false + } else { + if mvsValue.IsDeleted() { + // check for `nil` + if value != nil { + return false + } + } else { + // check for equality + if string(value) != string(mvsValue.Value()) { + return false + } + } + } + continue // value is valid, continue to next key + } + + parentValue := store.parent.Get(key) + if string(parentValue) != string(value) { + // this shouldnt happen because if we have a conflict it should always happen within multiversion store + panic("we shouldn't ever have a readset conflict in parent store") + } + // value was correct, we can continue to the next value + } + return true +} + +// Delete implements types.KVStore. +func (store *VersionIndexedStore) Delete(key []byte) { + // TODO: remove? + // store.mtx.Lock() + // defer store.mtx.Unlock() + // defer telemetry.MeasureSince(time.Now(), "store", "mvkv", "delete") + + types.AssertValidKey(key) + store.setValue(key, nil, true, true) +} + +// Has implements types.KVStore. +func (store *VersionIndexedStore) Has(key []byte) bool { + // necessary locking happens within store.Get + return store.Get(key) != nil +} + +// Set implements types.KVStore. +func (store *VersionIndexedStore) Set(key []byte, value []byte) { + // TODO: remove? + // store.mtx.Lock() + // defer store.mtx.Unlock() + // defer telemetry.MeasureSince(time.Now(), "store", "mvkv", "set") + + types.AssertValidKey(key) + store.setValue(key, value, false, true) +} + +// Iterator implements types.KVStore. +func (v *VersionIndexedStore) Iterator(start []byte, end []byte) dbm.Iterator { + return v.iterator(start, end, true) +} + +// ReverseIterator implements types.KVStore. +func (v *VersionIndexedStore) ReverseIterator(start []byte, end []byte) dbm.Iterator { + return v.iterator(start, end, false) +} + +// TODO: still needs iterateset tracking +// Iterator implements types.KVStore. +func (store *VersionIndexedStore) iterator(start []byte, end []byte, ascending bool) dbm.Iterator { + // TODO: remove? + // store.mtx.Lock() + // defer store.mtx.Unlock() + + // get the sorted keys from MVS + // TODO: ideally we take advantage of mvs keys already being sorted + // TODO: ideally merge btree and mvs keys into a single sorted btree + memDB := store.multiVersionStore.CollectIteratorItems(store.transactionIndex) + + // TODO: ideally we persist writeset keys into a sorted btree for later use + // make a set of total keys across mvkv and mvs to iterate + for key := range store.writeset { + memDB.Set([]byte(key), []byte{}) + } + + var parent, memIterator types.Iterator + + // make a memIterator + memIterator = store.newMemIterator(start, end, memDB, ascending, store) + + if ascending { + parent = store.parent.Iterator(start, end) + } else { + parent = store.parent.ReverseIterator(start, end) + } + + mergeIterator := NewMVSMergeIterator(parent, memIterator, ascending, store) + + iterationTracker := NewIterationTracker(start, end, ascending, store.writeset) + trackedIterator := NewTrackedIterator(mergeIterator, iterationTracker, store) + + // mergeIterator + return trackedIterator + +} + +// GetStoreType implements types.KVStore. +func (v *VersionIndexedStore) GetStoreType() types.StoreType { + return v.parent.GetStoreType() +} + +// CacheWrap implements types.KVStore. +func (*VersionIndexedStore) CacheWrap(storeKey types.StoreKey) types.CacheWrap { + panic("CacheWrap not supported for version indexed store") +} + +// CacheWrapWithListeners implements types.KVStore. +func (*VersionIndexedStore) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + panic("CacheWrapWithListeners not supported for version indexed store") +} + +// CacheWrapWithTrace implements types.KVStore. +func (*VersionIndexedStore) CacheWrapWithTrace(storeKey types.StoreKey, w io.Writer, tc types.TraceContext) types.CacheWrap { + panic("CacheWrapWithTrace not supported for version indexed store") +} + +// GetWorkingHash implements types.KVStore. +func (v *VersionIndexedStore) GetWorkingHash() ([]byte, error) { + panic("should never attempt to get working hash from version indexed store") +} + +// Only entrypoint to mutate writeset +func (store *VersionIndexedStore) setValue(key, value []byte, deleted bool, dirty bool) { + types.AssertValidKey(key) + + keyStr := string(key) + store.writeset[keyStr] = value + if dirty { + store.dirtySet[keyStr] = struct{}{} + } +} + +func (store *VersionIndexedStore) WriteToMultiVersionStore() { + // TODO: remove? + // store.mtx.Lock() + // defer store.mtx.Unlock() + // defer telemetry.MeasureSince(time.Now(), "store", "mvkv", "write_mvs") + store.multiVersionStore.SetWriteset(store.transactionIndex, store.incarnation, store.writeset) + store.multiVersionStore.SetReadset(store.transactionIndex, store.readset) + store.multiVersionStore.SetIterateset(store.transactionIndex, store.iterateset) +} + +func (store *VersionIndexedStore) WriteEstimatesToMultiVersionStore() { + // TODO: remove? + // store.mtx.Lock() + // defer store.mtx.Unlock() + // defer telemetry.MeasureSince(time.Now(), "store", "mvkv", "write_mvs") + store.multiVersionStore.SetEstimatedWriteset(store.transactionIndex, store.incarnation, store.writeset) + // TODO: do we need to write readset and iterateset in this case? I don't think so since if this is called it means we aren't doing validation +} + +func (store *VersionIndexedStore) UpdateReadSet(key []byte, value []byte) { + // add to readset + keyStr := string(key) + store.readset[keyStr] = value + // add to dirty set + store.dirtySet[keyStr] = struct{}{} +} + +// Write implements types.CacheWrap so this store can exist on the cache multi store +func (store *VersionIndexedStore) Write() { + panic("not implemented") +} + +// GetEvents implements types.CacheWrap so this store can exist on the cache multi store +func (store *VersionIndexedStore) GetEvents() []abci.Event { + panic("not implemented") +} + +// ResetEvents implements types.CacheWrap so this store can exist on the cache multi store +func (store *VersionIndexedStore) ResetEvents() { + panic("not implemented") +} + +func (store *VersionIndexedStore) UpdateIterateSet(iterationTracker iterationTracker) { + // append to iterateset + store.iterateset = append(store.iterateset, iterationTracker) +} diff --git a/store/multiversion/mvkv_test.go b/store/multiversion/mvkv_test.go new file mode 100644 index 000000000..44304fd50 --- /dev/null +++ b/store/multiversion/mvkv_test.go @@ -0,0 +1,389 @@ +package multiversion_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/store/cachekv" + "github.com/cosmos/cosmos-sdk/store/dbadapter" + "github.com/cosmos/cosmos-sdk/store/multiversion" + "github.com/cosmos/cosmos-sdk/store/types" + scheduler "github.com/cosmos/cosmos-sdk/types/occ" + "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" +) + +func TestVersionIndexedStoreGetters(t *testing.T) { + mem := dbadapter.Store{DB: dbm.NewMemDB()} + parentKVStore := cachekv.NewStore(mem, types.NewKVStoreKey("mock"), 1000) + mvs := multiversion.NewMultiVersionStore(parentKVStore) + // initialize a new VersionIndexedStore + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 1, 2, make(chan scheduler.Abort)) + + // mock a value in the parent store + parentKVStore.Set([]byte("key1"), []byte("value1")) + + // read key that doesn't exist + val := vis.Get([]byte("key2")) + require.Nil(t, val) + require.False(t, vis.Has([]byte("key2"))) + + // read key that falls down to parent store + val2 := vis.Get([]byte("key1")) + require.Equal(t, []byte("value1"), val2) + require.True(t, vis.Has([]byte("key1"))) + // verify value now in readset + require.Equal(t, []byte("value1"), vis.GetReadset()["key1"]) + + // read the same key that should now be served from the readset (can be verified by setting a different value for the key in the parent store) + parentKVStore.Set([]byte("key1"), []byte("value2")) // realistically shouldn't happen, modifying to verify readset access + val3 := vis.Get([]byte("key1")) + require.True(t, vis.Has([]byte("key1"))) + require.Equal(t, []byte("value1"), val3) + + // test deleted value written to MVS but not parent store + mvs.SetWriteset(0, 2, map[string][]byte{ + "delKey": nil, + }) + parentKVStore.Set([]byte("delKey"), []byte("value4")) + valDel := vis.Get([]byte("delKey")) + require.Nil(t, valDel) + require.False(t, vis.Has([]byte("delKey"))) + + // set different key in MVS - for various indices + mvs.SetWriteset(0, 2, map[string][]byte{ + "delKey": nil, + "key3": []byte("value3"), + }) + mvs.SetWriteset(2, 1, map[string][]byte{ + "key3": []byte("value4"), + }) + mvs.SetEstimatedWriteset(5, 0, map[string][]byte{ + "key3": nil, + }) + + // read the key that falls down to MVS + val4 := vis.Get([]byte("key3")) + // should equal value3 because value4 is later than the key in question + require.Equal(t, []byte("value3"), val4) + require.True(t, vis.Has([]byte("key3"))) + + // try a read that falls through to MVS with a later tx index + vis2 := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 3, 2, make(chan scheduler.Abort)) + val5 := vis2.Get([]byte("key3")) + // should equal value3 because value4 is later than the key in question + require.Equal(t, []byte("value4"), val5) + require.True(t, vis2.Has([]byte("key3"))) + + // test estimate values writing to abortChannel + abortChannel := make(chan scheduler.Abort) + vis3 := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 6, 2, abortChannel) + go func() { + vis3.Get([]byte("key3")) + }() + abort := <-abortChannel // read the abort from the channel + require.Equal(t, 5, abort.DependentTxIdx) + require.Equal(t, scheduler.ErrReadEstimate, abort.Err) + + vis.Set([]byte("key4"), []byte("value4")) + // verify proper response for GET + val6 := vis.Get([]byte("key4")) + require.True(t, vis.Has([]byte("key4"))) + require.Equal(t, []byte("value4"), val6) + // verify that its in the writeset + require.Equal(t, []byte("value4"), vis.GetWriteset()["key4"]) + // verify that its not in the readset + require.Nil(t, vis.GetReadset()["key4"]) +} + +func TestVersionIndexedStoreSetters(t *testing.T) { + mem := dbadapter.Store{DB: dbm.NewMemDB()} + parentKVStore := cachekv.NewStore(mem, types.NewKVStoreKey("mock"), 1000) + mvs := multiversion.NewMultiVersionStore(parentKVStore) + // initialize a new VersionIndexedStore + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 1, 2, make(chan scheduler.Abort)) + + // test simple set + vis.Set([]byte("key1"), []byte("value1")) + require.Equal(t, []byte("value1"), vis.GetWriteset()["key1"]) + + mvs.SetWriteset(0, 1, map[string][]byte{ + "key2": []byte("value2"), + }) + vis.Delete([]byte("key2")) + require.Nil(t, vis.Get([]byte("key2"))) + // because the delete should be at the writeset level, we should not have populated the readset + require.Zero(t, len(vis.GetReadset())) + + // try setting the value again, and then read + vis.Set([]byte("key2"), []byte("value3")) + require.Equal(t, []byte("value3"), vis.Get([]byte("key2"))) + require.Zero(t, len(vis.GetReadset())) +} + +func TestVersionIndexedStoreBoilerplateFunctions(t *testing.T) { + mem := dbadapter.Store{DB: dbm.NewMemDB()} + parentKVStore := cachekv.NewStore(mem, types.NewKVStoreKey("mock"), 1000) + mvs := multiversion.NewMultiVersionStore(parentKVStore) + // initialize a new VersionIndexedStore + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 1, 2, make(chan scheduler.Abort)) + + // asserts panics where appropriate + require.Panics(t, func() { vis.CacheWrap(types.NewKVStoreKey("mock")) }) + require.Panics(t, func() { vis.CacheWrapWithListeners(types.NewKVStoreKey("mock"), nil) }) + require.Panics(t, func() { vis.CacheWrapWithTrace(types.NewKVStoreKey("mock"), nil, nil) }) + require.Panics(t, func() { vis.GetWorkingHash() }) + + // assert properly returns store type + require.Equal(t, types.StoreTypeDB, vis.GetStoreType()) +} + +func TestVersionIndexedStoreWrite(t *testing.T) { + mem := dbadapter.Store{DB: dbm.NewMemDB()} + parentKVStore := cachekv.NewStore(mem, types.NewKVStoreKey("mock"), 1000) + mvs := multiversion.NewMultiVersionStore(parentKVStore) + // initialize a new VersionIndexedStore + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 1, 2, make(chan scheduler.Abort)) + + mvs.SetWriteset(0, 1, map[string][]byte{ + "key3": []byte("value3"), + }) + + require.False(t, mvs.Has(3, []byte("key1"))) + require.False(t, mvs.Has(3, []byte("key2"))) + require.True(t, mvs.Has(3, []byte("key3"))) + + // write some keys + vis.Set([]byte("key1"), []byte("value1")) + vis.Set([]byte("key2"), []byte("value2")) + vis.Delete([]byte("key3")) + + vis.WriteToMultiVersionStore() + + require.Equal(t, []byte("value1"), mvs.GetLatest([]byte("key1")).Value()) + require.Equal(t, []byte("value2"), mvs.GetLatest([]byte("key2")).Value()) + require.True(t, mvs.GetLatest([]byte("key3")).IsDeleted()) +} + +func TestVersionIndexedStoreWriteEstimates(t *testing.T) { + mem := dbadapter.Store{DB: dbm.NewMemDB()} + parentKVStore := cachekv.NewStore(mem, types.NewKVStoreKey("mock"), 1000) + mvs := multiversion.NewMultiVersionStore(parentKVStore) + // initialize a new VersionIndexedStore + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 1, 2, make(chan scheduler.Abort)) + + mvs.SetWriteset(0, 1, map[string][]byte{ + "key3": []byte("value3"), + }) + + require.False(t, mvs.Has(3, []byte("key1"))) + require.False(t, mvs.Has(3, []byte("key2"))) + require.True(t, mvs.Has(3, []byte("key3"))) + + // write some keys + vis.Set([]byte("key1"), []byte("value1")) + vis.Set([]byte("key2"), []byte("value2")) + vis.Delete([]byte("key3")) + + vis.WriteEstimatesToMultiVersionStore() + + require.True(t, mvs.GetLatest([]byte("key1")).IsEstimate()) + require.True(t, mvs.GetLatest([]byte("key2")).IsEstimate()) + require.True(t, mvs.GetLatest([]byte("key3")).IsEstimate()) +} + +func TestVersionIndexedStoreValidation(t *testing.T) { + mem := dbadapter.Store{DB: dbm.NewMemDB()} + parentKVStore := cachekv.NewStore(mem, types.NewKVStoreKey("mock"), 1000) + mvs := multiversion.NewMultiVersionStore(parentKVStore) + // initialize a new VersionIndexedStore + abortC := make(chan scheduler.Abort) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 2, 2, abortC) + // set some initial values + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + parentKVStore.Set([]byte("deletedKey"), []byte("foo")) + + mvs.SetWriteset(0, 1, map[string][]byte{ + "key1": []byte("value1"), + "key2": []byte("value2"), + "deletedKey": nil, + }) + + // load those into readset + vis.Get([]byte("key1")) + vis.Get([]byte("key2")) + vis.Get([]byte("key4")) + vis.Get([]byte("key5")) + vis.Get([]byte("keyDNE")) + vis.Get([]byte("deletedKey")) + + // everything checks out, so we should be able to validate successfully + require.True(t, vis.ValidateReadset()) + // modify underlying transaction key that is unrelated + mvs.SetWriteset(1, 1, map[string][]byte{ + "key3": []byte("value3"), + }) + // should still have valid readset + require.True(t, vis.ValidateReadset()) + + // modify underlying transaction key that is related + mvs.SetWriteset(1, 1, map[string][]byte{ + "key3": []byte("value3"), + "key1": []byte("value1_b"), + }) + // should now have invalid readset + require.False(t, vis.ValidateReadset()) + // reset so readset is valid again + mvs.SetWriteset(1, 1, map[string][]byte{ + "key3": []byte("value3"), + "key1": []byte("value1"), + }) + require.True(t, vis.ValidateReadset()) + + // mvs has a value that was initially read from parent + mvs.SetWriteset(1, 1, map[string][]byte{ + "key3": []byte("value3"), + "key1": []byte("value1"), + "key4": []byte("value4_b"), + }) + require.False(t, vis.ValidateReadset()) + // reset key + mvs.SetWriteset(1, 1, map[string][]byte{ + "key3": []byte("value3"), + "key1": []byte("value1"), + "key4": []byte("value4"), + }) + require.True(t, vis.ValidateReadset()) + + // mvs has a value that was initially read from parent - BUT in a later tx index + mvs.SetWriteset(4, 2, map[string][]byte{ + "key4": []byte("value4_c"), + }) + // readset should remain valid + require.True(t, vis.ValidateReadset()) + + // mvs has an estimate + mvs.SetEstimatedWriteset(1, 1, map[string][]byte{ + "key2": nil, + }) + // readset should be invalid now - but via abort channel write + go func() { + vis.ValidateReadset() + }() + abort := <-abortC // read the abort from the channel + require.Equal(t, 1, abort.DependentTxIdx) + + // test key deleted later + mvs.SetWriteset(1, 1, map[string][]byte{ + "key3": []byte("value3"), + "key1": []byte("value1"), + "key4": []byte("value4"), + "key2": nil, + }) + require.False(t, vis.ValidateReadset()) + // reset key2 + mvs.SetWriteset(1, 1, map[string][]byte{ + "key3": []byte("value3"), + "key1": []byte("value1"), + "key4": []byte("value4"), + "key2": []byte("value2"), + }) + + // lastly verify panic if parent kvstore has a conflict - this shouldn't happen but lets assert that it would panic + parentKVStore.Set([]byte("keyDNE"), []byte("foobar")) + require.Equal(t, []byte("foobar"), parentKVStore.Get([]byte("keyDNE"))) + require.Panics(t, func() { + vis.ValidateReadset() + }) +} + +func TestIterator(t *testing.T) { + mem := dbadapter.Store{DB: dbm.NewMemDB()} + parentKVStore := cachekv.NewStore(mem, types.NewKVStoreKey("mock"), 1000) + mvs := multiversion.NewMultiVersionStore(parentKVStore) + // initialize a new VersionIndexedStore + abortC := make(chan scheduler.Abort) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 2, 2, abortC) + + // set some initial values + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + parentKVStore.Set([]byte("deletedKey"), []byte("foo")) + mvs.SetWriteset(0, 1, map[string][]byte{ + "key1": []byte("value1"), + "key2": []byte("value2"), + "deletedKey": nil, + }) + // add an estimate to MVS + mvs.SetEstimatedWriteset(3, 1, map[string][]byte{ + "key3": []byte("value1_b"), + }) + + // iterate over the keys - exclusive on key5 + iter := vis.Iterator([]byte("000"), []byte("key5")) + + // verify domain is superset + start, end := iter.Domain() + require.Equal(t, []byte("000"), start) + require.Equal(t, []byte("key5"), end) + + vals := []string{} + defer iter.Close() + for ; iter.Valid(); iter.Next() { + vals = append(vals, string(iter.Value())) + } + require.Equal(t, []string{"value1", "value2", "value4"}, vals) + iter.Close() + + // test reverse iteration + vals2 := []string{} + iter2 := vis.ReverseIterator([]byte("000"), []byte("key6")) + defer iter2.Close() + for ; iter2.Valid(); iter2.Next() { + vals2 = append(vals2, string(iter2.Value())) + } + // has value5 because of end being key6 + require.Equal(t, []string{"value5", "value4", "value2", "value1"}, vals2) + iter2.Close() + + // add items to writeset + vis.Set([]byte("key3"), []byte("value3")) + vis.Set([]byte("key4"), []byte("valueNew")) + + // iterate over the keys - exclusive on key5 + iter3 := vis.Iterator([]byte("000"), []byte("key5")) + vals3 := []string{} + defer iter3.Close() + for ; iter3.Valid(); iter3.Next() { + vals3 = append(vals3, string(iter3.Value())) + } + require.Equal(t, []string{"value1", "value2", "value3", "valueNew"}, vals3) + iter3.Close() + + vis.Set([]byte("key6"), []byte("value6")) + // iterate over the keys, writeset being the last of the iteration range + iter4 := vis.Iterator([]byte("000"), []byte("key7")) + vals4 := []string{} + defer iter4.Close() + for ; iter4.Valid(); iter4.Next() { + vals4 = append(vals4, string(iter4.Value())) + } + require.Equal(t, []string{"value1", "value2", "value3", "valueNew", "value5", "value6"}, vals4) + iter4.Close() + + // add an estimate to MVS + mvs.SetEstimatedWriteset(1, 1, map[string][]byte{ + "key2": []byte("value1_b"), + }) + + go func() { + // new iter + iter4 := vis.Iterator([]byte("000"), []byte("key5")) + defer iter4.Close() + for ; iter4.Valid(); iter4.Next() { + } + }() + abort := <-abortC // read the abort from the channel + require.Equal(t, 1, abort.DependentTxIdx) + +} diff --git a/store/multiversion/store.go b/store/multiversion/store.go new file mode 100644 index 000000000..16b0e626b --- /dev/null +++ b/store/multiversion/store.go @@ -0,0 +1,427 @@ +package multiversion + +import ( + "bytes" + "sort" + "sync" + + "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/types/occ" + occtypes "github.com/cosmos/cosmos-sdk/types/occ" + db "github.com/tendermint/tm-db" +) + +type MultiVersionStore interface { + GetLatest(key []byte) (value MultiVersionValueItem) + GetLatestBeforeIndex(index int, key []byte) (value MultiVersionValueItem) + Has(index int, key []byte) bool + WriteLatestToStore() + SetWriteset(index int, incarnation int, writeset WriteSet) + InvalidateWriteset(index int, incarnation int) + SetEstimatedWriteset(index int, incarnation int, writeset WriteSet) + GetAllWritesetKeys() map[int][]string + CollectIteratorItems(index int) *db.MemDB + SetReadset(index int, readset ReadSet) + GetReadset(index int) ReadSet + ClearReadset(index int) + VersionedIndexedStore(index int, incarnation int, abortChannel chan occ.Abort) *VersionIndexedStore + SetIterateset(index int, iterateset Iterateset) + GetIterateset(index int) Iterateset + ClearIterateset(index int) + ValidateTransactionState(index int) (bool, []int) +} + +type WriteSet map[string][]byte +type ReadSet map[string][]byte +type Iterateset []iterationTracker + +var _ MultiVersionStore = (*Store)(nil) + +type Store struct { + // map that stores the key string -> MultiVersionValue mapping for accessing from a given key + multiVersionMap *sync.Map + // TODO: do we need to support iterators as well similar to how cachekv does it - yes + + txWritesetKeys *sync.Map // map of tx index -> writeset keys []string + txReadSets *sync.Map // map of tx index -> readset ReadSet + txIterateSets *sync.Map // map of tx index -> iterateset Iterateset + + parentStore types.KVStore +} + +func NewMultiVersionStore(parentStore types.KVStore) *Store { + return &Store{ + multiVersionMap: &sync.Map{}, + txWritesetKeys: &sync.Map{}, + txReadSets: &sync.Map{}, + txIterateSets: &sync.Map{}, + parentStore: parentStore, + } +} + +// VersionedIndexedStore creates a new versioned index store for a given incarnation and transaction index +func (s *Store) VersionedIndexedStore(index int, incarnation int, abortChannel chan occ.Abort) *VersionIndexedStore { + return NewVersionIndexedStore(s.parentStore, s, index, incarnation, abortChannel) +} + +// GetLatest implements MultiVersionStore. +func (s *Store) GetLatest(key []byte) (value MultiVersionValueItem) { + keyString := string(key) + mvVal, found := s.multiVersionMap.Load(keyString) + // if the key doesn't exist in the overall map, return nil + if !found { + return nil + } + latestVal, found := mvVal.(MultiVersionValue).GetLatest() + if !found { + return nil // this is possible IF there is are writeset that are then removed for that key + } + return latestVal +} + +// GetLatestBeforeIndex implements MultiVersionStore. +func (s *Store) GetLatestBeforeIndex(index int, key []byte) (value MultiVersionValueItem) { + keyString := string(key) + mvVal, found := s.multiVersionMap.Load(keyString) + // if the key doesn't exist in the overall map, return nil + if !found { + return nil + } + val, found := mvVal.(MultiVersionValue).GetLatestBeforeIndex(index) + // otherwise, we may have found a value for that key, but its not written before the index passed in + if !found { + return nil + } + // found a value prior to the passed in index, return that value (could be estimate OR deleted, but it is a definitive value) + return val +} + +// Has implements MultiVersionStore. It checks if the key exists in the multiversion store at or before the specified index. +func (s *Store) Has(index int, key []byte) bool { + + keyString := string(key) + mvVal, found := s.multiVersionMap.Load(keyString) + // if the key doesn't exist in the overall map, return nil + if !found { + return false // this is okay because the caller of this will THEN need to access the parent store to verify that the key doesnt exist there + } + _, foundVal := mvVal.(MultiVersionValue).GetLatestBeforeIndex(index) + return foundVal +} + +func (s *Store) removeOldWriteset(index int, newWriteSet WriteSet) { + writeset := make(map[string][]byte) + if newWriteSet != nil { + // if non-nil writeset passed in, we can use that to optimize removals + writeset = newWriteSet + } + // if there is already a writeset existing, we should remove that fully + oldKeys, loaded := s.txWritesetKeys.LoadAndDelete(index) + if loaded { + keys := oldKeys.([]string) + // we need to delete all of the keys in the writeset from the multiversion store + for _, key := range keys { + // small optimization to check if the new writeset is going to write this key, if so, we can leave it behind + if _, ok := writeset[key]; ok { + // we don't need to remove this key because it will be overwritten anyways - saves the operation of removing + rebalancing underlying btree + continue + } + // remove from the appropriate item if present in multiVersionMap + mvVal, found := s.multiVersionMap.Load(key) + // if the key doesn't exist in the overall map, return nil + if !found { + continue + } + mvVal.(MultiVersionValue).Remove(index) + } + } +} + +// SetWriteset sets a writeset for a transaction index, and also writes all of the multiversion items in the writeset to the multiversion store. +// TODO: returns a list of NEW keys added +func (s *Store) SetWriteset(index int, incarnation int, writeset WriteSet) { + // TODO: add telemetry spans + // remove old writeset if it exists + s.removeOldWriteset(index, writeset) + + writeSetKeys := make([]string, 0, len(writeset)) + for key, value := range writeset { + writeSetKeys = append(writeSetKeys, key) + loadVal, _ := s.multiVersionMap.LoadOrStore(key, NewMultiVersionItem()) // init if necessary + mvVal := loadVal.(MultiVersionValue) + if value == nil { + // delete if nil value + // TODO: sync map + mvVal.Delete(index, incarnation) + } else { + mvVal.Set(index, incarnation, value) + } + } + sort.Strings(writeSetKeys) // TODO: if we're sorting here anyways, maybe we just put it into a btree instead of a slice + s.txWritesetKeys.Store(index, writeSetKeys) +} + +// InvalidateWriteset iterates over the keys for the given index and incarnation writeset and replaces with ESTIMATEs +func (s *Store) InvalidateWriteset(index int, incarnation int) { + keysAny, found := s.txWritesetKeys.Load(index) + if !found { + return + } + keys := keysAny.([]string) + for _, key := range keys { + // invalidate all of the writeset items - is this suboptimal? - we could potentially do concurrently if slow because locking is on an item specific level + val, _ := s.multiVersionMap.LoadOrStore(key, NewMultiVersionItem()) + val.(MultiVersionValue).SetEstimate(index, incarnation) + } + // we leave the writeset in place because we'll need it for key removal later if/when we replace with a new writeset +} + +// SetEstimatedWriteset is used to directly write estimates instead of writing a writeset and later invalidating +func (s *Store) SetEstimatedWriteset(index int, incarnation int, writeset WriteSet) { + // remove old writeset if it exists + s.removeOldWriteset(index, writeset) + + writeSetKeys := make([]string, 0, len(writeset)) + // still need to save the writeset so we can remove the elements later: + for key := range writeset { + writeSetKeys = append(writeSetKeys, key) + + mvVal, _ := s.multiVersionMap.LoadOrStore(key, NewMultiVersionItem()) // init if necessary + mvVal.(MultiVersionValue).SetEstimate(index, incarnation) + } + sort.Strings(writeSetKeys) + s.txWritesetKeys.Store(index, writeSetKeys) +} + +// GetAllWritesetKeys implements MultiVersionStore. +func (s *Store) GetAllWritesetKeys() map[int][]string { + writesetKeys := make(map[int][]string) + // TODO: is this safe? + s.txWritesetKeys.Range(func(key, value interface{}) bool { + index := key.(int) + keys := value.([]string) + writesetKeys[index] = keys + return true + }) + + return writesetKeys +} + +func (s *Store) SetReadset(index int, readset ReadSet) { + s.txReadSets.Store(index, readset) +} + +func (s *Store) GetReadset(index int) ReadSet { + readsetAny, found := s.txReadSets.Load(index) + if !found { + return nil + } + return readsetAny.(ReadSet) +} + +func (s *Store) SetIterateset(index int, iterateset Iterateset) { + s.txIterateSets.Store(index, iterateset) +} + +func (s *Store) GetIterateset(index int) Iterateset { + iteratesetAny, found := s.txIterateSets.Load(index) + if !found { + return nil + } + return iteratesetAny.(Iterateset) +} + +func (s *Store) ClearReadset(index int) { + s.txReadSets.Delete(index) +} + +func (s *Store) ClearIterateset(index int) { + s.txReadSets.Delete(index) +} + +// CollectIteratorItems implements MultiVersionStore. It will return a memDB containing all of the keys present in the multiversion store within the iteration range prior to (exclusive of) the index. +func (s *Store) CollectIteratorItems(index int) *db.MemDB { + sortedItems := db.NewMemDB() + + // get all writeset keys prior to index + for i := 0; i < index; i++ { + writesetAny, found := s.txWritesetKeys.Load(i) + if !found { + continue + } + indexedWriteset := writesetAny.([]string) + // TODO: do we want to exclude keys out of the range or just let the iterator handle it? + for _, key := range indexedWriteset { + // TODO: inefficient because (logn) for each key + rebalancing? maybe theres a better way to add to a tree to reduce rebalancing overhead + sortedItems.Set([]byte(key), []byte{}) + } + } + return sortedItems +} + +func (s *Store) validateIterator(index int, tracker iterationTracker) bool { + // collect items from multiversion store + sortedItems := s.CollectIteratorItems(index) + // add the iterationtracker writeset keys to the sorted items + for key := range tracker.writeset { + sortedItems.Set([]byte(key), []byte{}) + } + validChannel := make(chan bool, 1) + abortChannel := make(chan occtypes.Abort, 1) + + // listen for abort while iterating + go func(iterationTracker iterationTracker, items *db.MemDB, returnChan chan bool, abortChan chan occtypes.Abort) { + var parentIter types.Iterator + expectedKeys := iterationTracker.iteratedKeys + foundKeys := 0 + iter := s.newMVSValidationIterator(index, iterationTracker.startKey, iterationTracker.endKey, items, iterationTracker.ascending, iterationTracker.writeset, abortChan) + if iterationTracker.ascending { + parentIter = s.parentStore.Iterator(iterationTracker.startKey, iterationTracker.endKey) + } else { + parentIter = s.parentStore.ReverseIterator(iterationTracker.startKey, iterationTracker.endKey) + } + // create a new MVSMergeiterator + mergeIterator := NewMVSMergeIterator(parentIter, iter, iterationTracker.ascending, NoOpHandler{}) + defer mergeIterator.Close() + for ; mergeIterator.Valid(); mergeIterator.Next() { + if (len(expectedKeys) - foundKeys) == 0 { + // if we have no more expected keys, then the iterator is invalid + returnChan <- false + return + } + key := mergeIterator.Key() + // TODO: is this ok to not delete the key since we shouldnt have duplicate keys? + if _, ok := expectedKeys[string(key)]; !ok { + // if key isn't found + returnChan <- false + return + } + // remove from expected keys + foundKeys += 1 + // delete(expectedKeys, string(key)) + + // if our iterator key was the early stop, then we can break + if bytes.Equal(key, iterationTracker.earlyStopKey) { + returnChan <- true + return + } + } + returnChan <- !((len(expectedKeys) - foundKeys) > 0) + }(tracker, sortedItems, validChannel, abortChannel) + select { + case <-abortChannel: + // if we get an abort, then we know that the iterator is invalid + return false + case valid := <-validChannel: + return valid + } +} + +func (s *Store) checkIteratorAtIndex(index int) bool { + valid := true + iterateSetAny, found := s.txIterateSets.Load(index) + if !found { + return true + } + iterateset := iterateSetAny.(Iterateset) + for _, iterationTracker := range iterateset { + iteratorValid := s.validateIterator(index, iterationTracker) + valid = valid && iteratorValid + } + return valid +} + +func (s *Store) checkReadsetAtIndex(index int) (bool, []int) { + conflictSet := make(map[int]struct{}) + valid := true + + readSetAny, found := s.txReadSets.Load(index) + if !found { + return true, []int{} + } + readset := readSetAny.(ReadSet) + // iterate over readset and check if the value is the same as the latest value relateive to txIndex in the multiversion store + for key, value := range readset { + // get the latest value from the multiversion store + latestValue := s.GetLatestBeforeIndex(index, []byte(key)) + if latestValue == nil { + // this is possible if we previously read a value from a transaction write that was later reverted, so this time we read from parent store + parentVal := s.parentStore.Get([]byte(key)) + if !bytes.Equal(parentVal, value) { + valid = false + } + } else { + // if estimate, mark as conflict index - but don't invalidate + if latestValue.IsEstimate() { + conflictSet[latestValue.Index()] = struct{}{} + } else if latestValue.IsDeleted() { + if value != nil { + // conflict + // TODO: would we want to return early? + valid = false + } + } else if !bytes.Equal(latestValue.Value(), value) { + valid = false + } + } + } + + conflictIndices := make([]int, 0, len(conflictSet)) + for index := range conflictSet { + conflictIndices = append(conflictIndices, index) + } + + sort.Ints(conflictIndices) + + return valid, conflictIndices +} + +// TODO: do we want to return bool + []int where bool indicates whether it was valid and then []int indicates only ones for which we need to wait due to estimates? - yes i think so? +func (s *Store) ValidateTransactionState(index int) (bool, []int) { + // defer telemetry.MeasureSince(time.Now(), "store", "mvs", "validate") + + // TODO: can we parallelize for all iterators? + iteratorValid := s.checkIteratorAtIndex(index) + + readsetValid, conflictIndices := s.checkReadsetAtIndex(index) + + return iteratorValid && readsetValid, conflictIndices +} + +func (s *Store) WriteLatestToStore() { + // sort the keys + keys := []string{} + s.multiVersionMap.Range(func(key, value interface{}) bool { + keys = append(keys, key.(string)) + return true + }) + sort.Strings(keys) + + for _, key := range keys { + val, ok := s.multiVersionMap.Load(key) + if !ok { + continue + } + mvValue, found := val.(MultiVersionValue).GetLatestNonEstimate() + if !found { + // this means that at some point, there was an estimate, but we have since removed it so there isn't anything writeable at the key, so we can skip + continue + } + // we shouldn't have any ESTIMATE values when performing the write, because we read the latest non-estimate values only + if mvValue.IsEstimate() { + panic("should not have any estimate values when writing to parent store") + } + // if the value is deleted, then delete it from the parent store + if mvValue.IsDeleted() { + // We use []byte(key) instead of conv.UnsafeStrToBytes because we cannot + // be sure if the underlying store might do a save with the byteslice or + // not. Once we get confirmation that .Delete is guaranteed not to + // save the byteslice, then we can assume only a read-only copy is sufficient. + s.parentStore.Delete([]byte(key)) + continue + } + if mvValue.Value() != nil { + s.parentStore.Set([]byte(key), mvValue.Value()) + } + } +} diff --git a/store/multiversion/store_test.go b/store/multiversion/store_test.go new file mode 100644 index 000000000..ae0f3afda --- /dev/null +++ b/store/multiversion/store_test.go @@ -0,0 +1,642 @@ +package multiversion_test + +import ( + "bytes" + "testing" + + "github.com/cosmos/cosmos-sdk/store/dbadapter" + "github.com/cosmos/cosmos-sdk/store/multiversion" + "github.com/cosmos/cosmos-sdk/types/occ" + "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" +) + +func TestMultiVersionStore(t *testing.T) { + store := multiversion.NewMultiVersionStore(nil) + + // Test Set and GetLatest + store.SetWriteset(1, 1, map[string][]byte{ + "key1": []byte("value1"), + }) + store.SetWriteset(2, 1, map[string][]byte{ + "key1": []byte("value2"), + }) + store.SetWriteset(3, 1, map[string][]byte{ + "key2": []byte("value3"), + }) + + require.Equal(t, []byte("value2"), store.GetLatest([]byte("key1")).Value()) + require.Equal(t, []byte("value3"), store.GetLatest([]byte("key2")).Value()) + + // Test SetEstimate + store.SetEstimatedWriteset(4, 1, map[string][]byte{ + "key1": nil, + }) + require.True(t, store.GetLatest([]byte("key1")).IsEstimate()) + + // Test Delete + store.SetWriteset(5, 1, map[string][]byte{ + "key1": nil, + }) + require.True(t, store.GetLatest([]byte("key1")).IsDeleted()) + + // Test GetLatestBeforeIndex + store.SetWriteset(6, 1, map[string][]byte{ + "key1": []byte("value4"), + }) + require.True(t, store.GetLatestBeforeIndex(5, []byte("key1")).IsEstimate()) + require.Equal(t, []byte("value4"), store.GetLatestBeforeIndex(7, []byte("key1")).Value()) + + // Test Has + require.True(t, store.Has(2, []byte("key1"))) + require.False(t, store.Has(0, []byte("key1"))) + require.False(t, store.Has(5, []byte("key4"))) +} + +func TestMultiVersionStoreHasLaterValue(t *testing.T) { + store := multiversion.NewMultiVersionStore(nil) + + store.SetWriteset(5, 1, map[string][]byte{ + "key1": []byte("value2"), + }) + + require.Nil(t, store.GetLatestBeforeIndex(4, []byte("key1"))) + require.Equal(t, []byte("value2"), store.GetLatestBeforeIndex(6, []byte("key1")).Value()) +} + +func TestMultiVersionStoreKeyDNE(t *testing.T) { + store := multiversion.NewMultiVersionStore(nil) + + require.Nil(t, store.GetLatest([]byte("key1"))) + require.Nil(t, store.GetLatestBeforeIndex(0, []byte("key1"))) + require.False(t, store.Has(0, []byte("key1"))) +} + +func TestMultiVersionStoreWriteToParent(t *testing.T) { + // initialize cachekv store + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + + mvs.SetWriteset(1, 1, map[string][]byte{ + "key1": []byte("value1"), + "key3": nil, + "key4": nil, + }) + mvs.SetWriteset(2, 1, map[string][]byte{ + "key1": []byte("value2"), + }) + mvs.SetWriteset(3, 1, map[string][]byte{ + "key2": []byte("value3"), + }) + + mvs.WriteLatestToStore() + + // assert state in parent store + require.Equal(t, []byte("value2"), parentKVStore.Get([]byte("key1"))) + require.Equal(t, []byte("value3"), parentKVStore.Get([]byte("key2"))) + require.False(t, parentKVStore.Has([]byte("key3"))) + require.False(t, parentKVStore.Has([]byte("key4"))) + + // verify no-op if mvs contains ESTIMATE + mvs.SetEstimatedWriteset(1, 2, map[string][]byte{ + "key1": []byte("value1"), + "key3": nil, + "key4": nil, + "key5": nil, + }) + mvs.WriteLatestToStore() + require.False(t, parentKVStore.Has([]byte("key5"))) +} + +func TestMultiVersionStoreWritesetSetAndInvalidate(t *testing.T) { + mvs := multiversion.NewMultiVersionStore(nil) + + writeset := make(map[string][]byte) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + + mvs.SetWriteset(1, 2, writeset) + require.Equal(t, []byte("value1"), mvs.GetLatest([]byte("key1")).Value()) + require.Equal(t, []byte("value2"), mvs.GetLatest([]byte("key2")).Value()) + require.True(t, mvs.GetLatest([]byte("key3")).IsDeleted()) + + writeset2 := make(map[string][]byte) + writeset2["key1"] = []byte("value3") + + mvs.SetWriteset(2, 1, writeset2) + require.Equal(t, []byte("value3"), mvs.GetLatest([]byte("key1")).Value()) + + // invalidate writeset1 + mvs.InvalidateWriteset(1, 2) + + // verify estimates + require.True(t, mvs.GetLatestBeforeIndex(2, []byte("key1")).IsEstimate()) + require.True(t, mvs.GetLatestBeforeIndex(2, []byte("key2")).IsEstimate()) + require.True(t, mvs.GetLatestBeforeIndex(2, []byte("key3")).IsEstimate()) + + // third writeset + writeset3 := make(map[string][]byte) + writeset3["key4"] = []byte("foo") + writeset3["key5"] = nil + + // write the writeset directly as estimate + mvs.SetEstimatedWriteset(3, 1, writeset3) + + require.True(t, mvs.GetLatest([]byte("key4")).IsEstimate()) + require.True(t, mvs.GetLatest([]byte("key5")).IsEstimate()) + + // try replacing writeset1 to verify old keys removed + writeset1_b := make(map[string][]byte) + writeset1_b["key1"] = []byte("value4") + + mvs.SetWriteset(1, 2, writeset1_b) + require.Equal(t, []byte("value4"), mvs.GetLatestBeforeIndex(2, []byte("key1")).Value()) + require.Nil(t, mvs.GetLatestBeforeIndex(2, []byte("key2"))) + // verify that GetLatest for key3 returns nil - because of removal from writeset + require.Nil(t, mvs.GetLatest([]byte("key3"))) + + // verify output for GetAllWritesetKeys + writesetKeys := mvs.GetAllWritesetKeys() + // we have 3 writesets + require.Equal(t, 3, len(writesetKeys)) + require.Equal(t, []string{"key1"}, writesetKeys[1]) + require.Equal(t, []string{"key1"}, writesetKeys[2]) + require.Equal(t, []string{"key4", "key5"}, writesetKeys[3]) + +} + +func TestMultiVersionStoreValidateState(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + readset := make(multiversion.ReadSet) + readset["key1"] = []byte("value1") + readset["key2"] = []byte("value2") + readset["key3"] = nil + readset["key4"] = []byte("value4") + readset["key5"] = []byte("value5") + mvs.SetReadset(5, readset) + + // assert no readset is valid + valid, conflicts := mvs.ValidateTransactionState(4) + require.True(t, valid) + require.Empty(t, conflicts) + + // assert readset index 5 is valid + valid, conflicts = mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Empty(t, conflicts) + + // introduce conflict + mvs.SetWriteset(2, 1, map[string][]byte{ + "key3": []byte("value6"), + }) + + // expect failure with empty conflicts + valid, conflicts = mvs.ValidateTransactionState(5) + require.False(t, valid) + require.Empty(t, conflicts) + + // add a conflict due to deletion + mvs.SetWriteset(3, 1, map[string][]byte{ + "key1": nil, + }) + + // expect failure with empty conflicts + valid, conflicts = mvs.ValidateTransactionState(5) + require.False(t, valid) + require.Empty(t, conflicts) + + // add a conflict due to estimate + mvs.SetEstimatedWriteset(4, 1, map[string][]byte{ + "key2": []byte("test"), + }) + + // expect index 4 to be returned + valid, conflicts = mvs.ValidateTransactionState(5) + require.False(t, valid) + require.Equal(t, []int{4}, conflicts) +} + +func TestMultiVersionStoreParentValidationMismatch(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + readset := make(multiversion.ReadSet) + readset["key1"] = []byte("value1") + readset["key2"] = []byte("value2") + readset["key3"] = nil + readset["key4"] = []byte("value4") + readset["key5"] = []byte("value5") + mvs.SetReadset(5, readset) + + // assert no readset is valid + valid, conflicts := mvs.ValidateTransactionState(4) + require.True(t, valid) + require.Empty(t, conflicts) + + // assert readset index 5 is valid + valid, conflicts = mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Empty(t, conflicts) + + // overwrite tx writeset for tx1 - no longer writes key1 + writeset2 := make(multiversion.WriteSet) + writeset2["key2"] = []byte("value2") + writeset2["key3"] = nil + mvs.SetWriteset(1, 3, writeset2) + + // assert readset index 5 is invalid - because of mismatch with parent store + valid, conflicts = mvs.ValidateTransactionState(5) + require.False(t, valid) + require.Empty(t, conflicts) +} + +func TestMVSValidationWithOnlyEstimate(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + readset := make(multiversion.ReadSet) + readset["key1"] = []byte("value1") + readset["key2"] = []byte("value2") + readset["key3"] = nil + readset["key4"] = []byte("value4") + readset["key5"] = []byte("value5") + mvs.SetReadset(5, readset) + + // add a conflict due to estimate + mvs.SetEstimatedWriteset(4, 1, map[string][]byte{ + "key2": []byte("test"), + }) + + valid, conflicts := mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Equal(t, []int{4}, conflicts) + +} + +func TestMVSIteratorValidation(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + // test basic iteration + iter := vis.ReverseIterator([]byte("key1"), []byte("key6")) + for ; iter.Valid(); iter.Next() { + // read value + iter.Value() + } + iter.Close() + vis.WriteToMultiVersionStore() + + // should be valid + valid, conflicts := mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Empty(t, conflicts) +} + +func TestMVSIteratorValidationWithEstimate(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + iter := vis.Iterator([]byte("key1"), []byte("key6")) + for ; iter.Valid(); iter.Next() { + // read value + iter.Value() + } + iter.Close() + vis.WriteToMultiVersionStore() + + writeset2 := make(multiversion.WriteSet) + writeset2["key2"] = []byte("value2") + mvs.SetEstimatedWriteset(2, 2, writeset2) + + // should be invalid + valid, conflicts := mvs.ValidateTransactionState(5) + require.False(t, valid) + require.Equal(t, []int{2}, conflicts) +} + +func TestMVSIteratorValidationWithKeySwitch(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + iter := vis.Iterator([]byte("key1"), []byte("key6")) + for ; iter.Valid(); iter.Next() { + // read value + iter.Value() + } + iter.Close() + vis.WriteToMultiVersionStore() + + // deletion of 2 and introduction of 3 + writeset2 := make(multiversion.WriteSet) + writeset2["key2"] = nil + writeset2["key3"] = []byte("valueX") + mvs.SetWriteset(2, 2, writeset2) + + // should be invalid + valid, conflicts := mvs.ValidateTransactionState(5) + require.False(t, valid) + require.Empty(t, conflicts) +} + +func TestMVSIteratorValidationWithKeyAdded(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + iter := vis.Iterator([]byte("key1"), []byte("key7")) + for ; iter.Valid(); iter.Next() { + // read value + iter.Value() + } + iter.Close() + vis.WriteToMultiVersionStore() + + // addition of key6 + writeset2 := make(multiversion.WriteSet) + writeset2["key6"] = []byte("value6") + mvs.SetWriteset(2, 2, writeset2) + + // should be invalid + valid, conflicts := mvs.ValidateTransactionState(5) + require.False(t, valid) + require.Empty(t, conflicts) +} + +func TestMVSIteratorValidationWithWritesetValues(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + // set a key BEFORE iteration occurred + vis.Set([]byte("key6"), []byte("value6")) + + iter := vis.Iterator([]byte("key1"), []byte("key7")) + for ; iter.Valid(); iter.Next() { + } + iter.Close() + vis.WriteToMultiVersionStore() + + // should be valid + valid, conflicts := mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Empty(t, conflicts) +} + +func TestMVSIteratorValidationWithWritesetValuesSetAfterIteration(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + readset := make(multiversion.ReadSet) + readset["key1"] = []byte("value1") + readset["key2"] = []byte("value2") + readset["key3"] = nil + readset["key4"] = []byte("value4") + readset["key5"] = []byte("value5") + mvs.SetReadset(5, readset) + + // no key6 because the iteration was performed BEFORE the write + iter := vis.Iterator([]byte("key1"), []byte("key7")) + for ; iter.Valid(); iter.Next() { + } + iter.Close() + + // write key 6 AFTER iterator went + vis.Set([]byte("key6"), []byte("value6")) + vis.WriteToMultiVersionStore() + + // should be valid + valid, conflicts := mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Empty(t, conflicts) +} + +func TestMVSIteratorValidationReverse(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + readset := make(multiversion.ReadSet) + readset["key1"] = []byte("value1") + readset["key2"] = []byte("value2") + readset["key3"] = nil + readset["key4"] = []byte("value4") + readset["key5"] = []byte("value5") + mvs.SetReadset(5, readset) + + // set a key BEFORE iteration occurred + vis.Set([]byte("key6"), []byte("value6")) + + iter := vis.ReverseIterator([]byte("key1"), []byte("key7")) + for ; iter.Valid(); iter.Next() { + } + iter.Close() + vis.WriteToMultiVersionStore() + + // should be valid + valid, conflicts := mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Empty(t, conflicts) +} + +func TestMVSIteratorValidationEarlyStop(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + readset := make(multiversion.ReadSet) + readset["key1"] = []byte("value1") + readset["key2"] = []byte("value2") + readset["key3"] = nil + readset["key4"] = []byte("value4") + mvs.SetReadset(5, readset) + + iter := vis.Iterator([]byte("key1"), []byte("key7")) + for ; iter.Valid(); iter.Next() { + // read the value and see if we want to break + if bytes.Equal(iter.Key(), []byte("key4")) { + break + } + } + iter.Close() + vis.WriteToMultiVersionStore() + + // removal of key5 - but irrelevant because of early stop + writeset2 := make(multiversion.WriteSet) + writeset2["key5"] = nil + mvs.SetWriteset(2, 2, writeset2) + + // should be valid + valid, conflicts := mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Empty(t, conflicts) +} + +// TODO: what about early stop with a new key added in the range? - especially if its the last key that we stopped at? +func TestMVSIteratorValidationEarlyStopAtEndOfRange(t *testing.T) { + parentKVStore := dbadapter.Store{DB: dbm.NewMemDB()} + mvs := multiversion.NewMultiVersionStore(parentKVStore) + vis := multiversion.NewVersionIndexedStore(parentKVStore, mvs, 5, 1, make(chan occ.Abort)) + + parentKVStore.Set([]byte("key2"), []byte("value0")) + parentKVStore.Set([]byte("key3"), []byte("value3")) + parentKVStore.Set([]byte("key4"), []byte("value4")) + parentKVStore.Set([]byte("key5"), []byte("value5")) + + writeset := make(multiversion.WriteSet) + writeset["key1"] = []byte("value1") + writeset["key2"] = []byte("value2") + writeset["key3"] = nil + mvs.SetWriteset(1, 2, writeset) + + // test basic iteration + iter := vis.Iterator([]byte("key1"), []byte("key7")) + for ; iter.Valid(); iter.Next() { + // read the value and see if we want to break + if bytes.Equal(iter.Key(), []byte("key5")) { + break + } + } + iter.Close() + vis.WriteToMultiVersionStore() + + // add key6 + writeset2 := make(multiversion.WriteSet) + writeset2["key6"] = []byte("value6") + mvs.SetWriteset(2, 2, writeset2) + + // should be valid + valid, conflicts := mvs.ValidateTransactionState(5) + require.True(t, valid) + require.Empty(t, conflicts) +} diff --git a/store/multiversion/trackediterator.go b/store/multiversion/trackediterator.go new file mode 100644 index 000000000..361d848cb --- /dev/null +++ b/store/multiversion/trackediterator.go @@ -0,0 +1,57 @@ +package multiversion + +import "github.com/cosmos/cosmos-sdk/store/types" + +// tracked iterator is a wrapper around an existing iterator to track the iterator progress and monitor which keys are iterated. +type trackedIterator struct { + types.Iterator + + iterateset iterationTracker + IterateSetHandler +} + +// TODO: test + +func NewTrackedIterator(iter types.Iterator, iterationTracker iterationTracker, iterateSetHandler IterateSetHandler) *trackedIterator { + return &trackedIterator{ + Iterator: iter, + iterateset: iterationTracker, + IterateSetHandler: iterateSetHandler, + } +} + +// Close calls first updates the iterateset from the iterator, and then calls iterator.Close() +func (ti *trackedIterator) Close() error { + // TODO: if there are more keys to the iterator, then we consider it early stopped? + if ti.Iterator.Valid() { + // TODO: test whether reaching end of iteration range means valid is true or false + ti.iterateset.SetEarlyStopKey(ti.Iterator.Key()) + } + // Update iterate set + ti.IterateSetHandler.UpdateIterateSet(ti.iterateset) + return ti.Iterator.Close() +} + +// Key calls the iterator.Key() and adds the key to the iterateset, then returns the key from the iterator +func (ti *trackedIterator) Key() []byte { + key := ti.Iterator.Key() + // add key to the tracker + ti.iterateset.AddKey(key) + return key +} + +// Value calls the iterator.Key() and adds the key to the iterateset, then returns the value from the iterator +func (ti *trackedIterator) Value() []byte { + key := ti.Iterator.Key() + // add key to the tracker + ti.iterateset.AddKey(key) + return ti.Iterator.Value() +} + +func (ti *trackedIterator) Next() { + // add current key to the tracker + key := ti.Iterator.Key() + ti.iterateset.AddKey(key) + // call next + ti.Iterator.Next() +} diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index e14280b46..5aaf3ad20 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -431,6 +431,11 @@ func (rs *Store) LastCommitID() types.CommitID { return c.CommitID() } +// LatestVersion returns the latest version in the store +func (rs *Store) LatestVersion() int64 { + return rs.LastCommitID().Version +} + func (rs *Store) GetWorkingHash() ([]byte, error) { storeInfos := []types.StoreInfo{} for key, store := range rs.stores { @@ -1048,10 +1053,6 @@ func (rs *Store) flushMetadata(db dbm.DB, version int64, cInfo *types.CommitInfo rs.logger.Info("App State Saved height=%d hash=%X\n", cInfo.CommitID().Version, cInfo.CommitID().Hash) } -func (rs *Store) SetOrphanConfig(opts *iavltree.Options) { - rs.orphanOpts = opts -} - func (rs *Store) LastCommitInfo() *types.CommitInfo { rs.lastCommitInfoMtx.RLock() defer rs.lastCommitInfoMtx.RUnlock() @@ -1197,3 +1198,19 @@ func flushPruningHeights(batch dbm.Batch, pruneHeights []int64) { batch.Set([]byte(pruneHeightsKey), bz) } + +func (rs *Store) SetKVStores(handler func(key types.StoreKey, s types.KVStore) types.CacheWrap) types.MultiStore { + panic("SetKVStores is not implemented for rootmulti") +} + +func (rs *Store) StoreKeys() []types.StoreKey { + res := make([]types.StoreKey, len(rs.keysByName)) + for _, sk := range rs.keysByName { + res = append(res, sk) + } + return res +} + +func (rs *Store) Close() error { + return rs.db.Close() +} diff --git a/store/types/cache.go b/store/types/cache.go index 53f45d6b3..b00335a76 100644 --- a/store/types/cache.go +++ b/store/types/cache.go @@ -47,7 +47,7 @@ type BoundedCache struct { CacheBackend limit int - mu *sync.Mutex + mu *sync.Mutex metricName []string } @@ -88,7 +88,7 @@ func (c *BoundedCache) emitKeysEvictedMetrics(keysToEvict int) { func (c *BoundedCache) Set(key string, val *CValue) { c.mu.Lock() defer c.mu.Unlock() - defer c.emitCacheSizeMetric() + // defer c.emitCacheSizeMetric() if c.Len() >= c.limit { numEntries := c.Len() @@ -112,7 +112,7 @@ func (c *BoundedCache) Set(key string, val *CValue) { func (c *BoundedCache) Delete(key string) { c.mu.Lock() defer c.mu.Unlock() - defer c.emitCacheSizeMetric() + // defer c.emitCacheSizeMetric() c.CacheBackend.Delete(key) } @@ -120,7 +120,7 @@ func (c *BoundedCache) Delete(key string) { func (c *BoundedCache) DeleteAll() { c.mu.Lock() defer c.mu.Unlock() - defer c.emitCacheSizeMetric() + // defer c.emitCacheSizeMetric() c.CacheBackend.Range(func(key string, _ *CValue) bool { c.CacheBackend.Delete(key) diff --git a/store/types/pruning.go b/store/types/pruning.go index dcb57b246..9641d724e 100644 --- a/store/types/pruning.go +++ b/store/types/pruning.go @@ -12,16 +12,15 @@ const ( var ( // PruneDefault defines a pruning strategy where the last 362880 heights are - // kept in addition to every 100th and where to-be pruned heights are pruned - // at every 10th height. The last 362880 heights are kept assuming the typical + // keptThe last 362880 heights are kept assuming the typical // block time is 5s and typical unbonding period is 21 days. If these values // do not match the applications' requirements, use the "custom" option. - PruneDefault = NewPruningOptions(362880, 100, 10) + PruneDefault = NewPruningOptions(362880, 0, 10) // PruneEverything defines a pruning strategy where all committed heights are // deleted, storing only the current height and where to-be pruned heights are // pruned at every 10th height. - PruneEverything = NewPruningOptions(2, 0, 10) + PruneEverything = NewPruningOptions(2, 0, 1) // PruneNothing defines a pruning strategy where all heights are kept on disk. PruneNothing = NewPruningOptions(0, 1, 0) diff --git a/store/types/store.go b/store/types/store.go index b34068e9a..0bf65fa1c 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -21,7 +21,6 @@ type Store interface { type Committer interface { Commit(bool) CommitID LastCommitID() CommitID - SetPruning(PruningOptions) GetPruning() PruningOptions } @@ -145,6 +144,14 @@ type MultiStore interface { // Resets the tracked event list ResetEvents() + + // LatestVersion returns the latest version in the store + LatestVersion() int64 + // SetKVStores is a generalized wrapper method + SetKVStores(handler func(key StoreKey, s KVStore) CacheWrap) MultiStore + + // StoreKeys returns a list of store keys + StoreKeys() []StoreKey } // From MultiStore.CacheMultiStore().... @@ -155,6 +162,11 @@ type CacheMultiStore interface { Write() } +type QueryMultiStore interface { + MultiStore + snapshottypes.Snapshotter +} + // CommitMultiStore is an interface for a MultiStore without cache capabilities. type CommitMultiStore interface { Committer @@ -207,6 +219,9 @@ type CommitMultiStore interface { // RollbackToVersion rollback the db to specific version(height). RollbackToVersion(version int64) error + + // Close the underline resources + io.Closer } //---------subsp------------------------------- diff --git a/storev2/commitment/store.go b/storev2/commitment/store.go new file mode 100644 index 000000000..a51073875 --- /dev/null +++ b/storev2/commitment/store.go @@ -0,0 +1,179 @@ +package commitment + +import ( + "fmt" + "io" + + "cosmossdk.io/errors" + "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" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/kv" + "github.com/cosmos/iavl" + sctypes "github.com/sei-protocol/sei-db/sc/types" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/proto/tendermint/crypto" +) + +var ( + _ types.CommitKVStore = (*Store)(nil) + _ types.Queryable = (*Store)(nil) +) + +// Store Implements types.KVStore and CommitKVStore. +type Store struct { + tree sctypes.Tree + logger log.Logger + changeSet iavl.ChangeSet +} + +func NewStore(tree sctypes.Tree, logger log.Logger) *Store { + return &Store{ + tree: tree, + logger: logger, + } +} + +func (st *Store) Commit(_ bool) types.CommitID { + panic("memiavl store is not supposed to be committed alone") +} + +func (st *Store) LastCommitID() types.CommitID { + hash := st.tree.RootHash() + return types.CommitID{ + Version: st.tree.Version(), + Hash: hash, + } +} + +// SetPruning panics as pruning options should be provided at initialization +// since IAVl accepts pruning options directly. +func (st *Store) SetPruning(_ types.PruningOptions) { + panic("cannot set pruning options on an initialized IAVL store") +} + +// SetPruning panics as pruning options should be provided at initialization +// since IAVl accepts pruning options directly. +func (st *Store) GetPruning() types.PruningOptions { + panic("cannot get pruning options on an initialized IAVL store") +} + +func (st *Store) GetWorkingHash() ([]byte, error) { + panic("not implemented") +} + +// Implements Store. +func (st *Store) GetStoreType() types.StoreType { + return types.StoreTypeIAVL +} + +func (st *Store) CacheWrap(k types.StoreKey) types.CacheWrap { + return cachekv.NewStore(st, k, types.DefaultCacheSizeLimit) +} + +// CacheWrapWithTrace implements the Store interface. +func (st *Store) CacheWrapWithTrace(k types.StoreKey, w io.Writer, tc types.TraceContext) types.CacheWrap { + return cachekv.NewStore(tracekv.NewStore(st, w, tc), k, types.DefaultCacheSizeLimit) +} + +func (st *Store) CacheWrapWithListeners(k types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + return cachekv.NewStore(listenkv.NewStore(st, k, listeners), k, types.DefaultCacheSizeLimit) +} + +// Implements types.KVStore. +// +// we assume Set is only called in `Commit`, so the written state is only visible after commit. +func (st *Store) Set(key, value []byte) { + st.changeSet.Pairs = append(st.changeSet.Pairs, &iavl.KVPair{ + Key: key, Value: value, + }) +} + +// Implements types.KVStore. +func (st *Store) Get(key []byte) []byte { + return st.tree.Get(key) +} + +// Implements types.KVStore. +func (st *Store) Has(key []byte) bool { + return st.tree.Has(key) +} + +// Implements types.KVStore. +// +// we assume Delete is only called in `Commit`, so the written state is only visible after commit. +func (st *Store) Delete(key []byte) { + st.changeSet.Pairs = append(st.changeSet.Pairs, &iavl.KVPair{ + Key: key, Delete: true, + }) +} + +func (st *Store) Iterator(start, end []byte) types.Iterator { + return st.tree.Iterator(start, end, true) +} + +func (st *Store) ReverseIterator(start, end []byte) types.Iterator { + return st.tree.Iterator(start, end, false) +} + +// SetInitialVersion sets the initial version of the IAVL tree. It is used when +// starting a new chain at an arbitrary height. +// implements interface StoreWithInitialVersion +func (st *Store) SetInitialVersion(_ int64) { + panic("memiavl store's SetInitialVersion is not supposed to be called directly") +} + +// PopChangeSet returns the change set and clear it +func (st *Store) PopChangeSet() iavl.ChangeSet { + cs := st.changeSet + st.changeSet = iavl.ChangeSet{} + return cs +} + +func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { + if req.Height > 0 && req.Height != st.tree.Version() { + return sdkerrors.QueryResult(errors.Wrap(sdkerrors.ErrInvalidHeight, "invalid height")) + } + res.Height = st.tree.Version() + + switch req.Path { + case "/key": // get by key + res.Key = req.Data // data holds the key bytes + res.Value = st.tree.Get(res.Key) + if !req.Prove { + break + } + + // get proof from tree and convert to merkle.Proof before adding to result + commitmentProof := st.tree.GetProof(res.Key) + op := types.NewIavlCommitmentOp(res.Key, commitmentProof) + res.ProofOps = &crypto.ProofOps{Ops: []crypto.ProofOp{op.ProofOp()}} + case "/subspace": + pairs := kv.Pairs{ + Pairs: make([]kv.Pair, 0), + } + + subspace := req.Data + res.Key = subspace + + iterator := types.KVStorePrefixIterator(st, subspace) + for ; iterator.Valid(); iterator.Next() { + pairs.Pairs = append(pairs.Pairs, kv.Pair{Key: iterator.Key(), Value: iterator.Value()}) + } + iterator.Close() + + bz, err := pairs.Marshal() + if err != nil { + panic(fmt.Errorf("failed to marshal KV pairs: %w", err)) + } + + res.Value = bz + default: + return sdkerrors.QueryResult(errors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path)) + } + + return res +} diff --git a/storev2/commitment/store_test.go b/storev2/commitment/store_test.go new file mode 100644 index 000000000..9728a9b4b --- /dev/null +++ b/storev2/commitment/store_test.go @@ -0,0 +1,16 @@ +package commitment + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/store/types" + "github.com/sei-protocol/sei-db/sc/memiavl" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" +) + +func TestLastCommitID(t *testing.T) { + tree := memiavl.New(100) + store := NewStore(tree, log.NewNopLogger()) + require.Equal(t, types.CommitID{Hash: tree.RootHash()}, store.LastCommitID()) +} diff --git a/storev2/rootmulti/store.go b/storev2/rootmulti/store.go new file mode 100644 index 000000000..d5338b080 --- /dev/null +++ b/storev2/rootmulti/store.go @@ -0,0 +1,790 @@ +package rootmulti + +import ( + "fmt" + "io" + "math" + "sort" + "strings" + "sync" + + "cosmossdk.io/errors" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/store/cachemulti" + "github.com/cosmos/cosmos-sdk/store/mem" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + "github.com/cosmos/cosmos-sdk/store/transient" + "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/storev2/commitment" + "github.com/cosmos/cosmos-sdk/storev2/state" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + protoio "github.com/gogo/protobuf/io" + commonerrors "github.com/sei-protocol/sei-db/common/errors" + "github.com/sei-protocol/sei-db/config" + "github.com/sei-protocol/sei-db/proto" + "github.com/sei-protocol/sei-db/sc" + sctypes "github.com/sei-protocol/sei-db/sc/types" + "github.com/sei-protocol/sei-db/ss" + sstypes "github.com/sei-protocol/sei-db/ss/types" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" +) + +var ( + _ types.CommitMultiStore = (*Store)(nil) + _ types.Queryable = (*Store)(nil) +) + +type Store struct { + logger log.Logger + mtx sync.RWMutex + scStore sctypes.Committer + ssStore sstypes.StateStore + lastCommitInfo *types.CommitInfo + storesParams map[types.StoreKey]storeParams + storeKeys map[string]types.StoreKey + ckvStores map[types.StoreKey]types.CommitKVStore + pendingChanges chan VersionedChangesets +} + +func (rs *Store) LatestVersion() int64 { + //TODO implement me + panic("implement me") +} + +func (rs *Store) SetKVStores(handler func(key types.StoreKey, s types.KVStore) types.CacheWrap) types.MultiStore { + //TODO implement me + panic("implement me") +} + +func (rs *Store) StoreKeys() []types.StoreKey { + //TODO implement me + panic("implement me") +} + +type VersionedChangesets struct { + Version int64 + Changesets []*proto.NamedChangeSet +} + +func NewStore( + homeDir string, + logger log.Logger, + scConfig config.StateCommitConfig, + ssConfig config.StateStoreConfig, +) *Store { + scStore := sc.NewCommitStore(homeDir, logger, scConfig) + store := &Store{ + logger: logger, + scStore: scStore, + storesParams: make(map[types.StoreKey]storeParams), + storeKeys: make(map[string]types.StoreKey), + ckvStores: make(map[types.StoreKey]types.CommitKVStore), + pendingChanges: make(chan VersionedChangesets, 1000), + } + if ssConfig.Enable { + ssStore, err := ss.NewStateStore(homeDir, ssConfig) + if err != nil { + panic(err) + } + if err = ss.RecoverStateStore(homeDir, logger, ssStore); err != nil { + panic(err) + } + store.ssStore = ssStore + go store.StateStoreCommit() + } + return store + +} + +// Commit implements interface Committer, called by ABCI Commit +func (rs *Store) Commit(bumpVersion bool) types.CommitID { + if !bumpVersion { + return rs.lastCommitInfo.CommitID() + } + if err := rs.flush(); err != nil { + panic(err) + } + + rs.mtx.Lock() + defer rs.mtx.Unlock() + for _, store := range rs.ckvStores { + if store.GetStoreType() != types.StoreTypeIAVL { + _ = store.Commit(bumpVersion) + } + } + // Commit to SC Store + _, err := rs.scStore.Commit() + if err != nil { + panic(err) + } + + // The underlying sc store might be reloaded, reload the store as well. + for key := range rs.ckvStores { + store := rs.ckvStores[key] + if store.GetStoreType() == types.StoreTypeIAVL { + rs.ckvStores[key], err = rs.loadCommitStoreFromParams(key, rs.storesParams[key]) + if err != nil { + panic(fmt.Errorf("inconsistent store map, store %s not found", key.Name())) + } + } + } + + rs.lastCommitInfo = convertCommitInfo(rs.scStore.LastCommitInfo()) + rs.lastCommitInfo = amendCommitInfo(rs.lastCommitInfo, rs.storesParams) + return rs.lastCommitInfo.CommitID() +} + +// StateStoreCommit is a background routine to apply changes to SS store +func (rs *Store) StateStoreCommit() { + for pendingChangeSet := range rs.pendingChanges { + version := pendingChangeSet.Version + for _, cs := range pendingChangeSet.Changesets { + if err := rs.ssStore.ApplyChangeset(version, cs); err != nil { + panic(err) + } + } + } +} + +// Flush all the pending changesets to commit store. +func (rs *Store) flush() error { + var changeSets []*proto.NamedChangeSet + currentVersion := rs.lastCommitInfo.Version + for key := range rs.ckvStores { + // it'll unwrap the inter-block cache + store := rs.GetCommitKVStore(key) + if commitStore, ok := store.(*commitment.Store); ok { + cs := commitStore.PopChangeSet() + if len(cs.Pairs) > 0 { + changeSets = append(changeSets, &proto.NamedChangeSet{ + Name: key.Name(), + Changeset: cs, + }) + } + } + } + if changeSets != nil && len(changeSets) > 0 { + sort.SliceStable(changeSets, func(i, j int) bool { + return changeSets[i].Name < changeSets[j].Name + }) + if rs.ssStore != nil { + rs.pendingChanges <- VersionedChangesets{ + Version: currentVersion, + Changesets: changeSets, + } + } + } + return rs.scStore.ApplyChangeSets(changeSets) +} + +func (rs *Store) Close() error { + err := rs.scStore.Close() + close(rs.pendingChanges) + if rs.ssStore != nil { + err = commonerrors.Join(err, rs.ssStore.Close()) + } + return err +} + +// LastCommitID Implements interface Committer +func (rs *Store) LastCommitID() types.CommitID { + if rs.lastCommitInfo == nil { + v, err := rs.scStore.GetLatestVersion() + if err != nil { + panic(fmt.Errorf("failed to get latest version: %w", err)) + } + return types.CommitID{Version: v} + } + + return rs.lastCommitInfo.CommitID() +} + +// Implements interface Committer +func (rs *Store) SetPruning(types.PruningOptions) { +} + +// Implements interface Committer +func (rs *Store) GetPruning() types.PruningOptions { + return types.PruneDefault +} + +// Implements interface Store +func (rs *Store) GetStoreType() types.StoreType { + return types.StoreTypeMulti +} + +// Implements interface CacheWrapper +func (rs *Store) CacheWrap(storeKey types.StoreKey) types.CacheWrap { + return rs.CacheMultiStore().CacheWrap(storeKey) +} + +// Implements interface CacheWrapper +func (rs *Store) CacheWrapWithTrace(storeKey types.StoreKey, _ io.Writer, _ types.TraceContext) types.CacheWrap { + return rs.CacheWrap(storeKey) +} + +func (rs *Store) CacheWrapWithListeners(k types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + return rs.CacheMultiStore().CacheWrapWithListeners(k, listeners) +} + +// Implements interface MultiStore +func (rs *Store) CacheMultiStore() types.CacheMultiStore { + rs.mtx.RLock() + defer rs.mtx.RUnlock() + stores := make(map[types.StoreKey]types.CacheWrapper) + for k, v := range rs.ckvStores { + store := types.KVStore(v) + stores[k] = store + } + return cachemulti.NewStore(nil, stores, rs.storeKeys, nil, nil, nil) +} + +// CacheMultiStoreWithVersion Implements interface MultiStore +// used to createQueryContext, abci_query or grpc query service. +func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStore, error) { + if version <= 0 || (rs.lastCommitInfo != nil && version == rs.lastCommitInfo.Version) { + return rs.CacheMultiStore(), nil + } + stores := make(map[types.StoreKey]types.CacheWrapper) + // add the transient/mem stores registered in current app. + for k, store := range rs.ckvStores { + if store.GetStoreType() != types.StoreTypeIAVL { + stores[k] = store + } + } + // TODO: May need to add historical SC store as well for nodes that doesn't enable ss but still need historical queries + + // add SS stores for historical queries + if rs.ssStore != nil { + for k, store := range rs.ckvStores { + if store.GetStoreType() == types.StoreTypeIAVL { + stores[k] = state.NewStore(rs.ssStore, k, version) + } + } + } + + return cachemulti.NewStore(nil, stores, rs.storeKeys, nil, nil, nil), nil +} + +// GetStore Implements interface MultiStore +func (rs *Store) GetStore(key types.StoreKey) types.Store { + return rs.ckvStores[key] +} + +// GetKVStore Implements interface MultiStore +func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore { + return rs.ckvStores[key] +} + +// Implements interface MultiStore +func (rs *Store) TracingEnabled() bool { + return false +} + +// Implements interface MultiStore +func (rs *Store) SetTracer(_ io.Writer) types.MultiStore { + return nil +} + +// Implements interface MultiStore +func (rs *Store) SetTracingContext(types.TraceContext) types.MultiStore { + return nil +} + +// Implements interface Snapshotter +// not needed, memiavl manage its own snapshot/pruning strategy +func (rs *Store) PruneSnapshotHeight(_ int64) { +} + +// Implements interface Snapshotter +// not needed, memiavl manage its own snapshot/pruning strategy +func (rs *Store) SetSnapshotInterval(_ uint64) { +} + +// Implements interface CommitMultiStore +func (rs *Store) MountStoreWithDB(key types.StoreKey, typ types.StoreType, _ dbm.DB) { + if key == nil { + panic("MountIAVLStore() key cannot be nil") + } + if _, ok := rs.storesParams[key]; ok { + panic(fmt.Sprintf("store duplicate store key %v", key)) + } + if _, ok := rs.storeKeys[key.Name()]; ok { + panic(fmt.Sprintf("store duplicate store key name %v", key)) + } + rs.storesParams[key] = newStoreParams(key, typ) + rs.storeKeys[key.Name()] = key +} + +// Implements interface CommitMultiStore +func (rs *Store) GetCommitStore(key types.StoreKey) types.CommitStore { + return rs.GetCommitKVStore(key) +} + +// GetCommitKVStore Implements interface CommitMultiStore +func (rs *Store) GetCommitKVStore(key types.StoreKey) types.CommitKVStore { + return rs.ckvStores[key] +} + +// Implements interface CommitMultiStore +// used by normal node startup. +func (rs *Store) LoadLatestVersion() error { + return rs.LoadVersionAndUpgrade(0, nil) +} + +// Implements interface CommitMultiStore +func (rs *Store) LoadLatestVersionAndUpgrade(upgrades *types.StoreUpgrades) error { + return rs.LoadVersionAndUpgrade(0, upgrades) +} + +// Implements interface CommitMultiStore +// used by node startup with UpgradeStoreLoader +func (rs *Store) LoadVersionAndUpgrade(version int64, upgrades *types.StoreUpgrades) error { + if version > math.MaxUint32 { + return fmt.Errorf("version overflows uint32: %d", version) + } + + storesKeys := make([]types.StoreKey, 0, len(rs.storesParams)) + for key := range rs.storesParams { + storesKeys = append(storesKeys, key) + } + // deterministic iteration order for upgrades + sort.Slice(storesKeys, func(i, j int) bool { + return storesKeys[i].Name() < storesKeys[j].Name() + }) + + initialStores := make([]string, 0, len(storesKeys)) + for _, key := range storesKeys { + if rs.storesParams[key].typ == types.StoreTypeIAVL { + initialStores = append(initialStores, key.Name()) + } + } + if err := rs.scStore.Initialize(initialStores); err != nil { + return err + } + + var treeUpgrades []*proto.TreeNameUpgrade + for _, key := range storesKeys { + switch { + case upgrades.IsDeleted(key.Name()): + treeUpgrades = append(treeUpgrades, &proto.TreeNameUpgrade{Name: key.Name(), Delete: true}) + case upgrades.IsAdded(key.Name()) || upgrades.RenamedFrom(key.Name()) != "": + treeUpgrades = append(treeUpgrades, &proto.TreeNameUpgrade{Name: key.Name(), RenameFrom: upgrades.RenamedFrom(key.Name())}) + } + } + + if len(treeUpgrades) > 0 { + if err := rs.scStore.ApplyUpgrades(treeUpgrades); err != nil { + return err + } + } + var err error + newStores := make(map[types.StoreKey]types.CommitKVStore, len(storesKeys)) + for _, key := range storesKeys { + newStores[key], err = rs.loadCommitStoreFromParams(key, rs.storesParams[key]) + if err != nil { + return err + } + } + + rs.mtx.Lock() + defer rs.mtx.Unlock() + rs.ckvStores = newStores + // to keep the root hash compatible with cosmos-sdk 0.46 + if rs.scStore.Version() != 0 { + rs.lastCommitInfo = convertCommitInfo(rs.scStore.LastCommitInfo()) + rs.lastCommitInfo = amendCommitInfo(rs.lastCommitInfo, rs.storesParams) + } else { + rs.lastCommitInfo = &types.CommitInfo{} + } + return nil +} + +func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, params storeParams) (types.CommitKVStore, error) { + switch params.typ { + case types.StoreTypeMulti: + panic("recursive MultiStores not yet supported") + case types.StoreTypeIAVL: + tree := rs.scStore.GetTreeByName(key.Name()) + if tree == nil { + return nil, fmt.Errorf("new store is not added in upgrades: %s", key.Name()) + } + return types.CommitKVStore(commitment.NewStore(tree, rs.logger)), nil + case types.StoreTypeDB: + panic("recursive MultiStores not yet supported") + case types.StoreTypeTransient: + _, ok := key.(*types.TransientStoreKey) + if !ok { + return nil, fmt.Errorf("invalid StoreKey for StoreTypeTransient: %s", key.String()) + } + return transient.NewStore(), nil + case types.StoreTypeMemory: + if _, ok := key.(*types.MemoryStoreKey); !ok { + return nil, fmt.Errorf("unexpected key type for a MemoryStoreKey; got: %s", key.String()) + } + return mem.NewStore(), nil + + default: + panic(fmt.Sprintf("unrecognized store type %v", params.typ)) + } +} + +// Implements interface CommitMultiStore +// used by export cmd +func (rs *Store) LoadVersion(ver int64) error { + return rs.LoadVersionAndUpgrade(ver, nil) +} + +// SetInterBlockCache is a noop since we do caching on its own, which works well with zero-copy. +func (rs *Store) SetInterBlockCache(_ types.MultiStorePersistentCache) {} + +// SetInitialVersion Implements interface CommitMultiStore +// used by InitChain when the initial height is bigger than 1 +func (rs *Store) SetInitialVersion(version int64) error { + return rs.scStore.SetInitialVersion(version) +} + +// Implements interface CommitMultiStore +func (rs *Store) SetIAVLCacheSize(_ int) { +} + +// Implements interface CommitMultiStore +func (rs *Store) SetIAVLDisableFastNode(_ bool) { +} + +// Implements interface CommitMultiStore +func (rs *Store) SetLazyLoading(_ bool) { +} + +// RollbackToVersion delete the versions after `target` and update the latest version. +// it should only be called in standalone cli commands. +func (rs *Store) RollbackToVersion(target int64) error { + if target <= 0 { + return fmt.Errorf("invalid rollback height target: %d", target) + } + + if target > math.MaxUint32 { + return fmt.Errorf("rollback height target %d exceeds max uint32", target) + } + return rs.scStore.Rollback(target) +} + +// getStoreByName performs a lookup of a StoreKey given a store name typically +// provided in a path. The StoreKey is then used to perform a lookup and return +// a Store. If the Store is wrapped in an inter-block cache, it will be unwrapped +// prior to being returned. If the StoreKey does not exist, nil is returned. +func (rs *Store) GetStoreByName(name string) types.Store { + key := rs.storeKeys[name] + if key == nil { + return nil + } + + return rs.GetCommitKVStore(key) +} + +// Implements interface Queryable +func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { + version := req.Height + if version <= 0 { + version = rs.scStore.Version() + } + path := req.Path + storeName, subPath, err := parsePath(path) + if err != nil { + return sdkerrors.QueryResult(err) + } + var store types.Queryable + + if !req.Prove && version < rs.lastCommitInfo.Version && rs.ssStore != nil { + // Serve abci query from ss store if no proofs needed + store = types.Queryable(state.NewStore(rs.ssStore, types.NewKVStoreKey(storeName), version)) + } else if version < rs.lastCommitInfo.Version { + // Serve abci query from historical sc store if proofs needed + scStore, err := rs.scStore.LoadVersion(version, true) + defer scStore.Close() + if err != nil { + return sdkerrors.QueryResult(err) + } + store = types.Queryable(commitment.NewStore(scStore.GetTreeByName(storeName), rs.logger)) + } else { + // Serve directly from latest sc store + store = types.Queryable(commitment.NewStore(rs.scStore.GetTreeByName(storeName), rs.logger)) + } + + // trim the path and execute the query + req.Path = subPath + res := store.Query(req) + + if !req.Prove || !rootmulti.RequireProof(subPath) { + return res + } + if res.ProofOps == nil || len(res.ProofOps.Ops) == 0 { + return sdkerrors.QueryResult(errors.Wrap(sdkerrors.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned")) + } + commitInfo := convertCommitInfo(rs.scStore.LastCommitInfo()) + commitInfo = amendCommitInfo(commitInfo, rs.storesParams) + // Restore origin path and append proof op. + res.ProofOps.Ops = append(res.ProofOps.Ops, commitInfo.ProofOp(storeName)) + return res +} + +// parsePath expects a format like /[/] +// Must start with /, subpath may be empty +// Returns error if it doesn't start with / +func parsePath(path string) (storeName string, subpath string, err error) { + if !strings.HasPrefix(path, "/") { + return storeName, subpath, errors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid path: %s", path) + } + + paths := strings.SplitN(path[1:], "/", 2) + storeName = paths[0] + + if len(paths) == 2 { + subpath = "/" + paths[1] + } + + return storeName, subpath, nil +} + +type storeParams struct { + key types.StoreKey + typ types.StoreType +} + +func newStoreParams(key types.StoreKey, typ types.StoreType) storeParams { + return storeParams{ + key: key, + typ: typ, + } +} + +func mergeStoreInfos(commitInfo *types.CommitInfo, storeInfos []types.StoreInfo) *types.CommitInfo { + infos := make([]types.StoreInfo, 0, len(commitInfo.StoreInfos)+len(storeInfos)) + infos = append(infos, commitInfo.StoreInfos...) + infos = append(infos, storeInfos...) + sort.SliceStable(infos, func(i, j int) bool { + return infos[i].Name < infos[j].Name + }) + return &types.CommitInfo{ + Version: commitInfo.Version, + StoreInfos: infos, + } +} + +// amendCommitInfo add mem stores commit infos to keep it compatible with cosmos-sdk 0.46 +func amendCommitInfo(commitInfo *types.CommitInfo, storeParams map[types.StoreKey]storeParams) *types.CommitInfo { + var extraStoreInfos []types.StoreInfo + for key := range storeParams { + typ := storeParams[key].typ + if typ != types.StoreTypeIAVL && typ != types.StoreTypeTransient { + extraStoreInfos = append(extraStoreInfos, types.StoreInfo{ + Name: key.Name(), + CommitId: types.CommitID{}, + }) + } + } + return mergeStoreInfos(commitInfo, extraStoreInfos) +} + +func convertCommitInfo(commitInfo *proto.CommitInfo) *types.CommitInfo { + storeInfos := make([]types.StoreInfo, len(commitInfo.StoreInfos)) + for i, storeInfo := range commitInfo.StoreInfos { + storeInfos[i] = types.StoreInfo{ + Name: storeInfo.Name, + CommitId: types.CommitID{ + Version: storeInfo.CommitId.Version, + Hash: storeInfo.CommitId.Hash, + }, + } + } + return &types.CommitInfo{ + Version: commitInfo.Version, + StoreInfos: storeInfos, + } +} + +// GetWorkingHash returns the working app hash +func (rs *Store) GetWorkingHash() ([]byte, error) { + if err := rs.flush(); err != nil { + return nil, err + } + commitInfo := convertCommitInfo(rs.scStore.WorkingCommitInfo()) + // for sdk 0.46 and backward compatibility + commitInfo = amendCommitInfo(commitInfo, rs.storesParams) + return commitInfo.Hash(), nil +} + +func (rs *Store) GetEvents() []abci.Event { + panic("should never attempt to get events from commit multi store") +} + +func (rs *Store) ResetEvents() { + panic("should never attempt to reset events from commit multi store") +} + +// ListeningEnabled will always return false for seiDB +func (rs *Store) ListeningEnabled(_ types.StoreKey) bool { + return false +} + +// AddListeners is no-opts for seiDB +func (rs *Store) AddListeners(_ types.StoreKey, _ []types.WriteListener) { + return +} + +// Restore Implements interface Snapshotter +func (rs *Store) Restore( + height uint64, format uint32, protoReader protoio.Reader, +) (snapshottypes.SnapshotItem, error) { + if rs.scStore != nil { + if err := rs.scStore.Close(); err != nil { + return snapshottypes.SnapshotItem{}, fmt.Errorf("failed to close db: %w", err) + } + } + item, err := rs.restore(int64(height), protoReader) + if err != nil { + return snapshottypes.SnapshotItem{}, err + } + + return item, rs.LoadLatestVersion() +} + +func (rs *Store) restore(height int64, protoReader protoio.Reader) (snapshottypes.SnapshotItem, error) { + var ( + ssImporter chan sstypes.SnapshotNode + snapshotItem snapshottypes.SnapshotItem + storeKey string + restoreErr error + ) + scImporter, err := rs.scStore.Importer(height) + if err != nil { + return snapshottypes.SnapshotItem{}, err + } + if rs.ssStore != nil { + ssImporter = make(chan sstypes.SnapshotNode, 10000) + go func() { + err := rs.ssStore.Import(height, ssImporter) + if err != nil { + panic(err) + } + }() + } +loop: + for { + snapshotItem = snapshottypes.SnapshotItem{} + err = protoReader.ReadMsg(&snapshotItem) + if err == io.EOF { + break + } else if err != nil { + restoreErr = errors.Wrap(err, "invalid protobuf message") + break loop + } + + switch item := snapshotItem.Item.(type) { + case *snapshottypes.SnapshotItem_Store: + storeKey = item.Store.Name + if err = scImporter.AddTree(storeKey); err != nil { + restoreErr = err + break loop + } + case *snapshottypes.SnapshotItem_IAVL: + if item.IAVL.Height > math.MaxInt8 { + restoreErr = errors.Wrapf(sdkerrors.ErrLogic, "node height %v cannot exceed %v", + item.IAVL.Height, math.MaxInt8) + break loop + } + node := &sctypes.SnapshotNode{ + Key: item.IAVL.Key, + Value: item.IAVL.Value, + Height: int8(item.IAVL.Height), + Version: item.IAVL.Version, + } + // Protobuf does not differentiate between []byte{} as nil, but fortunately IAVL does + // not allow nil keys nor nil values for leaf nodes, so we can always set them to empty. + if node.Key == nil { + node.Key = []byte{} + } + if node.Height == 0 && node.Value == nil { + node.Value = []byte{} + } + scImporter.AddNode(node) + + // Check if we should also import to SS store + if rs.ssStore != nil && node.Height == 0 && ssImporter != nil { + ssImporter <- sstypes.SnapshotNode{ + StoreKey: storeKey, + Key: node.Key, + Value: node.Value, + } + } + default: + // unknown element, could be an extension + break loop + } + } + + if err = scImporter.Close(); err != nil { + if restoreErr == nil { + restoreErr = err + } + } + if ssImporter != nil { + close(ssImporter) + } + + return snapshotItem, restoreErr +} + +// Snapshot Implements the interface from Snapshotter +func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error { + if height > math.MaxUint32 { + return fmt.Errorf("height overflows uint32: %d", height) + } + + exporter, err := rs.scStore.Exporter(int64(height)) + if err != nil { + return err + } + defer exporter.Close() + for { + item, err := exporter.Next() + if err != nil { + if err == commonerrors.ErrorExportDone { + break + } + return err + } + + switch item := item.(type) { + case *sctypes.SnapshotNode: + if err := protoWriter.WriteMsg(&snapshottypes.SnapshotItem{ + Item: &snapshottypes.SnapshotItem_IAVL{ + IAVL: &snapshottypes.SnapshotIAVLItem{ + Key: item.Key, + Value: item.Value, + Height: int32(item.Height), + Version: item.Version, + }, + }, + }); err != nil { + return err + } + case string: + if err := protoWriter.WriteMsg(&snapshottypes.SnapshotItem{ + Item: &snapshottypes.SnapshotItem_Store{ + Store: &snapshottypes.SnapshotStoreItem{ + Name: item, + }, + }, + }); err != nil { + return err + } + default: + return fmt.Errorf("unknown item type %T", item) + } + } + + return nil +} diff --git a/storev2/rootmulti/store_test.go b/storev2/rootmulti/store_test.go new file mode 100644 index 000000000..d8a77ccd7 --- /dev/null +++ b/storev2/rootmulti/store_test.go @@ -0,0 +1,15 @@ +package rootmulti + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/store/types" + "github.com/sei-protocol/sei-db/config" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" +) + +func TestLastCommitID(t *testing.T) { + store := NewStore(t.TempDir(), log.NewNopLogger(), config.StateCommitConfig{}, config.StateStoreConfig{}) + require.Equal(t, types.CommitID{}, store.LastCommitID()) +} diff --git a/storev2/state/store.go b/storev2/state/store.go new file mode 100644 index 000000000..72e4b0ce9 --- /dev/null +++ b/storev2/state/store.go @@ -0,0 +1,127 @@ +package state + +import ( + "cosmossdk.io/errors" + "fmt" + "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" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/kv" + sstypes "github.com/sei-protocol/sei-db/ss/types" + abci "github.com/tendermint/tendermint/abci/types" +) + +const StoreTypeSSStore = 100 + +var ( + _ types.KVStore = (*Store)(nil) + _ types.Queryable = (*Store)(nil) +) + +// Store wraps a SS store and implements a cosmos KVStore +type Store struct { + store sstypes.StateStore + storeKey types.StoreKey + version int64 +} + +func NewStore(store sstypes.StateStore, storeKey types.StoreKey, version int64) *Store { + return &Store{store, storeKey, version} +} + +func (st *Store) GetStoreType() types.StoreType { + return StoreTypeSSStore +} + +func (st *Store) CacheWrap(storeKey types.StoreKey) types.CacheWrap { + return cachekv.NewStore(st, storeKey, types.DefaultCacheSizeLimit) +} + +func (st *Store) CacheWrapWithTrace(storeKey types.StoreKey, w io.Writer, tc types.TraceContext) types.CacheWrap { + return cachekv.NewStore(tracekv.NewStore(st, w, tc), storeKey, types.DefaultCacheSizeLimit) +} + +func (st *Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + return cachekv.NewStore(listenkv.NewStore(st, storeKey, listeners), storeKey, types.DefaultCacheSizeLimit) +} + +func (st *Store) Get(key []byte) []byte { + value, err := st.store.Get(st.storeKey.Name(), st.version, key) + if err != nil { + panic(err) + } + return value +} + +func (st *Store) Has(key []byte) bool { + has, err := st.store.Has(st.storeKey.Name(), st.version, key) + if err != nil { + panic(err) + } + return has +} + +func (st *Store) Set(_, _ []byte) { + panic("write operation is not supported") +} + +func (st *Store) Delete(_ []byte) { + panic("write operation is not supported") +} + +func (st *Store) Iterator(start, end []byte) types.Iterator { + itr, err := st.store.Iterator(st.storeKey.Name(), st.version, start, end) + if err != nil { + panic(err) + } + return itr +} + +func (st *Store) ReverseIterator(start, end []byte) types.Iterator { + itr, err := st.store.ReverseIterator(st.storeKey.Name(), st.version, start, end) + if err != nil { + panic(err) + } + return itr +} + +func (st *Store) GetWorkingHash() ([]byte, error) { + panic("get working hash operation is not supported") +} + +func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { + if req.Height > 0 && req.Height > st.version { + return sdkerrors.QueryResult(errors.Wrap(sdkerrors.ErrInvalidHeight, "invalid height")) + } + switch req.Path { + case "/key": // get by key + res.Key = req.Data // data holds the key bytes + res.Value = st.Get(res.Key) + case "/subspace": + pairs := kv.Pairs{ + Pairs: make([]kv.Pair, 0), + } + + subspace := req.Data + res.Key = subspace + iterator := types.KVStorePrefixIterator(st, subspace) + for ; iterator.Valid(); iterator.Next() { + pairs.Pairs = append(pairs.Pairs, kv.Pair{Key: iterator.Key(), Value: iterator.Value()}) + } + iterator.Close() + + bz, err := pairs.Marshal() + if err != nil { + panic(fmt.Errorf("failed to marshal KV pairs: %w", err)) + } + res.Value = bz + default: + return sdkerrors.QueryResult(errors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path)) + } + + return res +} diff --git a/tasks/scheduler.go b/tasks/scheduler.go new file mode 100644 index 000000000..1c5727d27 --- /dev/null +++ b/tasks/scheduler.go @@ -0,0 +1,457 @@ +package tasks + +import ( + "context" + "fmt" + "sort" + "sync" + "sync/atomic" + "time" + + "github.com/cosmos/cosmos-sdk/store/multiversion" + store "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/occ" + "github.com/cosmos/cosmos-sdk/utils/tracing" + "github.com/tendermint/tendermint/abci/types" +) + +type status string + +const ( + // statusPending tasks are ready for execution + // all executing tasks are in pending state + statusPending status = "pending" + // statusExecuted tasks are ready for validation + // these tasks did not abort during execution + statusExecuted status = "executed" + // statusAborted means the task has been aborted + // these tasks transition to pending upon next execution + statusAborted status = "aborted" + // statusValidated means the task has been validated + // tasks in this status can be reset if an earlier task fails validation + statusValidated status = "validated" + // statusWaiting tasks are waiting for another tx to complete + statusWaiting status = "waiting" +) + +var ( + TotalExecute = atomic.Int64{} + TotalReset = atomic.Int64{} + TotalRerun = atomic.Int64{} + TotalValidate = atomic.Int64{} +) + +type deliverTxTask struct { + Ctx sdk.Context + AbortCh chan occ.Abort + + Status status + Dependencies []int + Abort *occ.Abort + Index int + Incarnation int + Request types.RequestDeliverTx + Response *types.ResponseDeliverTx + VersionStores map[sdk.StoreKey]*multiversion.VersionIndexedStore + ValidateCh chan struct{} +} + +func (dt *deliverTxTask) Reset() { + TotalReset.Add(1) + dt.Status = statusPending + dt.Response = nil + dt.Abort = nil + dt.AbortCh = nil + dt.Dependencies = nil + dt.VersionStores = nil +} + +func (dt *deliverTxTask) Increment() { + dt.Incarnation++ + dt.ValidateCh = make(chan struct{}, 1) +} + +// Scheduler processes tasks concurrently +type Scheduler interface { + ProcessAll(ctx sdk.Context, reqs []*sdk.DeliverTxEntry) ([]types.ResponseDeliverTx, error) +} + +type scheduler struct { + deliverTx func(ctx sdk.Context, req types.RequestDeliverTx) (res types.ResponseDeliverTx) + workers int + multiVersionStores map[sdk.StoreKey]multiversion.MultiVersionStore + tracingInfo *tracing.Info + allTasks []*deliverTxTask + executeCh chan func() + validateCh chan func() +} + +// NewScheduler creates a new scheduler +func NewScheduler(workers int, tracingInfo *tracing.Info, deliverTxFunc func(ctx sdk.Context, req types.RequestDeliverTx) (res types.ResponseDeliverTx)) Scheduler { + return &scheduler{ + workers: workers, + deliverTx: deliverTxFunc, + tracingInfo: tracingInfo, + } +} + +func (s *scheduler) invalidateTask(task *deliverTxTask) { + for _, mv := range s.multiVersionStores { + mv.InvalidateWriteset(task.Index, task.Incarnation) + mv.ClearReadset(task.Index) + mv.ClearIterateset(task.Index) + } +} + +func start(ctx context.Context, ch chan func(), workers int) { + for i := 0; i < workers; i++ { + go func() { + for { + select { + case <-ctx.Done(): + return + case work := <-ch: + work() + } + } + }() + } +} + +func (s *scheduler) DoValidate(work func()) { + s.validateCh <- work +} + +func (s *scheduler) DoExecute(work func()) { + s.executeCh <- work +} + +func (s *scheduler) findConflicts(task *deliverTxTask) (bool, []int) { + var conflicts []int + uniq := make(map[int]struct{}) + valid := true + for _, mv := range s.multiVersionStores { + ok, mvConflicts := mv.ValidateTransactionState(task.Index) + for _, c := range mvConflicts { + if _, ok := uniq[c]; !ok { + conflicts = append(conflicts, c) + uniq[c] = struct{}{} + } + } + // any non-ok value makes valid false + valid = ok && valid + } + sort.Ints(conflicts) + return valid, conflicts +} + +func toTasks(reqs []*sdk.DeliverTxEntry) []*deliverTxTask { + res := make([]*deliverTxTask, 0, len(reqs)) + for idx, r := range reqs { + res = append(res, &deliverTxTask{ + Request: r.Request, + Index: idx, + Status: statusPending, + ValidateCh: make(chan struct{}, 1), + }) + } + return res +} + +func collectResponses(tasks []*deliverTxTask) []types.ResponseDeliverTx { + res := make([]types.ResponseDeliverTx, 0, len(tasks)) + for _, t := range tasks { + res = append(res, *t.Response) + } + return res +} + +func (s *scheduler) tryInitMultiVersionStore(ctx sdk.Context) { + if s.multiVersionStores != nil { + return + } + mvs := make(map[sdk.StoreKey]multiversion.MultiVersionStore) + keys := ctx.MultiStore().StoreKeys() + for _, sk := range keys { + mvs[sk] = multiversion.NewMultiVersionStore(ctx.MultiStore().GetKVStore(sk)) + } + s.multiVersionStores = mvs +} + +func indexesValidated(tasks []*deliverTxTask, idx []int) bool { + for _, i := range idx { + if tasks[i].Status != statusValidated { + return false + } + } + return true +} + +func allValidated(tasks []*deliverTxTask) bool { + for _, t := range tasks { + if t.Status != statusValidated { + return false + } + } + return true +} + +func (s *scheduler) PrefillEstimates(ctx sdk.Context, reqs []*sdk.DeliverTxEntry) { + // iterate over TXs, update estimated writesets where applicable + for i, req := range reqs { + mappedWritesets := req.EstimatedWritesets + // order shouldnt matter for storeKeys because each storeKey partitioned MVS is independent + for storeKey, writeset := range mappedWritesets { + // we use `-1` to indicate a prefill incarnation + s.multiVersionStores[storeKey].SetEstimatedWriteset(i, -1, writeset) + } + } +} + +func (s *scheduler) ProcessAll(ctx sdk.Context, reqs []*sdk.DeliverTxEntry) ([]types.ResponseDeliverTx, error) { + startTime := time.Now() + + // initialize mutli-version stores if they haven't been initialized yet + s.tryInitMultiVersionStore(ctx) + s.PrefillEstimates(ctx, reqs) + + tasks := toTasks(reqs) + s.allTasks = tasks + s.executeCh = make(chan func(), len(tasks)) + s.validateCh = make(chan func(), len(tasks)) + TotalExecute.Store(0) + TotalValidate.Store(0) + TotalRerun.Store(0) + TotalReset.Store(0) + defer func() { + fmt.Printf("[Debug] ProcessAll %d txs took %s, total execute %d, total validate %d, total reset %d, total rerun %d \n", + len(reqs), time.Since(startTime), TotalExecute.Load(), TotalValidate.Load(), TotalReset.Load(), TotalRerun.Load()) + }() + workers := s.workers + if s.workers < 1 { + workers = len(tasks) + } + + workerCtx, cancel := context.WithCancel(ctx.Context()) + defer cancel() + start(workerCtx, s.executeCh, workers) + start(workerCtx, s.validateCh, workers) + + toExecute := tasks + var totalExecuteAllLatency = int64(0) + var totalValidateAllLatency = int64(0) + for !allValidated(tasks) { + var err error + + // execute sets statuses of tasks to either executed or aborted + if len(toExecute) > 0 { + executeAllStartTime := time.Now() + err = s.executeAll(ctx, toExecute) + totalExecuteAllLatency += time.Since(executeAllStartTime).Microseconds() + if err != nil { + return nil, err + } + } + + // validate returns any that should be re-executed + // note this processes ALL tasks, not just those recently executed + validateAllStartTime := time.Now() + toExecute, err = s.validateAll(ctx, tasks) + totalValidateAllLatency += time.Since(validateAllStartTime).Microseconds() + if err != nil { + return nil, err + } + } + for _, mv := range s.multiVersionStores { + mv.WriteLatestToStore() + } + return collectResponses(tasks), nil +} + +func (s *scheduler) shouldRerun(task *deliverTxTask) bool { + switch task.Status { + + case statusAborted, statusPending: + return true + + // validated tasks can become unvalidated if an earlier re-run task now conflicts + case statusExecuted, statusValidated: + if valid, conflicts := s.findConflicts(task); !valid { + s.invalidateTask(task) + + // if the conflicts are now validated, then rerun this task + if indexesValidated(s.allTasks, conflicts) { + return true + } else { + // otherwise, wait for completion + task.Dependencies = conflicts + task.Status = statusWaiting + return false + } + } else if len(conflicts) == 0 { + // mark as validated, which will avoid re-validating unless a lower-index re-validates + task.Status = statusValidated + return false + } + // conflicts and valid, so it'll validate next time + return false + + case statusWaiting: + // if conflicts are done, then this task is ready to run again + return indexesValidated(s.allTasks, task.Dependencies) + } + panic("unexpected status: " + task.Status) +} + +func (s *scheduler) validateTask(ctx sdk.Context, task *deliverTxTask) bool { + TotalValidate.Add(1) + if s.shouldRerun(task) { + TotalRerun.Add(1) + return false + } + return true +} + +func (s *scheduler) findFirstNonValidated() (int, bool) { + for i, t := range s.allTasks { + if t.Status != statusValidated { + return i, true + } + } + return 0, false +} + +func (s *scheduler) validateAll(ctx sdk.Context, tasks []*deliverTxTask) ([]*deliverTxTask, error) { + //ctx, span := s.traceSpan(ctx, "SchedulerValidateAll", nil) + //defer span.End() + + var mx sync.Mutex + var res []*deliverTxTask + + wg := sync.WaitGroup{} + for i := 0; i < len(tasks); i++ { + t := tasks[i] + wg.Add(1) + s.DoValidate(func() { + defer wg.Done() + if !s.validateTask(ctx, t) { + t.Reset() + t.Increment() + mx.Lock() + res = append(res, t) + mx.Unlock() + } + }) + } + wg.Wait() + + return res, nil +} + +// ExecuteAll executes all tasks concurrently +// Tasks are updated with their status +// TODO: error scenarios +func (s *scheduler) executeAll(ctx sdk.Context, tasks []*deliverTxTask) error { + //ctx, span := s.traceSpan(ctx, "SchedulerExecuteAll", nil) + //defer span.End() + + // validationWg waits for all validations to complete + // validations happen in separate goroutines in order to wait on previous index + validationWg := &sync.WaitGroup{} + validationWg.Add(len(tasks)) + + for _, task := range tasks { + t := task + s.DoExecute(func() { + s.prepareAndRunTask(validationWg, ctx, t) + }) + } + + validationWg.Wait() + + return nil +} + +func (s *scheduler) prepareAndRunTask(wg *sync.WaitGroup, ctx sdk.Context, task *deliverTxTask) { + //eCtx, eSpan := s.traceSpan(ctx, "SchedulerExecute", task) + //defer eSpan.End() + task.Ctx = ctx + + s.executeTask(task.Ctx, task) + TotalExecute.Add(1) + go func() { + defer wg.Done() + defer close(task.ValidateCh) + // wait on previous task to finish validation + if task.Index > 0 { + <-s.allTasks[task.Index-1].ValidateCh + } + if !s.validateTask(task.Ctx, task) { + task.Reset() + } + task.ValidateCh <- struct{}{} + }() +} + +// prepareTask initializes the context and version stores for a task +func (s *scheduler) prepareTask(ctx sdk.Context, task *deliverTxTask) { + ctx = ctx.WithTxIndex(task.Index) + + //_, span := s.traceSpan(ctx, "SchedulerPrepare", task) + //defer span.End() + + // initialize the context + abortCh := make(chan occ.Abort, len(s.multiVersionStores)) + + // if there are no stores, don't try to wrap, because there's nothing to wrap + if len(s.multiVersionStores) > 0 { + // non-blocking + cms := ctx.MultiStore().CacheMultiStore() + + // init version stores by store key + vs := make(map[store.StoreKey]*multiversion.VersionIndexedStore) + for storeKey, mvs := range s.multiVersionStores { + vs[storeKey] = mvs.VersionedIndexedStore(task.Index, task.Incarnation, abortCh) + } + + // save off version store so we can ask it things later + task.VersionStores = vs + ms := cms.SetKVStores(func(k store.StoreKey, kvs sdk.KVStore) store.CacheWrap { + return vs[k] + }) + + ctx = ctx.WithMultiStore(ms) + } + + task.AbortCh = abortCh + task.Ctx = ctx +} + +// executeTask executes a single task +func (s *scheduler) executeTask(ctx sdk.Context, task *deliverTxTask) { + + s.prepareTask(ctx, task) + + //dCtx, dSpan := s.traceSpan(task.Ctx, "SchedulerDeliverTx", task) + //defer dSpan.End() + //task.Ctx = dCtx + + resp := s.deliverTx(task.Ctx, task.Request) + + close(task.AbortCh) + + if abt, ok := <-task.AbortCh; ok { + task.Status = statusAborted + task.Abort = &abt + return + } + + // write from version store to multiversion stores + for _, v := range task.VersionStores { + v.WriteToMultiVersionStore() + } + + task.Status = statusExecuted + task.Response = &resp +} diff --git a/tasks/scheduler_test.go b/tasks/scheduler_test.go new file mode 100644 index 000000000..42db778cb --- /dev/null +++ b/tasks/scheduler_test.go @@ -0,0 +1,146 @@ +package tasks + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tm-db" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/cosmos/cosmos-sdk/store/cachekv" + "github.com/cosmos/cosmos-sdk/store/cachemulti" + "github.com/cosmos/cosmos-sdk/store/dbadapter" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/utils/tracing" +) + +type mockDeliverTxFunc func(ctx sdk.Context, req types.RequestDeliverTx) types.ResponseDeliverTx + +var testStoreKey = sdk.NewKVStoreKey("mock") +var itemKey = []byte("key") + +func requestList(n int) []*sdk.DeliverTxEntry { + tasks := make([]*sdk.DeliverTxEntry, n) + for i := 0; i < n; i++ { + tasks[i] = &sdk.DeliverTxEntry{ + Request: types.RequestDeliverTx{ + Tx: []byte(fmt.Sprintf("%d", i)), + }, + } + + } + return tasks +} + +func initTestCtx(injectStores bool) sdk.Context { + ctx := sdk.Context{}.WithContext(context.Background()) + keys := make(map[string]sdk.StoreKey) + stores := make(map[sdk.StoreKey]sdk.CacheWrapper) + db := dbm.NewMemDB() + if injectStores { + mem := dbadapter.Store{DB: db} + stores[testStoreKey] = cachekv.NewStore(mem, testStoreKey, 1000) + keys[testStoreKey.Name()] = testStoreKey + } + store := cachemulti.NewStore(db, stores, keys, nil, nil, nil) + ctx = ctx.WithMultiStore(&store) + return ctx +} + +func TestProcessAll(t *testing.T) { + tests := []struct { + name string + workers int + runs int + requests []*sdk.DeliverTxEntry + deliverTxFunc mockDeliverTxFunc + addStores bool + expectedErr error + assertions func(t *testing.T, ctx sdk.Context, res []types.ResponseDeliverTx) + }{ + { + name: "Test every tx accesses same key", + workers: 50, + runs: 50, + addStores: true, + requests: requestList(100), + deliverTxFunc: func(ctx sdk.Context, req types.RequestDeliverTx) types.ResponseDeliverTx { + // all txs read and write to the same key to maximize conflicts + kv := ctx.MultiStore().GetKVStore(testStoreKey) + val := string(kv.Get(itemKey)) + + // write to the store with this tx's index + kv.Set(itemKey, req.Tx) + + // return what was read from the store (final attempt should be index-1) + return types.ResponseDeliverTx{ + Info: val, + } + }, + assertions: func(t *testing.T, ctx sdk.Context, res []types.ResponseDeliverTx) { + for idx, response := range res { + if idx == 0 { + require.Equal(t, "", response.Info) + } else { + // the info is what was read from the kv store by the tx + // each tx writes its own index, so the info should be the index of the previous tx + require.Equal(t, fmt.Sprintf("%d", idx-1), response.Info) + } + } + // confirm last write made it to the parent store + latest := ctx.MultiStore().GetKVStore(testStoreKey).Get(itemKey) + require.Equal(t, []byte(fmt.Sprintf("%d", len(res)-1)), latest) + }, + expectedErr: nil, + }, + //{ + // name: "Test no stores on context should not panic", + // workers: 50, + // runs: 1, + // addStores: false, + // requests: requestList(50), + // deliverTxFunc: func(ctx sdk.Context, req types.RequestDeliverTx) types.ResponseDeliverTx { + // return types.ResponseDeliverTx{ + // Info: fmt.Sprintf("%d", ctx.TxIndex()), + // } + // }, + // assertions: func(t *testing.T, ctx sdk.Context, res []types.ResponseDeliverTx) { + // for idx, response := range res { + // require.Equal(t, fmt.Sprintf("%d", idx), response.Info) + // } + // }, + // expectedErr: nil, + //}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i := 0; i < tt.runs; i++ { + // set a tracer provider + tp := trace.NewNoopTracerProvider() + otel.SetTracerProvider(trace.NewNoopTracerProvider()) + tr := tp.Tracer("scheduler-test") + ti := &tracing.Info{ + Tracer: &tr, + } + + s := NewScheduler(tt.workers, ti, tt.deliverTxFunc) + ctx := initTestCtx(tt.addStores) + + res, err := s.ProcessAll(ctx, tt.requests) + require.Len(t, res, len(tt.requests)) + + if !errors.Is(err, tt.expectedErr) { + t.Errorf("Expected error %v, got %v", tt.expectedErr, err) + } else { + tt.assertions(t, ctx, res) + } + } + }) + } +} diff --git a/types/accesscontrol/constants.pb.go b/types/accesscontrol/constants.pb.go index e7ee6a802..a270fa662 100644 --- a/types/accesscontrol/constants.pb.go +++ b/types/accesscontrol/constants.pb.go @@ -531,4 +531,4 @@ var fileDescriptor_36568f7561081112 = []byte{ 0xed, 0x1f, 0xef, 0xfb, 0x1d, 0x3f, 0xff, 0xf3, 0x78, 0xf0, 0x97, 0xbf, 0xed, 0x3b, 0xa7, 0x53, 0x4b, 0xff, 0xd1, 0x52, 0xb6, 0xeb, 0x3f, 0xff, 0x21, 0x00, 0x00, 0xff, 0xff, 0x60, 0xc1, 0x7c, 0xe3, 0x13, 0x0c, 0x00, 0x00, -} +} \ No newline at end of file diff --git a/types/accesscontrol/validation.go b/types/accesscontrol/validation.go index 40a525a92..ec83885c6 100644 --- a/types/accesscontrol/validation.go +++ b/types/accesscontrol/validation.go @@ -10,6 +10,7 @@ var ( ) type StoreKeyToResourceTypePrefixMap map[string]map[ResourceType][]byte +type ResourceTypeToStoreKeyMap map[ResourceType]string func DefaultStoreKeyToResourceTypePrefixMap() StoreKeyToResourceTypePrefixMap { return StoreKeyToResourceTypePrefixMap{ diff --git a/types/context.go b/types/context.go index ef847d3a3..e36e88dc8 100644 --- a/types/context.go +++ b/types/context.go @@ -34,6 +34,7 @@ type Context struct { voteInfo []abci.VoteInfo gasMeter GasMeter blockGasMeter GasMeter + occEnabled bool checkTx bool recheckTx bool // if recheckTx == true, then checkTx must also be true minGasPrice DecCoins @@ -104,6 +105,10 @@ func (c Context) IsReCheckTx() bool { return c.recheckTx } +func (c Context) IsOCCEnabled() bool { + return c.occEnabled +} + func (c Context) MinGasPrices() DecCoins { return c.minGasPrice } @@ -281,6 +286,12 @@ func (c Context) WithIsCheckTx(isCheckTx bool) Context { return c } +// WithIsOCCEnabled enables or disables whether OCC is used as the concurrency algorithm +func (c Context) WithIsOCCEnabled(isOCCEnabled bool) Context { + c.occEnabled = isOCCEnabled + return c +} + // WithIsRecheckTx called with true will also set true on checkTx in order to // enforce the invariant that if recheckTx = true then checkTx = true as well. func (c Context) WithIsReCheckTx(isRecheckTx bool) Context { diff --git a/types/context_test.go b/types/context_test.go index 92f5dccaf..e49a82903 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -87,6 +87,7 @@ func (s *contextTestSuite) TestContextWithCustom() { height := int64(1) chainid := "chainid" ischeck := true + isOCC := true txbytes := []byte("txbytes") logger := mocks.NewMockLogger(ctrl) voteinfos := []abci.VoteInfo{{}} @@ -106,10 +107,13 @@ func (s *contextTestSuite) TestContextWithCustom() { WithGasMeter(meter). WithMinGasPrices(minGasPrices). WithBlockGasMeter(blockGasMeter). - WithHeaderHash(headerHash) + WithHeaderHash(headerHash). + WithIsOCCEnabled(isOCC) + s.Require().Equal(height, ctx.BlockHeight()) s.Require().Equal(chainid, ctx.ChainID()) s.Require().Equal(ischeck, ctx.IsCheckTx()) + s.Require().Equal(isOCC, ctx.IsOCCEnabled()) s.Require().Equal(txbytes, ctx.TxBytes()) s.Require().Equal(logger, ctx.Logger()) s.Require().Equal(voteinfos, ctx.VoteInfos()) diff --git a/types/occ/types.go b/types/occ/types.go new file mode 100644 index 000000000..de321b7cb --- /dev/null +++ b/types/occ/types.go @@ -0,0 +1,22 @@ +package occ + +import ( + "errors" +) + +var ( + ErrReadEstimate = errors.New("multiversion store value contains estimate, cannot read, aborting") +) + +// Abort contains the information for a transaction's conflict +type Abort struct { + DependentTxIdx int + Err error +} + +func NewEstimateAbort(dependentTxIdx int) Abort { + return Abort{ + DependentTxIdx: dependentTxIdx, + Err: ErrReadEstimate, + } +} diff --git a/types/store.go b/types/store.go index 5fb34b5fa..f1646b41c 100644 --- a/types/store.go +++ b/types/store.go @@ -21,6 +21,7 @@ type ( MultiStore = types.MultiStore CacheMultiStore = types.CacheMultiStore CommitMultiStore = types.CommitMultiStore + QueryMultiStore = types.QueryMultiStore MultiStorePersistentCache = types.MultiStorePersistentCache KVStore = types.KVStore Iterator = types.Iterator diff --git a/types/tx_batch.go b/types/tx_batch.go new file mode 100644 index 000000000..b053aa5fa --- /dev/null +++ b/types/tx_batch.go @@ -0,0 +1,34 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/store/multiversion" + abci "github.com/tendermint/tendermint/abci/types" +) + +// DeliverTxEntry represents an individual transaction's request within a batch. +// This can be extended to include tx-level tracing or metadata +type DeliverTxEntry struct { + Request abci.RequestDeliverTx + EstimatedWritesets MappedWritesets +} + +// EstimatedWritesets represents an estimated writeset for a transaction mapped by storekey to the writeset estimate. +type MappedWritesets map[StoreKey]multiversion.WriteSet + +// DeliverTxBatchRequest represents a request object for a batch of transactions. +// This can be extended to include request-level tracing or metadata +type DeliverTxBatchRequest struct { + TxEntries []*DeliverTxEntry +} + +// DeliverTxResult represents an individual transaction's response within a batch. +// This can be extended to include tx-level tracing or metadata +type DeliverTxResult struct { + Response abci.ResponseDeliverTx +} + +// DeliverTxBatchResponse represents a response object for a batch of transactions. +// This can be extended to include response-level tracing or metadata +type DeliverTxBatchResponse struct { + Results []*DeliverTxResult +} diff --git a/x/accesscontrol/keeper/keeper.go b/x/accesscontrol/keeper/keeper.go index 1ca93f602..44189a6d6 100644 --- a/x/accesscontrol/keeper/keeper.go +++ b/x/accesscontrol/keeper/keeper.go @@ -12,6 +12,7 @@ import ( "github.com/yourbasic/graph" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/multiversion" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" acltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" @@ -40,6 +41,7 @@ type ( MessageDependencyGeneratorMapper DependencyGeneratorMap AccountKeeper authkeeper.AccountKeeper StakingKeeper stakingkeeper.Keeper + ResourceTypeStoreKeyMapping acltypes.ResourceTypeToStoreKeyMap } ) @@ -493,6 +495,67 @@ func (k Keeper) IterateWasmDependencies(ctx sdk.Context, handler func(wasmDepend } } +type storeKeyMap map[string]sdk.StoreKey + +func (k Keeper) GetStoreKeyMap(ctx sdk.Context) storeKeyMap { + storeKeyMap := make(storeKeyMap) + for _, storeKey := range ctx.MultiStore().StoreKeys() { + storeKeyMap[storeKey.Name()] = storeKey + } + return storeKeyMap +} + +func (k Keeper) UpdateWritesetsWithAccessOps(accessOps []acltypes.AccessOperation, mappedWritesets sdk.MappedWritesets, storeKeyMap storeKeyMap) sdk.MappedWritesets { + for _, accessOp := range accessOps { + // we only want writes and unknowns (assumed writes) + if accessOp.AccessType != acltypes.AccessType_WRITE && accessOp.AccessType != acltypes.AccessType_UNKNOWN { + continue + } + // the accessOps should only have SPECIFIC identifiers (we don't want wildcards) + if accessOp.IdentifierTemplate == "*" { + continue + } + // check the resource type to store key map for potential store key + if storeKeyStr, ok := k.ResourceTypeStoreKeyMapping[accessOp.ResourceType]; ok { + // check that we have a storekey corresponding to that string + if storeKey, ok2 := storeKeyMap[storeKeyStr]; ok2 { + // if we have a StoreKey, add it to the writeset - writing empty bytes is ok because it will be saved as EstimatedWriteset + if _, ok := mappedWritesets[storeKey]; !ok { + mappedWritesets[storeKey] = make(multiversion.WriteSet) + } + mappedWritesets[storeKey][accessOp.IdentifierTemplate] = []byte{} + } + } + + } + return mappedWritesets +} + +// GenerateEstimatedWritesets utilizes the existing patterns for access operation generation to estimate the writesets for a transaction +func (k Keeper) GenerateEstimatedWritesets(ctx sdk.Context, txDecoder sdk.TxDecoder, anteDepGen sdk.AnteDepGenerator, txIndex int, txBytes []byte) (sdk.MappedWritesets, error) { + storeKeyMap := k.GetStoreKeyMap(ctx) + writesets := make(sdk.MappedWritesets) + tx, err := txDecoder(txBytes) + if err != nil { + return nil, err + } + // generate antedeps accessOps for tx + anteDeps, err := anteDepGen([]acltypes.AccessOperation{}, tx, txIndex) + if err != nil { + return nil, err + } + writesets = k.UpdateWritesetsWithAccessOps(anteDeps, writesets, storeKeyMap) + + // generate accessOps for each message + msgs := tx.GetMsgs() + for _, msg := range msgs { + msgDependencies := k.GetMessageDependencies(ctx, msg) + // update estimated writeset for each message deps + writesets = k.UpdateWritesetsWithAccessOps(msgDependencies, writesets, storeKeyMap) + } + return writesets, nil +} + func (k Keeper) BuildDependencyDag(ctx sdk.Context, txDecoder sdk.TxDecoder, anteDepGen sdk.AnteDepGenerator, txs [][]byte) (*types.Dag, error) { defer MeasureBuildDagDuration(time.Now(), "BuildDependencyDag") // contains the latest msg index for a specific Access Operation diff --git a/x/accesscontrol/keeper/keeper_test.go b/x/accesscontrol/keeper/keeper_test.go index f08cd1ade..6e696b8bb 100644 --- a/x/accesscontrol/keeper/keeper_test.go +++ b/x/accesscontrol/keeper/keeper_test.go @@ -20,6 +20,7 @@ import ( aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" acltestutil "github.com/cosmos/cosmos-sdk/x/accesscontrol/testutil" "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -2669,6 +2670,42 @@ func (suite *KeeperTestSuite) TestBuildSelectorOps_AccessOperationSelectorType_C req.NoError(err) } +func TestGenerateEstimatedDependencies(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + + accounts := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(30000000)) + // setup test txs + msgs := []sdk.Msg{ + banktypes.NewMsgSend(accounts[0], accounts[1], sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1)))), + } + // set up testing mapping + app.AccessControlKeeper.ResourceTypeStoreKeyMapping = map[acltypes.ResourceType]string{ + acltypes.ResourceType_KV_BANK_BALANCES: banktypes.StoreKey, + acltypes.ResourceType_KV_AUTH_ADDRESS_STORE: authtypes.StoreKey, + } + + storeKeyMap := app.AccessControlKeeper.GetStoreKeyMap(ctx) + + txBuilder := simapp.MakeTestEncodingConfig().TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs(msgs...) + require.NoError(t, err) + bz, err := simapp.MakeTestEncodingConfig().TxConfig.TxEncoder()(txBuilder.GetTx()) + require.NoError(t, err) + + writesets, err := app.AccessControlKeeper.GenerateEstimatedWritesets(ctx, simapp.MakeTestEncodingConfig().TxConfig.TxDecoder(), app.GetAnteDepGenerator(), 0, bz) + require.NoError(t, err) + + // check writesets + require.Equal(t, 2, len(writesets)) + bankWritesets := writesets[storeKeyMap[banktypes.StoreKey]] + require.Equal(t, 3, len(bankWritesets)) + + authWritesets := writesets[storeKeyMap[authtypes.StoreKey]] + require.Equal(t, 1, len(authWritesets)) + +} + func TestKeeperTestSuite(t *testing.T) { t.Parallel() suite.Run(t, new(KeeperTestSuite)) diff --git a/x/accesscontrol/keeper/options.go b/x/accesscontrol/keeper/options.go index 365280ab3..6dd7f3b36 100644 --- a/x/accesscontrol/keeper/options.go +++ b/x/accesscontrol/keeper/options.go @@ -1,5 +1,7 @@ package keeper +import acltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" + type optsFn func(*Keeper) func (f optsFn) Apply(keeper *Keeper) { @@ -25,3 +27,9 @@ func (oldGenerator DependencyGeneratorMap) Merge(newGenerator DependencyGenerato } return oldGenerator } + +func WithResourceTypeToStoreKeyMap(resourceTypeStoreKeyMapping acltypes.ResourceTypeToStoreKeyMap) optsFn { + return optsFn(func(k *Keeper) { + k.ResourceTypeStoreKeyMapping = resourceTypeStoreKeyMapping + }) +} diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 4e6462c16..2f1717f17 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -1152,3 +1152,61 @@ func (suite *AnteTestSuite) TestAnteHandlerReCheck() { _, err = suite.anteHandler(suite.ctx, tx, false) suite.Require().NotNil(err, "antehandler on recheck did not fail once feePayer no longer has sufficient funds") } + +func (suite *AnteTestSuite) TestDisableSeqNo() { + suite.SetupTest(false) // setup + authParams := types.Params{ + MaxMemoCharacters: types.DefaultMaxMemoCharacters, + TxSigLimit: types.DefaultTxSigLimit, + TxSizeCostPerByte: types.DefaultTxSizeCostPerByte, + SigVerifyCostED25519: types.DefaultSigVerifyCostED25519, + SigVerifyCostSecp256k1: types.DefaultSigVerifyCostSecp256k1, + DisableSeqnoCheck: true, + } + suite.app.AccountKeeper.SetParams(suite.ctx, authParams) + + // Same data for every test cases + accounts := suite.CreateTestAccounts(1) + feeAmount := testdata.NewTestFeeAmount() + gasLimit := testdata.NewTestGasLimit() + + // Variable data per test case + var ( + accNums []uint64 + msgs []sdk.Msg + privs []cryptotypes.PrivKey + accSeqs []uint64 + ) + + testCases := []TestCase{ + { + "good tx from one signer", + func() { + msg := testdata.NewTestMsg(accounts[0].acc.GetAddress()) + msgs = []sdk.Msg{msg} + + privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{0} + }, + false, + true, + nil, + }, + { + "test sending it again succeeds (disable seqno check is true)", + func() { + privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{0} + }, + false, + true, + nil, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() + tc.malleate() + + suite.RunTestCase(privs, msgs, feeAmount, gasLimit, accNums, accSeqs, suite.ctx.ChainID(), tc) + }) + } +} diff --git a/x/auth/ante/batch_sigverify.go b/x/auth/ante/batch_sigverify.go index ec9c7e325..399a0ef56 100644 --- a/x/auth/ante/batch_sigverify.go +++ b/x/auth/ante/batch_sigverify.go @@ -132,11 +132,14 @@ func (v *SR25519BatchVerifier) VerifyTxs(ctx sdk.Context, txs []sdk.Tx) { sig := sigsList[i][j] if sig.Sequence != seqNum { - v.errors[i] = sdkerrors.Wrapf( - sdkerrors.ErrWrongSequence, - "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, - ) - continue + params := v.ak.GetParams(ctx) + if !params.GetDisableSeqnoCheck() { + v.errors[i] = sdkerrors.Wrapf( + sdkerrors.ErrWrongSequence, + "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, + ) + continue + } } switch data := sig.Data.(type) { diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 3df25abb0..503d7dbef 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -268,10 +268,13 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul // Check account sequence number. if sig.Sequence != acc.GetSequence() { - return ctx, sdkerrors.Wrapf( - sdkerrors.ErrWrongSequence, - "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, - ) + params := svd.ak.GetParams(ctx) + if !params.GetDisableSeqnoCheck() { + return ctx, sdkerrors.Wrapf( + sdkerrors.ErrWrongSequence, + "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, + ) + } } // retrieve signer data diff --git a/x/auth/keeper/migrations.go b/x/auth/keeper/migrations.go index d3ad7a2f8..4e16d9288 100644 --- a/x/auth/keeper/migrations.go +++ b/x/auth/keeper/migrations.go @@ -41,3 +41,9 @@ func (m Migrator) Migrate1to2(ctx sdk.Context) error { return iterErr } + +func (m Migrator) Migrate2to3(ctx sdk.Context) error { + defaultParams := types.DefaultParams() + m.keeper.SetParams(ctx, defaultParams) + return nil +} diff --git a/x/auth/keeper/v2_to_v3_test.go b/x/auth/keeper/v2_to_v3_test.go new file mode 100644 index 000000000..92b3e631b --- /dev/null +++ b/x/auth/keeper/v2_to_v3_test.go @@ -0,0 +1,28 @@ +package keeper_test + +import ( + "github.com/cosmos/cosmos-sdk/x/auth/keeper" + "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/stretchr/testify/require" + "testing" +) + +func TestMigrate2to3(t *testing.T) { + app, ctx := createTestApp(true) + + prevParams := types.Params{ + MaxMemoCharacters: types.DefaultMaxMemoCharacters, + TxSigLimit: types.DefaultTxSigLimit, + TxSizeCostPerByte: types.DefaultTxSizeCostPerByte, + SigVerifyCostED25519: types.DefaultSigVerifyCostED25519, + SigVerifyCostSecp256k1: types.DefaultSigVerifyCostSecp256k1, + } + + app.AccountKeeper.SetParams(ctx, prevParams) + // migrate to default params + m := keeper.NewMigrator(app.AccountKeeper, app.GRPCQueryRouter()) + err := m.Migrate2to3(ctx) + require.NoError(t, err) + params := app.AccountKeeper.GetParams(ctx) + require.Equal(t, params.DisableSeqnoCheck, false) +} diff --git a/x/auth/legacy/v040/migrate_test.go b/x/auth/legacy/v040/migrate_test.go index b1e12ffce..2e391a226 100644 --- a/x/auth/legacy/v040/migrate_test.go +++ b/x/auth/legacy/v040/migrate_test.go @@ -241,6 +241,7 @@ func TestMigrate(t *testing.T) { } ], "params": { + "disable_seqno_check": false, "max_memo_characters": "10", "sig_verify_cost_ed25519": "40", "sig_verify_cost_secp256k1": "50", diff --git a/x/auth/module.go b/x/auth/module.go index ef13f74a5..ef2d1f2e2 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -134,6 +134,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err != nil { panic(err) } + err = cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3) + if err != nil { + panic(err) + } } // InitGenesis performs genesis initialization for the auth module. It returns @@ -153,7 +157,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 2 } +func (AppModule) ConsensusVersion() uint64 { return 3 } // AppModuleSimulation functions diff --git a/x/auth/types/auth.pb.go b/x/auth/types/auth.pb.go index fa52ac5a8..c13ed7a46 100644 --- a/x/auth/types/auth.pb.go +++ b/x/auth/types/auth.pb.go @@ -113,6 +113,7 @@ type Params struct { TxSizeCostPerByte uint64 `protobuf:"varint,3,opt,name=tx_size_cost_per_byte,json=txSizeCostPerByte,proto3" json:"tx_size_cost_per_byte,omitempty" yaml:"tx_size_cost_per_byte"` SigVerifyCostED25519 uint64 `protobuf:"varint,4,opt,name=sig_verify_cost_ed25519,json=sigVerifyCostEd25519,proto3" json:"sig_verify_cost_ed25519,omitempty" yaml:"sig_verify_cost_ed25519"` SigVerifyCostSecp256k1 uint64 `protobuf:"varint,5,opt,name=sig_verify_cost_secp256k1,json=sigVerifyCostSecp256k1,proto3" json:"sig_verify_cost_secp256k1,omitempty" yaml:"sig_verify_cost_secp256k1"` + DisableSeqnoCheck bool `protobuf:"varint,6,opt,name=disable_seqno_check,json=disableSeqnoCheck,proto3" json:"disable_seqno_check,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -182,6 +183,13 @@ func (m *Params) GetSigVerifyCostSecp256k1() uint64 { return 0 } +func (m *Params) GetDisableSeqnoCheck() bool { + if m != nil { + return m.DisableSeqnoCheck + } + return false +} + func init() { proto.RegisterType((*BaseAccount)(nil), "cosmos.auth.v1beta1.BaseAccount") proto.RegisterType((*ModuleAccount)(nil), "cosmos.auth.v1beta1.ModuleAccount") @@ -191,50 +199,51 @@ func init() { func init() { proto.RegisterFile("cosmos/auth/v1beta1/auth.proto", fileDescriptor_7e1f7e915d020d2d) } var fileDescriptor_7e1f7e915d020d2d = []byte{ - // 674 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x54, 0x4d, 0x4f, 0xdb, 0x4a, - 0x14, 0x8d, 0x5f, 0xf2, 0xf8, 0x98, 0x00, 0x12, 0x26, 0x80, 0x93, 0xf7, 0x64, 0x5b, 0x5e, 0xe5, - 0x49, 0x2f, 0x8e, 0x92, 0x8a, 0x4a, 0x64, 0x51, 0x15, 0xd3, 0x2e, 0x50, 0x0b, 0x42, 0x46, 0xea, - 0xa2, 0xaa, 0xe4, 0x8e, 0x9d, 0xc1, 0x58, 0x64, 0x32, 0xc6, 0x33, 0x46, 0x31, 0xbf, 0xa0, 0xcb, - 0x2e, 0xbb, 0xe4, 0x47, 0xf0, 0x0f, 0xba, 0xe9, 0x12, 0xb1, 0xea, 0xca, 0xad, 0xc2, 0xa6, 0xea, - 0x32, 0xfb, 0x4a, 0x95, 0x67, 0x9c, 0x90, 0xa0, 0x74, 0x95, 0xb9, 0xe7, 0x9c, 0x7b, 0xee, 0x9d, - 0x7b, 0xe3, 0x01, 0xaa, 0x47, 0x28, 0x26, 0xb4, 0x09, 0x63, 0x76, 0xd6, 0xbc, 0x6c, 0xb9, 0x88, - 0xc1, 0x16, 0x0f, 0xcc, 0x30, 0x22, 0x8c, 0xc8, 0x1b, 0x82, 0x37, 0x39, 0x94, 0xf3, 0xb5, 0xaa, - 0x00, 0x1d, 0x2e, 0x69, 0xe6, 0x0a, 0x1e, 0xd4, 0x2a, 0x3e, 0xf1, 0x89, 0xc0, 0xb3, 0x53, 0x8e, - 0x56, 0x7d, 0x42, 0xfc, 0x1e, 0x6a, 0xf2, 0xc8, 0x8d, 0x4f, 0x9b, 0xb0, 0x9f, 0x08, 0xca, 0xf8, - 0x25, 0x81, 0xb2, 0x05, 0x29, 0xda, 0xf3, 0x3c, 0x12, 0xf7, 0x99, 0xac, 0x80, 0x45, 0xd8, 0xed, - 0x46, 0x88, 0x52, 0x45, 0xd2, 0xa5, 0xfa, 0xb2, 0x3d, 0x0e, 0xe5, 0x77, 0x60, 0x31, 0x8c, 0x5d, - 0xe7, 0x1c, 0x25, 0xca, 0x5f, 0xba, 0x54, 0x2f, 0xb7, 0x2b, 0xa6, 0xb0, 0x35, 0xc7, 0xb6, 0xe6, - 0x5e, 0x3f, 0xb1, 0x1a, 0x3f, 0x53, 0xad, 0x12, 0xc6, 0x6e, 0x2f, 0xf0, 0x32, 0xed, 0xff, 0x04, - 0x07, 0x0c, 0xe1, 0x90, 0x25, 0xa3, 0x54, 0x5b, 0x4f, 0x20, 0xee, 0x75, 0x8c, 0x07, 0xd6, 0xb0, - 0x17, 0xc2, 0xd8, 0x7d, 0x85, 0x12, 0xf9, 0x39, 0x58, 0x83, 0xa2, 0x05, 0xa7, 0x1f, 0x63, 0x17, - 0x45, 0x4a, 0x51, 0x97, 0xea, 0x25, 0xab, 0x3a, 0x4a, 0xb5, 0x4d, 0x91, 0x36, 0xcb, 0x1b, 0xf6, - 0x6a, 0x0e, 0x1c, 0xf1, 0x58, 0xae, 0x81, 0x25, 0x8a, 0x2e, 0x62, 0xd4, 0xf7, 0x90, 0x52, 0xca, - 0x72, 0xed, 0x49, 0xdc, 0x51, 0x3e, 0x5c, 0x6b, 0x85, 0x4f, 0xd7, 0x5a, 0xe1, 0xc7, 0xb5, 0x56, - 0xb8, 0xbb, 0x69, 0x2c, 0xe5, 0xd7, 0x3d, 0x30, 0x3e, 0x4b, 0x60, 0xf5, 0x90, 0x74, 0xe3, 0xde, - 0x64, 0x02, 0xef, 0xc1, 0x8a, 0x0b, 0x29, 0x72, 0x72, 0x77, 0x3e, 0x86, 0x72, 0x5b, 0x37, 0xe7, - 0x6c, 0xc2, 0x9c, 0x9a, 0x9c, 0xf5, 0xcf, 0x6d, 0xaa, 0x49, 0xa3, 0x54, 0xdb, 0x10, 0xdd, 0x4e, - 0x7b, 0x18, 0x76, 0xd9, 0x9d, 0x9a, 0xb1, 0x0c, 0x4a, 0x7d, 0x88, 0x11, 0x1f, 0xe3, 0xb2, 0xcd, - 0xcf, 0xb2, 0x0e, 0xca, 0x21, 0x8a, 0x70, 0x40, 0x69, 0x40, 0xfa, 0x54, 0x29, 0xea, 0xc5, 0xfa, - 0xb2, 0x3d, 0x0d, 0x75, 0x6a, 0xe3, 0x3b, 0xdc, 0xdd, 0x34, 0xd6, 0x66, 0x5a, 0x3e, 0x30, 0xbe, - 0x15, 0xc1, 0xc2, 0x31, 0x8c, 0x20, 0xa6, 0xf2, 0x11, 0xd8, 0xc0, 0x70, 0xe0, 0x60, 0x84, 0x89, - 0xe3, 0x9d, 0xc1, 0x08, 0x7a, 0x0c, 0x45, 0x62, 0x99, 0x25, 0x4b, 0x1d, 0xa5, 0x5a, 0x4d, 0xf4, - 0x37, 0x47, 0x64, 0xd8, 0xeb, 0x18, 0x0e, 0x0e, 0x11, 0x26, 0xfb, 0x13, 0x4c, 0xde, 0x05, 0x2b, - 0x6c, 0xe0, 0xd0, 0xc0, 0x77, 0x7a, 0x01, 0x0e, 0x18, 0x6f, 0xba, 0x64, 0x6d, 0x3f, 0x5c, 0x74, - 0x9a, 0x35, 0x6c, 0xc0, 0x06, 0x27, 0x81, 0xff, 0x3a, 0x0b, 0x64, 0x1b, 0x6c, 0x72, 0xf2, 0x0a, - 0x39, 0x1e, 0xa1, 0xcc, 0x09, 0x51, 0xe4, 0xb8, 0x09, 0x43, 0xf9, 0x6a, 0xf5, 0x51, 0xaa, 0xfd, - 0x3b, 0xe5, 0xf1, 0x58, 0x66, 0xd8, 0xeb, 0x99, 0xd9, 0x15, 0xda, 0x27, 0x94, 0x1d, 0xa3, 0xc8, - 0x4a, 0x18, 0x92, 0x2f, 0xc0, 0x76, 0x56, 0xed, 0x12, 0x45, 0xc1, 0x69, 0x22, 0xf4, 0xa8, 0xdb, - 0xde, 0xd9, 0x69, 0xed, 0x8a, 0xa5, 0x5b, 0x9d, 0x61, 0xaa, 0x55, 0x4e, 0x02, 0xff, 0x0d, 0x57, - 0x64, 0xa9, 0x2f, 0x5f, 0x70, 0x7e, 0x94, 0x6a, 0xaa, 0xa8, 0xf6, 0x07, 0x03, 0xc3, 0xae, 0xd0, - 0x99, 0x3c, 0x01, 0xcb, 0x09, 0xa8, 0x3e, 0xce, 0xa0, 0xc8, 0x0b, 0xdb, 0x3b, 0x4f, 0xcf, 0x5b, - 0xca, 0xdf, 0xbc, 0xe8, 0xb3, 0x61, 0xaa, 0x6d, 0xcd, 0x14, 0x3d, 0x19, 0x2b, 0x46, 0xa9, 0xa6, - 0xcf, 0x2f, 0x3b, 0x31, 0x31, 0xec, 0x2d, 0x3a, 0x37, 0xb7, 0xb3, 0x94, 0xff, 0x67, 0x25, 0x6b, - 0xff, 0xcb, 0x50, 0x95, 0x6e, 0x87, 0xaa, 0xf4, 0x7d, 0xa8, 0x4a, 0x1f, 0xef, 0xd5, 0xc2, 0xed, - 0xbd, 0x5a, 0xf8, 0x7a, 0xaf, 0x16, 0xde, 0xfe, 0xe7, 0x07, 0xec, 0x2c, 0x76, 0x4d, 0x8f, 0xe0, - 0xfc, 0x2d, 0xc8, 0x7f, 0x1a, 0xb4, 0x7b, 0xde, 0x1c, 0x88, 0xa7, 0x85, 0x25, 0x21, 0xa2, 0xee, - 0x02, 0xff, 0x52, 0x9f, 0xfc, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x49, 0x90, 0x16, 0xd9, 0x76, 0x04, - 0x00, 0x00, + // 704 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x54, 0xc1, 0x6e, 0xda, 0x4a, + 0x14, 0xc5, 0x2f, 0x3c, 0x42, 0x86, 0x24, 0x12, 0x86, 0x24, 0x86, 0xf7, 0x64, 0x5b, 0x5e, 0xf1, + 0xa4, 0x87, 0x11, 0x54, 0xa9, 0x14, 0x16, 0x55, 0x63, 0xda, 0x45, 0xd4, 0x26, 0x8a, 0x8c, 0xd4, + 0x45, 0x55, 0xc9, 0x1d, 0x9b, 0x89, 0x63, 0x81, 0x3d, 0x8e, 0x67, 0x1c, 0xe1, 0x7c, 0x41, 0x77, + 0xed, 0xb2, 0xcb, 0x7c, 0x44, 0xfe, 0xa0, 0x9b, 0x2e, 0xa3, 0xac, 0xba, 0xb2, 0x2a, 0xb2, 0xa9, + 0xba, 0x64, 0x5f, 0xa9, 0xb2, 0xc7, 0x10, 0x88, 0xe8, 0x8a, 0xb9, 0xe7, 0x9c, 0x7b, 0xee, 0x9d, + 0x7b, 0xf1, 0x00, 0xd1, 0xc2, 0xc4, 0xc5, 0xa4, 0x05, 0x43, 0x7a, 0xde, 0xba, 0x6c, 0x9b, 0x88, + 0xc2, 0x76, 0x1a, 0xa8, 0x7e, 0x80, 0x29, 0xe6, 0x2b, 0x8c, 0x57, 0x53, 0x28, 0xe3, 0xeb, 0x35, + 0x06, 0x1a, 0xa9, 0xa4, 0x95, 0x29, 0xd2, 0xa0, 0x5e, 0xb5, 0xb1, 0x8d, 0x19, 0x9e, 0x9c, 0x32, + 0xb4, 0x66, 0x63, 0x6c, 0x8f, 0x50, 0x2b, 0x8d, 0xcc, 0xf0, 0xac, 0x05, 0xbd, 0x88, 0x51, 0xca, + 0x2f, 0x0e, 0x94, 0x34, 0x48, 0xd0, 0xa1, 0x65, 0xe1, 0xd0, 0xa3, 0xbc, 0x00, 0xd6, 0xe1, 0x60, + 0x10, 0x20, 0x42, 0x04, 0x4e, 0xe6, 0x1a, 0x1b, 0xfa, 0x2c, 0xe4, 0xdf, 0x81, 0x75, 0x3f, 0x34, + 0x8d, 0x21, 0x8a, 0x84, 0xbf, 0x64, 0xae, 0x51, 0xea, 0x54, 0x55, 0x66, 0xab, 0xce, 0x6c, 0xd5, + 0x43, 0x2f, 0xd2, 0x9a, 0x3f, 0x63, 0xa9, 0xea, 0x87, 0xe6, 0xc8, 0xb1, 0x12, 0xed, 0xff, 0xd8, + 0x75, 0x28, 0x72, 0x7d, 0x1a, 0x4d, 0x63, 0xa9, 0x1c, 0x41, 0x77, 0xd4, 0x55, 0x1e, 0x58, 0x45, + 0x2f, 0xf8, 0xa1, 0xf9, 0x0a, 0x45, 0xfc, 0x73, 0xb0, 0x0d, 0x59, 0x0b, 0x86, 0x17, 0xba, 0x26, + 0x0a, 0x84, 0x35, 0x99, 0x6b, 0xe4, 0xb5, 0xda, 0x34, 0x96, 0x76, 0x58, 0xda, 0x32, 0xaf, 0xe8, + 0x5b, 0x19, 0x70, 0x92, 0xc6, 0x7c, 0x1d, 0x14, 0x09, 0xba, 0x08, 0x91, 0x67, 0x21, 0x21, 0x9f, + 0xe4, 0xea, 0xf3, 0xb8, 0x2b, 0x7c, 0xb8, 0x96, 0x72, 0x9f, 0xaf, 0xa5, 0xdc, 0x8f, 0x6b, 0x29, + 0x77, 0x77, 0xd3, 0x2c, 0x66, 0xd7, 0x3d, 0x52, 0xbe, 0x70, 0x60, 0xeb, 0x18, 0x0f, 0xc2, 0xd1, + 0x7c, 0x02, 0xef, 0xc1, 0xa6, 0x09, 0x09, 0x32, 0x32, 0xf7, 0x74, 0x0c, 0xa5, 0x8e, 0xac, 0xae, + 0xd8, 0x84, 0xba, 0x30, 0x39, 0xed, 0x9f, 0xdb, 0x58, 0xe2, 0xa6, 0xb1, 0x54, 0x61, 0xdd, 0x2e, + 0x7a, 0x28, 0x7a, 0xc9, 0x5c, 0x98, 0x31, 0x0f, 0xf2, 0x1e, 0x74, 0x51, 0x3a, 0xc6, 0x0d, 0x3d, + 0x3d, 0xf3, 0x32, 0x28, 0xf9, 0x28, 0x70, 0x1d, 0x42, 0x1c, 0xec, 0x11, 0x61, 0x4d, 0x5e, 0x6b, + 0x6c, 0xe8, 0x8b, 0x50, 0xb7, 0x3e, 0xbb, 0xc3, 0xdd, 0x4d, 0x73, 0x7b, 0xa9, 0xe5, 0x23, 0xe5, + 0x63, 0x1e, 0x14, 0x4e, 0x61, 0x00, 0x5d, 0xc2, 0x9f, 0x80, 0x8a, 0x0b, 0xc7, 0x86, 0x8b, 0x5c, + 0x6c, 0x58, 0xe7, 0x30, 0x80, 0x16, 0x45, 0x01, 0x5b, 0x66, 0x5e, 0x13, 0xa7, 0xb1, 0x54, 0x67, + 0xfd, 0xad, 0x10, 0x29, 0x7a, 0xd9, 0x85, 0xe3, 0x63, 0xe4, 0xe2, 0xde, 0x1c, 0xe3, 0x0f, 0xc0, + 0x26, 0x1d, 0x1b, 0xc4, 0xb1, 0x8d, 0x91, 0xe3, 0x3a, 0x34, 0x6d, 0x3a, 0xaf, 0xed, 0x3d, 0x5c, + 0x74, 0x91, 0x55, 0x74, 0x40, 0xc7, 0x7d, 0xc7, 0x7e, 0x9d, 0x04, 0xbc, 0x0e, 0x76, 0x52, 0xf2, + 0x0a, 0x19, 0x16, 0x26, 0xd4, 0xf0, 0x51, 0x60, 0x98, 0x11, 0x45, 0xd9, 0x6a, 0xe5, 0x69, 0x2c, + 0xfd, 0xbb, 0xe0, 0xf1, 0x58, 0xa6, 0xe8, 0xe5, 0xc4, 0xec, 0x0a, 0xf5, 0x30, 0xa1, 0xa7, 0x28, + 0xd0, 0x22, 0x8a, 0xf8, 0x0b, 0xb0, 0x97, 0x54, 0xbb, 0x44, 0x81, 0x73, 0x16, 0x31, 0x3d, 0x1a, + 0x74, 0xf6, 0xf7, 0xdb, 0x07, 0x6c, 0xe9, 0x5a, 0x77, 0x12, 0x4b, 0xd5, 0xbe, 0x63, 0xbf, 0x49, + 0x15, 0x49, 0xea, 0xcb, 0x17, 0x29, 0x3f, 0x8d, 0x25, 0x91, 0x55, 0xfb, 0x83, 0x81, 0xa2, 0x57, + 0xc9, 0x52, 0x1e, 0x83, 0xf9, 0x08, 0xd4, 0x1e, 0x67, 0x10, 0x64, 0xf9, 0x9d, 0xfd, 0xa7, 0xc3, + 0xb6, 0xf0, 0x77, 0x5a, 0xf4, 0xd9, 0x24, 0x96, 0x76, 0x97, 0x8a, 0xf6, 0x67, 0x8a, 0x69, 0x2c, + 0xc9, 0xab, 0xcb, 0xce, 0x4d, 0x14, 0x7d, 0x97, 0xac, 0xcc, 0xe5, 0x55, 0x50, 0x19, 0x38, 0x04, + 0x9a, 0x23, 0x64, 0x10, 0x74, 0xe1, 0x25, 0xcb, 0x42, 0xd6, 0x50, 0x28, 0xc8, 0x5c, 0xa3, 0xa8, + 0x97, 0x33, 0xaa, 0x9f, 0x30, 0xbd, 0x84, 0xe8, 0x16, 0xb3, 0xff, 0x38, 0xa7, 0xf5, 0xbe, 0x4e, + 0x44, 0xee, 0x76, 0x22, 0x72, 0xdf, 0x27, 0x22, 0xf7, 0xe9, 0x5e, 0xcc, 0xdd, 0xde, 0x8b, 0xb9, + 0x6f, 0xf7, 0x62, 0xee, 0xed, 0x7f, 0xb6, 0x43, 0xcf, 0x43, 0x53, 0xb5, 0xb0, 0x9b, 0xbd, 0x1d, + 0xd9, 0x4f, 0x93, 0x0c, 0x86, 0xad, 0x31, 0x7b, 0x8a, 0x68, 0xe4, 0x23, 0x62, 0x16, 0xd2, 0x2f, + 0xfb, 0xc9, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1b, 0xbd, 0x76, 0x46, 0xa6, 0x04, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -271,6 +280,9 @@ func (this *Params) Equal(that interface{}) bool { if this.SigVerifyCostSecp256k1 != that1.SigVerifyCostSecp256k1 { return false } + if this.DisableSeqnoCheck != that1.DisableSeqnoCheck { + return false + } return true } func (m *BaseAccount) Marshal() (dAtA []byte, err error) { @@ -396,6 +408,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.DisableSeqnoCheck { + i-- + if m.DisableSeqnoCheck { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } if m.SigVerifyCostSecp256k1 != 0 { i = encodeVarintAuth(dAtA, i, uint64(m.SigVerifyCostSecp256k1)) i-- @@ -502,6 +524,9 @@ func (m *Params) Size() (n int) { if m.SigVerifyCostSecp256k1 != 0 { n += 1 + sovAuth(uint64(m.SigVerifyCostSecp256k1)) } + if m.DisableSeqnoCheck { + n += 2 + } return n } @@ -941,6 +966,26 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DisableSeqnoCheck", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.DisableSeqnoCheck = bool(v != 0) default: iNdEx = preIndex skippy, err := skipAuth(dAtA[iNdEx:]) diff --git a/x/auth/types/params.go b/x/auth/types/params.go index dbe41ac0e..865f8bf3c 100644 --- a/x/auth/types/params.go +++ b/x/auth/types/params.go @@ -24,6 +24,7 @@ var ( KeyTxSizeCostPerByte = []byte("TxSizeCostPerByte") KeySigVerifyCostED25519 = []byte("SigVerifyCostED25519") KeySigVerifyCostSecp256k1 = []byte("SigVerifyCostSecp256k1") + KeyDisableSeqnoCheck = []byte("KeyDisableSeqnoCheck") ) var _ paramtypes.ParamSet = &Params{} @@ -55,6 +56,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyTxSizeCostPerByte, &p.TxSizeCostPerByte, validateTxSizeCostPerByte), paramtypes.NewParamSetPair(KeySigVerifyCostED25519, &p.SigVerifyCostED25519, validateSigVerifyCostED25519), paramtypes.NewParamSetPair(KeySigVerifyCostSecp256k1, &p.SigVerifyCostSecp256k1, validateSigVerifyCostSecp256k1), + paramtypes.NewParamSetPair(KeyDisableSeqnoCheck, &p.DisableSeqnoCheck, func(i interface{}) error { return nil }), } } diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index e8576d12d..bf98e1b9c 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "google.golang.org/grpc/codes" "google.golang.org/grpc/status" diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index d126ddd75..bb045afd2 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -229,6 +229,5 @@ func (k BaseViewKeeper) ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) er // getAccountStore gets the account store of the given address. func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) prefix.Store { store := ctx.KVStore(k.storeKey) - return prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr)) }