diff --git a/orm/CHANGELOG.md b/orm/CHANGELOG.md new file mode 100644 index 0000000000..578771668f --- /dev/null +++ b/orm/CHANGELOG.md @@ -0,0 +1,41 @@ + + +# Changelog + +## [Unreleased] + +### API-Breaking Changes + +- [14822](https://github.com/cosmos/cosmos-sdk/pull/14822) Migrate to cosmossdk.io/core genesis API \ No newline at end of file diff --git a/orm/model/ormdb/json.go b/orm/model/ormdb/genesis.go similarity index 76% rename from orm/model/ormdb/json.go rename to orm/model/ormdb/genesis.go index 95151a5e78..1f983704e1 100644 --- a/orm/model/ormdb/json.go +++ b/orm/model/ormdb/genesis.go @@ -5,15 +5,24 @@ import ( "fmt" "sort" + "cosmossdk.io/core/appmodule" "golang.org/x/exp/maps" "google.golang.org/protobuf/reflect/protoreflect" "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/orm/types/ormerrors" - "github.com/cosmos/cosmos-sdk/orm/types/ormjson" ) -func (m moduleDB) DefaultJSON(target ormjson.WriteTarget) error { +type appModuleGenesisWrapper struct { + moduleDB +} + +func (m appModuleGenesisWrapper) IsOnePerModuleType() {} + +func (m appModuleGenesisWrapper) IsAppModule() {} + +func (m appModuleGenesisWrapper) DefaultGenesis(target appmodule.GenesisTarget) error { tableNames := maps.Keys(m.tablesByName) sort.Slice(tableNames, func(i, j int) bool { ti, tj := tableNames[i], tableNames[j] @@ -22,7 +31,7 @@ func (m moduleDB) DefaultJSON(target ormjson.WriteTarget) error { for _, name := range tableNames { table := m.tablesByName[name] - w, err := target.OpenWriter(name) + w, err := target(string(name)) if err != nil { return err } @@ -40,7 +49,7 @@ func (m moduleDB) DefaultJSON(target ormjson.WriteTarget) error { return nil } -func (m moduleDB) ValidateJSON(source ormjson.ReadSource) error { +func (m appModuleGenesisWrapper) ValidateGenesis(source appmodule.GenesisSource) error { errMap := map[protoreflect.FullName]error{} names := maps.Keys(m.tablesByName) sort.Slice(names, func(i, j int) bool { @@ -48,7 +57,7 @@ func (m moduleDB) ValidateJSON(source ormjson.ReadSource) error { return ti.Name() < tj.Name() }) for _, name := range names { - r, err := source.OpenReader(name) + r, err := source(string(name)) if err != nil { return err } @@ -80,7 +89,7 @@ func (m moduleDB) ValidateJSON(source ormjson.ReadSource) error { return nil } -func (m moduleDB) ImportJSON(ctx context.Context, source ormjson.ReadSource) error { +func (m appModuleGenesisWrapper) InitGenesis(ctx context.Context, source appmodule.GenesisSource) error { var names []string for name := range m.tablesByName { names = append(names, string(name)) @@ -91,7 +100,7 @@ func (m moduleDB) ImportJSON(ctx context.Context, source ormjson.ReadSource) err fullName := protoreflect.FullName(name) table := m.tablesByName[fullName] - r, err := source.OpenReader(fullName) + r, err := source(string(fullName)) if err != nil { return errors.Wrapf(err, "table %s", fullName) } @@ -114,7 +123,7 @@ func (m moduleDB) ImportJSON(ctx context.Context, source ormjson.ReadSource) err return nil } -func (m moduleDB) ExportJSON(ctx context.Context, sink ormjson.WriteTarget) error { +func (m appModuleGenesisWrapper) ExportGenesis(ctx context.Context, sink appmodule.GenesisTarget) error { // Ensure that we export the tables in a deterministic order. tableNames := maps.Keys(m.tablesByName) sort.Slice(tableNames, func(i, j int) bool { @@ -123,7 +132,7 @@ func (m moduleDB) ExportJSON(ctx context.Context, sink ormjson.WriteTarget) erro }) for _, name := range tableNames { - w, err := sink.OpenWriter(name) + w, err := sink(string(name)) if err != nil { return err } diff --git a/orm/model/ormdb/module.go b/orm/model/ormdb/module.go index 0c2f71e114..598fdbb31d 100644 --- a/orm/model/ormdb/module.go +++ b/orm/model/ormdb/module.go @@ -7,13 +7,12 @@ import ( "fmt" "math" + "cosmossdk.io/core/appmodule" "cosmossdk.io/core/store" "google.golang.org/protobuf/reflect/protoregistry" ormv1alpha1 "cosmossdk.io/api/cosmos/orm/v1alpha1" - "github.com/cosmos/cosmos-sdk/orm/types/ormjson" - "google.golang.org/protobuf/reflect/protodesc" "github.com/cosmos/cosmos-sdk/orm/encoding/encodeutil" @@ -31,18 +30,19 @@ import ( type ModuleDB interface { ormtable.Schema - // DefaultJSON writes default JSON for each table in the module to the target. - DefaultJSON(ormjson.WriteTarget) error + // GenesisHandler returns an implementation of appmodule.HasGenesis + // to be embedded in or called from app module implementations. + // Ex: + // type Keeper struct { + // appmodule.HasGenesis + // } + // + // func NewKeeper(db ModuleDB) *Keeper { + // return &Keeper{HasGenesis: db.GenesisHandler()} + // } + GenesisHandler() appmodule.HasGenesis - // ValidateJSON validates JSON for each table in the module. - ValidateJSON(ormjson.ReadSource) error - - // ImportJSON imports JSON for each table in the module which has JSON - // defined in the read source. - ImportJSON(context.Context, ormjson.ReadSource) error - - // ExportJSON exports JSON for each table in the module. - ExportJSON(context.Context, ormjson.WriteTarget) error + private() } type moduleDB struct { @@ -212,3 +212,8 @@ func (m moduleDB) EncodeEntry(entry ormkv.Entry) (k, v []byte, err error) { func (m moduleDB) GetTable(message proto.Message) ormtable.Table { return m.tablesByName[message.ProtoReflect().Descriptor().FullName()] } +func (m moduleDB) GenesisHandler() appmodule.HasGenesis { + return appModuleGenesisWrapper{m} +} + +func (moduleDB) private() {} diff --git a/orm/model/ormdb/module_test.go b/orm/model/ormdb/module_test.go index 9a27bf29ee..204cfb30fe 100644 --- a/orm/model/ormdb/module_test.go +++ b/orm/model/ormdb/module_test.go @@ -13,6 +13,7 @@ import ( ormv1alpha1 "cosmossdk.io/api/cosmos/orm/v1alpha1" "cosmossdk.io/core/appconfig" "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/genesis" "cosmossdk.io/core/store" dbm "github.com/cosmos/cosmos-db" @@ -32,7 +33,6 @@ import ( "github.com/cosmos/cosmos-sdk/orm/model/ormtable" "github.com/cosmos/cosmos-sdk/orm/testing/ormtest" "github.com/cosmos/cosmos-sdk/orm/types/ormerrors" - "github.com/cosmos/cosmos-sdk/orm/types/ormjson" ) // These tests use a simulated bank keeper. Addresses and balances use @@ -225,40 +225,40 @@ func TestModuleDB(t *testing.T) { } // check JSON - target := ormjson.NewRawMessageTarget() - assert.NilError(t, db.DefaultJSON(target)) + target := genesis.RawJSONTarget{} + assert.NilError(t, db.GenesisHandler().DefaultGenesis(target.Target())) rawJson, err := target.JSON() assert.NilError(t, err) golden.Assert(t, string(rawJson), "default_json.golden") - target = ormjson.NewRawMessageTarget() - assert.NilError(t, db.ExportJSON(ctx, target)) + target = genesis.RawJSONTarget{} + assert.NilError(t, db.GenesisHandler().ExportGenesis(ctx, target.Target())) rawJson, err = target.JSON() assert.NilError(t, err) goodJSON := `{ "testpb.Supply": [] }` - source, err := ormjson.NewRawMessageSource(json.RawMessage(goodJSON)) + source, err := genesis.SourceFromRawJSON(json.RawMessage(goodJSON)) assert.NilError(t, err) - assert.NilError(t, db.ValidateJSON(source)) - assert.NilError(t, db.ImportJSON(ormtable.WrapContextDefault(ormtest.NewMemoryBackend()), source)) + assert.NilError(t, db.GenesisHandler().ValidateGenesis(source)) + assert.NilError(t, db.GenesisHandler().InitGenesis(ormtable.WrapContextDefault(ormtest.NewMemoryBackend()), source)) badJSON := `{ "testpb.Balance": 5, "testpb.Supply": {} } ` - source, err = ormjson.NewRawMessageSource(json.RawMessage(badJSON)) + source, err = genesis.SourceFromRawJSON(json.RawMessage(badJSON)) assert.NilError(t, err) - assert.ErrorIs(t, db.ValidateJSON(source), ormerrors.JSONValidationError) + assert.ErrorIs(t, db.GenesisHandler().ValidateGenesis(source), ormerrors.JSONValidationError) backend2 := ormtest.NewMemoryBackend() ctx2 := ormtable.WrapContextDefault(backend2) - source, err = ormjson.NewRawMessageSource(rawJson) + source, err = genesis.SourceFromRawJSON(rawJson) assert.NilError(t, err) - assert.NilError(t, db.ValidateJSON(source)) - assert.NilError(t, db.ImportJSON(ctx2, source)) + assert.NilError(t, db.GenesisHandler().ValidateGenesis(source)) + assert.NilError(t, db.GenesisHandler().InitGenesis(ctx2, source)) testkv.AssertBackendsEqual(t, backend, backend2) } diff --git a/orm/types/ormjson/json.go b/orm/types/ormjson/json.go deleted file mode 100644 index 712505ae56..0000000000 --- a/orm/types/ormjson/json.go +++ /dev/null @@ -1,27 +0,0 @@ -package ormjson - -import ( - "io" - - "google.golang.org/protobuf/reflect/protoreflect" -) - -// ReadSource is a source for reading tables in JSON format. It -// may abstract over a single JSON object or JSON in separate files that -// can be streamed over. -type ReadSource interface { - // OpenReader returns an io.ReadCloser for the named table. If there - // is no JSON for this table, this method will return nil. It is - // important the caller closes the reader when done with it. - OpenReader(tableName protoreflect.FullName) (io.ReadCloser, error) -} - -// WriteTarget is a target for writing tables in JSON format. It -// may abstract over a single JSON object or JSON in separate files that -// can be written incrementally. -type WriteTarget interface { - // OpenWriter returns an io.WriteCloser for the named table. It is - // important the caller closers the writer AND checks the error - // when done with it. - OpenWriter(tableName protoreflect.FullName) (io.WriteCloser, error) -} diff --git a/orm/types/ormjson/raw.go b/orm/types/ormjson/raw.go deleted file mode 100644 index 976d0aec8e..0000000000 --- a/orm/types/ormjson/raw.go +++ /dev/null @@ -1,79 +0,0 @@ -package ormjson - -import ( - "bytes" - "encoding/json" - "io" - - "google.golang.org/protobuf/reflect/protoreflect" -) - -type rawMessageSource struct { - m map[string]json.RawMessage -} - -// NewRawMessageSource returns a new ReadSource for the provided -// json.RawMessage where it is assumed that the raw message is a JSON -// map where each table's JSON referenced by the map key corresponding -// to the tables full protobuf name. -func NewRawMessageSource(message json.RawMessage) (ReadSource, error) { - var m map[string]json.RawMessage - err := json.Unmarshal(message, &m) - if err != nil { - return nil, err - } - return &rawMessageSource{m}, err -} - -func (r rawMessageSource) OpenReader(tableName protoreflect.FullName) (io.ReadCloser, error) { - j, ok := r.m[string(tableName)] - if !ok { - return nil, nil - } - return readCloserWrapper{bytes.NewReader(j)}, nil -} - -type readCloserWrapper struct { - io.Reader -} - -func (r readCloserWrapper) Close() error { return nil } - -var _ ReadSource = rawMessageSource{} - -// RawMessageTarget is a WriteTarget wrapping a raw JSON map. -type RawMessageTarget struct { - m map[string]json.RawMessage -} - -// NewRawMessageTarget returns a new WriteTarget where each table's JSON -// is written to a map key corresponding to the table's full protobuf name. -func NewRawMessageTarget() *RawMessageTarget { - return &RawMessageTarget{} -} - -func (r *RawMessageTarget) OpenWriter(tableName protoreflect.FullName) (io.WriteCloser, error) { - if r.m == nil { - r.m = map[string]json.RawMessage{} - } - - return &rawWriter{Buffer: &bytes.Buffer{}, sink: r, table: tableName}, nil -} - -// JSON returns the JSON map that was written as a json.RawMessage. -func (r *RawMessageTarget) JSON() (json.RawMessage, error) { - return json.MarshalIndent(r.m, "", " ") -} - -type rawWriter struct { - *bytes.Buffer - table protoreflect.FullName - sink *RawMessageTarget -} - -func (r rawWriter) Close() error { - r.sink.m[string(r.table)] = r.Buffer.Bytes() - return nil -} - -var _ WriteTarget = &RawMessageTarget{}