From c50c6b25495188bb2f2ff111b551ef36d9e40975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Toledano?= Date: Mon, 19 Aug 2024 12:16:35 +0200 Subject: [PATCH 01/26] docs: update upgrading for nested messages simulation (#21354) --- UPGRADING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/UPGRADING.md b/UPGRADING.md index d1cf652c234d..7218b4e5161b 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -39,6 +39,11 @@ baseAppOptions = append(baseAppOptions, baseapp.SetIncludeNestedMsgsGas([]sdk.Me app.App = appBuilder.Build(db, traceStore, baseAppOptions...) ``` +To be able to simulate nested messages within a transaction, message types containing nested messages must implement the +`HasNestedMsgs` interface. This interface requires a single method: `GetMsgs() ([]sdk.Msg, error)`, which should return +the nested messages. By implementing this interface, the BaseApp can simulate these nested messages during +transaction simulation. + ## [v0.52.x](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.52.0-alpha.0) Documentation to migrate an application from v0.50.x to server/v2 is available elsewhere. From 294b608022c7a5d6423559672c56c2487f50ba26 Mon Sep 17 00:00:00 2001 From: son trinh Date: Mon, 19 Aug 2024 17:26:56 +0700 Subject: [PATCH 02/26] feat(runtime/v2): Add pre and post msg handler register (#21346) --- core/appmodule/v2/handlers.go | 20 ++++++++++++-------- runtime/v2/manager.go | 9 ++++++++- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/core/appmodule/v2/handlers.go b/core/appmodule/v2/handlers.go index abb9e95a1d1d..91c488773c45 100644 --- a/core/appmodule/v2/handlers.go +++ b/core/appmodule/v2/handlers.go @@ -19,12 +19,12 @@ type ( // msg handler type PreMsgRouter interface { - // Register will register a specific message handler hooking into the message with + // RegisterPreHandler will register a specific message handler hooking into the message with // the provided name. - Register(msgName string, handler PreMsgHandler) - // RegisterGlobal will register a global message handler hooking into any message + RegisterPreHandler(msgName string, handler PreMsgHandler) + // RegisterGlobalPreHandler will register a global message handler hooking into any message // being executed. - RegisterGlobal(handler PreMsgHandler) + RegisterGlobalPreHandler(handler PreMsgHandler) } type HasPreMsgHandlers interface { @@ -40,11 +40,15 @@ type HasMsgHandlers interface { } type PostMsgRouter interface { - // Register will register a specific message handler hooking after the execution of message with + // RegisterPostHandler will register a specific message handler hooking after the execution of message with // the provided name. - Register(msgName string, handler PostMsgHandler) - // RegisterGlobal will register a global message handler hooking after the execution of any message. - RegisterGlobal(handler PreMsgHandler) + RegisterPostHandler(msgName string, handler PostMsgHandler) + // RegisterGlobalPostHandler will register a global message handler hooking after the execution of any message. + RegisterGlobalPostHandler(handler PostMsgHandler) +} + +type HasPostMsgHandlers interface { + RegisterPostMsgHandlers(router PostMsgRouter) } // query handler diff --git a/runtime/v2/manager.go b/runtime/v2/manager.go index 093140bcd370..9fe4c5fb80dd 100644 --- a/runtime/v2/manager.go +++ b/runtime/v2/manager.go @@ -424,7 +424,14 @@ func (m *MM[T]) RegisterServices(app *App[T]) error { } } - // TODO: register pre and post msg + // register pre and post msg + if module, ok := module.(appmodulev2.HasPreMsgHandlers); ok { + module.RegisterPreMsgHandlers(app.msgRouterBuilder) + } + + if module, ok := module.(appmodulev2.HasPostMsgHandlers); ok { + module.RegisterPostMsgHandlers(app.msgRouterBuilder) + } } return nil From 6f30de3a41d37a4359751f9d9e508b28fc620697 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 19 Aug 2024 13:14:34 +0000 Subject: [PATCH 03/26] refactor: remove x/exp dep (#21281) --- baseapp/baseapp.go | 7 +++---- go.mod | 2 +- runtime/v2/app.go | 2 +- runtime/v2/go.mod | 2 +- runtime/v2/manager.go | 5 +++-- scripts/dep-assert.sh | 6 ++++++ server/v2/api/grpc/server.go | 5 +++-- server/v2/go.mod | 2 +- server/v2/stf/core_event_service.go | 12 ++---------- server/v2/stf/go.mod | 2 +- store/v2/commitment/store.go | 8 +++----- store/v2/go.mod | 2 +- store/v2/go.sum | 4 ++-- tests/systemtests/cli.go | 2 +- tests/systemtests/go.mod | 2 +- tests/systemtests/system.go | 4 ++-- tools/confix/cmd/diff.go | 5 +++-- tools/confix/cmd/migrate.go | 5 +++-- tools/confix/go.mod | 2 +- types/events.go | 6 ++---- types/module/module.go | 5 +++-- x/auth/ante/unorderedtx/manager.go | 9 +++------ x/auth/go.mod | 2 +- x/bank/depinject.go | 6 +++--- x/bank/go.mod | 2 +- x/epochs/depinject.go | 12 ++++-------- x/epochs/go.mod | 2 +- x/epochs/keeper/abci_test.go | 15 ++++++++++----- x/feegrant/module/depinject.go | 23 ----------------------- x/feegrant/module/module.go | 22 ++++++++++++++++++++++ x/genutil/client/cli/migrate.go | 7 +++---- x/gov/depinject.go | 11 +++-------- x/gov/go.mod | 2 +- x/group/go.mod | 2 +- x/group/keeper/invariants.go | 16 ++++++++++------ x/staking/depinject.go | 14 +++++++------- x/staking/go.mod | 2 +- 37 files changed, 115 insertions(+), 122 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index a6a60a6d376f..75f3b6a6a811 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -4,8 +4,9 @@ import ( "context" "errors" "fmt" + "maps" "math" - "sort" + "slices" "strconv" "sync" @@ -14,7 +15,6 @@ import ( "github.com/cometbft/cometbft/crypto/tmhash" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" - "golang.org/x/exp/maps" "google.golang.org/protobuf/reflect/protoreflect" "cosmossdk.io/core/header" @@ -340,8 +340,7 @@ func (app *BaseApp) MountTransientStores(keys map[string]*storetypes.TransientSt // MountMemoryStores mounts all in-memory KVStores with the BaseApp's internal // commit multi-store. func (app *BaseApp) MountMemoryStores(keys map[string]*storetypes.MemoryStoreKey) { - skeys := maps.Keys(keys) - sort.Strings(skeys) + skeys := slices.Sorted(maps.Keys(keys)) for _, key := range skeys { memKey := keys[key] app.MountStore(memKey, storetypes.StoreTypeMemory) diff --git a/go.mod b/go.mod index a41a5adf64fe..380330c50c45 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,6 @@ require ( github.com/tendermint/go-amino v0.16.0 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b golang.org/x/crypto v0.26.0 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc golang.org/x/sync v0.8.0 google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 google.golang.org/grpc v1.65.0 @@ -164,6 +163,7 @@ require ( go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sys v0.24.0 // indirect diff --git a/runtime/v2/app.go b/runtime/v2/app.go index 08f2498255c5..ff888039be57 100644 --- a/runtime/v2/app.go +++ b/runtime/v2/app.go @@ -3,9 +3,9 @@ package runtime import ( "encoding/json" "errors" + "slices" gogoproto "github.com/cosmos/gogoproto/proto" - "golang.org/x/exp/slices" runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2" "cosmossdk.io/core/legacy" diff --git a/runtime/v2/go.mod b/runtime/v2/go.mod index e7f197f94489..4831b66fe920 100644 --- a/runtime/v2/go.mod +++ b/runtime/v2/go.mod @@ -24,7 +24,6 @@ require ( cosmossdk.io/x/tx v0.13.3 github.com/cosmos/gogoproto v1.7.0 github.com/spf13/viper v1.19.0 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 ) @@ -91,6 +90,7 @@ require ( github.com/tidwall/btree v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect diff --git a/runtime/v2/manager.go b/runtime/v2/manager.go index 9fe4c5fb80dd..bdeaf02afe36 100644 --- a/runtime/v2/manager.go +++ b/runtime/v2/manager.go @@ -5,11 +5,12 @@ import ( "encoding/json" "errors" "fmt" + "maps" "reflect" + "slices" "sort" gogoproto "github.com/cosmos/gogoproto/proto" - "golang.org/x/exp/maps" "google.golang.org/grpc" proto "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" @@ -41,7 +42,7 @@ func NewModuleManager[T transaction.Tx]( modules map[string]appmodulev2.AppModule, ) *MM[T] { // good defaults for the module manager order - modulesName := maps.Keys(modules) + modulesName := slices.Sorted(maps.Keys(modules)) if len(config.PreBlockers) == 0 { config.PreBlockers = modulesName } diff --git a/scripts/dep-assert.sh b/scripts/dep-assert.sh index 2f4dfd0dbf64..2599115a19cd 100755 --- a/scripts/dep-assert.sh +++ b/scripts/dep-assert.sh @@ -22,6 +22,7 @@ done # no runtime/v2 or server/v2 imports in x/ modules RUNTIMEV2_REGEX="cosmossdk.io/runtime/v2" SEVERV2_REGEX="cosmossdk.io/server/v2" +XEXP_REGEX="golang.org/x/exp" find ./x/ -type f -name 'go.mod' -print0 | while IFS= read -r -d '' file do d=$(dirname "$file") @@ -34,4 +35,9 @@ do echo "${d} has a dependency on server/v2!" exit 1 fi + + if cd "$CWD/$d" && go list -test -f '{{ .Imports }}' ./... | grep -q -E "${XEXP_REGEX}"; then + echo "${d} has a dependency on golang.org/x/exp" + exit 1 + fi done \ No newline at end of file diff --git a/server/v2/api/grpc/server.go b/server/v2/api/grpc/server.go index 006a970e09b9..b66be16da602 100644 --- a/server/v2/api/grpc/server.go +++ b/server/v2/api/grpc/server.go @@ -5,13 +5,14 @@ import ( "errors" "fmt" "io" + "maps" "net" + "slices" "strconv" "github.com/cosmos/gogoproto/proto" "github.com/spf13/pflag" "github.com/spf13/viper" - "golang.org/x/exp/maps" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" @@ -65,7 +66,7 @@ func (s *Server[T]) Init(appI serverv2.AppI[T], v *viper.Viper, logger log.Logge ) // Reflection allows external clients to see what services and methods the gRPC server exposes. - gogoreflection.Register(grpcSrv, maps.Keys(methodsMap), logger.With("sub-module", "grpc-reflection")) + gogoreflection.Register(grpcSrv, slices.Collect(maps.Keys(methodsMap)), logger.With("sub-module", "grpc-reflection")) s.grpcSrv = grpcSrv s.config = cfg diff --git a/server/v2/go.mod b/server/v2/go.mod index 5e5cedf830db..607ca7384469 100644 --- a/server/v2/go.mod +++ b/server/v2/go.mod @@ -38,7 +38,6 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc golang.org/x/sync v0.8.0 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 @@ -102,6 +101,7 @@ require ( github.com/tidwall/btree v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sys v0.24.0 // indirect diff --git a/server/v2/stf/core_event_service.go b/server/v2/stf/core_event_service.go index a27eddd35cd5..48b2507b433d 100644 --- a/server/v2/stf/core_event_service.go +++ b/server/v2/stf/core_event_service.go @@ -4,11 +4,11 @@ import ( "bytes" "context" "encoding/json" + "maps" "slices" "github.com/cosmos/gogoproto/jsonpb" gogoproto "github.com/cosmos/gogoproto/proto" - "golang.org/x/exp/maps" "cosmossdk.io/core/event" transaction "cosmossdk.io/core/transaction" @@ -49,12 +49,6 @@ func (em *eventManager) EmitKV(eventType string, attrs ...event.Attribute) error return nil } -// EmitNonConsensus emits an typed event that is defined in the protobuf file. -// These events will not be added to consensus. -func (em *eventManager) EmitNonConsensus(event transaction.Msg) error { - return em.Emit(event) -} - // TypedEventToEvent takes typed event and converts to Event object func TypedEventToEvent(tev transaction.Msg) (event.Event, error) { evtType := gogoproto.MessageName(tev) @@ -70,9 +64,7 @@ func TypedEventToEvent(tev transaction.Msg) (event.Event, error) { } // sort the keys to ensure the order is always the same - keys := maps.Keys(attrMap) - slices.Sort(keys) - + keys := slices.Sorted(maps.Keys(attrMap)) attrs := make([]event.Attribute, 0, len(attrMap)) for _, k := range keys { v := attrMap[k] diff --git a/server/v2/stf/go.mod b/server/v2/stf/go.mod index a11fe22895ee..50cb2a8821ac 100644 --- a/server/v2/stf/go.mod +++ b/server/v2/stf/go.mod @@ -9,13 +9,13 @@ require ( github.com/cosmos/gogoproto v1.7.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/btree v1.7.0 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d ) require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/store/v2/commitment/store.go b/store/v2/commitment/store.go index 68c83e1c3de1..da0440987524 100644 --- a/store/v2/commitment/store.go +++ b/store/v2/commitment/store.go @@ -4,11 +4,11 @@ import ( "errors" "fmt" "io" + "maps" "math" - "sort" + "slices" protoio "github.com/cosmos/gogoproto/io" - "golang.org/x/exp/maps" corelog "cosmossdk.io/core/log" corestore "cosmossdk.io/core/store" @@ -111,9 +111,7 @@ func (c *CommitStore) LoadVersion(targetVersion uint64) error { func (c *CommitStore) LoadVersionAndUpgrade(targetVersion uint64, upgrades *corestore.StoreUpgrades) error { // deterministic iteration order for upgrades (as the underlying store may change and // upgrades make store changes where the execution order may matter) - storeKeys := maps.Keys(c.multiTrees) - sort.Strings(storeKeys) - + storeKeys := slices.Sorted(maps.Keys(c.multiTrees)) removeTree := func(storeKey string) error { if oldTree, ok := c.multiTrees[storeKey]; ok { if err := oldTree.Close(); err != nil { diff --git a/store/v2/go.mod b/store/v2/go.mod index 9f2dc4f4c507..1a446e696501 100644 --- a/store/v2/go.mod +++ b/store/v2/go.mod @@ -20,7 +20,6 @@ require ( github.com/stretchr/testify v1.9.0 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d go.uber.org/mock v0.4.0 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/sync v0.8.0 ) @@ -59,6 +58,7 @@ require ( github.com/rs/zerolog v1.33.0 // indirect github.com/tidwall/btree v1.7.0 // indirect golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.17.0 // indirect google.golang.org/protobuf v1.34.2 // indirect diff --git a/store/v2/go.sum b/store/v2/go.sum index 8af3e61c137d..5c023c9b2bcb 100644 --- a/store/v2/go.sum +++ b/store/v2/go.sum @@ -228,8 +228,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/tests/systemtests/cli.go b/tests/systemtests/cli.go index bae6c55eaf73..697cc6b85225 100644 --- a/tests/systemtests/cli.go +++ b/tests/systemtests/cli.go @@ -8,6 +8,7 @@ import ( "os" "os/exec" "path/filepath" + "slices" "strings" "testing" "time" @@ -15,7 +16,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "golang.org/x/exp/slices" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index a4d405ded4df..c2bff18e7ff0 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -29,7 +29,6 @@ require ( github.com/creachadair/tomledit v0.0.26 github.com/tidwall/gjson v1.14.2 github.com/tidwall/sjson v1.2.5 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc ) require ( @@ -147,6 +146,7 @@ require ( go.etcd.io/bbolt v1.3.8 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect diff --git a/tests/systemtests/system.go b/tests/systemtests/system.go index 1c39cc150df5..8505d20d7868 100644 --- a/tests/systemtests/system.go +++ b/tests/systemtests/system.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "io" + "maps" "os" "os/exec" "path/filepath" @@ -23,7 +24,6 @@ import ( tmtypes "github.com/cometbft/cometbft/types" "github.com/stretchr/testify/require" "github.com/tidwall/sjson" - "golang.org/x/exp/maps" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" @@ -336,7 +336,7 @@ func (s *SystemUnderTest) withEachPid(cb func(p *os.Process)) { pids := maps.Keys(s.pids) s.pidsLock.RUnlock() - for _, pid := range pids { + for pid := range pids { p, err := os.FindProcess(pid) if err != nil { continue diff --git a/tools/confix/cmd/diff.go b/tools/confix/cmd/diff.go index f6d71bcaa5c5..89226a112236 100644 --- a/tools/confix/cmd/diff.go +++ b/tools/confix/cmd/diff.go @@ -3,11 +3,12 @@ package cmd import ( "errors" "fmt" + "maps" "path/filepath" + "slices" "strings" "github.com/spf13/cobra" - "golang.org/x/exp/maps" "cosmossdk.io/tools/confix" @@ -43,7 +44,7 @@ func DiffCommand() *cobra.Command { targetVersion := args[0] if _, ok := confix.Migrations[targetVersion]; !ok { - return fmt.Errorf("unknown version %q, supported versions are: %q", targetVersion, maps.Keys(confix.Migrations)) + return fmt.Errorf("unknown version %q, supported versions are: %q", targetVersion, slices.Collect(maps.Keys(confix.Migrations))) } targetVersionFile, err := confix.LoadLocalConfig(targetVersion, configType) diff --git a/tools/confix/cmd/migrate.go b/tools/confix/cmd/migrate.go index a7122161d14e..7e6c01e03401 100644 --- a/tools/confix/cmd/migrate.go +++ b/tools/confix/cmd/migrate.go @@ -4,11 +4,12 @@ import ( "context" "errors" "fmt" + "maps" "path/filepath" + "slices" "strings" "github.com/spf13/cobra" - "golang.org/x/exp/maps" "cosmossdk.io/tools/confix" @@ -60,7 +61,7 @@ In case of any error in updating the file, no output is written.`, targetVersion := args[0] plan, ok := confix.Migrations[targetVersion] if !ok { - return fmt.Errorf("unknown version %q, supported versions are: %q", targetVersion, maps.Keys(confix.Migrations)) + return fmt.Errorf("unknown version %q, supported versions are: %q", targetVersion, slices.Collect(maps.Keys(confix.Migrations))) } rawFile, err := confix.LoadConfig(configPath) diff --git a/tools/confix/go.mod b/tools/confix/go.mod index a9268468fbb5..23b8e71db64d 100644 --- a/tools/confix/go.mod +++ b/tools/confix/go.mod @@ -9,7 +9,6 @@ require ( github.com/pelletier/go-toml/v2 v2.2.2 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc gotest.tools/v3 v3.5.1 ) @@ -140,6 +139,7 @@ require ( go.etcd.io/bbolt v1.3.8 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect diff --git a/types/events.go b/types/events.go index 748b35ce63d4..55568c385897 100644 --- a/types/events.go +++ b/types/events.go @@ -3,6 +3,7 @@ package types import ( "encoding/json" "fmt" + "maps" "reflect" "slices" "strings" @@ -10,7 +11,6 @@ import ( abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" "github.com/cosmos/gogoproto/jsonpb" "github.com/cosmos/gogoproto/proto" - "golang.org/x/exp/maps" "github.com/cosmos/cosmos-sdk/codec" ) @@ -100,9 +100,7 @@ func TypedEventToEvent(tev proto.Message) (Event, error) { } // sort the keys to ensure the order is always the same - keys := maps.Keys(attrMap) - slices.Sort(keys) - + keys := slices.Sorted(maps.Keys(attrMap)) attrs := make([]abci.EventAttribute, 0, len(attrMap)) for _, k := range keys { v := attrMap[k] diff --git a/types/module/module.go b/types/module/module.go index 06be7817eb14..e24bc4f64f30 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -24,12 +24,13 @@ import ( "encoding/json" "errors" "fmt" + "maps" + "slices" "sort" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" - "golang.org/x/exp/maps" "google.golang.org/grpc" "cosmossdk.io/core/appmodule" @@ -832,7 +833,7 @@ func (m *Manager) GetVersionMap() appmodule.VersionMap { // ModuleNames returns list of all module names, without any particular order. func (m *Manager) ModuleNames() []string { - return maps.Keys(m.Modules) + return slices.Collect(maps.Keys(m.Modules)) } // DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name, diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index 97bf4d5cd7f1..8b5a91ed2a01 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -8,13 +8,12 @@ import ( "errors" "fmt" "io" + "maps" "os" "path/filepath" - "sort" + "slices" "sync" "time" - - "golang.org/x/exp/maps" ) const ( @@ -162,9 +161,7 @@ func (m *Manager) exportSnapshot(height uint64, snapshotWriter func([]byte) erro var buf bytes.Buffer w := bufio.NewWriter(&buf) - keys := maps.Keys(m.txHashes) - sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i][:], keys[j][:]) < 0 }) - + keys := slices.SortedFunc(maps.Keys(m.txHashes), func(i, j TxHash) int { return bytes.Compare(i[:], j[:]) }) timestamp := time.Unix(int64(height), 0) for _, txHash := range keys { timeoutTime := m.txHashes[txHash] diff --git a/x/auth/go.mod b/x/auth/go.mod index 19dda15d6834..47250dfc23ae 100644 --- a/x/auth/go.mod +++ b/x/auth/go.mod @@ -25,7 +25,6 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 @@ -156,6 +155,7 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect diff --git a/x/bank/depinject.go b/x/bank/depinject.go index 1d6f7dd3e533..ecc05abf4732 100644 --- a/x/bank/depinject.go +++ b/x/bank/depinject.go @@ -2,10 +2,10 @@ package bank import ( "fmt" + "maps" + "slices" "sort" - "golang.org/x/exp/maps" - modulev1 "cosmossdk.io/api/cosmos/bank/module/v1" "cosmossdk.io/core/appmodule" "cosmossdk.io/depinject" @@ -103,7 +103,7 @@ func InvokeSetSendRestrictions( return nil } - modules := maps.Keys(restrictions) + modules := slices.Collect(maps.Keys(restrictions)) order := config.RestrictionsOrder if len(order) == 0 { order = modules diff --git a/x/bank/go.mod b/x/bank/go.mod index bf0f89bb211e..a3704a5eeaa5 100644 --- a/x/bank/go.mod +++ b/x/bank/go.mod @@ -149,7 +149,7 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect diff --git a/x/epochs/depinject.go b/x/epochs/depinject.go index f09f9f95d9f8..24640e7c641f 100644 --- a/x/epochs/depinject.go +++ b/x/epochs/depinject.go @@ -2,9 +2,8 @@ package epochs import ( "fmt" - "sort" - - "golang.org/x/exp/maps" + "maps" + "slices" modulev1 "cosmossdk.io/api/cosmos/epochs/module/v1" "cosmossdk.io/core/appmodule" @@ -56,12 +55,9 @@ func InvokeSetHooks(keeper *keeper.Keeper, hooks map[string]types.EpochHooksWrap // Default ordering is lexical by module name. // Explicit ordering can be added to the module config if required. - modNames := maps.Keys(hooks) - order := modNames - sort.Strings(order) - + modNames := slices.Sorted(maps.Keys(hooks)) var multiHooks types.MultiEpochHooks - for _, modName := range order { + for _, modName := range modNames { hook, ok := hooks[modName] if !ok { return fmt.Errorf("can't find epoch hooks for module %s", modName) diff --git a/x/epochs/go.mod b/x/epochs/go.mod index 1081adf465f4..559f1f9b9419 100644 --- a/x/epochs/go.mod +++ b/x/epochs/go.mod @@ -146,7 +146,7 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect diff --git a/x/epochs/keeper/abci_test.go b/x/epochs/keeper/abci_test.go index e3d5f84ff55d..7a864d8ebf41 100644 --- a/x/epochs/keeper/abci_test.go +++ b/x/epochs/keeper/abci_test.go @@ -1,12 +1,12 @@ package keeper_test import ( - "sort" + "maps" + "slices" "testing" "time" "github.com/stretchr/testify/require" - "golang.org/x/exp/maps" "cosmossdk.io/core/header" "cosmossdk.io/x/epochs/types" @@ -89,9 +89,14 @@ func (suite *KeeperTestSuite) TestEpochInfoBeginBlockChanges() { suite.Require().NoError(err) // get sorted heights - heights := maps.Keys(test.blockHeightTimePairs) - sort.Slice(heights, func(i, j int) bool { return heights[i] < heights[j] }) - + heights := slices.SortedFunc(maps.Keys(test.blockHeightTimePairs), func(i, j int) int { + if test.blockHeightTimePairs[i].Before(test.blockHeightTimePairs[j]) { + return -1 + } else if test.blockHeightTimePairs[i].After(test.blockHeightTimePairs[j]) { + return 1 + } + return 0 + }) for _, h := range heights { // for each height in order, run begin block suite.Ctx = suite.Ctx.WithHeaderInfo(header.Info{Height: int64(h), Time: test.blockHeightTimePairs[h]}) diff --git a/x/feegrant/module/depinject.go b/x/feegrant/module/depinject.go index 3fb6afa68984..018b09d3d593 100644 --- a/x/feegrant/module/depinject.go +++ b/x/feegrant/module/depinject.go @@ -7,12 +7,9 @@ import ( "cosmossdk.io/depinject/appconfig" "cosmossdk.io/x/feegrant" "cosmossdk.io/x/feegrant/keeper" - "cosmossdk.io/x/feegrant/simulation" "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/types/module" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" ) var _ depinject.OnePerModuleType = AppModule{} @@ -41,23 +38,3 @@ func ProvideModule(in FeegrantInputs) (keeper.Keeper, appmodule.AppModule) { m := NewAppModule(in.Cdc, in.AccountKeeper, in.BankKeeper, k, in.Registry) return k, m } - -// AppModuleSimulation functions - -// GenerateGenesisState creates a randomized GenState of the feegrant module. -func (AppModule) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RegisterStoreDecoder registers a decoder for feegrant module's types -func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { - sdr[feegrant.StoreKey] = simulation.NewDecodeStore(am.cdc) -} - -// WeightedOperations returns all the feegrant module operations with their respective weights. -func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { - return simulation.WeightedOperations( - am.registry, simState.AppParams, simState.Cdc, simState.TxConfig, - am.accountKeeper, am.bankKeeper, am.keeper, am.accountKeeper.AddressCodec(), - ) -} diff --git a/x/feegrant/module/module.go b/x/feegrant/module/module.go index 134160422723..163c91cef1ef 100644 --- a/x/feegrant/module/module.go +++ b/x/feegrant/module/module.go @@ -16,11 +16,13 @@ import ( "cosmossdk.io/x/feegrant" "cosmossdk.io/x/feegrant/client/cli" "cosmossdk.io/x/feegrant/keeper" + "cosmossdk.io/x/feegrant/simulation" sdkclient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" ) var ( @@ -152,3 +154,23 @@ func (AppModule) ConsensusVersion() uint64 { return 2 } func (am AppModule) EndBlock(ctx context.Context) error { return EndBlocker(ctx, am.keeper) } + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the feegrant module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// RegisterStoreDecoder registers a decoder for feegrant module's types +func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { + sdr[feegrant.StoreKey] = simulation.NewDecodeStore(am.cdc) +} + +// WeightedOperations returns all the feegrant module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return simulation.WeightedOperations( + am.registry, simState.AppParams, simState.Cdc, simState.TxConfig, + am.accountKeeper, am.bankKeeper, am.keeper, am.accountKeeper.AddressCodec(), + ) +} diff --git a/x/genutil/client/cli/migrate.go b/x/genutil/client/cli/migrate.go index 1ee0fc07f0ca..08eb01ced8c9 100644 --- a/x/genutil/client/cli/migrate.go +++ b/x/genutil/client/cli/migrate.go @@ -3,12 +3,12 @@ package cli import ( "encoding/json" "fmt" - "sort" + "maps" + "slices" "strings" "time" "github.com/spf13/cobra" - "golang.org/x/exp/maps" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -52,8 +52,7 @@ func MigrateHandler(cmd *cobra.Command, args []string, migrations types.Migratio migrationFunc, ok := migrations[target] if !ok || migrationFunc == nil { versions := maps.Keys(migrations) - sort.Strings(versions) - return fmt.Errorf("unknown migration function for version: %s (supported versions %s)", target, strings.Join(versions, ", ")) + return fmt.Errorf("unknown migration function for version: %s (supported versions %s)", target, strings.Join(slices.Sorted(versions), ", ")) } importGenesis := args[1] diff --git a/x/gov/depinject.go b/x/gov/depinject.go index 72f9b4767169..46af43b1c782 100644 --- a/x/gov/depinject.go +++ b/x/gov/depinject.go @@ -2,12 +2,10 @@ package gov import ( "fmt" + "maps" "slices" - "sort" "strings" - "golang.org/x/exp/maps" - modulev1 "cosmossdk.io/api/cosmos/gov/module/v1" "cosmossdk.io/core/appmodule" "cosmossdk.io/depinject" @@ -122,12 +120,9 @@ func InvokeSetHooks(keeper *keeper.Keeper, govHooks map[string]govtypes.GovHooks // Default ordering is lexical by module name. // Explicit ordering can be added to the module config if required. - modNames := maps.Keys(govHooks) - order := modNames - sort.Strings(order) - + modNames := slices.Sorted(maps.Keys(govHooks)) var multiHooks govtypes.MultiGovHooks - for _, modName := range order { + for _, modName := range modNames { hook, ok := govHooks[modName] if !ok { return fmt.Errorf("can't find staking hooks for module %s", modName) diff --git a/x/gov/go.mod b/x/gov/go.mod index a0b3c9ca9954..e41756b00731 100644 --- a/x/gov/go.mod +++ b/x/gov/go.mod @@ -28,7 +28,6 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 @@ -158,6 +157,7 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 diff --git a/x/group/go.mod b/x/group/go.mod index 1f67ec61ef22..a1df92725fb7 100644 --- a/x/group/go.mod +++ b/x/group/go.mod @@ -31,7 +31,6 @@ require ( github.com/manifoldco/promptui v0.9.0 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 @@ -165,6 +164,7 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect diff --git a/x/group/keeper/invariants.go b/x/group/keeper/invariants.go index d3f47201a208..33034b5d7506 100644 --- a/x/group/keeper/invariants.go +++ b/x/group/keeper/invariants.go @@ -2,10 +2,9 @@ package keeper import ( "fmt" + "maps" "math" - "sort" - - "golang.org/x/exp/maps" + "slices" storetypes "cosmossdk.io/core/store" "cosmossdk.io/x/group" @@ -58,9 +57,14 @@ func GroupTotalWeightInvariantHelper(ctx sdk.Context, storeService storetypes.KV groups[groupInfo.Id] = groupInfo } - groupByIDs := maps.Keys(groups) - sort.Slice(groupByIDs, func(i, j int) bool { - return groupByIDs[i] < groupByIDs[j] + groupByIDs := slices.Collect(maps.Keys(groups)) + slices.SortFunc(groupByIDs, func(i, j uint64) int { + if groupByIDs[i] < groupByIDs[j] { + return -1 + } else if groupByIDs[i] > groupByIDs[j] { + return 1 + } + return 0 }) for _, groupID := range groupByIDs { diff --git a/x/staking/depinject.go b/x/staking/depinject.go index a4dfc2630d52..4adee385d4d1 100644 --- a/x/staking/depinject.go +++ b/x/staking/depinject.go @@ -2,10 +2,10 @@ package staking import ( "fmt" + "maps" + "slices" "sort" - "golang.org/x/exp/maps" - modulev1 "cosmossdk.io/api/cosmos/staking/module/v1" "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" @@ -92,7 +92,11 @@ func InvokeSetStakingHooks( return nil } - modNames := maps.Keys(stakingHooks) + if len(stakingHooks) == 0 { + return nil + } + + modNames := slices.Collect(maps.Keys(stakingHooks)) order := config.HooksOrder if len(order) == 0 { order = modNames @@ -103,10 +107,6 @@ func InvokeSetStakingHooks( return fmt.Errorf("len(hooks_order: %v) != len(hooks modules: %v)", order, modNames) } - if len(modNames) == 0 { - return nil - } - var multiHooks types.MultiStakingHooks for _, modName := range order { hook, ok := stakingHooks[modName] diff --git a/x/staking/go.mod b/x/staking/go.mod index 0b2c17eeae9a..170146613aa8 100644 --- a/x/staking/go.mod +++ b/x/staking/go.mod @@ -23,7 +23,6 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 @@ -173,6 +172,7 @@ require ( require ( cosmossdk.io/schema v0.1.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect ) replace github.com/cosmos/cosmos-sdk => ../../. From c286e6ef7dae310ac283ff0657db7eb5442af666 Mon Sep 17 00:00:00 2001 From: Facundo Medica <14063057+facundomedica@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:02:01 +0200 Subject: [PATCH 04/26] fix(x/protocolpool)!: do not incur into extra writes if there are no continuous funds (#21356) --- x/protocolpool/keeper/keeper.go | 25 +++++++++++++++++++++++++ x/protocolpool/keeper/keeper_test.go | 23 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/x/protocolpool/keeper/keeper.go b/x/protocolpool/keeper/keeper.go index ca79d60e817c..f0d6cff755a7 100644 --- a/x/protocolpool/keeper/keeper.go +++ b/x/protocolpool/keeper/keeper.go @@ -177,6 +177,31 @@ func (k Keeper) SetToDistribute(ctx context.Context) error { // Calculate the amount to be distributed amountToDistribute := distributionBalance.Sub(lastBalance) + // Check if there are any recipients to distribute to, if not, send straight to the community pool and avoid + // setting the distributions + hasContinuousFunds := false + err = k.ContinuousFund.Walk(ctx, nil, func(_ sdk.AccAddress, _ types.ContinuousFund) (bool, error) { + hasContinuousFunds = true + return true, nil + }) + if err != nil { + return err + } + + // if there are no continuous funds, send all the funds to the community pool and reset the last balance + if !hasContinuousFunds { + poolCoins := sdk.NewCoins(sdk.NewCoin(denom, amountToDistribute)) + if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ProtocolPoolDistrAccount, types.ModuleName, poolCoins); err != nil { + return err + } + + if !lastBalance.IsZero() { // only reset if the last balance is not zero (so we leave it at zero/nil) + return k.LastBalance.Set(ctx, math.ZeroInt()) + } + + return nil + } + if err = k.Distributions.Set(ctx, k.HeaderService.HeaderInfo(ctx).Time, amountToDistribute); err != nil { return fmt.Errorf("error while setting Distributions: %w", err) } diff --git a/x/protocolpool/keeper/keeper_test.go b/x/protocolpool/keeper/keeper_test.go index a543f0c30dae..fa147d973146 100644 --- a/x/protocolpool/keeper/keeper_test.go +++ b/x/protocolpool/keeper/keeper_test.go @@ -186,9 +186,32 @@ func (suite *KeeperTestSuite) TestSetToDistribute() { distrBal := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000))) suite.bankKeeper.EXPECT().GetAllBalances(suite.ctx, poolDistrAcc.GetAddress()).Return(distrBal).AnyTimes() + // because there are no continuous funds, all are going to the community pool + suite.bankKeeper.EXPECT().SendCoinsFromModuleToModule(suite.ctx, poolDistrAcc.GetName(), poolAcc.GetName(), distrBal) + err := suite.poolKeeper.SetToDistribute(suite.ctx) suite.Require().NoError(err) + // Verify that LastBalance was not set (zero balance) + _, err = suite.poolKeeper.LastBalance.Get(suite.ctx) + suite.Require().ErrorContains(err, "not found") + + // create new continuous fund and distribute again + addrCdc := address.NewBech32Codec("cosmos") + addrStr := "cosmos1qypq2q2l8z4wz2z2l8z4wz2z2l8z4wz2srklj6" + addrBz, err := addrCdc.StringToBytes(addrStr) + suite.Require().NoError(err) + + err = suite.poolKeeper.ContinuousFund.Set(suite.ctx, addrBz, types.ContinuousFund{ + Recipient: addrStr, + Percentage: math.LegacyMustNewDecFromStr("0.3"), + Expiry: nil, + }) + suite.Require().NoError(err) + + err = suite.poolKeeper.SetToDistribute(suite.ctx) + suite.Require().NoError(err) + // Verify that LastBalance was set correctly lastBalance, err := suite.poolKeeper.LastBalance.Get(suite.ctx) suite.Require().NoError(err) From ee8331b97f47bbf8ab087a611e4962202e5dbed1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 08:28:54 +0200 Subject: [PATCH 05/26] build(deps): Bump github.com/creachadair/atomicfile from 0.3.4 to 0.3.5 in /tools/confix (#21365) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- simapp/go.mod | 2 +- simapp/go.sum | 8 ++++---- simapp/v2/go.mod | 2 +- simapp/v2/go.sum | 8 ++++---- tools/confix/go.mod | 2 +- tools/confix/go.sum | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/simapp/go.mod b/simapp/go.mod index 6bd576f9aca8..cea48bf6acaa 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -92,7 +92,7 @@ require ( github.com/cosmos/iavl v1.2.1-0.20240725141113-7adc688cf179 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect - github.com/creachadair/atomicfile v0.3.4 // indirect + github.com/creachadair/atomicfile v0.3.5 // indirect github.com/creachadair/tomledit v0.0.26 // indirect github.com/danieljoos/wincred v1.2.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect diff --git a/simapp/go.sum b/simapp/go.sum index 1b6fd52fabc0..2f3730710dc5 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -330,10 +330,10 @@ github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStK github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creachadair/atomicfile v0.3.4 h1:AjNK7To+S1p+nk7uJXJMZFpcV9XHOyAaULyDeU6LEqM= -github.com/creachadair/atomicfile v0.3.4/go.mod h1:ByEUbfQyms+tRtE7Wk7WdS6PZeyMzfSFlNX1VoKEh6E= -github.com/creachadair/mds v0.13.3 h1:OqXNRorXKsuvfjor+0ixtrpA4IINApH8zgm23XLlngk= -github.com/creachadair/mds v0.13.3/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= +github.com/creachadair/atomicfile v0.3.5 h1:i93bxeaH/rQR6XfJslola3XkOM1nEP3eIexuk9SWcSc= +github.com/creachadair/atomicfile v0.3.5/go.mod h1:m7kIY2OUMygtETnMYe141rubsG4b+EusFLinlxxdHYM= +github.com/creachadair/mds v0.16.0 h1:v6DlvKXClowXFg4hkjLCR1FEFiREMf0qgX+Lm5GsEKk= +github.com/creachadair/mds v0.16.0/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= github.com/creachadair/tomledit v0.0.26 h1:MoDdgHIHZ5PctBVsAZDjxdxreWUEa9ObPKTRkk5PPwA= github.com/creachadair/tomledit v0.0.26/go.mod h1:SJi1OxKpMyR141tq1lzsbPtIg3j8TeVPM/ZftfieD7o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index 61d91c6ede06..08f043f23dc7 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -95,7 +95,7 @@ require ( github.com/cosmos/iavl v1.2.1-0.20240731145221-594b181f427e // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect - github.com/creachadair/atomicfile v0.3.4 // indirect + github.com/creachadair/atomicfile v0.3.5 // indirect github.com/creachadair/tomledit v0.0.26 // indirect github.com/danieljoos/wincred v1.2.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index 32df13f2635e..b19103551ebd 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -334,10 +334,10 @@ github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStK github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creachadair/atomicfile v0.3.4 h1:AjNK7To+S1p+nk7uJXJMZFpcV9XHOyAaULyDeU6LEqM= -github.com/creachadair/atomicfile v0.3.4/go.mod h1:ByEUbfQyms+tRtE7Wk7WdS6PZeyMzfSFlNX1VoKEh6E= -github.com/creachadair/mds v0.13.3 h1:OqXNRorXKsuvfjor+0ixtrpA4IINApH8zgm23XLlngk= -github.com/creachadair/mds v0.13.3/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= +github.com/creachadair/atomicfile v0.3.5 h1:i93bxeaH/rQR6XfJslola3XkOM1nEP3eIexuk9SWcSc= +github.com/creachadair/atomicfile v0.3.5/go.mod h1:m7kIY2OUMygtETnMYe141rubsG4b+EusFLinlxxdHYM= +github.com/creachadair/mds v0.16.0 h1:v6DlvKXClowXFg4hkjLCR1FEFiREMf0qgX+Lm5GsEKk= +github.com/creachadair/mds v0.16.0/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= github.com/creachadair/tomledit v0.0.26 h1:MoDdgHIHZ5PctBVsAZDjxdxreWUEa9ObPKTRkk5PPwA= github.com/creachadair/tomledit v0.0.26/go.mod h1:SJi1OxKpMyR141tq1lzsbPtIg3j8TeVPM/ZftfieD7o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/tools/confix/go.mod b/tools/confix/go.mod index 23b8e71db64d..fb05e9128d14 100644 --- a/tools/confix/go.mod +++ b/tools/confix/go.mod @@ -4,7 +4,7 @@ go 1.23 require ( github.com/cosmos/cosmos-sdk v0.50.9 - github.com/creachadair/atomicfile v0.3.4 + github.com/creachadair/atomicfile v0.3.5 github.com/creachadair/tomledit v0.0.26 github.com/pelletier/go-toml/v2 v2.2.2 github.com/spf13/cobra v1.8.1 diff --git a/tools/confix/go.sum b/tools/confix/go.sum index c3bd8d174c6f..d23a139e159c 100644 --- a/tools/confix/go.sum +++ b/tools/confix/go.sum @@ -161,10 +161,10 @@ github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5X 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.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creachadair/atomicfile v0.3.4 h1:AjNK7To+S1p+nk7uJXJMZFpcV9XHOyAaULyDeU6LEqM= -github.com/creachadair/atomicfile v0.3.4/go.mod h1:ByEUbfQyms+tRtE7Wk7WdS6PZeyMzfSFlNX1VoKEh6E= -github.com/creachadair/mds v0.13.3 h1:OqXNRorXKsuvfjor+0ixtrpA4IINApH8zgm23XLlngk= -github.com/creachadair/mds v0.13.3/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= +github.com/creachadair/atomicfile v0.3.5 h1:i93bxeaH/rQR6XfJslola3XkOM1nEP3eIexuk9SWcSc= +github.com/creachadair/atomicfile v0.3.5/go.mod h1:m7kIY2OUMygtETnMYe141rubsG4b+EusFLinlxxdHYM= +github.com/creachadair/mds v0.16.0 h1:v6DlvKXClowXFg4hkjLCR1FEFiREMf0qgX+Lm5GsEKk= +github.com/creachadair/mds v0.16.0/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= github.com/creachadair/tomledit v0.0.26 h1:MoDdgHIHZ5PctBVsAZDjxdxreWUEa9ObPKTRkk5PPwA= github.com/creachadair/tomledit v0.0.26/go.mod h1:SJi1OxKpMyR141tq1lzsbPtIg3j8TeVPM/ZftfieD7o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= From aeb0f275f9ca87248d7af573f622e00036225094 Mon Sep 17 00:00:00 2001 From: Ezequiel Raynaudo Date: Tue, 20 Aug 2024 03:49:00 -0300 Subject: [PATCH 06/26] docs(x/feegrant): Update readme (#21364) --- x/feegrant/README.md | 97 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 22 deletions(-) diff --git a/x/feegrant/README.md b/x/feegrant/README.md index 07524449a862..f60720a51ff4 100644 --- a/x/feegrant/README.md +++ b/x/feegrant/README.md @@ -35,13 +35,13 @@ This module allows accounts to grant fee allowances and to use fees from their a `Grant` is stored in the KVStore to record a grant with full context. Every grant will contain `granter`, `grantee` and what kind of `allowance` is granted. `granter` is an account address who is giving permission to `grantee` (the beneficiary account address) to pay for some or all of `grantee`'s transaction fees. `allowance` defines what kind of fee allowance (`BasicAllowance` or `PeriodicAllowance`, see below) is granted to `grantee`. `allowance` accepts an interface which implements `FeeAllowanceI`, encoded as `Any` type. There can be only one existing fee grant allowed for a `grantee` and `granter`, self grants are not allowed. ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1beta1/feegrant.proto#L83-L93 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/feegrant/proto/cosmos/feegrant/v1beta1/feegrant.proto#L86-L96 ``` `FeeAllowanceI` looks like: ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/x/feegrant/fees.go#L9-L32 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/feegrant/fees.go#L10-L34 ``` ### Fee Allowance types @@ -57,7 +57,7 @@ There are two types of fee allowances present at the moment: `BasicAllowance` is permission for `grantee` to use fee from a `granter`'s account. If any of the `spend_limit` or `expiration` reaches its limit, the grant will be removed from the state. ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1beta1/feegrant.proto#L15-L28 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/feegrant/proto/cosmos/feegrant/v1beta1/feegrant.proto#L15-L33 ``` * `spend_limit` is the limit of coins that are allowed to be used from the `granter` account. If it is empty, it assumes there's no spend limit, `grantee` can use any number of available coins from `granter` account address before the expiration. @@ -71,7 +71,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1be `PeriodicAllowance` is a repeating fee allowance for the mentioned period, we can mention when the grant can expire as well as when a period can reset. We can also define the maximum number of coins that can be used in a mentioned period of time. ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1beta1/feegrant.proto#L34-L68 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/feegrant/proto/cosmos/feegrant/v1beta1/feegrant.proto#L35-L71 ``` * `basic` is the instance of `BasicAllowance` which is optional for periodic fee allowance. If empty, the grant will have no `expiration` and no `spend_limit`. @@ -89,7 +89,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1be `AllowedMsgAllowance` is a fee allowance, it can be any of `BasicFeeAllowance`, `PeriodicAllowance` but restricted only to the allowed messages mentioned by the granter. ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1beta1/feegrant.proto#L70-L81 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/feegrant/proto/cosmos/feegrant/v1beta1/feegrant.proto#L73-L84 ``` * `allowance` is either `BasicAllowance` or `PeriodicAllowance`. @@ -101,25 +101,25 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1be `feegrant` module introduces a `FeeGranter` flag for CLI for the sake of executing transactions with fee granter. When this flag is set, `clientCtx` will append the granter account address for transactions generated through CLI. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/client/cmd.go#L249-L260 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/client/cmd.go#L256-L267 ``` ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/client/tx/tx.go#L109-L109 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/client/tx/tx.go#L129-L131 ``` ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/x/auth/tx/builder.go#L275-L284 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/auth/tx/builder.go#L208 ``` ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/tx/v1beta1/tx.proto#L203-L224 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/proto/cosmos/tx/v1beta1/tx.proto#L216-L243 ``` Example cmd: -```go -./simd tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --from validator-key --fee-granter=cosmos1xh44hxt7spr67hqaa7nyx5gnutrz5fraw6grxn --chain-id=testnet --fees="10stake" +```shell +simd tx gov submit-legacy-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --from validator-key --fee-granter=cosmos1xh44hxt7spr67hqaa7nyx5gnutrz5fraw6grxn --chain-id=testnet --fees="10stake" ``` ### Granted Fee Deductions @@ -147,7 +147,7 @@ Fee allowance grants are stored in the state as follows: * Grant: `0x00 | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> ProtocolBuffer(Grant)` ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/x/feegrant/feegrant.pb.go#L222-L230 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/feegrant/feegrant.pb.go#L222-L230 ``` ### FeeAllowanceQueue @@ -165,7 +165,7 @@ Fee allowance queue keys are stored in the state as follows: A fee allowance grant will be created with the `MsgGrantAllowance` message. ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1beta1/tx.proto#L25-L39 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/feegrant/proto/cosmos/feegrant/v1beta1/tx.proto#L30-L44 ``` ### Msg/RevokeAllowance @@ -173,7 +173,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1be An allowed grant fee allowance can be removed with the `MsgRevokeAllowance` message. ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/feegrant/v1beta1/tx.proto#L41-L54 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/feegrant/proto/cosmos/feegrant/v1beta1/tx.proto#L49-L62 ``` ## Events @@ -255,18 +255,49 @@ grantee: cosmos1.. granter: cosmos1.. ``` -##### grants +##### grants-by-grantee -The `grants` command allows users to query all grants for a given grantee. +The `grants-by-grantee ` command allows users to query all grants for a given grantee. ```shell -simd query feegrant grants [grantee] [flags] +simd query feegrant grants-by-grantee [grantee] [flags] ``` Example: ```shell -simd query feegrant grants cosmos1.. +simd query feegrant grants-by-grantee cosmos1.. +``` + +Example Output: + +```yml +allowances: +- allowance: + '@type': /cosmos.feegrant.v1beta1.BasicAllowance + expiration: null + spend_limit: + - amount: "100" + denom: stake + grantee: cosmos1.. + granter: cosmos1.. +pagination: + next_key: null + total: "0" +``` + +##### grants-by-granter + +The `grants-by-granter` command allows users to query all grants created by a given granter. + +```shell +simd query feegrant grants-by-granter [granter] [flags] +``` + +Example: + +```shell +simd query feegrant grants-by-granter cosmos1.. ``` Example Output: @@ -296,24 +327,46 @@ simd tx feegrant --help ##### grant -The `grant` command allows users to grant fee allowances to another account. The fee allowance can have an expiration date, a total spend limit, and/or a periodic spend limit. +The `grant` command allows users to grant fee allowances to another account. The fee allowance can have an expiration date, a total spend limit, a periodic spend limit, and/or allowed messages. ```shell simd tx feegrant grant [granter] [grantee] [flags] ``` -Example (one-time spend limit): +Examples: + +###### One-time spend limit ```shell simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake ``` -Example (periodic spend limit): +###### Periodic spend limit ```shell -simd tx feegrant grant cosmos1.. cosmos1.. --period 3600 --period-limit 10stake +simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake --period 3600 --period-limit 10stake ``` +###### With expiration + +```shell +simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake --expiration 2024-10-31T15:04:05Z +``` + +###### With allowed messages + +```shell +simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake --expiration 2024-10-31T15:04:05Z --allowed-messages "/cosmos.gov.v1beta1.MsgSubmitProposal,/cosmos.gov.v1beta1.MsgVote" +``` + +Available flags: + +- `--spend-limit`: The maximum amount of tokens the grantee can spend +- `--period`: The time duration in seconds for periodic allowance +- `--period-limit`: The maximum amount of tokens the grantee can spend within each period +- `--expiration`: The date and time when the grant expires (RFC3339 format) +- `--allowed-messages`: Comma-separated list of allowed message type URLs + ##### revoke The `revoke` command allows users to revoke a granted fee allowance. From 27d3d4892b1b83d8f0b74a4e3ed411f285c8e833 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 20 Aug 2024 09:06:25 -0400 Subject: [PATCH 07/26] feat(schema/appdata)!: make commit async (#21306) --- indexer/postgres/indexer.go | 6 +-- indexer/postgres/tests/init_schema_test.go | 6 ++- schema/appdata/async.go | 52 ++++++---------------- schema/appdata/async_test.go | 45 ++++++++++++------- schema/appdata/forwarder.go | 2 +- schema/appdata/listener.go | 7 ++- schema/appdata/mux.go | 25 ++++++++--- schema/appdata/mux_test.go | 18 +++++--- schema/appdata/packet.go | 9 +++- schema/testing/appdatasim/app_data_test.go | 6 +-- 10 files changed, 100 insertions(+), 76 deletions(-) diff --git a/indexer/postgres/indexer.go b/indexer/postgres/indexer.go index a69eefff1cd0..ab911d8d22ba 100644 --- a/indexer/postgres/indexer.go +++ b/indexer/postgres/indexer.go @@ -68,14 +68,14 @@ func StartIndexer(ctx context.Context, logger SqlLogger, config Config) (appdata return mm.InitializeSchema(ctx, tx) }, - Commit: func(data appdata.CommitData) error { + Commit: func(data appdata.CommitData) (completionCallback func() error, err error) { err = tx.Commit() if err != nil { - return err + return nil, err } tx, err = db.BeginTx(ctx, nil) - return err + return nil, err }, }, nil } diff --git a/indexer/postgres/tests/init_schema_test.go b/indexer/postgres/tests/init_schema_test.go index 8c4288ba344f..ae7da66c525a 100644 --- a/indexer/postgres/tests/init_schema_test.go +++ b/indexer/postgres/tests/init_schema_test.go @@ -58,7 +58,11 @@ func testInitSchema(t *testing.T, disableRetainDeletions bool, goldenFileName st })) require.NotNil(t, listener.Commit) - require.NoError(t, listener.Commit(appdata.CommitData{})) + cb, err := listener.Commit(appdata.CommitData{}) + require.NoError(t, err) + if cb != nil { + require.NoError(t, cb()) + } golden.Assert(t, buf.String(), goldenFileName) } diff --git a/schema/appdata/async.go b/schema/appdata/async.go index 4112ae839fe9..59c671186e7c 100644 --- a/schema/appdata/async.go +++ b/schema/appdata/async.go @@ -19,50 +19,24 @@ type AsyncListenerOptions struct { DoneWaitGroup *sync.WaitGroup } -// AsyncListenerMux returns a listener that forwards received events to all the provided listeners asynchronously -// with each listener processing in a separate go routine. All callbacks in the returned listener will return nil -// except for Commit which will return an error or nil once all listeners have processed the commit. The context -// is used to signal that the listeners should stop listening and return. bufferSize is the size of the buffer for the -// channels used to send events to the listeners. +// AsyncListenerMux is a convenience function that calls AsyncListener for each listener +// with the provided options and combines them using ListenerMux. func AsyncListenerMux(opts AsyncListenerOptions, listeners ...Listener) Listener { asyncListeners := make([]Listener, len(listeners)) - commitChans := make([]chan error, len(listeners)) for i, l := range listeners { - commitChan := make(chan error) - commitChans[i] = commitChan - asyncListeners[i] = AsyncListener(opts, commitChan, l) + asyncListeners[i] = AsyncListener(opts, l) } - mux := ListenerMux(asyncListeners...) - muxCommit := mux.Commit - mux.Commit = func(data CommitData) error { - if muxCommit != nil { - err := muxCommit(data) - if err != nil { - return err - } - } - - for _, commitChan := range commitChans { - err := <-commitChan - if err != nil { - return err - } - } - return nil - } - - return mux + return ListenerMux(asyncListeners...) } // AsyncListener returns a listener that forwards received events to the provided listener listening in asynchronously // in a separate go routine. The listener that is returned will return nil for all methods including Commit and -// an error or nil will only be returned in commitChan once the sender has sent commit and the receiving listener has -// processed it. Thus commitChan can be used as a synchronization and error checking mechanism. The go routine +// an error or nil will only be returned when the callback returned by Commit is called. +// Thus Commit() can be used as a synchronization and error checking mechanism. The go routine // that is being used for listening will exit when context.Done() returns and no more events will be received by the listener. // bufferSize is the size of the buffer for the channel that is used to send events to the listener. -// Instead of using AsyncListener directly, it is recommended to use AsyncListenerMux which does coordination directly -// via its Commit callback. -func AsyncListener(opts AsyncListenerOptions, commitChan chan<- error, listener Listener) Listener { +func AsyncListener(opts AsyncListenerOptions, listener Listener) Listener { + commitChan := make(chan error) packetChan := make(chan Packet, opts.BufferSize) res := Listener{} ctx := opts.Context @@ -151,11 +125,11 @@ func AsyncListener(opts AsyncListenerOptions, commitChan chan<- error, listener } } - if listener.Commit != nil { - res.Commit = func(data CommitData) error { - packetChan <- data - return nil - } + res.Commit = func(data CommitData) (func() error, error) { + packetChan <- data + return func() error { + return <-commitChan + }, nil } return res diff --git a/schema/appdata/async_test.go b/schema/appdata/async_test.go index c1df2d4ca6c0..856575f71be1 100644 --- a/schema/appdata/async_test.go +++ b/schema/appdata/async_test.go @@ -47,7 +47,12 @@ func TestAsyncListenerMux(t *testing.T) { BufferSize: 16, Context: ctx, DoneWaitGroup: wg, }, listener1, listener2) - callAllCallbacksOnces(t, res) + completeCb := callAllCallbacksOnces(t, res) + if completeCb != nil { + if err := completeCb(); err != nil { + t.Fatal(err) + } + } expectedCalls := []string{ "InitializeModuleData", @@ -72,15 +77,23 @@ func TestAsyncListenerMux(t *testing.T) { listener1 := callCollector(1, func(name string, _ int, _ Packet) { calls1 = append(calls1, name) }) - listener1.Commit = func(data CommitData) error { - return fmt.Errorf("error") + listener1.Commit = func(data CommitData) (completionCallback func() error, err error) { + return nil, fmt.Errorf("error") } listener2 := callCollector(2, func(name string, _ int, _ Packet) { calls2 = append(calls2, name) }) res := AsyncListenerMux(AsyncListenerOptions{}, listener1, listener2) - err := res.Commit(CommitData{}) + cb, err := res.Commit(CommitData{}) + if err != nil { + t.Fatalf("expected first error to be nil, got %v", err) + } + if cb == nil { + t.Fatalf("expected completion callback") + } + + err = cb() if err == nil || err.Error() != "error" { t.Fatalf("expected error, got %v", err) } @@ -89,21 +102,19 @@ func TestAsyncListenerMux(t *testing.T) { func TestAsyncListener(t *testing.T) { t.Run("call cancel", func(t *testing.T) { - commitChan := make(chan error) ctx, cancel := context.WithCancel(context.Background()) wg := &sync.WaitGroup{} var calls []string listener := callCollector(1, func(name string, _ int, _ Packet) { calls = append(calls, name) }) - res := AsyncListener(AsyncListenerOptions{BufferSize: 16, Context: ctx, DoneWaitGroup: wg}, - commitChan, listener) - - callAllCallbacksOnces(t, res) + res := AsyncListener(AsyncListenerOptions{BufferSize: 16, Context: ctx, DoneWaitGroup: wg}, listener) - err := <-commitChan - if err != nil { - t.Fatalf("expected nil, got %v", err) + completeCb := callAllCallbacksOnces(t, res) + if completeCb != nil { + if err := completeCb(); err != nil { + t.Fatal(err) + } } checkExpectedCallOrder(t, calls, []string{ @@ -124,7 +135,6 @@ func TestAsyncListener(t *testing.T) { }) t.Run("error", func(t *testing.T) { - commitChan := make(chan error) var calls []string listener := callCollector(1, func(name string, _ int, _ Packet) { calls = append(calls, name) @@ -134,11 +144,14 @@ func TestAsyncListener(t *testing.T) { return fmt.Errorf("error") } - res := AsyncListener(AsyncListenerOptions{BufferSize: 16}, commitChan, listener) + res := AsyncListener(AsyncListenerOptions{BufferSize: 16}, listener) - callAllCallbacksOnces(t, res) + completeCb := callAllCallbacksOnces(t, res) + if completeCb == nil { + t.Fatalf("expected completion callback") + } - err := <-commitChan + err := completeCb() if err == nil || err.Error() != "error" { t.Fatalf("expected error, got %v", err) } diff --git a/schema/appdata/forwarder.go b/schema/appdata/forwarder.go index 2fb4113c8564..973b3c3bbacc 100644 --- a/schema/appdata/forwarder.go +++ b/schema/appdata/forwarder.go @@ -10,6 +10,6 @@ func PacketForwarder(f func(Packet) error) Listener { OnKVPair: func(data KVPairData) error { return f(data) }, OnObjectUpdate: func(data ObjectUpdateData) error { return f(data) }, StartBlock: func(data StartBlockData) error { return f(data) }, - Commit: func(data CommitData) error { return f(data) }, + Commit: func(data CommitData) (func() error, error) { return nil, f(data) }, } } diff --git a/schema/appdata/listener.go b/schema/appdata/listener.go index d4786cb02564..0a7efa926a83 100644 --- a/schema/appdata/listener.go +++ b/schema/appdata/listener.go @@ -37,5 +37,10 @@ type Listener struct { // indexers should commit their data when this is called and return an error if // they are unable to commit. Data sources MUST call Commit when data is committed, // otherwise it should be assumed that indexers have not persisted their state. - Commit func(CommitData) error + // Commit is designed to support async processing so that implementations may return + // a completion callback to wait for commit to complete. Callers should first check + // if err is nil and then if it is, check if completionCallback is nil and if not + // call it and check for an error. Commit should be designed to be non-blocking if + // possible, but calling completionCallback should be blocking. + Commit func(CommitData) (completionCallback func() error, err error) } diff --git a/schema/appdata/mux.go b/schema/appdata/mux.go index 8e6b886577d2..c35472dc0130 100644 --- a/schema/appdata/mux.go +++ b/schema/appdata/mux.go @@ -107,20 +107,33 @@ func ListenerMux(listeners ...Listener) Listener { } } - commitCbs := make([]func(CommitData) error, 0, len(listeners)) + commitCbs := make([]func(CommitData) (func() error, error), 0, len(listeners)) for _, l := range listeners { if l.Commit != nil { commitCbs = append(commitCbs, l.Commit) } } - if len(commitCbs) > 0 { - mux.Commit = func(data CommitData) error { + n := len(commitCbs) + if n > 0 { + mux.Commit = func(data CommitData) (func() error, error) { + waitCbs := make([]func() error, 0, n) for _, cb := range commitCbs { - if err := cb(data); err != nil { - return err + wait, err := cb(data) + if err != nil { + return nil, err + } + if wait != nil { + waitCbs = append(waitCbs, wait) } } - return nil + return func() error { + for _, cb := range waitCbs { + if err := cb(); err != nil { + return err + } + } + return nil + }, nil } } diff --git a/schema/appdata/mux_test.go b/schema/appdata/mux_test.go index 70787fada8a5..4f3897238cf5 100644 --- a/schema/appdata/mux_test.go +++ b/schema/appdata/mux_test.go @@ -40,7 +40,12 @@ func TestListenerMux(t *testing.T) { res := ListenerMux(callCollector(1, onCall), callCollector(2, onCall)) - callAllCallbacksOnces(t, res) + completeCb := callAllCallbacksOnces(t, res) + if completeCb != nil { + if err := completeCb(); err != nil { + t.Fatal(err) + } + } checkExpectedCallOrder(t, calls, []string{ "InitializeModuleData 1", @@ -61,7 +66,7 @@ func TestListenerMux(t *testing.T) { }) } -func callAllCallbacksOnces(t *testing.T, listener Listener) { +func callAllCallbacksOnces(t *testing.T, listener Listener) (completeCb func() error) { t.Helper() if err := listener.InitializeModuleData(ModuleInitializationData{}); err != nil { t.Error(err) @@ -81,9 +86,12 @@ func callAllCallbacksOnces(t *testing.T, listener Listener) { if err := listener.OnObjectUpdate(ObjectUpdateData{}); err != nil { t.Error(err) } - if err := listener.Commit(CommitData{}); err != nil { + var err error + completeCb, err = listener.Commit(CommitData{}) + if err != nil { t.Error(err) } + return completeCb } func callCollector(i int, onCall func(string, int, Packet)) Listener { @@ -112,9 +120,9 @@ func callCollector(i int, onCall func(string, int, Packet)) Listener { onCall("OnObjectUpdate", i, nil) return nil }, - Commit: func(CommitData) error { + Commit: func(data CommitData) (completionCallback func() error, err error) { onCall("Commit", i, nil) - return nil + return nil, nil }, } } diff --git a/schema/appdata/packet.go b/schema/appdata/packet.go index e5fe6be966b7..e4f6d94e5d7d 100644 --- a/schema/appdata/packet.go +++ b/schema/appdata/packet.go @@ -57,5 +57,12 @@ func (c CommitData) apply(l *Listener) error { if l.Commit == nil { return nil } - return l.Commit(c) + cb, err := l.Commit(c) + if err != nil { + return err + } + if cb != nil { + return cb() + } + return nil } diff --git a/schema/testing/appdatasim/app_data_test.go b/schema/testing/appdatasim/app_data_test.go index 29701c4411e7..eba8a8984ffb 100644 --- a/schema/testing/appdatasim/app_data_test.go +++ b/schema/testing/appdatasim/app_data_test.go @@ -84,9 +84,9 @@ func writerListener(w io.Writer) appdata.Listener { OnTx: nil, OnEvent: nil, OnKVPair: nil, - Commit: func(data appdata.CommitData) error { - _, err := fmt.Fprintf(w, "Commit: %v\n", data) - return err + Commit: func(data appdata.CommitData) (completionCallback func() error, err error) { + _, err = fmt.Fprintf(w, "Commit: %v\n", data) + return nil, err }, InitializeModuleData: func(data appdata.ModuleInitializationData) error { bz, err := json.Marshal(data) From da27d8b9a166ed6ccc69ee839f4e986148a81f12 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 20 Aug 2024 10:49:06 -0400 Subject: [PATCH 08/26] feat(schema/appdata)!: efficiency & data model improvements aligned with server/v2 (#21305) --- core/store/changeset.go | 2 +- schema/appdata/async.go | 5 ++ schema/appdata/batch.go | 41 +++++++++++++++ schema/appdata/batch_test.go | 85 ++++++++++++++++++++++++++++++++ schema/appdata/data.go | 38 +++++++++----- schema/appdata/listener.go | 9 ++++ schema/appdata/mux.go | 10 ++++ schema/appdata/packet.go | 2 + schema/decoding/decoding_test.go | 12 +++-- schema/decoding/middleware.go | 56 +++++++++++++-------- schema/decoding/resolver.go | 21 ++++++++ 11 files changed, 243 insertions(+), 38 deletions(-) create mode 100644 schema/appdata/batch.go create mode 100644 schema/appdata/batch_test.go diff --git a/core/store/changeset.go b/core/store/changeset.go index b1233e8abfaa..35837059c627 100644 --- a/core/store/changeset.go +++ b/core/store/changeset.go @@ -10,7 +10,7 @@ type Changeset struct { } // StateChanges represents a set of changes to the state of an actor in storage. -type StateChanges struct { +type StateChanges = struct { Actor []byte // actor represents the space in storage where state is stored, previously this was called a "storekey" StateChanges KVPairs // StateChanges is a list of key-value pairs representing the changes to the state. } diff --git a/schema/appdata/async.go b/schema/appdata/async.go index 59c671186e7c..b85d0e492e90 100644 --- a/schema/appdata/async.go +++ b/schema/appdata/async.go @@ -132,5 +132,10 @@ func AsyncListener(opts AsyncListenerOptions, listener Listener) Listener { }, nil } + res.onBatch = func(batch PacketBatch) error { + packetChan <- batch + return nil + } + return res } diff --git a/schema/appdata/batch.go b/schema/appdata/batch.go new file mode 100644 index 000000000000..1d4802092bea --- /dev/null +++ b/schema/appdata/batch.go @@ -0,0 +1,41 @@ +package appdata + +// BatchablePacket is the interface that packet types which can be batched implement. +// All types that implement Packet except CommitData also implement BatchablePacket. +// CommitData should not be batched because it forces synchronization of asynchronous listeners. +type BatchablePacket interface { + Packet + isBatchablePacket() +} + +// PacketBatch is a batch of packets that can be sent to a listener. +// If listener processing is asynchronous, the batch of packets will be sent +// all at once in a single operation which can be more efficient than sending +// each packet individually. +type PacketBatch []BatchablePacket + +func (p PacketBatch) apply(l *Listener) error { + if l.onBatch != nil { + return l.onBatch(p) + } + + for _, packet := range p { + if err := packet.apply(l); err != nil { + return err + } + } + + return nil +} + +func (ModuleInitializationData) isBatchablePacket() {} + +func (StartBlockData) isBatchablePacket() {} + +func (TxData) isBatchablePacket() {} + +func (EventData) isBatchablePacket() {} + +func (KVPairData) isBatchablePacket() {} + +func (ObjectUpdateData) isBatchablePacket() {} diff --git a/schema/appdata/batch_test.go b/schema/appdata/batch_test.go new file mode 100644 index 000000000000..557079e225c4 --- /dev/null +++ b/schema/appdata/batch_test.go @@ -0,0 +1,85 @@ +package appdata + +import ( + "context" + "reflect" + "testing" +) + +func TestBatch(t *testing.T) { + l, got := batchListener() + + if err := l.SendPacket(testBatch); err != nil { + t.Error(err) + } + + if !reflect.DeepEqual(*got, testBatch) { + t.Errorf("got %v, expected %v", *got, testBatch) + } +} + +var testBatch = PacketBatch{ + ModuleInitializationData{}, + StartBlockData{}, + TxData{}, + EventData{}, + KVPairData{}, + ObjectUpdateData{}, +} + +func batchListener() (Listener, *PacketBatch) { + var got = new(PacketBatch) + l := Listener{ + InitializeModuleData: func(m ModuleInitializationData) error { + *got = append(*got, m) + return nil + }, + StartBlock: func(b StartBlockData) error { + *got = append(*got, b) + return nil + }, + OnTx: func(t TxData) error { + *got = append(*got, t) + return nil + }, + OnEvent: func(e EventData) error { + *got = append(*got, e) + return nil + }, + OnKVPair: func(k KVPairData) error { + *got = append(*got, k) + return nil + }, + OnObjectUpdate: func(o ObjectUpdateData) error { + *got = append(*got, o) + return nil + }, + } + + return l, got +} + +func TestBatchAsync(t *testing.T) { + l, got := batchListener() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + l = AsyncListenerMux(AsyncListenerOptions{Context: ctx}, l) + + if err := l.SendPacket(testBatch); err != nil { + t.Error(err) + } + + // commit to synchronize + cb, err := l.Commit(CommitData{}) + if err != nil { + t.Error(err) + } + if err := cb(); err != nil { + t.Error(err) + } + + if !reflect.DeepEqual(*got, testBatch) { + t.Errorf("got %v, expected %v", *got, testBatch) + } +} diff --git a/schema/appdata/data.go b/schema/appdata/data.go index 7e02fbc5db8f..1ef3f012c11e 100644 --- a/schema/appdata/data.go +++ b/schema/appdata/data.go @@ -41,8 +41,14 @@ type TxData struct { JSON ToJSON } -// EventData represents event data that is passed to a listener. +// EventData represents event data that is passed to a listener when events are received. type EventData struct { + // Events are the events that are received. + Events []Event +} + +// Event represents the data for a single event. +type Event struct { // TxIndex is the index of the transaction in the block to which this event is associated. // It should be set to a negative number if the event is not associated with a transaction. // Canonically -1 should be used to represent begin block processing and -2 should be used to @@ -52,16 +58,23 @@ type EventData struct { // MsgIndex is the index of the message in the transaction to which this event is associated. // If TxIndex is negative, this index could correspond to the index of the message in // begin or end block processing if such indexes exist, or it can be set to zero. - MsgIndex uint32 + MsgIndex int32 // EventIndex is the index of the event in the message to which this event is associated. - EventIndex uint32 + EventIndex int32 // Type is the type of the event. Type string - // Data is the JSON representation of the event data. It should generally be a JSON object. + // Data lazily returns the JSON representation of the event. Data ToJSON + + // Attributes lazily returns the key-value attribute representation of the event. + Attributes ToEventAttributes +} + +type EventAttribute = struct { + Key, Value string } // ToBytes is a function that lazily returns the raw byte representation of data. @@ -70,18 +83,21 @@ type ToBytes = func() ([]byte, error) // ToJSON is a function that lazily returns the JSON representation of data. type ToJSON = func() (json.RawMessage, error) +// ToEventAttributes is a function that lazily returns the key-value attribute representation of an event. +type ToEventAttributes = func() ([]EventAttribute, error) + // KVPairData represents a batch of key-value pair data that is passed to a listener. type KVPairData struct { - Updates []ModuleKVPairUpdate + Updates []ActorKVPairUpdate } -// ModuleKVPairUpdate represents a key-value pair update for a specific module. -type ModuleKVPairUpdate struct { - // ModuleName is the name of the module that the key-value pair belongs to. - ModuleName string +// ActorKVPairUpdate represents a key-value pair update for a specific module or account. +type ActorKVPairUpdate = struct { + // Actor is the byte representation of the module or account that is updating the key-value pair. + Actor []byte - // Update is the key-value pair update. - Update schema.KVPairUpdate + // StateChanges are key-value pair updates. + StateChanges []schema.KVPairUpdate } // ObjectUpdateData represents object update data that is passed to a listener. diff --git a/schema/appdata/listener.go b/schema/appdata/listener.go index 0a7efa926a83..f02b4c467bd4 100644 --- a/schema/appdata/listener.go +++ b/schema/appdata/listener.go @@ -42,5 +42,14 @@ type Listener struct { // if err is nil and then if it is, check if completionCallback is nil and if not // call it and check for an error. Commit should be designed to be non-blocking if // possible, but calling completionCallback should be blocking. + // When listener processing is pushed into background go routines using AsyncListener + // or AsyncListenerMux, the Commit completion callback will synchronize the processing of + // all listeners. Producers that do not want to block on Commit in a given block + // can delay calling the completion callback until the start of the next block to + // give listeners time to complete their processing. Commit func(CommitData) (completionCallback func() error, err error) + + // onBatch can be used internally to efficiently forward packet batches to + // async listeners. + onBatch func(PacketBatch) error } diff --git a/schema/appdata/mux.go b/schema/appdata/mux.go index c35472dc0130..81a4fa795db8 100644 --- a/schema/appdata/mux.go +++ b/schema/appdata/mux.go @@ -137,5 +137,15 @@ func ListenerMux(listeners ...Listener) Listener { } } + mux.onBatch = func(batch PacketBatch) error { + for _, listener := range listeners { + err := batch.apply(&listener) + if err != nil { + return err + } + } + return nil + } + return mux } diff --git a/schema/appdata/packet.go b/schema/appdata/packet.go index e4f6d94e5d7d..ff824ea7a83d 100644 --- a/schema/appdata/packet.go +++ b/schema/appdata/packet.go @@ -2,6 +2,8 @@ package appdata // Packet is the interface that all listener data structures implement so that this data can be "packetized" // and processed in a stream, possibly asynchronously. +// Valid implementations are ModuleInitializationData, StartBlockData, TxData, EventData, KVPairData, ObjectUpdateData, +// and CommitData. type Packet interface { apply(*Listener) error } diff --git a/schema/decoding/decoding_test.go b/schema/decoding/decoding_test.go index a671d2f4c35b..c8f71ae94b83 100644 --- a/schema/decoding/decoding_test.go +++ b/schema/decoding/decoding_test.go @@ -297,12 +297,14 @@ func (t testStore) GetUInt64(key []byte) uint64 { func (t testStore) Set(key, value []byte) { if t.listener.OnKVPair != nil { - err := t.listener.OnKVPair(appdata.KVPairData{Updates: []appdata.ModuleKVPairUpdate{ + err := t.listener.OnKVPair(appdata.KVPairData{Updates: []appdata.ActorKVPairUpdate{ { - ModuleName: t.modName, - Update: schema.KVPairUpdate{ - Key: key, - Value: value, + Actor: []byte(t.modName), + StateChanges: []schema.KVPairUpdate{ + { + Key: key, + Value: value, + }, }, }, }}) diff --git a/schema/decoding/middleware.go b/schema/decoding/middleware.go index 57c0783c6281..2c269dcab417 100644 --- a/schema/decoding/middleware.go +++ b/schema/decoding/middleware.go @@ -23,6 +23,7 @@ func Middleware(target appdata.Listener, resolver DecoderResolver, opts Middlewa onKVPair := target.OnKVPair moduleCodecs := map[string]*schema.ModuleCodec{} + moduleNames := map[string]string{} target.OnKVPair = func(data appdata.KVPairData) error { // first forward kv pair updates @@ -34,17 +35,28 @@ func Middleware(target appdata.Listener, resolver DecoderResolver, opts Middlewa } for _, kvUpdate := range data.Updates { + moduleName, ok := moduleNames[string(kvUpdate.Actor)] + if !ok { + var err error + moduleName, err = resolver.DecodeModuleName(kvUpdate.Actor) + if err != nil { + return err + } + + moduleNames[string(kvUpdate.Actor)] = moduleName + } + // look for an existing codec - pcdc, ok := moduleCodecs[kvUpdate.ModuleName] + pcdc, ok := moduleCodecs[moduleName] if !ok { - if opts.ModuleFilter != nil && !opts.ModuleFilter(kvUpdate.ModuleName) { + if opts.ModuleFilter != nil && !opts.ModuleFilter(moduleName) { // we don't care about this module so store nil and continue - moduleCodecs[kvUpdate.ModuleName] = nil + moduleCodecs[moduleName] = nil continue } // look for a new codec - cdc, found, err := resolver.LookupDecoder(kvUpdate.ModuleName) + cdc, found, err := resolver.LookupDecoder(moduleName) if err != nil { return err } @@ -52,16 +64,16 @@ func Middleware(target appdata.Listener, resolver DecoderResolver, opts Middlewa if !found { // store nil to indicate we've seen this module and don't have a codec // and keep processing the kv updates - moduleCodecs[kvUpdate.ModuleName] = nil + moduleCodecs[moduleName] = nil continue } pcdc = &cdc - moduleCodecs[kvUpdate.ModuleName] = pcdc + moduleCodecs[moduleName] = pcdc if initializeModuleData != nil { err = initializeModuleData(appdata.ModuleInitializationData{ - ModuleName: kvUpdate.ModuleName, + ModuleName: moduleName, Schema: cdc.Schema, }) if err != nil { @@ -80,22 +92,24 @@ func Middleware(target appdata.Listener, resolver DecoderResolver, opts Middlewa continue } - updates, err := pcdc.KVDecoder(kvUpdate.Update) - if err != nil { - return err - } + for _, u := range kvUpdate.StateChanges { + updates, err := pcdc.KVDecoder(u) + if err != nil { + return err + } - if len(updates) == 0 { - // no updates - continue - } + if len(updates) == 0 { + // no updates + continue + } - err = target.OnObjectUpdate(appdata.ObjectUpdateData{ - ModuleName: kvUpdate.ModuleName, - Updates: updates, - }) - if err != nil { - return err + err = target.OnObjectUpdate(appdata.ObjectUpdateData{ + ModuleName: moduleName, + Updates: updates, + }) + if err != nil { + return err + } } } diff --git a/schema/decoding/resolver.go b/schema/decoding/resolver.go index db0ec0bb1726..cb022dbb6947 100644 --- a/schema/decoding/resolver.go +++ b/schema/decoding/resolver.go @@ -1,6 +1,7 @@ package decoding import ( + "fmt" "sort" "cosmossdk.io/schema" @@ -8,6 +9,12 @@ import ( // DecoderResolver is an interface that allows indexers to discover and use module decoders. type DecoderResolver interface { + // DecodeModuleName decodes a module name from a byte slice passed as the actor in a KVPairUpdate. + DecodeModuleName([]byte) (string, error) + + // EncodeModuleName encodes a module name into a byte slice that can be used as the actor in a KVPairUpdate. + EncodeModuleName(string) ([]byte, error) + // IterateAll iterates over all available module decoders. IterateAll(func(moduleName string, cdc schema.ModuleCodec) error) error @@ -27,6 +34,20 @@ type moduleSetDecoderResolver struct { moduleSet map[string]interface{} } +func (a moduleSetDecoderResolver) DecodeModuleName(bytes []byte) (string, error) { + if _, ok := a.moduleSet[string(bytes)]; ok { + return string(bytes), nil + } + return "", fmt.Errorf("module %s not found", bytes) +} + +func (a moduleSetDecoderResolver) EncodeModuleName(s string) ([]byte, error) { + if _, ok := a.moduleSet[s]; ok { + return []byte(s), nil + } + return nil, fmt.Errorf("module %s not found", s) +} + func (a moduleSetDecoderResolver) IterateAll(f func(string, schema.ModuleCodec) error) error { keys := make([]string, 0, len(a.moduleSet)) for k := range a.moduleSet { From 08a3da44b100c86b71a41fbd33d23abb26b7a646 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 20 Aug 2024 11:01:29 -0400 Subject: [PATCH 09/26] feat(schema/indexer): add address codec param (#21361) --- schema/addressutil/codec.go | 8 +++++ schema/addressutil/hex.go | 24 +++++++++++++++ schema/addressutil/hex_test.go | 54 ++++++++++++++++++++++++++++++++++ schema/indexer/indexer.go | 5 ++++ schema/indexer/manager.go | 6 ++++ 5 files changed, 97 insertions(+) create mode 100644 schema/addressutil/codec.go create mode 100644 schema/addressutil/hex.go create mode 100644 schema/addressutil/hex_test.go diff --git a/schema/addressutil/codec.go b/schema/addressutil/codec.go new file mode 100644 index 000000000000..cadde8e516cd --- /dev/null +++ b/schema/addressutil/codec.go @@ -0,0 +1,8 @@ +package addressutil + +type AddressCodec interface { + // StringToBytes decodes text to bytes + StringToBytes(text string) ([]byte, error) + // BytesToString encodes bytes to text + BytesToString(bz []byte) (string, error) +} diff --git a/schema/addressutil/hex.go b/schema/addressutil/hex.go new file mode 100644 index 000000000000..1d6ecae467ce --- /dev/null +++ b/schema/addressutil/hex.go @@ -0,0 +1,24 @@ +package addressutil + +import ( + "encoding/hex" + "fmt" +) + +// HexAddressCodec is a basic address codec that encodes and decodes addresses as hex strings. +// It is intended to be used as a fallback codec when no other codec is provided. +type HexAddressCodec struct{} + +func (h HexAddressCodec) StringToBytes(text string) ([]byte, error) { + if len(text) < 2 || text[:2] != "0x" { + return nil, fmt.Errorf("invalid hex address: %s", text) + } + + return hex.DecodeString(text[2:]) +} + +func (h HexAddressCodec) BytesToString(bz []byte) (string, error) { + return fmt.Sprintf("0x%x", bz), nil +} + +var _ AddressCodec = HexAddressCodec{} diff --git a/schema/addressutil/hex_test.go b/schema/addressutil/hex_test.go new file mode 100644 index 000000000000..e4a0f0ee01f9 --- /dev/null +++ b/schema/addressutil/hex_test.go @@ -0,0 +1,54 @@ +package addressutil + +import ( + "bytes" + "testing" +) + +func TestHexAddressCodec(t *testing.T) { + tt := []struct { + text string + bz []byte + err bool + }{ + { + text: "0x1234", + bz: []byte{0x12, 0x34}, + }, + { + text: "0x", + bz: []byte{}, + }, + { + text: "0x123", + err: true, + }, + { + text: "1234", + err: true, + }, + } + + h := HexAddressCodec{} + for _, tc := range tt { + bz, err := h.StringToBytes(tc.text) + if tc.err && err == nil { + t.Fatalf("expected error, got none") + } + if !tc.err && err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !tc.err && !bytes.Equal(bz, tc.bz) { + t.Fatalf("expected %v, got %v", tc.bz, bz) + } + + // check address rendering if no error + if !tc.err { + if str, err := h.BytesToString(tc.bz); err != nil { + t.Fatalf("unexpected error: %v", err) + } else if str != tc.text { + t.Fatalf("expected %s, got %s", tc.text, str) + } + } + } +} diff --git a/schema/indexer/indexer.go b/schema/indexer/indexer.go index 57ada8bb80c1..3b82e3254e5a 100644 --- a/schema/indexer/indexer.go +++ b/schema/indexer/indexer.go @@ -3,6 +3,7 @@ package indexer import ( "context" + "cosmossdk.io/schema/addressutil" "cosmossdk.io/schema/appdata" "cosmossdk.io/schema/logutil" "cosmossdk.io/schema/view" @@ -62,6 +63,10 @@ type InitParams struct { // Logger is a logger the indexer can use to write log messages. It may be nil if the indexer does not need // to write logs. Logger logutil.Logger + + // AddressCodec is the address codec that the indexer can use to encode and decode addresses. It is + // expected to be non-nil. + AddressCodec addressutil.AddressCodec } // InitResult is the indexer initialization result and includes the indexer's listener implementation. diff --git a/schema/indexer/manager.go b/schema/indexer/manager.go index 5a7e39faad0a..60c19b4dd5c7 100644 --- a/schema/indexer/manager.go +++ b/schema/indexer/manager.go @@ -3,6 +3,7 @@ package indexer import ( "context" + "cosmossdk.io/schema/addressutil" "cosmossdk.io/schema/appdata" "cosmossdk.io/schema/decoding" "cosmossdk.io/schema/logutil" @@ -29,6 +30,11 @@ type ManagerOptions struct { // be used to pass down other parameters to indexers if necessary. If it is omitted, context.Background // will be used. Context context.Context + + // AddressCodec is the address codec that indexers can use to encode and decode addresses. It should always be + // provided, but if it is omitted, the indexer manager will use a default codec which encodes and decodes addresses + // as hex strings. + AddressCodec addressutil.AddressCodec } // ManagerConfig is the configuration of the indexer manager and contains the configuration for each indexer target. From 95dcf845c3b0dfc00ddde7200a25f96cece564f6 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 20 Aug 2024 18:52:49 -0400 Subject: [PATCH 10/26] fix(schema)!: fixes and key restrictions based on indexer testing (#21362) --- schema/kind.go | 16 ++ schema/object_type.go | 8 +- schema/object_type_test.go | 39 +++ schema/testing/appdatasim/app_data.go | 23 +- .../testdata/app_sim_example_schema.txt | 234 +++++++++--------- .../appdatasim/testdata/diff_example.txt | 108 ++++---- schema/testing/example_schema.go | 3 + schema/testing/field.go | 8 +- schema/testing/fmt.go | 53 ++++ schema/testing/fmt_test.go | 61 +++++ schema/testing/module_schema.go | 6 +- schema/testing/object.go | 132 +++++----- schema/testing/statesim/object_coll.go | 38 +-- schema/testing/statesim/object_coll_diff.go | 2 +- 14 files changed, 440 insertions(+), 291 deletions(-) create mode 100644 schema/testing/fmt.go create mode 100644 schema/testing/fmt_test.go diff --git a/schema/kind.go b/schema/kind.go index e5457420149b..1aec2b62f407 100644 --- a/schema/kind.go +++ b/schema/kind.go @@ -79,6 +79,8 @@ const ( // Go Encoding: string which matches the IntegerFormat regex // JSON Encoding: base10 integer string // Canonically encoded values should include no leading zeros. + // Equality comparison with integers should be done using numerical equality rather + // than string equality. IntegerStringKind // DecimalStringKind represents an arbitrary precision decimal or integer number. @@ -87,6 +89,8 @@ const ( // Canonically encoded values should include no leading zeros or trailing zeros, // and exponential notation with a lowercase 'e' should be used for any numbers // with an absolute value less than or equal to 1e-6 or greater than or equal to 1e6. + // Equality comparison with decimals should be done using numerical equality rather + // than string equality. DecimalStringKind // BoolKind represents a boolean true or false value. @@ -369,6 +373,18 @@ func (t Kind) ValidateValue(value interface{}) error { return nil } +// ValidKeyKind returns true if the kind is a valid key kind. +// All kinds except Float32Kind, Float64Kind, and JSONKind are valid key kinds +// because they do not define a strict form of equality. +func (t Kind) ValidKeyKind() bool { + switch t { + case Float32Kind, Float64Kind, JSONKind: + return false + default: + return true + } +} + var ( integerRegex = regexp.MustCompile(IntegerFormat) decimalRegex = regexp.MustCompile(DecimalFormat) diff --git a/schema/object_type.go b/schema/object_type.go index 379d7d4a8382..6555faf39ac5 100644 --- a/schema/object_type.go +++ b/schema/object_type.go @@ -11,7 +11,9 @@ type ObjectType struct { // KeyFields is a list of fields that make up the primary key of the object. // It can be empty in which case indexers should assume that this object is // a singleton and only has one value. Field names must be unique within the - // object between both key and value fields. Key fields CANNOT be nullable. + // object between both key and value fields. + // Key fields CANNOT be nullable and Float32Kind, Float64Kind, and JSONKind types + // are not allowed. KeyFields []Field // ValueFields is a list of fields that are not part of the primary key of the object. @@ -53,6 +55,10 @@ func (o ObjectType) validate(types map[string]Type) error { return fmt.Errorf("invalid key field %q: %v", field.Name, err) //nolint:errorlint // false positive due to using go1.12 } + if !field.Kind.ValidKeyKind() { + return fmt.Errorf("key field %q of kind %q uses an invalid key field kind", field.Name, field.Kind) + } + if field.Nullable { return fmt.Errorf("key field %q cannot be nullable", field.Name) } diff --git a/schema/object_type_test.go b/schema/object_type_test.go index 68a85111b7b6..b6039b9eed60 100644 --- a/schema/object_type_test.go +++ b/schema/object_type_test.go @@ -189,6 +189,45 @@ func TestObjectType_Validate(t *testing.T) { }, errContains: "enum \"enum1\" has different values", }, + { + name: "float32 key field", + objectType: ObjectType{ + Name: "o1", + KeyFields: []Field{ + { + Name: "field1", + Kind: Float32Kind, + }, + }, + }, + errContains: "invalid key field kind", + }, + { + name: "float64 key field", + objectType: ObjectType{ + Name: "o1", + KeyFields: []Field{ + { + Name: "field1", + Kind: Float64Kind, + }, + }, + }, + errContains: "invalid key field kind", + }, + { + name: "json key field", + objectType: ObjectType{ + Name: "o1", + KeyFields: []Field{ + { + Name: "field1", + Kind: JSONKind, + }, + }, + }, + errContains: "invalid key field kind", + }, } for _, tt := range tests { diff --git a/schema/testing/appdatasim/app_data.go b/schema/testing/appdatasim/app_data.go index 2f6138bfe824..471cf5cb2b1f 100644 --- a/schema/testing/appdatasim/app_data.go +++ b/schema/testing/appdatasim/app_data.go @@ -8,6 +8,7 @@ import ( "cosmossdk.io/schema" "cosmossdk.io/schema/appdata" + schematesting "cosmossdk.io/schema/testing" "cosmossdk.io/schema/testing/statesim" "cosmossdk.io/schema/view" ) @@ -92,10 +93,10 @@ func (a *Simulator) BlockDataGenN(minUpdatesPerBlock, maxUpdatesPerBlock int) *r packets = append(packets, appdata.StartBlockData{Height: a.blockNum + 1}) updateSet := map[string]bool{} - // filter out any updates to the same key from this block, otherwise we can end up with weird errors + // filter out any updates to the same key from this block, otherwise we can end up with hard to debug errors updateGen := a.state.UpdateGen().Filter(func(data appdata.ObjectUpdateData) bool { for _, update := range data.Updates { - _, existing := updateSet[fmt.Sprintf("%s:%v", data.ModuleName, update.Key)] + _, existing := updateSet[a.formatUpdateKey(data.ModuleName, update)] if existing { return false } @@ -106,7 +107,8 @@ func (a *Simulator) BlockDataGenN(minUpdatesPerBlock, maxUpdatesPerBlock int) *r for i := 0; i < numUpdates; i++ { data := updateGen.Draw(t, fmt.Sprintf("update[%d]", i)) for _, update := range data.Updates { - updateSet[fmt.Sprintf("%s:%v", data.ModuleName, update.Key)] = true + // we need to set the update here each time so that this is used to filter out duplicates in the next round + updateSet[a.formatUpdateKey(data.ModuleName, update)] = true } packets = append(packets, data) } @@ -117,6 +119,21 @@ func (a *Simulator) BlockDataGenN(minUpdatesPerBlock, maxUpdatesPerBlock int) *r }) } +func (a *Simulator) formatUpdateKey(moduleName string, update schema.ObjectUpdate) string { + mod, err := a.state.GetModule(moduleName) + if err != nil { + panic(err) + } + + objColl, err := mod.GetObjectCollection(update.TypeName) + if err != nil { + panic(err) + } + + ks := fmt.Sprintf("%s:%s:%s", moduleName, update.TypeName, schematesting.ObjectKeyString(objColl.ObjectType(), update.Key)) + return ks +} + // ProcessBlockData processes the given block data, advancing the app state based on the object updates in the block // and forwarding all packets to the attached listener. It is expected that the data passed came from BlockDataGen, // however, other data can be passed as long as any StartBlockData packet has the height set to the current height + 1. diff --git a/schema/testing/appdatasim/testdata/app_sim_example_schema.txt b/schema/testing/appdatasim/testdata/app_sim_example_schema.txt index 117d557ba5a4..fb1682175228 100644 --- a/schema/testing/appdatasim/testdata/app_sim_example_schema.txt +++ b/schema/testing/appdatasim/testdata/app_sim_example_schema.txt @@ -7,155 +7,155 @@ OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"11598611","Value":["016807","-016339012"],"Delete":false},{"TypeName":"test_uint16","Key":9407,"Value":{"valNotNull":0,"valNullable":null},"Delete":false}]} OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":-4371,"Value":{"valNotNull":-3532,"valNullable":-15},"Delete":false}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"\u000b𝜛࣢Ⱥ +\u001c","Value":{"Value1":-28,"Value2":"AAE5AAAAATgB"},"Delete":false},{"TypeName":"RetainDeletions","Key":".(","Value":[116120837,"/wwIyAAUciAC"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[false,false],"Delete":false},{"TypeName":"test_float64","Key":0,"Value":[-0.819610595703125,0.08682777894820155],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"+!𐅫a⍦","Value":[36,"fi07",0.000005021243239880513,2],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["˖|󺪆𝅲=鄖_.;ǀ⃣%; #~",16,512578],"Value":686,"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":-988,"Value":[6,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"?൙ဴ𑇑\".+AB","Value":{"Value1":-75,"Value2":"FdQcnKoeAAIB"},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":6,"Value":[6,null],"Delete":false},{"TypeName":"test_int32","Key":-7573,"Value":[-57,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\tA𐞙?\t",-5317218,1],"Value":6450,"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwMbGS8=","Value":["AwQA3EBwHgCEABQBAw==",null],"Delete":false},{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[false,false],"Delete":false},{"TypeName":"test_float64","Key":2818,"Value":{"valNotNull":1.036618793083456e+225,"valNullable":-0.0006897732815340143},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"561415.19400226923121396E-2","Value":{"valNotNull":"-24080E11","valNullable":"192.3"},"Delete":false},{"TypeName":"test_int8","Key":-95,"Value":{"valNotNull":-101,"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?Ⱥ","Value":{"Value1":2,"Value2":"2w==","Value3":0.05580937396734953,"Value4":16164100},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["৴ि𐞬a",-681,12863],"Value":1,"Delete":false},{"TypeName":"RetainDeletions","Key":"৯aࠤာAᬺⅤaȺ£Ρᵧa󠁳|𝙮 A","Value":{"Value1":440,"Value2":"9Q=="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float32","Key":-874,"Value":[-0.8046875,null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"CB4HBgJQBuoBFAIs4xcFRwfaoUJr4f4ACzQ5wX4qPkMAACsA1Ev/Fg==","Value":["xRQCHzcOCGqADAZNAQExHwAaBQISEagYGF4F5wEWFN/JGgHkAsYchgUCA2YRUneug+wEABUjRaAKBOoQAOATEg==","CUXz/xMEAP8BNw0PvPUBNF7rSPPDAQHTBg71MEsKHg=="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-1168504079346,"Value":{"valNotNull":-9566526662547645,"valNullable":-1936738738498935},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"+","Value":[3,"A2k="],"Delete":false}]} Commit: {} StartBlock: {2 } OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"ᾢ","Value":[3,"AQQF3LYA"],"Delete":false}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"_; ᾚ DzA{˭҄\nA ^$?ᾦ,:\u003c\"?_\u0014;|","Value":{"Value1":-15,"Value2":"PED/","Value3":7.997156312768529e-26,"Value4":33975920899014},"Delete":false},{"TypeName":"Simple","Key":"","Value":[-2,"FwY="],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AgDYbdMBAZ31DGsBs7UGnAp/BgX/BkQFAQ3Si9sd6x8Hrw==","Value":{"valNotNull":"/2ADvYQC/wATggAAAwYBLjQCAv8=","valNullable":null},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"GJQSAs0BGAILARUXAwIrnf8pBgIrRQOrSQNOEgfvA8ATAAEMVw8s/w==","Value":["GwADWP8AMB6z0AZCDgEDMv8DfQEQ","DAHaBAOt3g16AQAfNQEBeQYBAlv/AfgKUi0YAgg="],"Delete":false},{"TypeName":"test_duration","Key":468,"Value":[-52600,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":": Ⱥ","Value":[-14,"fmoD3wY="],"Delete":false},{"TypeName":"TwoKeys","Key":["Ⱥ꙱Lj",12],"Value":null,"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"$","Value":[13,"Uf8VAgYltOwK"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",-4],"Value":null,"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":false,"valNullable":null},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"\t;𞄱𑨁௺ⅦA×~ႂᛯaA","Value":{"Value1":2147483647,"Value2":"AAMBAgADGA4="},"Delete":false},{"TypeName":"RetainDeletions","Key":"\nȺ*|𑀾","Value":{"Value1":0,"Value2":"ChoCY0w="},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":["\u000b!","OQ=="],"Delete":false},{"TypeName":"Singleton","Key":null,"Value":["a",""],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":["Bz4X2gtkAw4DU4hgA72EAv8AE4IAAAMGAS40AgL/",null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"CB4HBgJQBuoBFAIs4xcFRwfaoUJr4f4ACzQ5wX4qPkMAACsA1Ev/Fg==","Value":null,"Delete":true},{"TypeName":"test_address","Key":"CB4HBgJQBuoBFAIs4xcFRwfaoUJr4f4ACzQ5wX4qPkMAACsA1Ev/Fg==","Value":{"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AA==","Value":{"valNotNull":"FRcD","valNullable":"K53/"},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":{"Value":"℘A⤯","Value2":"ALZMCik="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":[" (弡𞥃",124],"Value":null,"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":[false,null],"Delete":false},{"TypeName":"test_integer","Key":"64","Value":["-307711","-2"],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?Ⱥ","Value":[-278,"AgYltOwK",-6.0083863735198975,429016],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-97E-70","Value":{"valNotNull":"-650530110","valNullable":null},"Delete":false},{"TypeName":"test_decimal","Key":"561415.19400226923121396E-2","Value":null,"Delete":true}]} Commit: {} StartBlock: {3 } -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int32","Key":-103,"Value":{"valNotNull":-1887959808,"valNullable":2096073436},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"","Value":{"Value1":-4,"Value2":"","Value3":5.199354003997906e-290,"Value4":2703222758},"Delete":false},{"TypeName":"ThreeKeys","Key":["˖|󺪆𝅲=鄖_.;ǀ⃣%; #~",16,512578],"Value":11281,"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":7,"Value":{"valNotNull":1,"valNullable":150},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"?൙ဴ𑇑\".+AB","Value":[-1,"LP8="],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"72961530924372552","Value":["080207094","-598415299"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":-1.7392669057403718e+166,"Value":[1.556643269146063e-16,-1.1920928955078125e-7],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ऻॉ~$𒐈+Xʱ:²-~?ʳ~$ₜ\\",-787],"Value":null,"Delete":false},{"TypeName":"Singleton","Key":null,"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"\u000b𝜛࣢Ⱥ +\u001c","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":14,"Value":[4,1],"Delete":false},{"TypeName":"test_address","Key":"AgDYbdMBAZ31DGsBs7UGnAp/BgX/BkQFAQ3Si9sd6x8Hrw==","Value":["BQEBAemXEjNqrx2kATMdGuUCESLnES4KAfAC//v/A9gJIaQNAQH/kcYdDw==","lMhHJAXnpQG+wgIzzAoNWjoAGTIABQ=="],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["Ⱥ꙱Lj",12],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int32","Key":897,"Value":[454,-2],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float32","Key":-874,"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":0,"Value":[1,null],"Delete":false},{"TypeName":"test_decimal","Key":"-97E-70","Value":["36141e01","50562961530924372552"],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["৴ि𐞬a",-681,12863],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AAD/AAAFAAEAUQ==","Value":{"valNotNull":"Nw==","valNullable":"AABdSw=="},"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":["bar",null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"CB4HBgJQBuoBFAIs4xcFRwfaoUJr4f4ACzQ5wX4qPkMAACsA1Ev/Fg==","Value":null,"Delete":true},{"TypeName":"test_uint16","Key":9407,"Value":[15,3],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"433032","Value":{"valNotNull":"711","valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_string","Key":"~?ʳ~$ₜ\\","Value":["*¾",null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint32","Key":995,"Value":{"valNotNull":7,"valNullable":null},"Delete":false},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.999999971-05:00","Value":{"valNotNull":"1969-12-31T18:59:59.999999994-05:00","valNullable":"1969-12-31T18:59:59.999580498-05:00"},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_string","Key":"aή⃢\t{ǁ","Value":{"valNotNull":"ሢ϶","valNullable":null},"Delete":false},{"TypeName":"test_uint8","Key":2,"Value":{"valNotNull":17,"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["A*۽~Dz₱ {",-8,2],"Value":{"Value1":1056454},"Delete":false},{"TypeName":"TwoKeys","Key":["mA৴ pa _〩ãᛮDž𑣠ʰA%a",1],"Value":null,"Delete":false}]} Commit: {} StartBlock: {4 } OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-152,"Value":{"valNotNull":1476419818092,"valNullable":-163469},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"‮","Value":[-1,"GwE="],"Delete":false},{"TypeName":"ManyValues","Key":"","Value":[1,"",4.1017235364794545e-228,25],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":".(","Value":null,"Delete":true},{"TypeName":"Singleton","Key":null,"Value":{"Value":"ᾫ+=[฿́\u001b\u003cʰ+`𑱐@\u001b*Dž‮#₻\u0001῎ !a܏ῼ","Value2":"AgI="},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"?൙ဴ𑇑\".+AB","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":" ","Value":[-1,""],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["",11,107],"Value":{"Value1":-31402597},"Delete":false},{"TypeName":"Simple","Key":"\t;𞄱𑨁௺ⅦA×~ႂᛯaA","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint16","Key":0,"Value":{"valNotNull":68,"valNullable":null},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"PQYReIgDAAG/6fs+AVcXxgEGDXLQ30f0/w==","Value":["b+QAdJmb/0hGGAMzEoat/wYeAQcB/wO7Ae0BlgQFAP+i7A0rGA8ESIv+Oi+eFwIDHAMAygDjBogABwADAAC5Aw==",null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\tA𐞙?\t",-5317218,1],"Value":{"Value1":-220},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"617","Value":{"valNotNull":"688647620","valNullable":null},"Delete":false},{"TypeName":"test_bool","Key":false,"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"‮","Value":[-1,"GwE="],"Delete":false},{"TypeName":"ManyValues","Key":"_; ᾚ DzA{˭҄\nA ^$?ᾦ,:\u003c\"?_\u0014;|","Value":[0,"APMAAh8=",2.6405210300043274e-261,4678],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"+","Value":[-265,"7v+nXKjOoQ=="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":[" (弡𞥃",124],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int64","Key":-1,"Value":{"valNotNull":2070362465348116,"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":["AKjiCQIBAyv/AAD8AcQADwD/AEP7eg==","C2YHNQMBaxQz0wAPGXQqGQYCAAPQAhUB05AB7QUAbnLpM7hyjBwAb+QAdJmb/0hGGAMzEoat/wYeAQ=="],"Delete":false},{"TypeName":"test_float64","Key":5224,"Value":[-1683.1097246298846,null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AA==","Value":["Md4BCACgAADoAG8cHQ5tB0c1HAA=",null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["a\u003c",-84],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":2,"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float32","Key":-218792,"Value":[1.0914612,null],"Delete":false},{"TypeName":"test_duration","Key":-9223372036854775808,"Value":{"valNotNull":399806,"valNullable":-336},"Delete":false}]} Commit: {} StartBlock: {5 } -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":null},"Delete":false},{"TypeName":"test_uint64","Key":21,"Value":{"valNotNull":73,"valNullable":2},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AgDYbdMBAZ31DGsBs7UGnAp/BgX/BkQFAQ3Si9sd6x8Hrw==","Value":["BQBsCf9MAgQAGfzKAAu1AYAClAADAhlDAP+oChQBYQA5AA0LT19MujQyf/8FbQMDawAM",null],"Delete":false},{"TypeName":"test_enum","Key":"foo","Value":{"valNotNull":"foo","valNullable":"foo"},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":["𝔏؃\"ᵚ¡ $A\r",""],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["𒑏𑿞=A?¯ \t~",-6,53],"Value":-2,"Delete":false},{"TypeName":"Simple","Key":"?","Value":{"Value1":12,"Value2":"HAIBmK0D"},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"⍦","Value":[-202,"EQTRAwAELg=="],"Delete":false},{"TypeName":"ManyValues","Key":"`ⅤaAះA~~⹗=\u000b","Value":[-17,"okMB1d0=",-3.643491752614398e+288,1382771530458],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":0,"Value":[-1014342049.3947449,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["a\u003c",-84],"Value":null,"Delete":true},{"TypeName":"Simple","Key":"d⹘:","Value":[3016,"AQ=="],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwMbGS8=","Value":null,"Delete":true},{"TypeName":"test_decimal","Key":"-02","Value":["1219101",null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"9.5E+8","Value":{"valNotNull":"13333140202.01031939e81","valNullable":"7210210.1e+1"},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint16","Key":11,"Value":[6,14912],"Delete":false},{"TypeName":"test_duration","Key":-152,"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"`³Njॊ\u003c ?ᾩ‮₦~$","Value":{"Value1":2,"Value2":"lAAD4AAABQQbAwABAwHP"},"Delete":false},{"TypeName":"RetainDeletions","Key":"൴~𝔶ٞ蹯a_ ᛮ!؋aض©-?","Value":{"Value1":-6813,"Value2":"AhRPdlAC"},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"BkiVAAcAAJ6xA/dutlmcBe8DAA1UZAsB","Value":["AA57GQP/oifkJ8aYJENTAwLxPhPSAwEI1AA9xQMWAwEoBA==",null],"Delete":false},{"TypeName":"test_address","Key":"7QTt/24APN4FBA/TAG8B/wMBWOoCqP+HNg0FBQIdAw8F5AI=","Value":["BQNcFhh01gEBAm4BAfAlGwMKkCo=","aQQTfSUg2RkZARH/EP8IGAxENIBOGwbPFAA="],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":6,"Value":[-8,null],"Delete":false},{"TypeName":"test_address","Key":"AACHBAjyAgFHOQAABo+PGAK3Bj7TwwBb/wAB3gE=","Value":["ASwojxUABA8BAf/9AgUBIs4WAq9lqAEKAP8FAAgCGwEMDQKHZwEABA82AVZZAHO/ngS7AA==",null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AWvYAbSo5gQCAz8XAQYGjwCaRx0DSAUpAWQV","Value":["/z/eNBkL5QAgCwXergJOUCEC/+ICAp4BTgBsVw==","HhoELBAPigABQwIDAxsB7KEAGlIOEAAEYQL/GQA37QAJWg0A"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":" ","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"79","Value":["-7872","53"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint32","Key":1322158439,"Value":{"valNotNull":2415,"valNullable":null},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"_; ᾚ DzA{˭҄\nA ^$?ᾦ,:\u003c\"?_\u0014;|","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\tA𐞙?\t",-5317218,1],"Value":-2147483648,"Delete":false},{"TypeName":"ManyValues","Key":"‮۽𝅸\u003c#󠁋","Value":[-3,"",-5.385845077524242e-269,2468],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":null,"Delete":true},{"TypeName":"test_int8","Key":-6,"Value":{"valNotNull":122,"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":{"valNullable":false},"Delete":false},{"TypeName":"test_address","Key":"UQMARFtfJYloAQ5FAQE+P5ezAZMCP82oChQBYQA5AA0LT19MujQyf/8FbQMDawAM","Value":["zQIdDAwCA1MfywMMFUrXCRcsAAC3OAYBAAyUCi36BQQAAuUkAACrBgAHAgUCAcYAJgM=","HAIBmK0DtgEBBwEBLzEFjXltUcIBBAFcAuZTALIBmAeVArgXLpEyAwAd2rwXD/+2wOT37ekWAr4EAEvnhw=="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?Ⱥ","Value":{"Value4":80},"Delete":false},{"TypeName":"RetainDeletions","Key":"@‮:","Value":[3016,"AQ=="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AAD/AAAFAAEAUQ==","Value":null,"Delete":true},{"TypeName":"test_decimal","Key":"800","Value":["7119101",null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"","Value":{"Value2":"LpIWCQoAbw=="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint64","Key":96,"Value":[2,null],"Delete":false},{"TypeName":"test_uint8","Key":0,"Value":[178,null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"৯aࠤာAᬺⅤaȺ£Ρᵧa󠁳|𝙮 A","Value":{"Value2":""},"Delete":false},{"TypeName":"Singleton","Key":null,"Value":{"Value":"/ᾪ蹯a_ ᛮ!؋aض©-?","Value2":"4A=="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["Ⱥേ҈a҉Ⱥ",-114036639,4],"Value":2147483647,"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_string","Key":"aή⃢\t{ǁ","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-40715358873,"Value":{"valNotNull":-35986926993,"valNullable":null},"Delete":false},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.981789806-05:00","Value":["1969-12-31T18:57:57.72625051-05:00","1969-12-26T16:36:45.679781385-05:00"],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-40530.610059","Value":{"valNotNull":"-344079482.57151","valNullable":null},"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":{"valNotNull":"bar","valNullable":"baz"},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float32","Key":-218792,"Value":null,"Delete":true},{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":{"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-97E-70","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AA==","Value":null,"Delete":true},{"TypeName":"test_bytes","Key":"Bw==","Value":["AwYGBg2V","EWShfAE="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"A","Value":[3939571,"oAE="],"Delete":false},{"TypeName":"ThreeKeys","Key":["a .౺ऻ\u0026",-1,0],"Value":-343368,"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["`ҡ",-483],"Value":null,"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"aⅭȺ\ta\u0026A୵","Value":{"Value1":1627290802,"Value2":"DQA=","Value3":70375169.64453125,"Value4":7578767657429368},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"󠇯$ aḍa\r","Value":[59,""],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["mA৴ pa _〩ãᛮDž𑣠ʰA%a",1],"Value":null,"Delete":true}]} Commit: {} StartBlock: {6 } OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["A𞥟",981],"Value":null,"Delete":false},{"TypeName":"ManyValues","Key":"ᵕ؏­􏿽A","Value":{"Value1":-317,"Value2":"AA==","Value3":-37.62890625,"Value4":232},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AACHBAjyAgFHOQAABo+PGAK3Bj7TwwBb/wAB3gE=","Value":{"valNotNull":"HBwBHAY6AAKO+UwDKRICAT0lgRRvCRvHFFoNAigBAUEDHoQUfB2qApRB/z41AAubARsBATQg3gCppQMAAQwHAQ=="},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"9.5E+8","Value":["-2","88111430.0122412446"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":7,"Value":null,"Delete":true},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.999999999-05:00","Value":["1969-12-31T19:00:00.000000001-05:00",null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"൴~𝔶ٞ蹯a_ ᛮ!؋aض©-?","Value":{"Value2":""},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":14,"Value":{"valNotNull":116},"Delete":false},{"TypeName":"test_duration","Key":100403021838,"Value":[1547,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int64","Key":-34196421,"Value":[56,224549431],"Delete":false},{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":null},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["ⅷ_ŕ,A",-467,98],"Value":{"Value1":145},"Delete":false},{"TypeName":"RetainDeletions","Key":"?aa₽A\u001b=⇂́ᯫ𖽦ᩣ","Value":{"Value1":0,"Value2":""},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",-4],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":{"valNotNull":"HBwBHAY6AAKO+UwDKRICAT0lgRRvCRvHFFoNAigBAUEDHoQUfB2qApRB/z41AAubARsBATQg3gCppQMAAQwHAQ=="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-40530.610059","Value":["-2","88111430.0122412446"],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":0,"Value":null,"Delete":true},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.981789806-05:00","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":{"Value":"","Value2":"NeIMrxEMAgI="},"Delete":false},{"TypeName":"RetainDeletions","Key":"꙲󽬺","Value":[835552366,"ngY="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\u0026AȺ#˼%֘_ŕ,A",-467,98],"Value":{"Value1":145},"Delete":false},{"TypeName":"RetainDeletions","Key":"?aa₽A\u001b=⇂́ᯫ𖽦ᩣ","Value":{"Value1":0,"Value2":""},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["`ҡ",-483],"Value":null,"Delete":true}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":{"Value1":1174095848,"Value2":"AR//A0kBNVwGGGsHANYAAAAtJQ=="},"Delete":false}]} OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint64","Key":3,"Value":[14481555953,496],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"ǃ^@❽\u2028!𑿞a‮a`","Value":{"Value1":-33730,"Value2":"qKQ="},"Delete":false},{"TypeName":"Singleton","Key":null,"Value":["𞤎𞤡","BAconQGXHRuHXQN/GTUCSQACEg=="],"Delete":false}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"ൌ{ ༿","Value":[1110340689,"AQ==",0.00018342199999210607,1],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwcJA//C","Value":{"valNotNull":"DQ==","valNullable":null},"Delete":false},{"TypeName":"test_duration","Key":210213542904,"Value":[-207349773999415086,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":-3.0664227080502325e-103,"Value":[2.125936378595003e-239,null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"৯aࠤာAᬺⅤaȺ£Ρᵧa󠁳|𝙮 A","Value":null,"Delete":true},{"TypeName":"ManyValues","Key":"aⅭȺ\ta\u0026A୵","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"A","Value":{"Value2":"NwIDBwkD/8I="},"Delete":false},{"TypeName":"Simple","Key":"a ¥𐅝`B܆Å$*","Value":{"Value1":2147483647,"Value2":"4gYDABg="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"19201864880978510.28381871008156E9","Value":["14793512",null],"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"󠇯$ aḍa\r","Value":[-9,"0AEFPHM="],"Delete":false},{"TypeName":"ThreeKeys","Key":["",0,3265605],"Value":-3703028,"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["Ⱥേ҈a҉Ⱥ",-114036639,4],"Value":{"Value1":502},"Delete":false}]} Commit: {} StartBlock: {7 } OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":true},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"d⹘:","Value":{"Value2":""},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ऻॉ~$𒐈+Xʱ:²-~?ʳ~$ₜ\\",-787],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"‮","Value":{"Value2":""},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[false,null],"Delete":false},{"TypeName":"test_bool","Key":false,"Value":{"valNullable":true},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["A𞥟",981],"Value":null,"Delete":true}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ः𒑨Dz؅",-2],"Value":null,"Delete":false}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["@(\u0001\u0001\tᛰᾚ𐺭a'ᵆᾭaa",16,817744173394],"Value":{"Value1":-2},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwcJA//C","Value":{"valNotNull":"AWNXAw=="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"Bw==","Value":{"valNotNull":"AWNXAw=="},"Delete":false}]} OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-85","Value":["-2511998","-077.01427082957E-7"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":-988,"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_enum","Key":"foo","Value":null,"Delete":true},{"TypeName":"test_decimal","Key":"-02","Value":["-40892500970.58239","11e0"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_string","Key":"","Value":{"valNotNull":"実.*𑁤!؋A\u000b.{;?󠀮_? ‍*🄑󠇯","valNullable":"(Ⱥ#/\u003c_"},"Delete":false},{"TypeName":"test_integer","Key":"-1391361","Value":{"valNotNull":"-0105","valNullable":null},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AWvYAbSo5gQCAz8XAQYGjwCaRx0DSAUpAWQV","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":98,"Value":[-40,null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":-4371,"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_enum","Key":"foo","Value":{"valNotNull":"foo","valNullable":null},"Delete":false},{"TypeName":"test_uint32","Key":522395,"Value":[2730,3],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"sucDH0r/CmEAgjcBB7H1AgAcEtI=","Value":["GVr4AxwBAN14AAYApgFuif8HrpAE9FcABBcPAGpHAQLtE3UmLQwOAjgrEMMC4w//","irH/SwYtmFOeC3EE/wEdAxnJCn8Oapb/tWjEj28BLhs1"],"Delete":false},{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":["AwIBAz8EAA5dZQEATgEBAnG+p3MPVwYAEV1dBwMDAQADCgYEJQcD+EgAAAcB","t3xyAAYBDQQHAgHH1ANoVw//Pv+nAP89Ao8OANr3BUIBAg=="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":7,"Value":[190,null],"Delete":false}]} Commit: {} StartBlock: {8 } -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"$","Value":[0,""],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"\u000b𝜛࣢Ⱥ +\u001c","Value":[0,""],"Delete":false}]} OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"8E4","Value":{"valNotNull":"4043421E29","valNullable":null},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AACHBAjyAgFHOQAABo+PGAK3Bj7TwwBb/wAB3gE=","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["A𞥟",981],"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",55175],"Value":null,"Delete":false},{"TypeName":"RetainDeletions","Key":"`³Njॊ\u003c ?ᾩ‮₦~$","Value":{"Value1":3},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":468,"Value":[-4,-805402038367],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":null,"Delete":true},{"TypeName":"test_int32","Key":-24,"Value":[1,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"҉߃ ","Value":[-526,""],"Delete":false},{"TypeName":"Simple","Key":": Ⱥ","Value":[59,"Kw=="],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_enum","Key":"bar","Value":{"valNotNull":"foo","valNullable":null},"Delete":false},{"TypeName":"test_int64","Key":2481611475,"Value":[136,6],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":-3.0664227080502325e-103,"Value":[-0.34326171875,-1.9202818317669984e-13],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":null,"Delete":true},{"TypeName":"Singleton","Key":null,"Value":{"Value":"","Value2":"ClAs"},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?b⁠\r##﹍/$ͥ","Value":[10,"",5.231528162956238,42],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"ݙaس\u003cй?{E","Value":{"Value1":-15,"Value2":"o+MQ"},"Delete":false},{"TypeName":"RetainDeletions","Key":"൴~𝔶ٞ蹯a_ ᛮ!؋aض©-?","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwcJA//C","Value":{"valNullable":""},"Delete":false},{"TypeName":"test_uint32","Key":1322158439,"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ꬵ[Ⰶ\u2029\u0026𒐗🕳c҉\u0026฿a\u0026",-79424],"Value":null,"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":-128,"Value":[7,null],"Delete":false},{"TypeName":"test_int32","Key":-103,"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"ᾢ","Value":[-2356,"DA=="],"Delete":false},{"TypeName":"ManyValues","Key":"","Value":{"Value1":28,"Value2":"","Value3":-1.6098999622118156e+67,"Value4":14},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?≚a'","Value":{"Value1":-611,"Value2":"AgqTAG4=","Value3":-2.0360732649240822e+100,"Value4":0},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":0,"Value":[2.5625,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint64","Key":3,"Value":{"valNotNull":59,"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ः𒑨Dz؅",-2],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",55175],"Value":null,"Delete":false},{"TypeName":"RetainDeletions","Key":"?aa₽A\u001b=⇂́ᯫ𖽦ᩣ","Value":{"Value1":3},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-9223372036854775808,"Value":[-4,-805402038367],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":null,"Delete":true},{"TypeName":"test_int32","Key":-24,"Value":[1,null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"҉߃ ","Value":[-526,""],"Delete":false},{"TypeName":"Simple","Key":"A","Value":[59,"Kw=="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"UQMARFtfJYloAQ5FAQE+P5ezAZMCP82oChQBYQA5AA0LT19MujQyf/8FbQMDawAM","Value":["CRRWVxf/DVOzCAMAClAsCT0BAP8BPQ==",null],"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":["bar","foo"],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"BQ==","Value":{"valNotNull":"AQYYDVF9MQF2","valNullable":"qQU="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int64","Key":-1,"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"433032","Value":{"valNotNull":"25","valNullable":"937"},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":9863,"Value":[1851,null],"Delete":false},{"TypeName":"test_decimal","Key":"800","Value":["0448127215514e88",null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"@‮:","Value":null,"Delete":true},{"TypeName":"ManyValues","Key":"ᵕ؏­􏿽A","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"'","Value":{"Value1":-611,"Value2":"AgqTAG4="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":["$?A","BAtu"],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["h ʶ?\\A魘",47994411],"Value":null,"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint64","Key":96,"Value":{"valNotNull":4576150250879893,"valNullable":329},"Delete":false},{"TypeName":"test_duration","Key":-152,"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"󴵠","Value":[-3,"QwH/FQ=="],"Delete":false},{"TypeName":"ThreeKeys","Key":["_\u001b\u0026㉉",7,3662],"Value":{"Value1":-3316206},"Delete":false}]} Commit: {} StartBlock: {9 } -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ः𒑨Dz؅",-2],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["h ʶ?\\A魘",47994411],"Value":null,"Delete":true}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"_�é","Value":{"Value1":9,"Value2":"Ywc="},"Delete":false},{"TypeName":"Singleton","Key":null,"Value":null,"Delete":true}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"A%aa ¹­ ᾏaĵ¨","Value":[9,"A/faBuYCCecZ3ATQAQcC3gAsizI="],"Delete":false},{"TypeName":"ThreeKeys","Key":[" {a",2790155,310794],"Value":{"Value1":312},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int32","Key":892,"Value":[-3,null],"Delete":false},{"TypeName":"test_duration","Key":210213542904,"Value":[-722503,113854019],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":468,"Value":[12,null],"Delete":false},{"TypeName":"test_int16","Key":0,"Value":[3089,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"79","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["",11,107],"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[true,true],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":": Ⱥ","Value":{"Value1":-2147483648},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":14,"Value":null,"Delete":true},{"TypeName":"test_integer","Key":"-1391361","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"","Value":[-242379,"BngOEOsA"],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":6,"Value":null,"Delete":true},{"TypeName":"test_address","Key":"BkiVAAcAAJ6xA/dutlmcBe8DAA1UZAsB","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":" 😖₱ ̄؀ा󠁿","Value":[7541152,""],"Delete":false},{"TypeName":"ThreeKeys","Key":["ⅷ_ŕ,A",-467,98],"Value":2,"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int32","Key":892,"Value":[-3,null],"Delete":false},{"TypeName":"test_duration","Key":-9223372036854775808,"Value":[-722503,113854019],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-40715358873,"Value":[12,null],"Delete":false},{"TypeName":"test_int16","Key":0,"Value":[3089,null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"19201864880978510.28381871008156E9","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["",0,3265605],"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":{"valNotNull":false,"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"82509790016910","Value":{"valNotNull":"-51151","valNullable":null},"Delete":false},{"TypeName":"test_address","Key":"UQMARFtfJYloAQ5FAQE+P5ezAZMCP82oChQBYQA5AA0LT19MujQyf/8FbQMDawAM","Value":{"valNotNull":"xbA200EFExwKoFrhCgcAYwFvDgEBXAH8AADJAAQFDfgITwIFDh8BAXQMRUwBAgY8/wANBCQGANqvCWL/AYwA+g==","valNullable":"OgPvFo8DAA+2AgEBBM4BXSAA/wCBlzxUAVoC/wQBAbIMKiwD/0MBKAF4Bv8BAoIOUwALFSMuVgIAAZddBQEDBA=="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"64","Value":["13","-732"],"Delete":false},{"TypeName":"test_float32","Key":-2147483648,"Value":{"valNotNull":-0.38865662,"valNullable":null},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"ൌ{ ༿","Value":{"Value1":-152,"Value3":-204.96875},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"‮","Value":{"Value1":-44227},"Delete":false},{"TypeName":"Simple","Key":"A","Value":[837,"Aw=="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"�-\u003e𝟆Ⱥ`Ṙ|¤﮺̺","Value":[1137505,"UQAXACIMig=="],"Delete":false}]} Commit: {} StartBlock: {10 } -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":87208838869,"Value":[-9725,4968373],"Delete":false},{"TypeName":"test_duration","Key":468,"Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":87208838869,"Value":[-9725,4968373],"Delete":false},{"TypeName":"test_duration","Key":-40715358873,"Value":null,"Delete":true}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"","Value":[-1,"FQIK"],"Delete":false},{"TypeName":"Singleton","Key":null,"Value":{"Value":"œLj$࿇ ᾙ☇؄ೲȺ","Value2":"ADei6AACZTMDDss="},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[true,null],"Delete":false},{"TypeName":"test_enum","Key":"bar","Value":{"valNotNull":"baz","valNullable":"baz"},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\tA𐞙?\t",-5317218,1],"Value":{"Value1":1},"Delete":false},{"TypeName":"RetainDeletions","Key":"\u0026 ٱȺ+҉@","Value":[63,"AAE="],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":-1.7392669057403718e+166,"Value":[-1.0781831287525041e+139,111.37014762980289],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"GJQSAs0BGAILARUXAwIrnf8pBgIrRQOrSQNOEgfvA8ATAAEMVw8s/w==","Value":{"valNotNull":"em2zQwR2O7EAAAYLk23QBADE/wA="},"Delete":false},{"TypeName":"test_address","Key":"PQYReIgDAAG/6fs+AVcXxgEGDXLQ30f0/w==","Value":null,"Delete":true}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[true,null],"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":{"valNotNull":"baz","valNullable":"baz"},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":[" {a",2790155,310794],"Value":{"Value1":1},"Delete":false},{"TypeName":"RetainDeletions","Key":"\u0026 ٱȺ+҉@","Value":[63,"AAE="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":2818,"Value":[-1.0781831287525041e+139,111.37014762980289],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"sucDH0r/CmEAgjcBB7H1AgAcEtI=","Value":{"valNotNull":"em2zQwR2O7EAAAYLk23QBADE/wA="},"Delete":false},{"TypeName":"test_address","Key":"UQMARFtfJYloAQ5FAQE+P5ezAZMCP82oChQBYQA5AA0LT19MujQyf/8FbQMDawAM","Value":null,"Delete":true}]} OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"","Value":[-188,"",-2632691.375,17],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["A]$",-125,43],"Value":12654289,"Delete":false},{"TypeName":"RetainDeletions","Key":"?aa₽A\u001b=⇂́ᯫ𖽦ᩣ","Value":{"Value2":"ARM="},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":0,"Value":{"valNotNull":0,"valNullable":null},"Delete":false},{"TypeName":"test_float32","Key":1.7852577e+32,"Value":[1.6582896,null],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?b⁠\r##﹍/$ͥ","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",55175],"Value":null,"Delete":true},{"TypeName":"ThreeKeys","Key":["˖|󺪆𝅲=鄖_.;ǀ⃣%; #~",16,512578],"Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"A%aa ¹­ ᾏaĵ¨","Value":null,"Delete":true}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"‮","Value":{"Value2":"DAcBeTgAFAED"},"Delete":false},{"TypeName":"RetainDeletions","Key":"ʵ² *ᾍA@҂b⭗@‮൞","Value":{"Value1":547,"Value2":""},"Delete":false}]} -OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":4,"Value":[17,null],"Delete":false},{"TypeName":"test_uint8","Key":8,"Value":[2,12],"Delete":false}]} -OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"҉♰ᾜȺ൜堯Ⱥ៵\"","Value":{"Value1":-10,"Value2":"jg==","Value3":-0.11867497289509932,"Value4":24065},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["A]$",-125,43],"Value":12654289,"Delete":false},{"TypeName":"RetainDeletions","Key":"+","Value":{"Value2":"ARM="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":35,"Value":[0,51],"Delete":false},{"TypeName":"test_uint8","Key":107,"Value":[4,null],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-85","Value":{"valNotNull":"-25"},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["_\u001b\u0026㉉",7,3662],"Value":{"Value1":-80},"Delete":false},{"TypeName":"RetainDeletions","Key":"'","Value":[5521,"kwsBjw=="],"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["@(\u0001\u0001\tᛰᾚ𐺭a'ᵆᾭaa",16,817744173394],"Value":-1,"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"Nj#߁#҉♰ᾜȺ൜堯Ⱥ៵\"","Value":{"Value1":-10,"Value2":"jg==","Value3":-0.11867497289509932,"Value4":24065},"Delete":false},{"TypeName":"RetainDeletions","Key":"","Value":{"Value1":2204165,"Value2":"Jg=="},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["A*۽~Dz₱ {",-8,2],"Value":{"Value1":624},"Delete":false},{"TypeName":"ManyValues","Key":"ڥ\u0026\u000b","Value":{"Value1":0,"Value2":"BmQD","Value3":-6.822989118840796e-47,"Value4":654213},"Delete":false}]} +OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["{Ⱥ\t$࿐(#",117624,128273],"Value":14,"Delete":false},{"TypeName":"RetainDeletions","Key":"A%aa ¹­ ᾏaĵ¨","Value":{"Value2":"Av8="},"Delete":false}]} Commit: {} diff --git a/schema/testing/appdatasim/testdata/diff_example.txt b/schema/testing/appdatasim/testdata/diff_example.txt index fcdd45729de3..7c0ab0e14c34 100644 --- a/schema/testing/appdatasim/testdata/diff_example.txt +++ b/schema/testing/appdatasim/testdata/diff_example.txt @@ -2,78 +2,68 @@ App State Diff: MODULE COUNT ERROR: expected 2, got 1 Module all_kinds Object Collection test_address - OBJECT COUNT ERROR: expected 16, got 14 - Object key=0x0c6ff6530300000704ff285714816e0d0b03010d0102010302ff7400d60103c2110e3700c30105679f0910570048aa48f6b4680128821c98011d00240c2c00ff - valNotNull: expected [43 29 85 255 6 1 176 1 241 222 0 0 14 116 190 1 11 30 2 8 1 144 12 2 12 1 16 15 1 1 27 8 0 255 57 2 6 195 255 60 0 201 255 1 1 13 9 112 1 2 0 121 12 172 254 22 11 1 5 37 54 212 121 0], got [220 0 1 2 13 4 24 1 12 24 58 0 1 224 0 148 104 51 116 27 56 39 14 32 35 84 126 2 18 1 5 6] - valNullable: expected [189 125 119 246 192 0 3 170 24 6 10 123 0 7 34 118 1 212 187 7 1 249 110 146 10 14 0 3 223 134 65 0 15 248 153], got [29 201 1 2 1 63 13 0 191 75 1 2 240 10 209 58 15 137 184 141 148] - Object key=0x18f0037d00012c006d9c72096b011e01f600035108fe0303000100031f1f020f08002203000502010120060f1b0201180203006a00e0: NOT FOUND - Object key=0xa10f005de9c1010692980d213250ef13020697430007000bdc01010305054f4001b7ba39003a01d2ae0e59007eef4e19e9020e006974016d00001c00037b7028: NOT FOUND - Object key=0xff2619001c04b3031aa10d9d167f1f0046d6760216009c: NOT FOUND - Object Collection test_bytes - OBJECT COUNT ERROR: expected 5, got 4 - Object key=0x000a4f0f6e9b67f6: NOT FOUND - Object key=0x0e0827 - valNotNull: expected [159 2], got [41 6 2 75] - valNullable: expected [0 11 54 47 28], got [6] - Object key=0xff661b1c00 - valNullable: expected [15 20 0 1 132 7 37 3 28 2], got [0 8 1 170 90 0 1 201 97 138 53 2] - Object Collection test_decimal - OBJECT COUNT ERROR: expected 5, got 3 - Object key=-04360.6e32: NOT FOUND - Object key=-21918e-3: NOT FOUND - Object key=-37.02e01: NOT FOUND - Object key=41090120E-3 - valNotNull: expected 04.13921382165470301184220430, got 0255559.705E-4 - valNullable: expected -2e5, got nil - Object Collection test_duration - OBJECT COUNT ERROR: expected 1, got 2 - Object Collection test_enum - OBJECT COUNT ERROR: expected 1, got 2 + OBJECT COUNT ERROR: expected 14, got 13 + Object key=0x34009062001a03070500afc80101055a0700ac01293000: NOT FOUND + Object key=0x5b01cd8d349b030278030112d8e6020f00000600cc2f66016a016d01: NOT FOUND + Object Collection test_bool + Object key=false + valNotNull: expected true, got false + Object key=true + valNotNull: expected true, got false + Object Collection test_bytes + Object key=0x09: NOT FOUND + Object Collection test_decimal + OBJECT COUNT ERROR: expected 6, got 5 + Object key=-99910.16: NOT FOUND + Object key=309967364: NOT FOUND + Object Collection test_duration + OBJECT COUNT ERROR: expected 8, got 7 + Object key=-3m19.124749496s: NOT FOUND + Object key=45ns: NOT FOUND Object Collection test_float32 - OBJECT COUNT ERROR: expected 3, got 4 - Object Collection test_int16 - OBJECT COUNT ERROR: expected 9, got 8 - Object key=-44: NOT FOUND + Object key=-2: NOT FOUND Object Collection test_int32 - OBJECT COUNT ERROR: expected 2, got 1 - Object key=-453: NOT FOUND - Object key=205: NOT FOUND + OBJECT COUNT ERROR: expected 1, got 0 + Object key=-148250689: NOT FOUND Object Collection test_int64 - OBJECT COUNT ERROR: expected 3, got 5 - Object key=-41 - valNotNull: expected 244, got -5717 - valNullable: expected nil, got 0 - Object Collection test_int8 OBJECT COUNT ERROR: expected 4, got 3 - Object key=-2: NOT FOUND + Object key=1086011412347477: NOT FOUND + Object key=881248243728748743 + valNotNull: expected 1, got -154 + valNullable: expected 363352528, got nil + Object Collection test_int8 Object key=53 - valNotNull: expected 27, got 58 - valNullable: expected nil, got -10 + valNotNull: expected -7, got 58 + valNullable: expected 15, got -10 Object Collection test_integer - OBJECT COUNT ERROR: expected 7, got 6 - Object key=-31083911818: NOT FOUND - Object key=191 - valNotNull: expected 62, got -47110784 - valNullable: expected 9297555, got nil - Object Collection test_string - OBJECT COUNT ERROR: expected 2, got 1 - Object key=š℠¼々¢~;-Ⱥ!˃a[ʰᾌ?{ᪧ৵%ᾯ¦〈: NOT FOUND - Object Collection test_time OBJECT COUNT ERROR: expected 4, got 3 - Object key=1969-12-31 19:00:00.000000005 -0500 EST: NOT FOUND + Object key=12 + valNotNull: expected -3, got 101 + Object key=4: NOT FOUND + Object Collection test_string + Object key= + #[Dž¦&?=: NOT FOUND + Object Collection test_time Object key=1969-12-31 19:00:00.001598687 -0500 EST - valNotNull: expected 1969-12-31 19:00:00.007727197 -0500 EST, got 1969-12-31 19:00:00.034531678 -0500 EST - valNullable: expected 1969-12-31 19:00:00.000000484 -0500 EST, got 1969-12-31 19:00:00.000000033 -0500 EST + valNullable: expected nil, got 1969-12-31 19:00:00.000000033 -0500 EST Object Collection test_uint16 OBJECT COUNT ERROR: expected 4, got 3 - Object key=23712: NOT FOUND + Object key=1478: NOT FOUND Object Collection test_uint32 OBJECT COUNT ERROR: expected 3, got 2 - Object key=0: NOT FOUND + Object key=0 + valNotNull: expected 1, got 26 + valNullable: expected 321283034, got 2 + Object key=23067: NOT FOUND Object Collection test_uint64 - OBJECT COUNT ERROR: expected 1, got 2 - Object Collection test_uint8 - OBJECT COUNT ERROR: expected 3, got 2 + OBJECT COUNT ERROR: expected 2, got 0 Object key=1: NOT FOUND + Object key=50508131: NOT FOUND + Object Collection test_uint8 + OBJECT COUNT ERROR: expected 2, got 1 + Object key=119 + valNotNull: expected 6, got 30 + valNullable: expected nil, got 7 + Object key=72: NOT FOUND Module test_cases: actual module NOT FOUND BlockNum: expected 2, got 1 diff --git a/schema/testing/example_schema.go b/schema/testing/example_schema.go index 60ae8bba548e..36dd0a0b76dc 100644 --- a/schema/testing/example_schema.go +++ b/schema/testing/example_schema.go @@ -152,6 +152,9 @@ func mkTestObjectType(kind schema.Kind) schema.ObjectType { keyField := field keyField.Name = "key" + if !kind.ValidKeyKind() { + keyField.Kind = schema.Int32Kind + } val1Field := field val1Field.Name = "valNotNull" val2Field := field diff --git a/schema/testing/field.go b/schema/testing/field.go index 670f9356a681..b7debbc32c7a 100644 --- a/schema/testing/field.go +++ b/schema/testing/field.go @@ -35,6 +35,11 @@ var FieldGen = rapid.Custom(func(t *rapid.T) schema.Field { return field }) +// KeyFieldGen generates random key fields based on the validity criteria of key fields. +var KeyFieldGen = FieldGen.Filter(func(f schema.Field) bool { + return !f.Nullable && f.Kind.ValidKeyKind() +}) + // FieldValueGen generates random valid values for the field, aiming to exercise the full range of possible // values for the field. func FieldValueGen(field schema.Field) *rapid.Generator[any] { @@ -128,9 +133,8 @@ func ObjectKeyGen(keyFields []schema.Field) *rapid.Generator[any] { // Values that are for update may skip some fields in a ValueUpdates instance whereas values for insertion // will always contain all values. func ObjectValueGen(valueFields []schema.Field, forUpdate bool) *rapid.Generator[any] { - // special case where there are no value fields - // we shouldn't end up here, but just in case if len(valueFields) == 0 { + // if we have no value fields, always return nil return rapid.Just[any](nil) } diff --git a/schema/testing/fmt.go b/schema/testing/fmt.go new file mode 100644 index 000000000000..e486adfeb8b7 --- /dev/null +++ b/schema/testing/fmt.go @@ -0,0 +1,53 @@ +package schematesting + +import ( + "fmt" + + "github.com/cockroachdb/apd/v3" + + "cosmossdk.io/schema" +) + +// ObjectKeyString formats the object key as a string deterministically for storage in a map. +// The key must be valid for the object type and the object type must be valid. +// No validation is performed here. +func ObjectKeyString(objectType schema.ObjectType, key any) string { + keyFields := objectType.KeyFields + n := len(keyFields) + switch n { + case 0: + return "" + case 1: + valStr := fmtValue(keyFields[0].Kind, key) + return fmt.Sprintf("%s=%v", keyFields[0].Name, valStr) + default: + ks := key.([]interface{}) + res := "" + for i := 0; i < n; i++ { + if i != 0 { + res += ", " + } + valStr := fmtValue(keyFields[i].Kind, ks[i]) + res += fmt.Sprintf("%s=%v", keyFields[i].Name, valStr) + } + return res + } +} + +func fmtValue(kind schema.Kind, value any) string { + switch kind { + case schema.BytesKind, schema.AddressKind: + return fmt.Sprintf("0x%x", value) + case schema.DecimalStringKind, schema.IntegerStringKind: + // we need to normalize decimal & integer strings to remove leading & trailing zeros + d, _, err := apd.NewFromString(value.(string)) + if err != nil { + panic(err) + } + r := &apd.Decimal{} + r, _ = r.Reduce(d) + return r.String() + default: + return fmt.Sprintf("%v", value) + } +} diff --git a/schema/testing/fmt_test.go b/schema/testing/fmt_test.go new file mode 100644 index 000000000000..02cef05d5f1b --- /dev/null +++ b/schema/testing/fmt_test.go @@ -0,0 +1,61 @@ +package schematesting + +import ( + "testing" + + "cosmossdk.io/schema" +) + +func TestObjectKeyString(t *testing.T) { + tt := []struct { + objectType schema.ObjectType + key any + expected string + }{ + { + objectType: schema.ObjectType{ + Name: "Singleton", + ValueFields: []schema.Field{ + {Name: "Value", Kind: schema.StringKind}, + }, + }, + key: nil, + expected: "", + }, + { + objectType: schema.ObjectType{ + Name: "Simple", + KeyFields: []schema.Field{{Name: "Key", Kind: schema.StringKind}}, + }, + key: "key", + expected: "Key=key", + }, + { + objectType: schema.ObjectType{ + Name: "BytesAddressDecInt", + KeyFields: []schema.Field{ + {Name: "Bz", Kind: schema.BytesKind}, + {Name: "Addr", Kind: schema.AddressKind}, + {Name: "Dec", Kind: schema.DecimalStringKind}, + {Name: "Int", Kind: schema.IntegerStringKind}, + }, + }, + key: []interface{}{ + []byte{0x01, 0x02}, + []byte{0x03, 0x04}, + "123.4560000", // trailing zeros should get removed + "0000012345678900000000000", // leading zeros should get removed and this should be in exponential form + }, + expected: "Bz=0x0102, Addr=0x0304, Dec=123.456, Int=1.23456789E+19", + }, + } + + for _, tc := range tt { + t.Run(tc.objectType.Name, func(t *testing.T) { + actual := ObjectKeyString(tc.objectType, tc.key) + if actual != tc.expected { + t.Errorf("expected %s, got %s", tc.expected, actual) + } + }) + } +} diff --git a/schema/testing/module_schema.go b/schema/testing/module_schema.go index 9f62bfd2d281..8d25046540bf 100644 --- a/schema/testing/module_schema.go +++ b/schema/testing/module_schema.go @@ -29,7 +29,7 @@ var objectTypesGen = rapid.Custom(func(t *rapid.T) []schema.ObjectType { }).Filter(func(objectTypes []schema.ObjectType) bool { typeNames := map[string]bool{} for _, objectType := range objectTypes { - if hasDuplicateNames(typeNames, objectType.KeyFields) || hasDuplicateNames(typeNames, objectType.ValueFields) { + if hasDuplicateTypeNames(typeNames, objectType.KeyFields) || hasDuplicateTypeNames(typeNames, objectType.ValueFields) { return false } if typeNames[objectType.Name] { @@ -43,9 +43,9 @@ var objectTypesGen = rapid.Custom(func(t *rapid.T) []schema.ObjectType { // MustNewModuleSchema calls NewModuleSchema and panics if there's an error. This should generally be used // only in tests or initialization code. func MustNewModuleSchema(objectTypes []schema.ObjectType) schema.ModuleSchema { - schema, err := schema.NewModuleSchema(objectTypes) + sch, err := schema.NewModuleSchema(objectTypes) if err != nil { panic(err) } - return schema + return sch } diff --git a/schema/testing/object.go b/schema/testing/object.go index 8d7bd37a2a05..396e2537b383 100644 --- a/schema/testing/object.go +++ b/schema/testing/object.go @@ -7,7 +7,11 @@ import ( "cosmossdk.io/schema" ) -var fieldsGen = rapid.SliceOfNDistinct(FieldGen, 1, 12, func(f schema.Field) string { +var keyFieldsGen = rapid.SliceOfNDistinct(KeyFieldGen, 1, 6, func(f schema.Field) string { + return f.Name +}) + +var valueFieldsGen = rapid.SliceOfNDistinct(FieldGen, 1, 12, func(f schema.Field) string { return f.Name }) @@ -17,35 +21,44 @@ var ObjectTypeGen = rapid.Custom(func(t *rapid.T) schema.ObjectType { Name: NameGen.Draw(t, "name"), } - fields := fieldsGen.Draw(t, "fields") - numKeyFields := rapid.IntRange(0, len(fields)).Draw(t, "numKeyFields") - - typ.KeyFields = fields[:numKeyFields] - - for i := range typ.KeyFields { - // key fields can't be nullable - typ.KeyFields[i].Nullable = false - } - - typ.ValueFields = fields[numKeyFields:] - + typ.KeyFields = keyFieldsGen.Draw(t, "keyFields") + typ.ValueFields = valueFieldsGen.Draw(t, "valueFields") typ.RetainDeletions = boolGen.Draw(t, "retainDeletions") return typ }).Filter(func(typ schema.ObjectType) bool { - // filter out duplicate enum names + // filter out duplicate field names + fieldNames := map[string]bool{} + if hasDuplicateFieldNames(fieldNames, typ.KeyFields) { + return false + } + if hasDuplicateFieldNames(fieldNames, typ.ValueFields) { + return false + } + + // filter out duplicate type names typeNames := map[string]bool{typ.Name: true} - if hasDuplicateNames(typeNames, typ.KeyFields) { + if hasDuplicateTypeNames(typeNames, typ.KeyFields) { return false } - if hasDuplicateNames(typeNames, typ.ValueFields) { + if hasDuplicateTypeNames(typeNames, typ.ValueFields) { return false } return true }) -// hasDuplicateNames checks if there is type name in the fields -func hasDuplicateNames(typeNames map[string]bool, fields []schema.Field) bool { +func hasDuplicateFieldNames(typeNames map[string]bool, fields []schema.Field) bool { + for _, field := range fields { + if _, ok := typeNames[field.Name]; ok { + return true + } + typeNames[field.Name] = true + } + return false +} + +// hasDuplicateTypeNames checks if there is type name in the fields +func hasDuplicateTypeNames(typeNames map[string]bool, fields []schema.Field) bool { for _, field := range fields { if field.Kind != schema.EnumKind { continue @@ -68,60 +81,41 @@ func ObjectInsertGen(objectType schema.ObjectType) *rapid.Generator[schema.Objec // ObjectUpdateGen generates object updates that are valid for updates using the provided state map as a source // of valid existing keys. func ObjectUpdateGen(objectType schema.ObjectType, state *btree.Map[string, schema.ObjectUpdate]) *rapid.Generator[schema.ObjectUpdate] { - keyGen := ObjectKeyGen(objectType.KeyFields) - - if len(objectType.ValueFields) == 0 { - // special case where there are no value fields, - // so we just insert or delete, no updates - return rapid.Custom(func(t *rapid.T) schema.ObjectUpdate { - update := schema.ObjectUpdate{ - TypeName: objectType.Name, - } - - // 50% of the time delete existing key (when there are keys) - n := 0 - if state != nil { - n = state.Len() - } - if n > 0 && boolGen.Draw(t, "delete") { - i := rapid.IntRange(0, n-1).Draw(t, "index") - update.Key = state.Values()[i].Key - update.Delete = true - } else { - update.Key = keyGen.Draw(t, "key") - } + keyGen := ObjectKeyGen(objectType.KeyFields).Filter(func(key interface{}) bool { + // filter out keys that exist in the state + if state != nil { + _, exists := state.Get(ObjectKeyString(objectType, key)) + return !exists + } + return true + }) + insertValueGen := ObjectValueGen(objectType.ValueFields, false) + updateValueGen := ObjectValueGen(objectType.ValueFields, true) + return rapid.Custom(func(t *rapid.T) schema.ObjectUpdate { + update := schema.ObjectUpdate{ + TypeName: objectType.Name, + } - return update - }) - } else { - insertValueGen := ObjectValueGen(objectType.ValueFields, false) - updateValueGen := ObjectValueGen(objectType.ValueFields, true) - return rapid.Custom(func(t *rapid.T) schema.ObjectUpdate { - update := schema.ObjectUpdate{ - TypeName: objectType.Name, - } + // 50% of the time use existing key (when there are keys) + n := 0 + if state != nil { + n = state.Len() + } + if n > 0 && boolGen.Draw(t, "existingKey") { + i := rapid.IntRange(0, n-1).Draw(t, "index") + update.Key = state.Values()[i].Key - // 50% of the time use existing key (when there are keys) - n := 0 - if state != nil { - n = state.Len() - } - if n > 0 && boolGen.Draw(t, "existingKey") { - i := rapid.IntRange(0, n-1).Draw(t, "index") - update.Key = state.Values()[i].Key - - // delete 50% of the time - if boolGen.Draw(t, "delete") { - update.Delete = true - } else { - update.Value = updateValueGen.Draw(t, "value") - } + // delete 50% of the time + if boolGen.Draw(t, "delete") { + update.Delete = true } else { - update.Key = keyGen.Draw(t, "key") - update.Value = insertValueGen.Draw(t, "value") + update.Value = updateValueGen.Draw(t, "value") } + } else { + update.Key = keyGen.Draw(t, "key") + update.Value = insertValueGen.Draw(t, "value") + } - return update - }) - } + return update + }) } diff --git a/schema/testing/statesim/object_coll.go b/schema/testing/statesim/object_coll.go index 8531811de3c3..163a4205fcf3 100644 --- a/schema/testing/statesim/object_coll.go +++ b/schema/testing/statesim/object_coll.go @@ -48,7 +48,7 @@ func (o *ObjectCollection) ApplyUpdate(update schema.ObjectUpdate) error { return err } - keyStr := fmtObjectKey(o.objectType, update.Key) + keyStr := schematesting.ObjectKeyString(o.objectType, update.Key) cur, exists := o.objects.Get(keyStr) if update.Delete { if o.objectType.RetainDeletions && o.options.CanRetainDeletions { @@ -119,7 +119,7 @@ func (o *ObjectCollection) AllState(f func(schema.ObjectUpdate, error) bool) { // GetObject returns the object with the given key from the collection represented as an ObjectUpdate // itself. Deletions that are retained are returned as ObjectUpdate's with delete set to true. func (o *ObjectCollection) GetObject(key interface{}) (update schema.ObjectUpdate, found bool, err error) { - update, ok := o.objects.Get(fmtObjectKey(o.objectType, key)) + update, ok := o.objects.Get(schematesting.ObjectKeyString(o.objectType, key)) return update, ok, nil } @@ -132,37 +132,3 @@ func (o *ObjectCollection) ObjectType() schema.ObjectType { func (o *ObjectCollection) Len() (int, error) { return o.objects.Len(), nil } - -func fmtObjectKey(objectType schema.ObjectType, key any) string { - keyFields := objectType.KeyFields - n := len(keyFields) - switch n { - case 0: - return "" - case 1: - valStr := fmtValue(keyFields[0].Kind, key) - return fmt.Sprintf("%s=%v", keyFields[0].Name, valStr) - default: - ks := key.([]interface{}) - res := "" - for i := 0; i < n; i++ { - if i != 0 { - res += ", " - } - valStr := fmtValue(keyFields[i].Kind, ks[i]) - res += fmt.Sprintf("%s=%v", keyFields[i].Name, valStr) - } - return res - } -} - -func fmtValue(kind schema.Kind, value any) string { - switch kind { - case schema.BytesKind, schema.AddressKind: - return fmt.Sprintf("0x%x", value) - case schema.JSONKind: - return fmt.Sprintf("%s", value) - default: - return fmt.Sprintf("%v", value) - } -} diff --git a/schema/testing/statesim/object_coll_diff.go b/schema/testing/statesim/object_coll_diff.go index ce4f87efbef7..b38b577aec97 100644 --- a/schema/testing/statesim/object_coll_diff.go +++ b/schema/testing/statesim/object_coll_diff.go @@ -35,7 +35,7 @@ func DiffObjectCollections(expected, actual view.ObjectCollection) string { continue } - keyStr := fmtObjectKey(expected.ObjectType(), expectedUpdate.Key) + keyStr := schematesting.ObjectKeyString(expected.ObjectType(), expectedUpdate.Key) actualUpdate, found, err := actual.GetObject(expectedUpdate.Key) if err != nil { res += fmt.Sprintf("Object %s: ERROR: %v\n", keyStr, err) From bdb9232ed819387cceef59fe635858ec985ff816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Francisco=20L=C3=B3pez?= Date: Wed, 21 Aug 2024 10:36:34 +0200 Subject: [PATCH 11/26] refactor(cli): Standardize `Use` field convention and update readme (#21369) --- .golangci.yml | 3 ++ client/debug/main.go | 10 ++--- client/grpc/cmtservice/autocli.go | 4 +- client/keys/show.go | 2 +- client/v2/README.md | 24 +++++++++++ client/v2/autocli/msg_test.go | 8 ++-- .../v2/autocli/testdata/help-echo-msg.golden | 2 +- server/cmt_cmds.go | 2 +- server/module_hash.go | 2 +- server/start.go | 2 +- .../client/grpc/cmtservice/autocli.go | 4 +- server/v2/cometbft/commands.go | 2 +- testutil/x/counter/autocli.go | 2 +- tools/confix/cmd/mutate.go | 4 +- tools/confix/cmd/view.go | 2 +- .../cosmovisor/cmd/cosmovisor/add_upgrade.go | 2 +- .../cosmovisor/cmd/cosmovisor/version_test.go | 2 +- tools/hubl/internal/remote.go | 2 +- x/accounts/cli/cli.go | 6 +-- x/auth/autocli.go | 12 +++--- x/auth/client/cli/broadcast.go | 2 +- x/auth/client/cli/decode.go | 2 +- x/auth/client/cli/encode.go | 2 +- x/auth/client/cli/query.go | 2 +- x/auth/client/cli/tx_multisign.go | 4 +- x/auth/client/cli/tx_sign.go | 4 +- x/auth/client/cli/tx_simulate.go | 2 +- x/auth/client/cli/validate_sigs.go | 2 +- x/authz/client/cli/tx.go | 6 +-- x/authz/module/autocli.go | 12 +++--- x/bank/autocli.go | 24 +++++------ x/bank/client/cli/tx.go | 2 +- x/circuit/autocli.go | 8 ++-- x/consensus/autocli.go | 2 +- x/distribution/autocli.go | 24 +++++------ x/evidence/autocli.go | 2 +- x/feegrant/client/cli/tx.go | 2 +- x/feegrant/module/autocli.go | 8 ++-- x/genutil/client/cli/genaccount.go | 2 +- x/genutil/client/cli/gentx.go | 2 +- x/genutil/client/cli/init.go | 2 +- x/genutil/client/cli/migrate.go | 2 +- x/gov/autocli.go | 24 +++++------ x/gov/client/cli/tx.go | 4 +- x/group/client/cli/tx.go | 12 +++--- x/group/module/autocli.go | 42 +++++++++---------- x/mint/autocli.go | 2 +- x/nft/module/autocli.go | 14 +++---- x/params/autocli.go | 2 +- x/params/client/cli/tx.go | 2 +- x/protocolpool/autocli.go | 12 +++--- x/slashing/autocli.go | 4 +- x/staking/autocli.go | 34 +++++++-------- x/staking/client/cli/tx.go | 2 +- x/upgrade/autocli.go | 2 +- x/upgrade/client/cli/tx.go | 2 +- 56 files changed, 200 insertions(+), 173 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index fc4dd038ba30..158724cf53cf 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -76,6 +76,9 @@ issues: - text: "SA1019: params.SendEnabled is deprecated" # TODO remove once ready to remove from the sdk linters: - staticcheck + - text: "SA1029: Inappropriate key in context.WithValue" # TODO remove this when dependency is updated + linters: + - staticcheck - text: "leading space" linters: - nolintlint diff --git a/client/debug/main.go b/client/debug/main.go index f9f8a176f5ef..0cce37d16cd1 100644 --- a/client/debug/main.go +++ b/client/debug/main.go @@ -82,7 +82,7 @@ func getCodecInterfaces() *cobra.Command { // getCodecInterfaceImpls creates and returns a new cmd used for listing all registered implementations of a given interface on the application codec. func getCodecInterfaceImpls() *cobra.Command { return &cobra.Command{ - Use: "list-implementations [interface]", + Use: "list-implementations ", Short: "List the registered type URLs for the provided interface", Long: "List the registered type URLs that can be used for the provided interface name using the application codec", Example: fmt.Sprintf("%s debug codec list-implementations cosmos.crypto.PubKey", version.AppName), @@ -109,7 +109,7 @@ func getPubKeyFromString(ctx client.Context, pkstr string) (cryptotypes.PubKey, func PubkeyCmd() *cobra.Command { return &cobra.Command{ - Use: "pubkey [pubkey]", + Use: "pubkey ", Short: "Decode a pubkey from proto JSON", Long: "Decode a pubkey from proto JSON and display it's address.", Example: fmt.Sprintf(`%s debug pubkey '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ"}'`, version.AppName), @@ -181,7 +181,7 @@ func getPubKeyFromRawString(pkstr, keytype string) (cryptotypes.PubKey, error) { func PubkeyRawCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "pubkey-raw [pubkey] -t [{ed25519, secp256k1}]", + Use: "pubkey-raw [-t {ed25519, secp256k1}]", Short: "Decode a ED25519 or secp256k1 pubkey from hex, base64, or bech32", Long: "Decode a pubkey from hex, base64, or bech32.", Example: fmt.Sprintf(` @@ -247,7 +247,7 @@ func PubkeyRawCmd() *cobra.Command { func AddrCmd() *cobra.Command { return &cobra.Command{ - Use: "addr [address]", + Use: "addr
", Short: "Convert an address between hex and bech32", Example: fmt.Sprintf("%s debug addr cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg", version.AppName), Args: cobra.ExactArgs(1), @@ -303,7 +303,7 @@ func AddrCmd() *cobra.Command { func RawBytesCmd() *cobra.Command { return &cobra.Command{ - Use: "raw-bytes [raw-bytes]", + Use: "raw-bytes ", Short: "Convert raw bytes output (eg. [10 21 13 255]) to hex", Long: "Convert raw-bytes to hex.", Example: fmt.Sprintf("%s debug raw-bytes [72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 110 100]", version.AppName), diff --git a/client/grpc/cmtservice/autocli.go b/client/grpc/cmtservice/autocli.go index ea314c6f8c08..6d8be1f22994 100644 --- a/client/grpc/cmtservice/autocli.go +++ b/client/grpc/cmtservice/autocli.go @@ -25,7 +25,7 @@ var CometBFTAutoCLIDescriptor = &autocliv1.ServiceCommandDescriptor{ }, { RpcMethod: "GetBlockByHeight", - Use: "block-by-height [height]", + Use: "block-by-height ", Short: "Query for a committed block by height", Long: "Query for a specific committed block using the CometBFT RPC `block_by_height` method", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}}, @@ -38,7 +38,7 @@ var CometBFTAutoCLIDescriptor = &autocliv1.ServiceCommandDescriptor{ }, { RpcMethod: "GetValidatorSetByHeight", - Use: "validator-set-by-height [height]", + Use: "validator-set-by-height ", Short: "Query for a validator set by height", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}}, }, diff --git a/client/keys/show.go b/client/keys/show.go index 22c14ddaeb58..0c418b6ed6f9 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -37,7 +37,7 @@ const ( // ShowKeysCmd shows key information for a given key name. func ShowKeysCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "show [name_or_address [name_or_address...]]", + Use: "show [name_or_address...]", Short: "Retrieve key information by name or address", Long: `Display keys details. If multiple names or addresses are provided, then an ephemeral multisig key will be created under the name "multi" diff --git a/client/v2/README.md b/client/v2/README.md index 478683ee360b..9efc241748af 100644 --- a/client/v2/README.md +++ b/client/v2/README.md @@ -131,6 +131,30 @@ AutoCLI can create a gov proposal of any tx by simply setting the `GovProposal` Users can however use the `--no-proposal` flag to disable the proposal creation (which is useful if the authority isn't the gov module on a chain). ::: +### Conventions for the `Use` field in Cobra + +According to the [Cobra documentation](https://pkg.go.dev/github.com/spf13/cobra#Command) the following conventions should be followed for the `Use` field in Cobra commands: + +1. **Required arguments**: + * Should not be enclosed in brackets. They can be enclosed in angle brackets `< >` for clarity. + * Example: `command ` + +2. **Optional arguments**: + * Should be enclosed in square brackets `[ ]`. + * Example: `command [optional_argument]` + +3. **Alternative (mutually exclusive) arguments**: + * Should be enclosed in curly braces `{ }`. + * Example: `command {-a | -b}` for required alternatives. + * Example: `command [-a | -b]` for optional alternatives. + +4. **Multiple arguments**: + * Indicated with `...` after the argument. + * Example: `command argument...` + +5. **Combination of options**: + * Example: `command [-F file | -D dir]... [-f format] profile` + ### Specifying Subcommands By default, `autocli` generates a command for each method in your gRPC service. However, you can specify subcommands to group related commands together. To specify subcommands, use the `autocliv1.ServiceCommandDescriptor` struct. diff --git a/client/v2/autocli/msg_test.go b/client/v2/autocli/msg_test.go index 2c08022fde80..11e6fd2d2fce 100644 --- a/client/v2/autocli/msg_test.go +++ b/client/v2/autocli/msg_test.go @@ -41,7 +41,7 @@ var bankAutoCLI = &autocliv1.ServiceCommandDescriptor{ RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Send", - Use: "send [from_key_or_address] [to_address] [amount] [flags]", + Use: "send [flags]", Short: "Send coins from one account to another", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "from_address"}, {ProtoField: "to_address"}, {ProtoField: "amount"}}, }, @@ -64,7 +64,7 @@ func TestMsg(t *testing.T) { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Send", - Use: "send [from_key_or_address] [to_address] [amount] [flags]", + Use: "send [flags]", Short: "Send coins from one account to another", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "from_address"}, {ProtoField: "to_address"}, {ProtoField: "amount"}}, }, @@ -83,7 +83,7 @@ func TestMsg(t *testing.T) { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Send", - Use: "send [from_key_or_address] [to_address] [amount] [flags]", + Use: "send [flags]", Short: "Send coins from one account to another", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "to_address"}, {ProtoField: "amount"}}, // from_address should be automatically added @@ -104,7 +104,7 @@ func TestMsg(t *testing.T) { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Send", - Use: "send [from_key_or_address] [to_address] [amount] [flags]", + Use: "send [flags]", Short: "Send coins from one account to another", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "to_address"}, {ProtoField: "amount"}}, FlagOptions: map[string]*autocliv1.FlagOptions{ diff --git a/client/v2/autocli/testdata/help-echo-msg.golden b/client/v2/autocli/testdata/help-echo-msg.golden index 91c5e678c43e..1307509569c9 100644 --- a/client/v2/autocli/testdata/help-echo-msg.golden +++ b/client/v2/autocli/testdata/help-echo-msg.golden @@ -1,7 +1,7 @@ Send coins from one account to another Usage: - test send [from_key_or_address] [to_address] [amount] [flags] + test send [flags] Flags: -a, --account-number uint The account number of the signing account (offline mode only) diff --git a/server/cmt_cmds.go b/server/cmt_cmds.go index 6e13230e5260..fc4f1c6f562b 100644 --- a/server/cmt_cmds.go +++ b/server/cmt_cmds.go @@ -218,7 +218,7 @@ for. Each module documents its respective events under 'xx_events.md'. // QueryBlockCmd implements the default command for a Block query. func QueryBlockCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "block --type=[height|hash] [height|hash]", + Use: "block --type={height|hash} [height|hash]", Short: "Query for a committed block by height, hash, or event(s)", Long: "Query for a specific committed block using the CometBFT RPC `block` and `block_by_hash` method", Example: strings.TrimSpace(fmt.Sprintf(` diff --git a/server/module_hash.go b/server/module_hash.go index 966a29139038..4b18355a85e3 100644 --- a/server/module_hash.go +++ b/server/module_hash.go @@ -21,7 +21,7 @@ import ( // ModuleHashByHeightQuery retrieves the module hashes at a given height. func ModuleHashByHeightQuery[T servertypes.Application](appCreator servertypes.AppCreator[T]) *cobra.Command { cmd := &cobra.Command{ - Use: "module-hash-by-height [height]", + Use: "module-hash-by-height ", Short: "Get module hashes at a given height", Long: "Get module hashes at a given height. This command is useful for debugging and verifying the state of the application at a given height. Daemon should not be running when calling this command.", Example: fmt.Sprintf("%s module-hash-by-height 16841115", version.AppName), diff --git a/server/start.go b/server/start.go index 37089246b8b5..0392c09b2701 100644 --- a/server/start.go +++ b/server/start.go @@ -667,7 +667,7 @@ func InPlaceTestnetCreator[T types.Application](testnetAppCreator types.AppCreat } cmd := &cobra.Command{ - Use: "in-place-testnet [newChainID] [newOperatorAddress]", + Use: "in-place-testnet ", Short: "Create and start a testnet from current local state", Long: `Create and start a testnet from current local state. After utilizing this command the network will start. If the network is stopped, diff --git a/server/v2/cometbft/client/grpc/cmtservice/autocli.go b/server/v2/cometbft/client/grpc/cmtservice/autocli.go index ea314c6f8c08..6d8be1f22994 100644 --- a/server/v2/cometbft/client/grpc/cmtservice/autocli.go +++ b/server/v2/cometbft/client/grpc/cmtservice/autocli.go @@ -25,7 +25,7 @@ var CometBFTAutoCLIDescriptor = &autocliv1.ServiceCommandDescriptor{ }, { RpcMethod: "GetBlockByHeight", - Use: "block-by-height [height]", + Use: "block-by-height ", Short: "Query for a committed block by height", Long: "Query for a specific committed block using the CometBFT RPC `block_by_height` method", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}}, @@ -38,7 +38,7 @@ var CometBFTAutoCLIDescriptor = &autocliv1.ServiceCommandDescriptor{ }, { RpcMethod: "GetValidatorSetByHeight", - Use: "validator-set-by-height [height]", + Use: "validator-set-by-height ", Short: "Query for a validator set by height", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}}, }, diff --git a/server/v2/cometbft/commands.go b/server/v2/cometbft/commands.go index dac4fa63f8d1..ed8329731ac0 100644 --- a/server/v2/cometbft/commands.go +++ b/server/v2/cometbft/commands.go @@ -233,7 +233,7 @@ for. Each module documents its respective events under 'xx_events.md'. // QueryBlockCmd implements the default command for a Block query. func (s *CometBFTServer[T]) QueryBlockCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "block --type=[height|hash] [height|hash]", + Use: "block --type={height|hash} ", Short: "Query for a committed block by height, hash, or event(s)", Long: "Query for a specific committed block using the CometBFT RPC `block` and `block_by_hash` method", Example: strings.TrimSpace(fmt.Sprintf(` diff --git a/testutil/x/counter/autocli.go b/testutil/x/counter/autocli.go index 2067df6b81d5..572ec584e773 100644 --- a/testutil/x/counter/autocli.go +++ b/testutil/x/counter/autocli.go @@ -23,7 +23,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "IncreaseCount", - Use: "increase-count [count]", + Use: "increase-count ", Alias: []string{"increase-counter", "increase", "inc", "bump"}, Short: "Increase the counter by the specified amount", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "count"}}, diff --git a/tools/confix/cmd/mutate.go b/tools/confix/cmd/mutate.go index 772f38e7a86e..9dd4a34ff08f 100644 --- a/tools/confix/cmd/mutate.go +++ b/tools/confix/cmd/mutate.go @@ -20,7 +20,7 @@ import ( // SetCommand returns a CLI command to interactively update an application config value. func SetCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "set [config] [key] [value]", + Use: "set ", Short: "Set an application config value", Long: "Set an application config value. The [config] argument must be the path of the file when using the `confix` tool standalone, otherwise it must be the name of the config file without the .toml extension.", Args: cobra.ExactArgs(3), @@ -92,7 +92,7 @@ func SetCommand() *cobra.Command { // GetCommand returns a CLI command to interactively get an application config value. func GetCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "get [config] [key]", + Use: "get ", Short: "Get an application config value", Long: "Get an application config value. The [config] argument must be the path of the file when using the `confix` tool standalone, otherwise it must be the name of the config file without the .toml extension.", Args: cobra.ExactArgs(2), diff --git a/tools/confix/cmd/view.go b/tools/confix/cmd/view.go index 4c41c2963ef6..d88c68574057 100644 --- a/tools/confix/cmd/view.go +++ b/tools/confix/cmd/view.go @@ -16,7 +16,7 @@ func ViewCommand() *cobra.Command { flagOutputFormat := "output-format" cmd := &cobra.Command{ - Use: "view [config]", + Use: "view ", Short: "View the config file", Long: "View the config file. The [config] argument must be the path of the file when using the `confix` tool standalone, otherwise it must be the name of the config file without the .toml extension.", Args: cobra.ExactArgs(1), diff --git a/tools/cosmovisor/cmd/cosmovisor/add_upgrade.go b/tools/cosmovisor/cmd/cosmovisor/add_upgrade.go index b188ab05fdc4..a197f33bc1dc 100644 --- a/tools/cosmovisor/cmd/cosmovisor/add_upgrade.go +++ b/tools/cosmovisor/cmd/cosmovisor/add_upgrade.go @@ -15,7 +15,7 @@ import ( func NewAddUpgradeCmd() *cobra.Command { addUpgrade := &cobra.Command{ - Use: "add-upgrade [upgrade-name] [path to executable]", + Use: "add-upgrade ", Short: "Add APP upgrade binary to cosmovisor", SilenceUsage: true, Args: cobra.ExactArgs(2), diff --git a/tools/cosmovisor/cmd/cosmovisor/version_test.go b/tools/cosmovisor/cmd/cosmovisor/version_test.go index 9f4cfb896072..47dcb06cc74b 100644 --- a/tools/cosmovisor/cmd/cosmovisor/version_test.go +++ b/tools/cosmovisor/cmd/cosmovisor/version_test.go @@ -20,7 +20,7 @@ func TestVersionCommand_Error(t *testing.T) { rootCmd.SetOut(out) rootCmd.SetErr(out) - ctx := context.WithValue(context.Background(), log.ContextKey, logger) //nolint:staticcheck // temporary issue in dependency + ctx := context.WithValue(context.Background(), log.ContextKey, logger) //nolint:staticcheck // SA1029: temporary issue in dependency require.Error(t, rootCmd.ExecuteContext(ctx)) require.Contains(t, out.String(), "DAEMON_NAME is not set") diff --git a/tools/hubl/internal/remote.go b/tools/hubl/internal/remote.go index e792d6c1e661..0584c0800eb4 100644 --- a/tools/hubl/internal/remote.go +++ b/tools/hubl/internal/remote.go @@ -25,7 +25,7 @@ func InitCmd(config *config.Config, configDir string) *cobra.Command { var insecure bool cmd := &cobra.Command{ - Use: "init [foochain]", + Use: "init ", Short: "Initialize a new chain", Long: `To configure a new chain, run this command using the --init flag and the name of the chain as it's listed in the chain registry (https://github.com/cosmos/chain-registry). If the chain is not listed in the chain registry, you can use any unique name.`, diff --git a/x/accounts/cli/cli.go b/x/accounts/cli/cli.go index 12d7170ae821..e1458acbb045 100644 --- a/x/accounts/cli/cli.go +++ b/x/accounts/cli/cli.go @@ -41,7 +41,7 @@ func QueryCmd(name string) *cobra.Command { func GetTxInitCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "init [account-type] [json-message]", + Use: "init ", Short: "Initialize a new account", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { @@ -95,7 +95,7 @@ func GetTxInitCmd() *cobra.Command { func GetExecuteCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "execute [account-address] [execute-msg-type-url] [json-message]", + Use: "execute ", Short: "Execute state transition to account", Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { @@ -132,7 +132,7 @@ func GetExecuteCmd() *cobra.Command { func GetQueryAccountCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "query [account-address] [query-request-type-url] [json-message]", + Use: "query ", Short: "Query account state", Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/x/auth/autocli.go b/x/auth/autocli.go index 974daf4df5b7..676a3e4af702 100644 --- a/x/auth/autocli.go +++ b/x/auth/autocli.go @@ -24,19 +24,19 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Account", - Use: "account [address]", + Use: "account
", Short: "Query account by address", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}}, }, { RpcMethod: "AccountInfo", - Use: "account-info [address]", + Use: "account-info
", Short: "Query account info which is common to all account types.", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}}, }, { RpcMethod: "AccountAddressByID", - Use: "address-by-acc-num [acc-num]", + Use: "address-by-acc-num ", Short: "Query account address by account number", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "id"}}, }, @@ -47,20 +47,20 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "ModuleAccountByName", - Use: "module-account [module-name]", + Use: "module-account ", Short: "Query module account info by module name", Example: fmt.Sprintf("%s q auth module-account gov", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "name"}}, }, { RpcMethod: "AddressBytesToString", - Use: "address-bytes-to-string [address-bytes]", + Use: "address-bytes-to-string ", Short: "Transform an address bytes to string", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address_bytes"}}, }, { RpcMethod: "AddressStringToBytes", - Use: "address-string-to-bytes [address-string]", + Use: "address-string-to-bytes ", Short: "Transform an address string to bytes", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address_string"}}, }, diff --git a/x/auth/client/cli/broadcast.go b/x/auth/client/cli/broadcast.go index f110e459ddc6..dba2fedd5ee3 100644 --- a/x/auth/client/cli/broadcast.go +++ b/x/auth/client/cli/broadcast.go @@ -17,7 +17,7 @@ import ( // GetBroadcastCommand returns the tx broadcast command. func GetBroadcastCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "broadcast [file_path]", + Use: "broadcast ", Short: "Broadcast transactions generated offline", Long: strings.TrimSpace(`Broadcast transactions created with the --generate-only flag and signed with the sign command. Read a transaction from [file_path] and diff --git a/x/auth/client/cli/decode.go b/x/auth/client/cli/decode.go index 2d49806b1244..0b6337bb7742 100644 --- a/x/auth/client/cli/decode.go +++ b/x/auth/client/cli/decode.go @@ -16,7 +16,7 @@ const flagHex = "hex" // it into a JSON-encoded transaction. func GetDecodeCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "decode [protobuf-byte-string]", + Use: "decode ", Short: "Decode a binary encoded transaction string", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { diff --git a/x/auth/client/cli/encode.go b/x/auth/client/cli/encode.go index dd677d4110ef..5046f61a7ea7 100644 --- a/x/auth/client/cli/encode.go +++ b/x/auth/client/cli/encode.go @@ -15,7 +15,7 @@ import ( // Amino-serialized bytes func GetEncodeCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "encode [file]", + Use: "encode ", Short: "Encode transactions generated offline", Long: `Encode transactions created with the --generate-only flag or signed with the sign command. Read a transaction from , serialize it to the Protobuf wire protocol, and output it as base64. diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 93210ea7c7db..273dd707f6b4 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -79,7 +79,7 @@ for. Each module documents its respective events under 'xx_events.md'. // QueryTxCmd implements the default command for a tx query. func QueryTxCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "tx --type=[hash|acc_seq|signature] [hash|acc_seq|signature]", + Use: "tx --type={hash|acc_seq|signature} ", Short: "Query for a transaction by hash, \"/\" combination or comma-separated signatures in a committed block", Long: strings.TrimSpace(fmt.Sprintf(` Example: diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index ced781fed845..d98cae0ca1e8 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -29,7 +29,7 @@ import ( // GetMultiSignCommand returns the multi-sign command func GetMultiSignCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "multi-sign [file] [name] [[signature]...]", + Use: "multi-sign [...]", Aliases: []string{"multisign"}, Short: "Generate multisig signatures for transactions generated offline", Long: strings.TrimSpace( @@ -211,7 +211,7 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) { func GetMultiSignBatchCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "multisign-batch [file] [name] [[signature-file]...]", + Use: "multisign-batch <[signature-file>...]", Aliases: []string{"multi-sign-batch"}, Short: "Assemble multisig transactions in batch from batch signatures", Long: strings.TrimSpace( diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index b4d062884ccb..a4057650d041 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -31,7 +31,7 @@ const ( // GetSignBatchCommand returns the transaction sign-batch command. func GetSignBatchCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "sign-batch [file] ([file2]...)", + Use: "sign-batch [...]", Short: "Sign transaction batch files", Long: `Sign batch files of transactions generated with --generate-only. The command processes list of transactions from a file (one StdTx each line), or multiple files. @@ -322,7 +322,7 @@ func setOutputFile(cmd *cobra.Command) (func(), error) { // GetSignCommand returns the transaction sign command. func GetSignCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "sign [file]", + Use: "sign ", Short: "Sign a transaction generated offline", Long: `Sign a transaction created with the --generate-only flag. It will read a transaction from [file], sign it, and print its JSON encoding. diff --git a/x/auth/client/cli/tx_simulate.go b/x/auth/client/cli/tx_simulate.go index daff57403fce..ef570ebc82af 100644 --- a/x/auth/client/cli/tx_simulate.go +++ b/x/auth/client/cli/tx_simulate.go @@ -16,7 +16,7 @@ import ( // successful. func GetSimulateCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "simulate /path/to/unsigned-tx.json --from keyname", + Use: "simulate --from ", Short: "Simulate the gas usage of a transaction", Long: strings.TrimSpace(`Simulate whether a transaction will be successful: diff --git a/x/auth/client/cli/validate_sigs.go b/x/auth/client/cli/validate_sigs.go index 0638f78c38a9..f5bc6cf4e786 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -20,7 +20,7 @@ import ( func GetValidateSignaturesCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "validate-signatures [file]", + Use: "validate-signatures ", Short: "validate transactions signatures", Long: `Print the addresses that must sign the transaction, those who have already signed it, and make sure that signatures are in the correct order. diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go index e90d9a5b28b5..f8cc4b26a165 100644 --- a/x/authz/client/cli/tx.go +++ b/x/authz/client/cli/tx.go @@ -58,8 +58,8 @@ func GetTxCmd() *cobra.Command { // but it will be removed in future versions. func NewCmdExecAuthorization() *cobra.Command { cmd := &cobra.Command{ - Use: "legacy-exec [tx-json-file] --from [grantee]", - Short: "Execute tx on behalf of granter account. Deprecated, use exec instead.", + Use: "legacy-exec --from ", + Short: "Execute tx on behalf of granter account. Deprecated, use exec instead.", Example: fmt.Sprintf("$ %s tx authz exec tx.json --from grantee\n $ %[1]s tx bank send [granter] [recipient] [amount] --generate-only tx.json && %[1]s tx authz exec tx.json --from grantee", version.AppName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -95,7 +95,7 @@ func NewCmdExecAuthorization() *cobra.Command { // Migrating this command to AutoCLI is possible but would be CLI breaking. func NewCmdGrantAuthorization() *cobra.Command { cmd := &cobra.Command{ - Use: "grant [grantee] --from [granter]", + Use: "grant --from ", Short: "Grant authorization to an address", Long: fmt.Sprintf(`create a new grant authorization to an address to execute a transaction on your behalf: Examples: diff --git a/x/authz/module/autocli.go b/x/authz/module/autocli.go index 9ead5006c1aa..7f68728963fb 100644 --- a/x/authz/module/autocli.go +++ b/x/authz/module/autocli.go @@ -30,7 +30,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "GranterGrants", - Use: "grants-by-granter [granter-addr]", + Use: "grants-by-granter ", Short: "Query authorization grants granted by granter", PositionalArgs: []*autocliv1.PositionalArgDescriptor{ {ProtoField: "granter"}, @@ -38,7 +38,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "GranteeGrants", - Use: "grants-by-grantee [grantee-addr]", + Use: "grants-by-grantee ", Short: "Query authorization grants granted to a grantee", PositionalArgs: []*autocliv1.PositionalArgDescriptor{ {ProtoField: "grantee"}, @@ -52,7 +52,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Exec", - Use: "exec [msg-json-file] --from [grantee]", + Use: "exec --from ", Short: "Execute tx on behalf of granter account", Example: fmt.Sprintf("$ %s tx authz exec msg.json --from grantee\n $ %[1]s tx bank send [granter] [recipient] [amount] --generate-only | jq .body.messages > msg.json && %[1]s tx authz exec msg.json --from grantee", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -61,7 +61,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Revoke", - Use: "revoke [grantee] [msg-type-url] --from [granter]", + Use: "revoke --from ", Short: `Revoke authorization from a granter to a grantee`, Example: fmt.Sprintf(`%s tx authz revoke cosmos1skj.. %s --from=cosmos1skj..`, version.AppName, bank.SendAuthorization{}.MsgTypeURL()), @@ -72,13 +72,13 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "RevokeAll", - Use: "revoke-all --from [signer]", + Use: "revoke-all --from ", Short: "Revoke all authorizations from the signer", Example: fmt.Sprintf("%s tx authz revoke-all --from=cosmos1skj..", version.AppName), }, { RpcMethod: "PruneExpiredGrants", - Use: "prune-grants --from [granter]", + Use: "prune-grants --from ", Short: "Prune expired grants", Long: "Prune up to 75 expired grants in order to reduce the size of the store when the number of expired grants is large.", Example: fmt.Sprintf(`$ %s tx authz prune-grants --from [mykey]`, version.AppName), diff --git a/x/bank/autocli.go b/x/bank/autocli.go index ead3aa80d811..cb3fc3cd9a48 100644 --- a/x/bank/autocli.go +++ b/x/bank/autocli.go @@ -18,26 +18,26 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Balance", - Use: "balance [address] [denom]", + Use: "balance
", Short: "Query an account balance by address and denom", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}, {ProtoField: "denom"}}, }, { RpcMethod: "AllBalances", - Use: "balances [address]", + Use: "balances
", Short: "Query for account balances by address", Long: "Query the total balance of an account or of a specific denomination.", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}}, }, { RpcMethod: "SpendableBalances", - Use: "spendable-balances [address]", + Use: "spendable-balances
", Short: "Query for account spendable balances by address", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}}, }, { RpcMethod: "SpendableBalanceByDenom", - Use: "spendable-balance [address] [denom]", + Use: "spendable-balance
", Short: "Query the spendable balance of a single denom for a single account.", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}, {ProtoField: "denom"}}, }, @@ -50,7 +50,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "SupplyOf", - Use: "total-supply-of [denom]", + Use: "total-supply-of ", Short: "Query the supply of a single coin denom", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "denom"}}, }, @@ -61,7 +61,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "DenomMetadata", - Use: "denom-metadata [denom]", + Use: "denom-metadata ", Short: "Query the client metadata of a given coin denomination", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "denom"}}, }, @@ -72,13 +72,13 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "DenomOwners", - Use: "denom-owners [denom]", + Use: "denom-owners ", Short: "Query for all account addresses that own a particular token denomination.", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "denom"}}, }, { RpcMethod: "SendEnabled", - Use: "send-enabled [denom1 ...]", + Use: "send-enabled ...", Short: "Query for send enabled entries", Long: strings.TrimSpace(`Query for send enabled entries that have been specifically set. @@ -95,7 +95,7 @@ To look up all denoms, do not provide any arguments.`, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Send", - Use: "send [from_key_or_address] [to_address] [amount ...]", + Use: "send ...", Short: "Send funds from one account to another.", Long: `Send funds from one account to another. Note, the '--from' flag is ignored as it is implied from [from_key_or_address]. @@ -105,13 +105,13 @@ Note: multiple coins can be send by space separated.`, }, { RpcMethod: "Burn", - Use: "burn [from_key_or_address] [amount]", + Use: "burn ", Short: "Burns the amount specified from the given account.", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "from_address"}, {ProtoField: "amount", Varargs: true}}, }, { RpcMethod: "UpdateParams", - Use: "update-params-proposal [params]", + Use: "update-params-proposal ", Short: "Submit a proposal to update bank module params. Note: the entire params must be provided.", Example: fmt.Sprintf(`%s tx bank update-params-proposal '{ "default_send_enabled": true }'`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, @@ -119,7 +119,7 @@ Note: multiple coins can be send by space separated.`, }, { RpcMethod: "SetSendEnabled", - Use: "set-send-enabled-proposal [send_enabled]", + Use: "set-send-enabled-proposal ", Short: "Submit a proposal to set/update/delete send enabled entries", Example: fmt.Sprintf(`%s tx bank set-send-enabled-proposal '{"denom":"stake","enabled":true}'`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "send_enabled", Varargs: true}}, diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 1e86b92f7564..3d537522ebcf 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -39,7 +39,7 @@ func NewTxCmd() *cobra.Command { // For a better UX this command is limited to send funds from one account to two or more accounts. func NewMultiSendTxCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "multi-send [from_key_or_address] [to_address_1 to_address_2 ...] [amount]", + Use: "multi-send ... ", Short: "Send funds from one account to two or more accounts.", Long: `Send funds from one account to two or more accounts. By default, sends the [amount] to each address of the list. diff --git a/x/circuit/autocli.go b/x/circuit/autocli.go index de72b3dc28b5..e9055caf5185 100644 --- a/x/circuit/autocli.go +++ b/x/circuit/autocli.go @@ -16,7 +16,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Account", - Use: "account [address]", + Use: "account
", Short: "Query a specific account's permissions", PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}}, }, @@ -37,7 +37,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "AuthorizeCircuitBreaker", - Use: "authorize [grantee] [permissions_json] --from [granter]", + Use: "authorize --from ", Short: "Authorize an account to trip the circuit breaker.", Long: `Authorize an account to trip the circuit breaker. "SOME_MSGS" = 1, @@ -51,7 +51,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "TripCircuitBreaker", - Use: "disable [msg_type_urls]", + Use: "disable ", Short: "Disable a message from being executed", Example: fmt.Sprintf(`%s circuit disable "cosmos.bank.v1beta1.MsgSend cosmos.bank.v1beta1.MsgMultiSend"`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -60,7 +60,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "ResetCircuitBreaker", - Use: "reset [msg_type_urls]", + Use: "reset ", Short: "Enable a message to be executed", Example: fmt.Sprintf(`%s circuit reset "cosmos.bank.v1beta1.MsgSend cosmos.bank.v1beta1.MsgMultiSend"`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ diff --git a/x/consensus/autocli.go b/x/consensus/autocli.go index 14784dced7f4..e9c89ca63f4c 100644 --- a/x/consensus/autocli.go +++ b/x/consensus/autocli.go @@ -31,7 +31,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "UpdateParams", - Use: "update-params-proposal [params]", + Use: "update-params-proposal ", Short: "Submit a proposal to update consensus module params. Note: the entire params must be provided.", Example: fmt.Sprintf(`%s tx consensus update-params-proposal '{ params }'`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ diff --git a/x/distribution/autocli.go b/x/distribution/autocli.go index c53abc4eda4e..d793f2626df5 100644 --- a/x/distribution/autocli.go +++ b/x/distribution/autocli.go @@ -22,7 +22,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "ValidatorDistributionInfo", - Use: "validator-distribution-info [validator]", + Use: "validator-distribution-info ", Short: "Query validator distribution info", Example: fmt.Sprintf(`Example: $ %s query distribution validator-distribution-info [validator-address]`, version.AppName), @@ -32,7 +32,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "ValidatorOutstandingRewards", - Use: "validator-outstanding-rewards [validator]", + Use: "validator-outstanding-rewards ", Short: "Query distribution outstanding (un-withdrawn) rewards for a validator and all their delegations", Example: fmt.Sprintf(`$ %s query distribution validator-outstanding-rewards [validator-address]`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -41,7 +41,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "ValidatorCommission", - Use: "commission [validator]", + Use: "commission ", Short: "Query distribution validator commission", Example: fmt.Sprintf(`$ %s query distribution commission [validator-address]`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -50,7 +50,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "ValidatorSlashes", - Use: "slashes [validator] [start-height] [end-height]", + Use: "slashes ", Short: "Query distribution validator slashes", Example: fmt.Sprintf(`$ %s query distribution slashes [validator-address] 0 100`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -61,7 +61,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "DelegationRewards", - Use: "rewards-by-validator [delegator-addr] [validator-addr]", + Use: "rewards-by-validator ", Short: "Query all distribution delegator from a particular validator", Example: fmt.Sprintf("$ %s query distribution rewards [delegator-address] [validator-address]", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -71,7 +71,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "DelegationTotalRewards", - Use: "rewards [delegator-addr]", + Use: "rewards ", Short: "Query all distribution delegator rewards", Long: "Query all rewards earned by a delegator", Example: fmt.Sprintf("$ %s query distribution rewards [delegator-address]", version.AppName), @@ -92,7 +92,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "SetWithdrawAddress", - Use: "set-withdraw-addr [withdraw-addr]", + Use: "set-withdraw-addr ", Short: "Change the default withdraw address for rewards associated with an address", Example: fmt.Sprintf("%s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p --from mykey", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -101,7 +101,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "WithdrawDelegatorReward", - Use: "withdraw-rewards [validator-addr]", + Use: "withdraw-rewards ", Short: "Withdraw rewards from a given delegation address", PositionalArgs: []*autocliv1.PositionalArgDescriptor{ {ProtoField: "validator_address"}, @@ -109,7 +109,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "WithdrawValidatorCommission", - Use: "withdraw-validator-commission [validator-addr]", + Use: "withdraw-validator-commission ", Short: "Withdraw commissions from a validator address (must be a validator operator)", PositionalArgs: []*autocliv1.PositionalArgDescriptor{ {ProtoField: "validator_address"}, @@ -117,7 +117,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "DepositValidatorRewardsPool", - Use: "fund-validator-rewards-pool [validator-addr] [amount]", + Use: "fund-validator-rewards-pool ", Short: "Fund the validator rewards pool with the specified amount", Example: fmt.Sprintf("%s tx distribution fund-validator-rewards-pool cosmosvaloper1x20lytyf6zkcrv5edpkfkn8sz578qg5sqfyqnp 100uatom --from mykey", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -128,7 +128,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { { RpcMethod: "FundCommunityPool", Deprecated: fmt.Sprintf("Use %s tx protocolpool fund-community-pool", version.AppName), - Use: "fund-community-pool [amount]", + Use: "fund-community-pool ", Short: "Funds the community pool with the specified amount", Example: fmt.Sprintf(`$ %s tx distribution fund-community-pool 100uatom --from mykey`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -137,7 +137,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "UpdateParams", - Use: "update-params-proposal [params]", + Use: "update-params-proposal ", Short: "Submit a proposal to update distribution module params. Note: the entire params must be provided.", Example: fmt.Sprintf(`%s tx distribution update-params-proposal '{ "community_tax": "20000", "base_proposer_reward": "0", "bonus_proposer_reward": "0", "withdraw_addr_enabled": true }'`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, diff --git a/x/evidence/autocli.go b/x/evidence/autocli.go index cd3fda9bce6e..4a239beb9d62 100644 --- a/x/evidence/autocli.go +++ b/x/evidence/autocli.go @@ -17,7 +17,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Evidence", - Use: "evidence [hash]", + Use: "evidence ", Short: "Query for evidence by hash", Example: fmt.Sprintf("%s query evidence DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "hash"}}, diff --git a/x/feegrant/client/cli/tx.go b/x/feegrant/client/cli/tx.go index 00c3339b15db..2ba342b21a5c 100644 --- a/x/feegrant/client/cli/tx.go +++ b/x/feegrant/client/cli/tx.go @@ -48,7 +48,7 @@ func GetTxCmd() *cobra.Command { // This command is more powerful than AutoCLI generated command as it allows a better input validation. func NewCmdFeeGrant() *cobra.Command { cmd := &cobra.Command{ - Use: "grant [granter_key_or_address] [grantee]", + Use: "grant ", Aliases: []string{"grant-allowance"}, Short: "Grant Fee allowance to an address", Long: strings.TrimSpace( diff --git a/x/feegrant/module/autocli.go b/x/feegrant/module/autocli.go index f3bbd0597728..e8fe235fce20 100644 --- a/x/feegrant/module/autocli.go +++ b/x/feegrant/module/autocli.go @@ -16,7 +16,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Allowance", - Use: "grant [granter] [grantee]", + Use: "grant ", Short: "Query details of a single grant", Long: "Query details for a grant. You can find the fee-grant of a granter and grantee.", Example: fmt.Sprintf(`$ %s query feegrant grant [granter] [grantee]`, version.AppName), @@ -27,7 +27,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Allowances", - Use: "grants-by-grantee [grantee]", + Use: "grants-by-grantee ", Short: "Query all grants of a grantee", Long: "Queries all the grants for a grantee address.", Example: fmt.Sprintf(`$ %s query feegrant grants-by-grantee [grantee]`, version.AppName), @@ -37,7 +37,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "AllowancesByGranter", - Use: "grants-by-granter [granter]", + Use: "grants-by-granter ", Short: "Query all grants by a granter", Example: fmt.Sprintf(`$ %s query feegrant grants-by-granter [granter]`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -51,7 +51,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "RevokeAllowance", - Use: "revoke [granter] [grantee]", + Use: "revoke ", Short: "Revoke a fee grant", Long: "Revoke fee grant from a granter to a grantee. Note, the '--from' flag is ignored as it is implied from [granter]", Example: fmt.Sprintf(`$ %s tx feegrant revoke [granter] [grantee]`, version.AppName), diff --git a/x/genutil/client/cli/genaccount.go b/x/genutil/client/cli/genaccount.go index bafd4f2f9426..34acef113e2e 100644 --- a/x/genutil/client/cli/genaccount.go +++ b/x/genutil/client/cli/genaccount.go @@ -25,7 +25,7 @@ const ( // This command is provided as a default, applications are expected to provide their own command if custom genesis accounts are needed. func AddGenesisAccountCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]", + Use: "add-genesis-account [,...]", Short: "Add a genesis account to genesis.json", Long: `Add a genesis account to genesis.json. The provided account must specify the account address or key name and a list of initial coins. If a key name is given, diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 8e1302863320..dfeda2df59d7 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -32,7 +32,7 @@ func GenTxCmd(genMM genesisMM, genBalIterator types.GenesisBalancesIterator) *co fsCreateValidator, defaultsDesc := cli.CreateValidatorMsgFlagSet(ipDefault) cmd := &cobra.Command{ - Use: "gentx [key_name] [amount]", + Use: "gentx ", Short: "Generate a genesis tx carrying a self delegation", Args: cobra.ExactArgs(2), Long: fmt.Sprintf(`Generate a genesis transaction that creates a validator with a self-delegation, diff --git a/x/genutil/client/cli/init.go b/x/genutil/client/cli/init.go index 557050b10aee..8217e8744350 100644 --- a/x/genutil/client/cli/init.go +++ b/x/genutil/client/cli/init.go @@ -73,7 +73,7 @@ func displayInfo(dst io.Writer, info printInfo) error { // and the respective application. func InitCmd(mm genesisMM) *cobra.Command { cmd := &cobra.Command{ - Use: "init [moniker]", + Use: "init ", Short: "Initialize private validator, p2p, genesis, and application configuration files", Long: `Initialize validators's and node's configuration files.`, Args: cobra.ExactArgs(1), diff --git a/x/genutil/client/cli/migrate.go b/x/genutil/client/cli/migrate.go index 08eb01ced8c9..2763ba06cfb4 100644 --- a/x/genutil/client/cli/migrate.go +++ b/x/genutil/client/cli/migrate.go @@ -26,7 +26,7 @@ var MigrationMap = types.MigrationMap{} // When the application migration includes a SDK migration, the Cosmos SDK migration function should as well be called. func MigrateGenesisCmd(migrations types.MigrationMap) *cobra.Command { cmd := &cobra.Command{ - Use: "migrate [target-version] [genesis-file]", + Use: "migrate ", Short: "Migrate genesis to a specified target version", Long: "Migrate the source genesis into the target version and print to STDOUT", Example: fmt.Sprintf("%s migrate v0.47 /path/to/genesis.json --chain-id=cosmoshub-3 --genesis-time=2019-04-22T17:00:00Z", version.AppName), diff --git a/x/gov/autocli.go b/x/gov/autocli.go index 26508fb79821..b0f97e48c0f4 100644 --- a/x/gov/autocli.go +++ b/x/gov/autocli.go @@ -22,7 +22,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "MessageBasedParams", - Use: "params-by-msg-url [msg-url]", + Use: "params-by-msg-url ", Short: "Query the governance parameters of specific message", PositionalArgs: []*autocliv1.PositionalArgDescriptor{ {ProtoField: "msg_url"}, @@ -36,7 +36,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Proposal", - Use: "proposal [proposal-id]", + Use: "proposal ", Alias: []string{"proposer"}, Short: "Query details of a single proposal", Example: fmt.Sprintf("%s query gov proposal 1", version.AppName), @@ -46,7 +46,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Vote", - Use: "vote [proposal-id] [voter-addr]", + Use: "vote ", Short: "Query details of a single vote", Example: fmt.Sprintf("%s query gov vote 1 cosmos1...", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -56,7 +56,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Votes", - Use: "votes [proposal-id]", + Use: "votes ", Short: "Query votes of a single proposal", Example: fmt.Sprintf("%s query gov votes 1", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -65,7 +65,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Deposit", - Use: "deposit [proposal-id] [depositor-addr]", + Use: "deposit ", Short: "Query details of a deposit", PositionalArgs: []*autocliv1.PositionalArgDescriptor{ {ProtoField: "proposal_id"}, @@ -74,7 +74,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Deposits", - Use: "deposits [proposal-id]", + Use: "deposits ", Short: "Query deposits on a proposal", PositionalArgs: []*autocliv1.PositionalArgDescriptor{ {ProtoField: "proposal_id"}, @@ -82,7 +82,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "TallyResult", - Use: "tally [proposal-id]", + Use: "tally ", Short: "Query the tally of a proposal vote", Example: fmt.Sprintf("%s query gov tally 1", version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -102,7 +102,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { RpcMethod: "Deposit", - Use: "deposit [proposal-id] [deposit]", + Use: "deposit ", Short: "Deposit tokens for an active proposal", Long: fmt.Sprintf(`Submit a deposit for an active proposal. You can find the proposal-id by running "%s query gov proposals"`, version.AppName), Example: fmt.Sprintf(`$ %s tx gov deposit 1 10stake --from mykey`, version.AppName), @@ -113,7 +113,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "CancelProposal", - Use: "cancel-proposal [proposal-id]", + Use: "cancel-proposal ", Short: "Cancel governance proposal before the voting period ends. Must be signed by the proposal creator.", Example: fmt.Sprintf(`$ %s tx gov cancel-proposal 1 --from mykey`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ @@ -122,7 +122,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, { RpcMethod: "Vote", - Use: "vote [proposal-id] [option]", + Use: "vote