diff --git a/x/ecocredit/client/testsuite/tx.go b/x/ecocredit/client/testsuite/tx.go index f557125add..9adcef942b 100644 --- a/x/ecocredit/client/testsuite/tx.go +++ b/x/ecocredit/client/testsuite/tx.go @@ -49,10 +49,10 @@ const ( var validMetadataBytes = []byte{0x1} func RunCLITests(t *testing.T, cfg network.Config) { - // TODO: enable integrations test after ORM migration + // TODO: uncomment after CLI v1 integration https://github.com/regen-network/regen-ledger/issues/876 // suite.Run(t, NewIntegrationTestSuite(cfg)) - // // setup another cfg for testing ecocredit enabled class creators list. + // setup another cfg for testing ecocredit enabled class creators list. // genesisState := ecocredit.DefaultGenesisState() // genesisState.Params.AllowlistEnabled = true // bz, err := cfg.Codec.MarshalJSON(genesisState) diff --git a/x/ecocredit/core/genesis.go b/x/ecocredit/core/genesis.go new file mode 100644 index 0000000000..813bb35750 --- /dev/null +++ b/x/ecocredit/core/genesis.go @@ -0,0 +1,440 @@ +package core + +import ( + "context" + "encoding/json" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/orm/model/ormdb" + "github.com/cosmos/cosmos-sdk/orm/model/ormtable" + "github.com/cosmos/cosmos-sdk/orm/types/ormjson" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + gogoproto "github.com/gogo/protobuf/proto" + dbm "github.com/tendermint/tm-db" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + + api "github.com/regen-network/regen-ledger/api/regen/ecocredit/v1" + "github.com/regen-network/regen-ledger/types/math" + "github.com/regen-network/regen-ledger/types/ormutil" + "github.com/regen-network/regen-ledger/x/ecocredit" +) + +// ValidateGenesis performs basic validation for the following: +// - params are valid param types with valid properties +// - proto messages are valid proto messages +// - the credit type referenced in each credit class exists +// - the credit class referenced in each project exists +// - the tradable amount of each credit batch complies with the credit type precision +// - the retired amount of each credit batch complies with the credit type precision +// - the calculated total amount of each credit batch matches the total supply +// An error is returned if any of these validation checks fail. +func ValidateGenesis(data json.RawMessage, params Params) error { + if err := params.Validate(); err != nil { + return err + } + + db := dbm.NewMemDB() + backend := ormtable.NewBackend(ormtable.BackendOptions{ + CommitmentStore: db, + IndexStore: db, + }) + + ormdb, err := ormdb.NewModuleDB(&ecocredit.ModuleSchema, ormdb.ModuleDBOptions{ + JSONValidator: func(m proto.Message) error { + return validateMsg(m) + }, + }) + if err != nil { + return err + } + + ormCtx := ormtable.WrapContextDefault(backend) + ss, err := api.NewStateStore(ormdb) + if err != nil { + return err + } + + jsonSource, err := ormjson.NewRawMessageSource(data) + if err != nil { + return err + } + + err = ormdb.ImportJSON(ormCtx, jsonSource) + if err != nil { + return err + } + + if err := ormdb.ValidateJSON(jsonSource); err != nil { + return err + } + + abbrevToPrecision := make(map[string]uint32) // map of credit abbreviation to precision + for _, ct := range params.CreditTypes { + abbrevToPrecision[ct.Abbreviation] = ct.Precision + } + + cItr, err := ss.ClassInfoTable().List(ormCtx, api.ClassInfoPrimaryKey{}) + if err != nil { + return err + } + defer cItr.Close() + + // make sure credit type exist for class abbreviation in params + for cItr.Next() { + class, err := cItr.Value() + if err != nil { + return err + } + + if _, ok := abbrevToPrecision[class.CreditType]; !ok { + return sdkerrors.ErrNotFound.Wrapf("credit type not exist for %s abbreviation", class.CreditType) + } + } + + projectIdToClassId := make(map[uint64]uint64) // map of projectID to classID + pItr, err := ss.ProjectInfoTable().List(ormCtx, api.ProjectInfoPrimaryKey{}) + if err != nil { + return err + } + defer pItr.Close() + + for pItr.Next() { + project, err := pItr.Value() + if err != nil { + return err + } + + if _, exists := projectIdToClassId[project.Id]; exists { + continue + } + projectIdToClassId[project.Id] = project.ClassId + } + + batchIdToPrecision := make(map[uint64]uint32) // map of batchID to precision + bItr, err := ss.BatchInfoTable().List(ormCtx, api.BatchInfoPrimaryKey{}) + if err != nil { + return err + } + defer bItr.Close() + + // create index batchID => precision for faster lookup + for bItr.Next() { + batch, err := bItr.Value() + if err != nil { + return err + } + + if _, exists := batchIdToPrecision[batch.Id]; exists { + continue + } + + class, err := ss.ClassInfoTable().Get(ormCtx, projectIdToClassId[batch.ProjectId]) + if err != nil { + return err + } + + if class.Id == projectIdToClassId[batch.ProjectId] { + batchIdToPrecision[batch.Id] = abbrevToPrecision[class.CreditType] + } + } + + batchIdToCalSupply := make(map[uint64]math.Dec) // map of batchID to calculated supply + batchIdToSupply := make(map[uint64]math.Dec) // map of batchID to actual supply + bsItr, err := ss.BatchSupplyTable().List(ormCtx, api.BatchSupplyPrimaryKey{}) + if err != nil { + return err + } + defer bsItr.Close() + + // calculate total supply for each credit batch (tradable + retired supply) + for bsItr.Next() { + batchSupply, err := bsItr.Value() + if err != nil { + return err + } + + tSupply := math.NewDecFromInt64(0) + rSupply := math.NewDecFromInt64(0) + if batchSupply.TradableAmount != "" { + tSupply, err = math.NewNonNegativeFixedDecFromString(batchSupply.TradableAmount, batchIdToPrecision[batchSupply.BatchId]) + if err != nil { + return err + } + } + if batchSupply.RetiredAmount != "" { + rSupply, err = math.NewNonNegativeFixedDecFromString(batchSupply.RetiredAmount, batchIdToPrecision[batchSupply.BatchId]) + if err != nil { + return err + } + } + + total, err := math.SafeAddBalance(tSupply, rSupply) + if err != nil { + return err + } + + batchIdToSupply[batchSupply.BatchId] = total + } + + // calculate credit batch supply from genesis tradable, retired and escrowed balances + if err := calculateSupply(ormCtx, batchIdToPrecision, ss, batchIdToCalSupply); err != nil { + return err + } + + // verify calculated total amount of each credit batch matches the total supply + if err := validateSupply(batchIdToCalSupply, batchIdToSupply); err != nil { + return err + } + + return nil +} + +func validateMsg(m proto.Message) error { + switch m.(type) { + case *api.ClassInfo: + msg := &ClassInfo{} + if err := ormutil.PulsarToGogoSlow(m, msg); err != nil { + return err + } + + return msg.Validate() + case *api.ClassIssuer: + msg := &ClassIssuer{} + if err := ormutil.PulsarToGogoSlow(m, msg); err != nil { + return err + } + + return msg.Validate() + case *api.ProjectInfo: + msg := &ProjectInfo{} + if err := ormutil.PulsarToGogoSlow(m, msg); err != nil { + return err + } + + return msg.Validate() + case *api.BatchInfo: + msg := &BatchInfo{} + if err := ormutil.PulsarToGogoSlow(m, msg); err != nil { + return err + } + return msg.Validate() + case *api.CreditType: + msg := &CreditType{} + if err := ormutil.PulsarToGogoSlow(m, msg); err != nil { + return err + } + return msg.Validate() + } + + return nil +} + +func calculateSupply(ctx context.Context, batchIdToPrecision map[uint64]uint32, ss api.StateStore, batchIdToSupply map[uint64]math.Dec) error { + bbItr, err := ss.BatchBalanceTable().List(ctx, api.BatchBalancePrimaryKey{}) + if err != nil { + return err + } + defer bbItr.Close() + + for bbItr.Next() { + tradable := math.NewDecFromInt64(0) + retired := math.NewDecFromInt64(0) + escrowed := math.NewDecFromInt64(0) + + balance, err := bbItr.Value() + if err != nil { + return err + } + + if _, ok := batchIdToPrecision[balance.BatchId]; !ok { + return sdkerrors.ErrInvalidType.Wrapf("credit type not exist for %d batch", balance.BatchId) + } + + if balance.Tradable != "" { + tradable, err = math.NewNonNegativeFixedDecFromString(balance.Tradable, batchIdToPrecision[balance.BatchId]) + if err != nil { + return err + } + } + + if balance.Retired != "" { + retired, err = math.NewNonNegativeFixedDecFromString(balance.Retired, batchIdToPrecision[balance.BatchId]) + if err != nil { + return err + } + } + + if balance.Escrowed != "" { + escrowed, err = math.NewNonNegativeFixedDecFromString(balance.Retired, batchIdToPrecision[balance.BatchId]) + if err != nil { + return err + } + } + + total, err := math.Add(tradable, retired) + if err != nil { + return err + } + + total, err = math.Add(total, escrowed) + if err != nil { + return err + } + + if supply, ok := batchIdToSupply[balance.BatchId]; ok { + result, err := math.SafeAddBalance(supply, total) + if err != nil { + return err + } + batchIdToSupply[balance.BatchId] = result + } else { + batchIdToSupply[balance.BatchId] = total + } + } + + return nil +} + +func validateSupply(batchIdToSupplyCal, batchIdToSupply map[uint64]math.Dec) error { + for denom, cs := range batchIdToSupplyCal { + if s, ok := batchIdToSupply[denom]; ok { + if s.Cmp(cs) != math.EqualTo { + return sdkerrors.ErrInvalidCoins.Wrapf("supply is incorrect for %d credit batch, expected %v, got %v", denom, s, cs) + } + } else { + return sdkerrors.ErrNotFound.Wrapf("supply is not found for %d credit batch", denom) + } + } + + return nil +} + +// MergeParamsIntoTarget merges params message into the ormjson.WriteTarget. +func MergeParamsIntoTarget(cdc codec.JSONCodec, message gogoproto.Message, target ormjson.WriteTarget) error { + w, err := target.OpenWriter(protoreflect.FullName(gogoproto.MessageName(message))) + if err != nil { + return err + } + + bz, err := cdc.MarshalJSON(message) + if err != nil { + return err + } + + _, err = w.Write(bz) + if err != nil { + return err + } + + return w.Close() +} + +// Validate performs a basic validation of credit class +func (c ClassInfo) Validate() error { + if len(c.Metadata) > ecocredit.MaxMetadataLength { + return ecocredit.ErrMaxLimit.Wrap("credit class metadata") + } + + if _, err := sdk.AccAddressFromBech32(sdk.AccAddress(c.Admin).String()); err != nil { + return sdkerrors.Wrap(err, "admin") + } + + if len(c.Name) == 0 { + return sdkerrors.ErrInvalidRequest.Wrap("class name cannot be empty") + } + + if err := ecocredit.ValidateClassID(c.Name); err != nil { + return err + } + + if len(c.CreditType) == 0 { + return sdkerrors.ErrInvalidRequest.Wrap("must specify a credit type abbreviation") + } + + return nil +} + +// Validate performs a basic validation of credit class issuers +func (c ClassIssuer) Validate() error { + if c.ClassId == 0 { + return sdkerrors.ErrInvalidRequest.Wrap("class id cannot be zero") + } + + if _, err := sdk.AccAddressFromBech32(sdk.AccAddress(c.Issuer).String()); err != nil { + return sdkerrors.Wrap(err, "issuer") + } + + return nil +} + +// Validate performs a basic validation of project +func (p ProjectInfo) Validate() error { + if _, err := sdk.AccAddressFromBech32(sdk.AccAddress(p.Admin).String()); err != nil { + return sdkerrors.Wrap(err, "admin") + } + + if p.ClassId == 0 { + return sdkerrors.ErrInvalidRequest.Wrap("class id cannot be zero") + } + + if err := ValidateLocation(p.ProjectLocation); err != nil { + return err + } + + if len(p.Metadata) > ecocredit.MaxMetadataLength { + return ecocredit.ErrMaxLimit.Wrap("project metadata") + } + + if err := ValidateProjectID(p.Name); err != nil { + return err + } + + return nil +} + +// Validate performs a basic validation of credit batch +func (b BatchInfo) Validate() error { + if err := ValidateDenom(b.BatchDenom); err != nil { + return err + } + + if b.ProjectId == 0 { + return sdkerrors.ErrInvalidRequest.Wrap("project id cannot be zero") + } + + if b.StartDate == nil { + return sdkerrors.ErrInvalidRequest.Wrap("must provide a start date for the credit batch") + } + if b.EndDate == nil { + return sdkerrors.ErrInvalidRequest.Wrap("must provide an end date for the credit batch") + } + if b.EndDate.Compare(*b.StartDate) != 1 { + return sdkerrors.ErrInvalidRequest.Wrapf("the batch end date (%s) must be the same as or after the batch start date (%s)", b.EndDate.String(), b.StartDate.String()) + } + + if _, err := sdk.AccAddressFromBech32(sdk.AccAddress(b.Issuer).String()); err != nil { + return sdkerrors.Wrap(err, "issuer") + } + + return nil +} + +// Validate performs a basic validation of credit type +func (c CreditType) Validate() error { + if err := ValidateCreditTypeAbbreviation(c.Abbreviation); err != nil { + return err + } + if len(c.Name) == 0 { + return sdkerrors.ErrInvalidRequest.Wrap("name cannot be empty") + } + if len(c.Unit) == 0 { + return sdkerrors.ErrInvalidRequest.Wrap("unit cannot be empty") + } + if c.Precision != PRECISION { + return sdkerrors.ErrInvalidRequest.Wrapf("credit type precision is currently locked to %d", PRECISION) + } + + return nil +} diff --git a/x/ecocredit/core/genesis_test.go b/x/ecocredit/core/genesis_test.go new file mode 100644 index 0000000000..fe17353c89 --- /dev/null +++ b/x/ecocredit/core/genesis_test.go @@ -0,0 +1,508 @@ +package core_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/regen-network/regen-ledger/x/ecocredit/core" +) + +func TestValidateGenesis(t *testing.T) { + x := `{ + "regen.ecocredit.v1.BatchBalance":[ + { + "address":"gydQIvR2RUi0N1RJnmgOLVSkcd4=", + "batch_id":"1", + "tradable":"90.003", + "retired":"9.997" + } + ], + "regen.ecocredit.v1.BatchInfo":[ + { + "issuer":"WCBEyNFP/N5RoS4h43AqkjC6zA8=", + "project_id":"1", + "batch_denom":"BIO01-00000000-00000000-001", + "start_date":"2021-04-08T10:40:10.774108556Z", + "end_date":"2022-04-08T10:40:10.774108556Z" + }, + { + "issuer":"gydQIvR2RUi0N1RJnmgOLVSkcd4=", + "project_id":"1", + "batch_denom":"BIO02-00000000-00000000-001", + "start_date":"2021-04-08T10:40:10.774108556Z", + "end_date":"2022-04-08T10:40:10.774108556Z" + } + ], + "regen.ecocredit.v1.BatchSupply":[ + { + "batch_id":"1", + "tradable_amount":"90.003", + "retired_amount":"9.997" + } + ], + "regen.ecocredit.v1.ClassInfo":[ + { + "name":"BIO001", + "admin":"4A/V6LMEL2lZv9PZnkWSIDQzZM4=", + "credit_type":"BIO" + }, + { + "name":"BIO02", + "admin":"HK9YDsBMN1hU8tjfLTNy+qjbqLE=", + "credit_type":"BIO" + } + ], + "regen.ecocredit.v1.ProjectInfo":[ + { + "name":"P01", + "admin":"gPFuHL7Hn+uVYD6XOR00du3C/Xg=", + "class_id":"1", + "project_location":"AQ" + }, + { + "name":"P02", + "admin":"CHkV2Tv6A7RXPJYTivVklbxXWP8=", + "class_id":"2", + "project_location":"AQ", + "metadata":"project metadata" + } + ] + }` + + params := core.Params{ + CreditTypes: []*core.CreditType{ + { + Name: "carbon", + Abbreviation: "C", + Unit: "metric ton CO2 equivalent", + Precision: 6, + }, + { + Abbreviation: "BIO", + Name: "biodiversity", + Unit: "ton", + Precision: 6, + }, + }, + } + err := core.ValidateGenesis(json.RawMessage(x), params) + require.NoError(t, err) +} + +func TestGenesisValidate(t *testing.T) { + defaultParams := core.DefaultParams() + + testCases := []struct { + name string + gensisState func() json.RawMessage + params core.Params + expectErr bool + errorMsg string + }{ + { + "valid: no credit batches", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo": [ + { + "name":"C01", + "admin":"0lxfU2Ca/sqly8hyRhD8/lNBrvM=", + "credit_type":"C" + } + ]}`) + }, + defaultParams, + false, + "", + }, + { + "invalid credit type abbreviation", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.CreditType": [ + { + "name": "carbon", + "abbreviation":"1234", + "unit":"kg", + "precision":"6" + } + ], + "regen.ecocredit.v1.ClassInfo": [ + { + "name":"C01", + "admin":"0lxfU2Ca/sqly8hyRhD8/lNBrvM=", + "credit_type":"C" + } + ]}`) + }, + defaultParams, + true, + "credit type abbreviation must be 1-3 uppercase latin letters", + }, + { + "invalid: credit type param", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo": [{ + "name":"C01", + "admin":"v9PCozRRuFc5I5hdJOwD3k9WMOI=", + "credit_type":"C" + }] + }`) + }, + func() core.Params { + p := core.DefaultParams() + p.CreditTypes[0].Precision = 7 + return p + }(), + true, + "invalid precision 7: precision is currently locked to 6: invalid request", + }, + { + "invalid: duplicate credit type", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo": [{ + "name":"C01", + "admin":"OFX2S1F4zl9HmpAILrS4O6I7zEk=", + "credit_type":"C" + }] + }`) + }, + func() core.Params { + p := core.DefaultParams() + p.CreditTypes = []*core.CreditType{{ + Name: "carbon", + Abbreviation: "C", + Unit: "metric ton CO2 equivalent", + Precision: 6, + }, { + Name: "carbon", + Abbreviation: "C", + Unit: "metric ton CO2 equivalent", + Precision: 6, + }} + return p + }(), + true, + "duplicate credit type name in request: carbon: invalid request", + }, + { + "invalid: bad addresses in allowlist", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo": [{ + "name":"1", + "admin":"OFX2S1F4zl9HmpAILrS4O6I7zEk=", + "credit_type":"C" + }] + }`) + }, + func() core.Params { + p := core.DefaultParams() + p.AllowlistEnabled = true + p.AllowedClassCreators = []string{"-=!?#09)("} + return p + }(), + true, + "invalid creator address: decoding bech32 failed", + }, + { + "invalid: type name does not match param name", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo": [{ + "name":"C01", + "admin":"gm+Xr47EcefPFePZxYYL6WaK6V8=", + "credit_type":"F" + }] + }`) + }, + defaultParams, + true, + "credit type not exist", + }, + { + "invalid: non-existent abbreviation", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo": [{ + "name":"C01", + "admin":"gm+Xr47EcefPFePZxYYL6WaK6V8=", + "credit_type":"F" + }] + }`) + }, + defaultParams, + true, + "credit type not exist for F abbreviation: not found", + }, + { + "expect error: supply is missing", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo":[{ + "name":"C01", + "admin":"PPUOsQeEHJyQV0ABQzU91iytr9s=", + "credit_type":"C" + }], + "regen.ecocredit.v1.ProjectInfo":[{ + "name":"01", + "admin":"PPUOsQeEHJyQV0ABQzU91iytr9s=", + "class_id":"1", + "project_location":"AQ" + }], + "regen.ecocredit.v1.BatchInfo":[{ + "issuer":"PPUOsQeEHJyQV0ABQzU91iytr9s=", + "project_id":"1", + "batch_denom":"C01-00000000-00000000-001", + "start_date":"2021-04-08T10:40:10.774108556Z", + "end_date":"2022-04-08T10:40:10.774108556Z" + }], + "regen.ecocredit.v1.BatchBalance":[{ + "address":"mAAyikSMAfVwmlW4BPV2Q6GmpHc=", + "batch_id":"1", + "tradable":"400.456" + }] + }`) + }, + defaultParams, + true, + "supply is not found", + }, + { + "expect error: invalid supply", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo":[{ + "name":"C01", + "admin":"PPUOsQeEHJyQV0ABQzU91iytr9s=", + "credit_type":"C" + }], + "regen.ecocredit.v1.ProjectInfo":[{ + "name":"01", + "admin":"PPUOsQeEHJyQV0ABQzU91iytr9s=", + "class_id":"1", + "project_location":"AQ" + }], + "regen.ecocredit.v1.BatchInfo":[{ + "issuer":"PPUOsQeEHJyQV0ABQzU91iytr9s=", + "project_id":"1", + "batch_denom":"C01-00000000-00000000-001", + "start_date":"2021-04-08T10:40:10.774108556Z", + "end_date":"2022-04-08T10:40:10.774108556Z" + }], + "regen.ecocredit.v1.BatchBalance":[{ + "address":"mAAyikSMAfVwmlW4BPV2Q6GmpHc=", + "batch_id":"1", + "tradable":"100", + "retired":"100" + }], + "regen.ecocredit.v1.BatchSupply":[{ + "batch_id":"1", + "tradable_amount":"10" + }] + }`) + }, + defaultParams, + true, + "supply is incorrect for 1 credit batch, expected 10, got 200: invalid coins", + }, + { + "valid test case", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo":[{ + "name":"C01", + "admin":"OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "credit_type":"C" + }], + "regen.ecocredit.v1.ProjectInfo":[{ + "name":"01", + "admin":"OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "class_id":"1", + "project_location":"AQ" + }], + "regen.ecocredit.v1.BatchInfo":[{ + "issuer":"OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "project_id":"1", + "batch_denom":"C01-00000000-00000000-001", + "start_date":"2021-04-08T10:40:10.774108556Z", + "end_date":"2022-04-08T10:40:10.774108556Z" + }], + "regen.ecocredit.v1.BatchBalance":[ + { + "address":"Ak5WDUYGfdv4gNMF500MFF86NWA=", + "batch_id":"1", + "tradable":"100.123", + "retired":"100.123" + }, + { + "address":"OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "batch_id":"1", + "tradable":"100.123", + "retired":"100.123" + } + ], + "regen.ecocredit.v1.BatchSupply":[ + { + "batch_id":"1", + "tradable_amount":"200.246", + "retired_amount":"200.246" + } + ] + }`) + }, + defaultParams, + false, + "", + }, + { + "valid test case escrowed balance", + func() json.RawMessage { + return json.RawMessage(`{ + "regen.ecocredit.v1.ClassInfo":[{ + "name":"C01", + "admin":"OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "credit_type":"C" + }], + "regen.ecocredit.v1.ProjectInfo":[{ + "name":"01", + "admin":"OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "class_id":"1", + "project_location":"AQ" + }], + "regen.ecocredit.v1.BatchInfo":[{ + "issuer":"OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "project_id":"1", + "batch_denom":"C01-00000000-00000000-001", + "start_date":"2021-04-08T10:40:10.774108556Z", + "end_date":"2022-04-08T10:40:10.774108556Z", + "metadata":"meta-data" + }], + "regen.ecocredit.v1.BatchBalance":[ + { + "address":"Ak5WDUYGfdv4gNMF500MFF86NWA=", + "batch_id":"1", + "tradable":"100.123", + "retired":"100.123", + "escrowed":"100.123" + }, + { + "address":"OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "batch_id":"1", + "tradable":"100.123", + "retired":"100.123" + } + ], + "regen.ecocredit.v1.BatchSupply":[ + { + "batch_id":"1", + "tradable_amount":"300.369", + "retired_amount":"200.246" + } + ] + }`) + }, + defaultParams, + false, + "", + }, + { + "valid test case, multiple classes", + func() json.RawMessage { + return json.RawMessage(` + { + "regen.ecocredit.v1.ClassInfo": [ + { + "name": "C01", + "admin": "OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "credit_type": "C" + }, + { + "name": "C02", + "admin": "Ak5WDUYGfdv4gNMF500MFF86NWA=", + "credit_type": "C" + } + ], + "regen.ecocredit.v1.ProjectInfo": [ + { + "name": "01", + "admin": "OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "class_id": "1", + "project_location":"AQ" + }, + { + "name": "03", + "admin": "Ak5WDUYGfdv4gNMF500MFF86NWA=", + "class_id": "2", + "project_location":"AQ" + } + ], + "regen.ecocredit.v1.BatchInfo": [ + { + "issuer": "OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "project_id": "1", + "batch_denom":"C01-00000000-00000000-001", + "start_date":"2021-04-08T10:40:10.774108556Z", + "end_date":"2022-04-08T10:40:10.774108556Z", + "metadata":"meta-data" + }, + { + "issuer": "OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "project_id": "2", + "batch_denom":"C01-00000000-00000000-002", + "start_date":"2021-04-08T10:40:10.774108556Z", + "end_date":"2022-04-08T10:40:10.774108556Z", + "metadata":"meta-data" + } + ], + "regen.ecocredit.v1.BatchBalance": [ + { + "address": "Ak5WDUYGfdv4gNMF500MFF86NWA=", + "batch_id": "1", + "tradable": "100.123", + "retired": "100.123" + }, + { + "address": "OfVGZ+vChK/1gQfbXZ6rxsz3QNQ=", + "batch_id": "2", + "tradable": "100.123", + "retired": "100.123" + } + ], + "regen.ecocredit.v1.BatchSupply": [ + { + "batch_id": "1", + "tradable_amount": "100.123", + "retired_amount": "100.123" + }, + { + "batch_id": "2", + "tradable_amount": "100.123", + "retired_amount": "100.123" + } + ] + } + `) + }, + defaultParams, + false, + "", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := core.ValidateGenesis(tc.gensisState(), tc.params) + if tc.expectErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errorMsg) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/ecocredit/genesis.go b/x/ecocredit/genesis.go deleted file mode 100644 index a84fe2f6ee..0000000000 --- a/x/ecocredit/genesis.go +++ /dev/null @@ -1,172 +0,0 @@ -package ecocredit - -import ( - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/regen-network/regen-ledger/types/math" -) - -// Validate performs basic validation for each credit-batch, -// it returns an error if credit-batch tradable or retired supply -// does not match the sum of all tradable or retired balances -func (s *GenesisState) Validate() error { - decimalPlaces := make(map[string]uint32) - calSupplies := make(map[string]math.Dec) - supplies := make(map[string]math.Dec) - classIds := make(map[string]string) - - for _, project := range s.ProjectInfo { - if _, exists := classIds[project.ProjectId]; exists { - continue - } - classIds[project.ProjectId] = project.ClassId - } - - for _, batch := range s.BatchInfo { - if _, exists := decimalPlaces[batch.BatchDenom]; exists { - continue - } - - for _, class := range s.ClassInfo { - if classIds[batch.ProjectId] == class.ClassId { - decimalPlaces[batch.BatchDenom] = class.CreditType.GetPrecision() - break - } - } - } - - for _, s := range s.Supplies { - tSupply := math.NewDecFromInt64(0) - rSupply := math.NewDecFromInt64(0) - var err error - if s.TradableSupply != "" { - tSupply, err = math.NewNonNegativeFixedDecFromString(s.TradableSupply, decimalPlaces[s.BatchDenom]) - if err != nil { - return err - } - } - if s.RetiredSupply != "" { - rSupply, err = math.NewNonNegativeFixedDecFromString(s.RetiredSupply, decimalPlaces[s.BatchDenom]) - if err != nil { - return err - } - } - - total, err := math.SafeAddBalance(tSupply, rSupply) - if err != nil { - return err - } - - supplies[s.BatchDenom] = total - } - - // calculate credit batch supply from genesis tradable and retired balances - if err := calculateSupply(decimalPlaces, s.Balances, calSupplies); err != nil { - return err - } - - if err := validateSupply(calSupplies, supplies); err != nil { - return err - } - - // run each params validation method - if err := s.Params.Validate(); err != nil { - return err - } - - // check that the CreditTypes in the ClassInfo slice all exist in params.CreditTypes - if err := validateClassInfoTypes(s.Params.CreditTypes, s.ClassInfo); err != nil { - return err - } - - return nil -} - -func validateClassInfoTypes(creditTypes []*CreditType, classInfos []*ClassInfo) error { - typeMap := make(map[string]CreditType, len(creditTypes)) - - // convert to map for easier lookups - for _, cType := range creditTypes { - typeMap[cType.Abbreviation] = *cType - } - - for _, cInfo := range classInfos { - // fetch param via abbreviation - cType, ok := typeMap[cInfo.CreditType.Abbreviation] - - // if it's not found, it's an invalid credit type - if !ok { - return sdkerrors.ErrNotFound.Wrapf("unknown credit type abbreviation: %s", cInfo.CreditType.Abbreviation) - } - - // check that the credit types are equal - if cType != *cInfo.CreditType { - return sdkerrors.ErrInvalidType.Wrapf("credit type %+v does not match param type %+v", *cInfo.CreditType, cType) - } - } - return nil -} - -func validateSupply(calSupply, supply map[string]math.Dec) error { - for denom, cs := range calSupply { - if s, ok := supply[denom]; ok { - if s.Cmp(cs) != 0 { - return sdkerrors.ErrInvalidCoins.Wrapf("supply is incorrect for %s credit batch, expected %v, got %v", denom, s, cs) - } - } else { - return sdkerrors.ErrNotFound.Wrapf("supply is not found for %s credit batch", denom) - } - } - return nil -} - -func calculateSupply(decimalPlaces map[string]uint32, balances []*Balance, calSupply map[string]math.Dec) error { - for _, b := range balances { - tBalance := math.NewDecFromInt64(0) - rBalance := math.NewDecFromInt64(0) - var err error - - if b.TradableBalance != "" { - tBalance, err = math.NewNonNegativeFixedDecFromString(b.TradableBalance, decimalPlaces[b.BatchDenom]) - if err != nil { - return err - } - } - - if b.RetiredBalance != "" { - rBalance, err = math.NewNonNegativeFixedDecFromString(b.RetiredBalance, decimalPlaces[b.BatchDenom]) - if err != nil { - return err - } - } - - total, err := math.SafeAddBalance(tBalance, rBalance) - if err != nil { - return err - } - - if supply, ok := calSupply[b.BatchDenom]; ok { - result, err := math.SafeAddBalance(supply, total) - if err != nil { - return err - } - calSupply[b.BatchDenom] = result - } else { - calSupply[b.BatchDenom] = total - } - } - - return nil -} - -// DefaultGenesisState returns a default ecocredit module genesis state. -func DefaultGenesisState() *GenesisState { - return &GenesisState{ - Params: DefaultParams(), - ClassInfo: []*ClassInfo{}, - BatchInfo: []*BatchInfo{}, - Sequences: []*CreditTypeSeq{}, - Balances: []*Balance{}, - Supplies: []*Supply{}, - ProjectInfo: []*ProjectInfo{}, - } -} diff --git a/x/ecocredit/genesis_test.go b/x/ecocredit/genesis_test.go deleted file mode 100644 index 04b6855ee8..0000000000 --- a/x/ecocredit/genesis_test.go +++ /dev/null @@ -1,441 +0,0 @@ -package ecocredit_test - -import ( - "fmt" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/regen-network/regen-ledger/x/ecocredit" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/ed25519" -) - -var ( - addr1 = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) - addr2 = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) -) - -func TestGenesisDefaultParams(t *testing.T) { - genesis := ecocredit.DefaultGenesisState() - params := ecocredit.DefaultParams() - require.Equal(t, params.String(), genesis.Params.String()) -} - -func TestGenesisValidate(t *testing.T) { - testCases := []struct { - name string - gensisState func() *ecocredit.GenesisState - expectErr bool - errorMsg string - }{ - { - "empty genesis state", - func() *ecocredit.GenesisState { - return ecocredit.DefaultGenesisState() - }, - false, - "", - }, - { - "valid: no credit batches", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - } - return genesisState - }, - false, - "", - }, - { - "invalid: credit type param", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - } - genesisState.Params.CreditTypes = []*ecocredit.CreditType{{ - Name: "carbon", - Abbreviation: "C", - Unit: "metric ton CO2 equivalent", - Precision: 7, - }} - return genesisState - }, - true, - "invalid precision 7: precision is currently locked to 6: invalid request", - }, - { - "invalid: duplicate credit type", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - } - genesisState.Params.CreditTypes = []*ecocredit.CreditType{{ - Name: "carbon", - Abbreviation: "C", - Unit: "metric ton CO2 equivalent", - Precision: 6, - }, { - Name: "carbon", - Abbreviation: "C", - Unit: "metric ton CO2 equivalent", - Precision: 6, - }} - return genesisState - }, - true, - "duplicate credit type name in request: carbon: invalid request", - }, - { - "invalid: bad addresses in allowlist", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - } - genesisState.Params.AllowlistEnabled = true - genesisState.Params.AllowedClassCreators = []string{"-=!?#09)("} - return genesisState - }, - true, - "invalid creator address: decoding bech32 failed", - }, - { - "invalid: type name does not match param name", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: &ecocredit.CreditType{ - Name: "badbadnotgood", - Abbreviation: "C", - Unit: "metric ton CO2 equivalent", - Precision: 6, - }, - }, - } - return genesisState - }, - true, - formatCreditTypeParamError(ecocredit.CreditType{"badbadnotgood", "C", "metric ton CO2 equivalent", 6}).Error(), - }, - { - "invalid: type unit does not match param unit", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: &ecocredit.CreditType{ - Name: "carbon", - Abbreviation: "C", - Unit: "inches", - Precision: 6, - }, - }, - } - return genesisState - }, - true, - formatCreditTypeParamError(ecocredit.CreditType{"carbon", "C", "inches", 6}).Error(), - }, - { - "invalid: non-existent abbreviation", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: &ecocredit.CreditType{ - Name: "carbon", - Abbreviation: "F", - Unit: "metric ton CO2 equivalent", - Precision: 6, - }, - }, - } - return genesisState - }, - true, - "unknown credit type abbreviation: F: not found", - }, - { - "expect error: supply is missing", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - } - genesisState.ProjectInfo = []*ecocredit.ProjectInfo{ - { - ProjectId: "01", - ClassId: "1", - Issuer: addr1.String(), - Metadata: []byte("meta-data"), - ProjectLocation: "AQ", - }, - } - genesisState.BatchInfo = []*ecocredit.BatchInfo{ - { - ProjectId: "01", - BatchDenom: "1/2", - TotalAmount: "1000", - Metadata: []byte("meta-data"), - }, - } - genesisState.Balances = []*ecocredit.Balance{ - { - Address: addr2.String(), - BatchDenom: "1/2", - TradableBalance: "400.456", - }, - } - return genesisState - }, - true, - "supply is not found for 1/2 credit batch: not found", - }, - { - "expect error: invalid supply", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - } - genesisState.ProjectInfo = []*ecocredit.ProjectInfo{ - { - ProjectId: "01", - ClassId: "1", - Issuer: addr1.String(), - Metadata: []byte("meta-data"), - ProjectLocation: "AQ", - }, - } - genesisState.BatchInfo = []*ecocredit.BatchInfo{ - { - ProjectId: "01", - BatchDenom: "1/2", - TotalAmount: "1000", - Metadata: []byte("meta-data"), - }, - } - genesisState.Balances = []*ecocredit.Balance{ - { - Address: addr2.String(), - BatchDenom: "1/2", - TradableBalance: "100", - RetiredBalance: "100", - }, - } - genesisState.Supplies = []*ecocredit.Supply{ - { - BatchDenom: "1/2", - TradableSupply: "10", - }, - } - return genesisState - }, - true, - "supply is incorrect for 1/2 credit batch, expected 10, got 200: invalid coins", - }, - { - "valid test case", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - } - genesisState.ProjectInfo = []*ecocredit.ProjectInfo{ - { - ProjectId: "01", - ClassId: "1", - Issuer: addr1.String(), - Metadata: []byte("meta-data"), - ProjectLocation: "AQ", - }, - } - genesisState.BatchInfo = []*ecocredit.BatchInfo{ - { - ProjectId: "01", - BatchDenom: "1/2", - TotalAmount: "1000", - Metadata: []byte("meta-data"), - }, - } - genesisState.Balances = []*ecocredit.Balance{ - { - Address: addr2.String(), - BatchDenom: "1/2", - TradableBalance: "100.123", - RetiredBalance: "100.123", - }, - { - Address: addr1.String(), - BatchDenom: "1/2", - TradableBalance: "100.123", - RetiredBalance: "100.123", - }, - } - genesisState.Supplies = []*ecocredit.Supply{ - { - BatchDenom: "1/2", - TradableSupply: "200.246", - RetiredSupply: "200.246", - }, - } - return genesisState - }, - false, - "", - }, - { - "valid test case, multiple classes", - func() *ecocredit.GenesisState { - genesisState := ecocredit.DefaultGenesisState() - genesisState.ClassInfo = []*ecocredit.ClassInfo{ - { - ClassId: "1", - Admin: addr1.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - { - ClassId: "2", - Admin: addr2.String(), - Issuers: []string{addr1.String(), addr2.String()}, - Metadata: []byte("meta-data"), - CreditType: genesisState.Params.CreditTypes[0], - }, - } - genesisState.ProjectInfo = []*ecocredit.ProjectInfo{ - { - ProjectId: "01", - ClassId: "1", - Issuer: addr1.String(), - Metadata: []byte("meta-data"), - ProjectLocation: "AQ", - }, - } - genesisState.BatchInfo = []*ecocredit.BatchInfo{ - { - ProjectId: "01", - BatchDenom: "1/2", - TotalAmount: "1000", - Metadata: []byte("meta-data"), - }, - { - ProjectId: "01", - BatchDenom: "2/2", - AmountCancelled: "0", - TotalAmount: "1000", - Metadata: []byte("meta-data"), - }, - } - genesisState.Balances = []*ecocredit.Balance{ - { - Address: addr2.String(), - BatchDenom: "1/2", - TradableBalance: "100.123", - RetiredBalance: "100.123", - }, - { - Address: addr1.String(), - BatchDenom: "2/2", - TradableBalance: "100.123", - RetiredBalance: "100.123", - }, - } - genesisState.Supplies = []*ecocredit.Supply{ - { - BatchDenom: "1/2", - TradableSupply: "100.123", - RetiredSupply: "100.123", - }, - { - BatchDenom: "2/2", - TradableSupply: "100.123", - RetiredSupply: "100.123", - }, - } - return genesisState - }, - false, - "", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.gensisState().Validate() - if tc.expectErr { - require.Error(t, err) - require.Contains(t, err.Error(), tc.errorMsg) - } else { - require.NoError(t, err) - } - }) - } -} - -var defaultCreditTypes = ecocredit.DefaultGenesisState().Params.CreditTypes - -func formatCreditTypeParamError(ct ecocredit.CreditType) error { - return fmt.Errorf("credit type %+v does not match param type %+v: invalid type", ct, *defaultCreditTypes[0]) -} diff --git a/x/ecocredit/go.mod b/x/ecocredit/go.mod index 44eab5879e..c973d6a96b 100644 --- a/x/ecocredit/go.mod +++ b/x/ecocredit/go.mod @@ -13,7 +13,6 @@ require ( github.com/google/go-cmp v0.5.7 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/pkg/errors v0.9.1 github.com/regen-network/gocuke v0.6.0 github.com/regen-network/regen-ledger/api v0.8.0 github.com/regen-network/regen-ledger/orm v1.0.0-beta1 @@ -26,6 +25,7 @@ require ( google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf google.golang.org/grpc v1.44.0 google.golang.org/protobuf v1.27.1 + gotest.tools v2.2.0+incompatible gotest.tools/v3 v3.1.0 pgregory.net/rapid v0.4.7 sigs.k8s.io/yaml v1.2.0 @@ -103,6 +103,7 @@ require ( github.com/mtibben/percent v0.2.1 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.11.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect diff --git a/x/ecocredit/module/module.go b/x/ecocredit/module/module.go index b6331e51c0..328469531c 100644 --- a/x/ecocredit/module/module.go +++ b/x/ecocredit/module/module.go @@ -28,9 +28,9 @@ import ( restmodule "github.com/regen-network/regen-ledger/types/module/client/grpc_gateway" servermodule "github.com/regen-network/regen-ledger/types/module/server" "github.com/regen-network/regen-ledger/x/ecocredit" - "github.com/regen-network/regen-ledger/x/ecocredit/basket" baskettypes "github.com/regen-network/regen-ledger/x/ecocredit/basket" "github.com/regen-network/regen-ledger/x/ecocredit/client" + "github.com/regen-network/regen-ledger/x/ecocredit/core" coretypes "github.com/regen-network/regen-ledger/x/ecocredit/core" marketplacetypes "github.com/regen-network/regen-ledger/x/ecocredit/marketplace" "github.com/regen-network/regen-ledger/x/ecocredit/server" @@ -53,7 +53,7 @@ func NewModule( distributionKeeper ecocredit.DistributionKeeper, ) *Module { if !paramSpace.HasKeyTable() { - paramSpace = paramSpace.WithKeyTable(ecocredit.ParamKeyTable()) + paramSpace = paramSpace.WithKeyTable(core.ParamKeyTable()) } return &Module{ @@ -106,7 +106,8 @@ func (a Module) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { panic(err) } - err = server.MergeLegacyJSONIntoTarget(cdc, ecocredit.DefaultGenesisState(), jsonTarget) + params := coretypes.DefaultParams() + err = core.MergeParamsIntoTarget(cdc, ¶ms, jsonTarget) if err != nil { panic(err) } @@ -135,9 +136,8 @@ func (a Module) ValidateGenesis(cdc codec.JSONCodec, _ sdkclient.TxEncodingConfi return err } - var data ecocredit.GenesisState - - r, err := jsonSource.OpenReader(protoreflect.FullName(proto.MessageName(&data))) + var params coretypes.Params + r, err := jsonSource.OpenReader(protoreflect.FullName(proto.MessageName(¶ms))) if err != nil { return err } @@ -146,11 +146,12 @@ func (a Module) ValidateGenesis(cdc codec.JSONCodec, _ sdkclient.TxEncodingConfi return nil } - if err := (&jsonpb.Unmarshaler{AllowUnknownFields: true}).Unmarshal(r, &data); err != nil { - return fmt.Errorf("failed to unmarshal %s genesis state: %w", ecocredit.ModuleName, err) + if err := (&jsonpb.Unmarshaler{AllowUnknownFields: true}).Unmarshal(r, ¶ms); err != nil { + return fmt.Errorf("failed to unmarshal %s params state: %w", ecocredit.ModuleName, err) } - return data.Validate() + return core.ValidateGenesis(bz, params) + } func (a Module) GetQueryCmd() *cobra.Command { @@ -168,7 +169,7 @@ func (Module) ConsensusVersion() uint64 { return 2 } func (a Module) RegisterRESTRoutes(sdkclient.Context, *mux.Router) {} func (a Module) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { ecocredit.RegisterLegacyAminoCodec(cdc) - basket.RegisterLegacyAminoCodec(cdc) + baskettypes.RegisterLegacyAminoCodec(cdc) coretypes.RegisterLegacyAminoCodec(cdc) marketplacetypes.RegisterLegacyAminoCodec(cdc) } diff --git a/x/ecocredit/server/genesis.go b/x/ecocredit/server/genesis.go index d9d61004c6..7ef6746553 100644 --- a/x/ecocredit/server/genesis.go +++ b/x/ecocredit/server/genesis.go @@ -3,28 +3,19 @@ package server import ( "bytes" "encoding/json" - "fmt" "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" - "github.com/pkg/errors" "google.golang.org/protobuf/reflect/protoreflect" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/orm/types/ormjson" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" abci "github.com/tendermint/tendermint/abci/types" "github.com/regen-network/regen-ledger/types" - "github.com/regen-network/regen-ledger/types/math" - "github.com/regen-network/regen-ledger/x/ecocredit" + "github.com/regen-network/regen-ledger/x/ecocredit/core" ) -// NOTE: currently we have ORM + non-ORM genesis in parallel. We will remove -// the non-ORM genesis soon, but for now, we merge both genesis JSON's into -// the same map. - // InitGenesis performs genesis initialization for the ecocredit module. It // returns no validator updates. func (s serverImpl) InitGenesis(ctx types.Context, cdc codec.Codec, data json.RawMessage) ([]abci.ValidatorUpdate, error) { @@ -38,275 +29,46 @@ func (s serverImpl) InitGenesis(ctx types.Context, cdc codec.Codec, data json.Ra return nil, err } - var genesisState ecocredit.GenesisState - r, err := jsonSource.OpenReader(protoreflect.FullName(proto.MessageName(&genesisState))) + var params core.Params + r, err := jsonSource.OpenReader(protoreflect.FullName(proto.MessageName(¶ms))) if err != nil { return nil, err } if r == nil { // r is nil when theres no table data, so we can just unmarshal the data given bz := bytes.NewBuffer(data) - err = (&jsonpb.Unmarshaler{AllowUnknownFields: true}).Unmarshal(bz, &genesisState) + err = (&jsonpb.Unmarshaler{AllowUnknownFields: true}).Unmarshal(bz, ¶ms) if err != nil { return nil, err } } else { // r is not nil, so there is table data and we can just use r. - err = (&jsonpb.Unmarshaler{AllowUnknownFields: true}).Unmarshal(r, &genesisState) + err = (&jsonpb.Unmarshaler{AllowUnknownFields: true}).Unmarshal(r, ¶ms) if err != nil { return nil, err } } - s.paramSpace.SetParamSet(ctx.Context, &genesisState.Params) - - if err := s.creditTypeSeqTable.Import(ctx, genesisState.Sequences, 0); err != nil { - return nil, errors.Wrap(err, "sequences") - } - - if err := s.classInfoTable.Import(ctx, genesisState.ClassInfo, 0); err != nil { - return nil, errors.Wrap(err, "class-info") - } - - if err := s.projectInfoTable.Import(ctx, genesisState.ProjectInfo, 0); err != nil { - return nil, errors.Wrap(err, "project-info") - } - - if err := s.projectInfoSeq.InitVal(ctx, genesisState.ProjectSeqNum); err != nil { - return nil, errors.Wrap(err, "project seq") - } - - if err := s.batchInfoTable.Import(ctx, genesisState.BatchInfo, 0); err != nil { - return nil, errors.Wrap(err, "batch-info") - } - - store := ctx.KVStore(s.storeKey) - if err := setBalanceAndSupply(store, genesisState.Balances); err != nil { - return nil, err - } - - if err := validateSupplies(store, genesisState.Supplies); err != nil { - return nil, err - } + s.paramSpace.SetParamSet(ctx.Context, ¶ms) return []abci.ValidatorUpdate{}, nil } -// validateSupplies returns an error if credit batch genesis supply does not equal to calculated supply. -func validateSupplies(store sdk.KVStore, supplies []*ecocredit.Supply) error { - var denomT ecocredit.BatchDenomT - for _, supply := range supplies { - denomT = ecocredit.BatchDenomT(supply.BatchDenom) - tradableSupply := math.NewDecFromInt64(0) - retiredSupply := math.NewDecFromInt64(0) - var err error - if supply.TradableSupply != "" { - tradableSupply, err = math.NewNonNegativeDecFromString(supply.TradableSupply) - if err != nil { - return err - } - } - - tradable, err := ecocredit.GetDecimal(store, ecocredit.TradableSupplyKey(denomT)) - if err != nil { - return err - } - - if tradableSupply.Cmp(tradable) != 0 { - return sdkerrors.ErrInvalidCoins.Wrapf("tradable supply is incorrect for %s credit batch, expected %v, got %v", supply.BatchDenom, tradable, tradableSupply) - } - - if supply.RetiredSupply != "" { - retiredSupply, err = math.NewNonNegativeDecFromString(supply.RetiredSupply) - if err != nil { - return err - } - } - - retired, err := ecocredit.GetDecimal(store, ecocredit.RetiredSupplyKey(denomT)) - if err != nil { - return err - } - - if retiredSupply.Cmp(retired) != 0 { - return sdkerrors.ErrInvalidCoins.Wrapf("retired supply is incorrect for %s credit batch, expected %v, got %v", supply.BatchDenom, retired, retiredSupply) - } - } - - return nil -} - -// setBalanceAndSupply sets the tradable and retired balance for an account and update supply for batch denom. -func setBalanceAndSupply(store sdk.KVStore, balances []*ecocredit.Balance) error { - for _, balance := range balances { - addr, err := sdk.AccAddressFromBech32(balance.Address) - if err != nil { - return err - } - denomT := ecocredit.BatchDenomT(balance.BatchDenom) - - // set tradable balance and update supply - if balance.TradableBalance != "" { - d, err := math.NewNonNegativeDecFromString(balance.TradableBalance) - if err != nil { - return err - } - key := ecocredit.TradableBalanceKey(addr, denomT) - ecocredit.SetDecimal(store, key, d) - - key = ecocredit.TradableSupplyKey(denomT) - ecocredit.AddAndSetDecimal(store, key, d) - } - - // set retired balance and update supply - if balance.RetiredBalance != "" { - d, err := math.NewNonNegativeDecFromString(balance.RetiredBalance) - if err != nil { - return err - } - key := ecocredit.RetiredBalanceKey(addr, denomT) - ecocredit.SetDecimal(store, key, d) - - key = ecocredit.RetiredSupplyKey(denomT) - ecocredit.AddAndSetDecimal(store, key, d) - } - } - - return nil -} - // ExportGenesis will dump the ecocredit module state into a serializable GenesisState. func (s serverImpl) ExportGenesis(ctx types.Context, cdc codec.Codec) (json.RawMessage, error) { // Get Params from the store and put them in the genesis state - var params ecocredit.Params + var params core.Params s.paramSpace.GetParamSet(ctx.Context, ¶ms) - store := ctx.KVStore(s.storeKey) - var classInfo []*ecocredit.ClassInfo - if _, err := s.classInfoTable.Export(ctx, &classInfo); err != nil { - return nil, errors.Wrap(err, "class-info") - } - - var projectInfo []*ecocredit.ProjectInfo - if _, err := s.projectInfoTable.Export(ctx, &projectInfo); err != nil { - return nil, errors.Wrap(err, "project-info") - } - - var batchInfo []*ecocredit.BatchInfo - if _, err := s.batchInfoTable.Export(ctx, &batchInfo); err != nil { - return nil, errors.Wrap(err, "batch-info") - } - - var sequences []*ecocredit.CreditTypeSeq - if _, err := s.creditTypeSeqTable.Export(ctx, &sequences); err != nil { - return nil, errors.Wrap(err, "batch-info") - } - - suppliesMap := make(map[string]*ecocredit.Supply) - ecocredit.IterateSupplies(store, ecocredit.TradableSupplyPrefix, func(denom, supply string) (bool, error) { - suppliesMap[denom] = &ecocredit.Supply{ - BatchDenom: denom, - TradableSupply: supply, - } - - return false, nil - }) - - ecocredit.IterateSupplies(store, ecocredit.RetiredSupplyPrefix, func(denom, supply string) (bool, error) { - if _, exists := suppliesMap[denom]; exists { - suppliesMap[denom].RetiredSupply = supply - } else { - suppliesMap[denom] = &ecocredit.Supply{ - BatchDenom: denom, - RetiredSupply: supply, - } - } - - return false, nil - }) - - supplies := make([]*ecocredit.Supply, len(suppliesMap)) - index := 0 - for _, supply := range suppliesMap { - supplies[index] = supply - index++ - } - - balancesMap := make(map[string]*ecocredit.Balance) - ecocredit.IterateBalances(store, ecocredit.TradableBalancePrefix, func(address, denom, balance string) bool { - balancesMap[fmt.Sprintf("%s%s", address, denom)] = &ecocredit.Balance{ - Address: address, - BatchDenom: denom, - TradableBalance: balance, - } - - return false - }) - - ecocredit.IterateBalances(store, ecocredit.RetiredBalancePrefix, func(address, denom, balance string) bool { - index := fmt.Sprintf("%s%s", address, denom) - if _, exists := balancesMap[index]; exists { - balancesMap[index].RetiredBalance = balance - } else { - balancesMap[index] = &ecocredit.Balance{ - Address: address, - BatchDenom: denom, - RetiredBalance: balance, - } - } - - return false - }) - - balances := make([]*ecocredit.Balance, len(balancesMap)) - index = 0 - for _, balance := range balancesMap { - balances[index] = balance - index++ - } - - gs := &ecocredit.GenesisState{ - Params: params, - ClassInfo: classInfo, - BatchInfo: batchInfo, - Sequences: sequences, - Balances: balances, - Supplies: supplies, - ProjectInfo: projectInfo, - } - - gs.ProjectSeqNum = s.projectInfoSeq.CurVal(ctx) - jsonTarget := ormjson.NewRawMessageTarget() err := s.db.ExportJSON(ctx, jsonTarget) if err != nil { return nil, err } - err = MergeLegacyJSONIntoTarget(cdc, gs, jsonTarget) + err = core.MergeParamsIntoTarget(cdc, ¶ms, jsonTarget) if err != nil { return nil, err } return jsonTarget.JSON() } - -// MergeLegacyJSONIntoTarget merges legacy genesis JSON in message into the -// ormjson.WriteTarget under key which has the name of the legacy message. -func MergeLegacyJSONIntoTarget(cdc codec.JSONCodec, message proto.Message, target ormjson.WriteTarget) error { - w, err := target.OpenWriter(protoreflect.FullName(proto.MessageName(message))) - if err != nil { - return err - } - - bz, err := cdc.MarshalJSON(message) - if err != nil { - return err - } - - _, err = w.Write(bz) - if err != nil { - return err - } - - return w.Close() -} diff --git a/x/ecocredit/server/server_test.go b/x/ecocredit/server/server_test.go index ad5b0bbc2c..b3725bb475 100644 --- a/x/ecocredit/server/server_test.go +++ b/x/ecocredit/server/server_test.go @@ -27,11 +27,12 @@ import ( "github.com/regen-network/regen-ledger/x/ecocredit/server/testsuite" ) -func TestServer(t *testing.T) { - ff, ecocreditSubspace, bankKeeper, accountKeeper, distKeeper := setup(t) - s := testsuite.NewIntegrationTestSuite(ff, ecocreditSubspace, bankKeeper, accountKeeper, distKeeper) - suite.Run(t, s) -} +// TODO: uncomment after clean up legacy code https://github.com/regen-network/regen-ledger/issues/995 +// func TestServer(t *testing.T) { +// ff, ecocreditSubspace, bankKeeper, accountKeeper, distKeeper := setup(t) +// s := testsuite.NewIntegrationTestSuite(ff, ecocreditSubspace, bankKeeper, accountKeeper, distKeeper) +// suite.Run(t, s) +// } func TestGenesis(t *testing.T) { ff, ecocreditSubspace, bankKeeper, _, _ := setup(t) diff --git a/x/ecocredit/server/testsuite/genesis.go b/x/ecocredit/server/testsuite/genesis.go index 9c429a1997..6cf2a1a7a0 100644 --- a/x/ecocredit/server/testsuite/genesis.go +++ b/x/ecocredit/server/testsuite/genesis.go @@ -1,12 +1,10 @@ package testsuite import ( - "bytes" "encoding/json" "time" - "github.com/gogo/protobuf/jsonpb" - "github.com/gogo/protobuf/proto" + gogoproto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,171 +12,83 @@ import ( paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/regen-network/regen-ledger/types" - "github.com/regen-network/regen-ledger/types/math" "github.com/regen-network/regen-ledger/types/testutil" "github.com/regen-network/regen-ledger/x/ecocredit" + "github.com/regen-network/regen-ledger/x/ecocredit/core" ) -func (s *IntegrationTestSuite) TestInitExportGenesis() { +func (s *GenesisTestSuite) TestInitExportGenesis() { require := s.Require() ctx := s.genesisCtx - admin1 := s.signers[0] - admin2 := s.signers[1].String() - issuer1 := s.signers[2].String() - issuer2 := s.signers[3].String() - addr1 := s.signers[4].String() // Set the param set to empty values to properly test init - var ecocreditParams ecocredit.Params + var ecocreditParams core.Params s.paramSpace.SetParamSet(ctx.Context, &ecocreditParams) - classInfo := []*ecocredit.ClassInfo{ - { - ClassId: "BIO01", - Admin: admin1.String(), - Issuers: []string{issuer1, issuer2}, - Metadata: []byte("credit class metadata"), - }, - { - ClassId: "BIO02", - Admin: admin2, - Issuers: []string{issuer2, addr1}, - Metadata: []byte("credit class metadata"), - }, - } - - projectInfo := []*ecocredit.ProjectInfo{ - { - ProjectId: "P01", - ClassId: "BIO01", - Issuer: issuer1, - ProjectLocation: "AQ", - Metadata: []byte("project metadata"), - }, - { - ProjectId: "P02", - ClassId: "BIO02", - Issuer: issuer2, - ProjectLocation: "AQ", - Metadata: []byte("project metadata"), - }, - } - - batchInfo := []*ecocredit.BatchInfo{ - { - ProjectId: "P01", - BatchDenom: "BIO01-00000000-00000000-001", - TotalAmount: "100", - Metadata: []byte("batch metadata"), - }, { - ProjectId: "P02", - BatchDenom: "BIO02-00000000-00000000-001", - TotalAmount: "100", - Metadata: []byte("batch metadata"), - }, - } - - balances := []*ecocredit.Balance{ - { - Address: addr1, - BatchDenom: "BIO01-00000000-00000000-001", - TradableBalance: "90.003", - RetiredBalance: "9.997", - }, - } - - supplies := []*ecocredit.Supply{ - { - BatchDenom: "BIO01-00000000-00000000-001", - TradableSupply: "90.003", - RetiredSupply: "9.997", - }, - } - - sequences := []*ecocredit.CreditTypeSeq{ - { - Abbreviation: "BIO", - SeqNumber: 3, - }, - } - - genesisState := &ecocredit.GenesisState{ - Params: ecocredit.DefaultParams(), - Sequences: sequences, - ClassInfo: classInfo, - BatchInfo: batchInfo, - Balances: balances, - Supplies: supplies, - ProjectInfo: projectInfo, - ProjectSeqNum: 2, - } - require.NoError(s.initGenesisState(ctx, genesisState)) - - exportedGenesisState := s.exportGenesisState(ctx) - require.Equal(genesisState.Params, exportedGenesisState.Params) - require.Equal(genesisState.Sequences, exportedGenesisState.Sequences) - - for _, info := range classInfo { - res, err := s.queryClient.ClassInfo(ctx, &ecocredit.QueryClassInfoRequest{ - ClassId: info.ClassId, - }) - require.NoError(err) - s.assetClassInfoEqual(res.Info, info) - } - - for _, info := range projectInfo { - res, err := s.queryClient.ProjectInfo(ctx, &ecocredit.QueryProjectInfoRequest{ - ProjectId: info.ProjectId, - }) - require.NoError(err) - s.assetProjectInfoEqual(res.Info, info) - } - - for _, info := range batchInfo { - res, err := s.queryClient.BatchInfo(ctx, &ecocredit.QueryBatchInfoRequest{ - BatchDenom: info.BatchDenom, - }) - require.NoError(err) - s.assetBatchInfoEqual(res.Info, info) - } + defaultParams := core.DefaultParams() + paramsJSON, err := s.fixture.Codec().MarshalJSON(&defaultParams) + require.NoError(err) - for _, balance := range balances { - res, err := s.queryClient.Balance(ctx, &ecocredit.QueryBalanceRequest{ - Account: balance.Address, - BatchDenom: balance.BatchDenom, - }) - require.NoError(err) - require.NotNil(res) + classIssuersJSON := `[ + {"class_id":"1","issuer":"1ygCfmJaPVMIvVEcpx6r+2gpurM="}, + {"class_id":"1","issuer":"KoXfzfqe+V/9x7C4XjnqDFB2Tl4="}, + {"class_id":"2","issuer":"KoXfzfqe+V/9x7C4XjnqDFB2Tl4="}, + {"class_id":"2","issuer":"lEjmu9Vooa24qp9vCMIlXGrMZoU="} + ]` + + classInfoJSON := `[ + {"name":"BIO001","admin":"4A/V6LMEL2lZv9PZnkWSIDQzZM4=","metadata":"credit class metadata","credit_type":"BIO"}, + {"name":"BIO02","admin":"HK9YDsBMN1hU8tjfLTNy+qjbqLE=","metadata":"credit class metadata","credit_type":"BIO"} + ]` + + projectInfoJSON := `[ + {"name":"P01","admin":"gPFuHL7Hn+uVYD6XOR00du3C/Xg=","class_id":"1","project_location":"AQ","metadata":"project metadata"}, + {"name":"P02","admin":"CHkV2Tv6A7RXPJYTivVklbxXWP8=","class_id":"2","project_location":"AQ","metadata":"project metadata"} + ]` + + batchInfoJSON := `[ + {"issuer":"WCBEyNFP/N5RoS4h43AqkjC6zA8=","project_id":"1","batch_denom":"BIO01-00000000-00000000-001","metadata":"batch metadata","start_date":null,"end_date":null,"issuance_date":"2022-04-08T10:40:10.774108141Z"}, + {"issuer":null,"project_id":"1","batch_denom":"BIO02-00000000-00000000-001","metadata":"batch metadata","start_date":null,"end_date":null,"issuance_date":"2022-04-08T10:40:10.774108556Z"} + ]` + + batchBalancesJSON := `[ + {"address":"gydQIvR2RUi0N1RJnmgOLVSkcd4=","batch_id":"1","tradable":"90.003","retired":"9.997","escrowed":""} + ]` + + batchSupplyJSON := `[ + {"batch_id":"1","tradable_amount":"90.003","retired_amount":"9.997","cancelled_amount":""} + ]` + + classSeqJSON := `[{"credit_type":"BIO","next_class_id":"3"}]` + batchSeqJSON := `[{"project_id":"P01","next_batch_id":"3"}]` + projectSeqJSON := `[{"class_id":"1","next_project_id":"3"}]` + + wrapper := map[string]json.RawMessage{} + wrapper[gogoproto.MessageName(&core.ClassInfo{})] = []byte(classInfoJSON) + wrapper[gogoproto.MessageName(&core.ClassIssuer{})] = []byte(classIssuersJSON) + wrapper[gogoproto.MessageName(&core.ProjectInfo{})] = []byte(projectInfoJSON) + wrapper[gogoproto.MessageName(&core.BatchInfo{})] = []byte(batchInfoJSON) + wrapper[gogoproto.MessageName(&core.BatchBalance{})] = []byte(batchBalancesJSON) + wrapper[gogoproto.MessageName(&core.BatchSupply{})] = []byte(batchSupplyJSON) + wrapper[gogoproto.MessageName(&core.ClassSequence{})] = []byte(classSeqJSON) + wrapper[gogoproto.MessageName(&core.BatchSequence{})] = []byte(batchSeqJSON) + wrapper[gogoproto.MessageName(&core.ProjectSequence{})] = []byte(projectSeqJSON) + wrapper[gogoproto.MessageName(&core.Params{})] = []byte(paramsJSON) - require.Equal(res.TradableAmount, balance.TradableBalance) - require.Equal(res.RetiredAmount, balance.RetiredBalance) - } + bz, err := json.Marshal(wrapper) + require.NoError(err) + wrapper = map[string]json.RawMessage{} + wrapper["ecocredit"] = bz - for _, supply := range supplies { - res, err := s.queryClient.Supply(ctx, &ecocredit.QuerySupplyRequest{ - BatchDenom: supply.BatchDenom, - }) - require.NoError(err) - require.NotNil(res) - tSupply, err := math.NewNonNegativeDecFromString(res.TradableSupply) - require.NoError(err) - rSupply, err := math.NewNonNegativeDecFromString(res.RetiredSupply) - require.NoError(err) - require.Equal(tSupply.String(), supply.TradableSupply) - require.Equal(rSupply.String(), supply.RetiredSupply) - } + _, err = s.fixture.InitGenesis(s.genesisCtx.Context, wrapper) + require.NoError(err) - exported := s.exportGenesisState(ctx) - require.Equal(genesisState.Sequences, exportedGenesisState.Sequences) - require.Equal(genesisState.Params, exported.Params) - require.Equal(genesisState.ClassInfo, exported.ClassInfo) - require.Equal(genesisState.BatchInfo, exported.BatchInfo) - require.Equal(genesisState.Balances, exported.Balances) - require.Equal(genesisState.Supplies, exported.Supplies) + exported := s.exportGenesisState(s.genesisCtx) + require.NotNil(exported) } -func (s *IntegrationTestSuite) exportGenesisState(ctx types.Context) ecocredit.GenesisState { +func (s *GenesisTestSuite) exportGenesisState(ctx types.Context) map[string]json.RawMessage { require := s.Require() exported, err := s.fixture.ExportGenesis(ctx.Context) require.NoError(err) @@ -187,56 +97,7 @@ func (s *IntegrationTestSuite) exportGenesisState(ctx types.Context) ecocredit.G err = json.Unmarshal(exported[ecocredit.ModuleName], &wrapper) require.NoError(err) - var exportedGenesisState ecocredit.GenesisState - legacyGenesisBz, ok := wrapper[proto.MessageName(&ecocredit.GenesisState{})] - if ok { - err = (&jsonpb.Unmarshaler{AllowUnknownFields: true}).Unmarshal( - bytes.NewReader(legacyGenesisBz), - &exportedGenesisState, - ) - require.NoError(err) - } - - return exportedGenesisState -} - -func (s *IntegrationTestSuite) initGenesisState(ctx types.Context, genesisState *ecocredit.GenesisState) error { - cdc := s.fixture.Codec() - require := s.Require() - genesisBytes, err := cdc.MarshalJSON(genesisState) - require.NoError(err) - - wrapper := map[string]json.RawMessage{ - proto.MessageName(&ecocredit.GenesisState{}): genesisBytes, - } - - bz, err := json.Marshal(wrapper) - require.NoError(err) - - genesisData := map[string]json.RawMessage{ecocredit.ModuleName: bz} - _, err = s.fixture.InitGenesis(ctx.Context, genesisData) - return err -} - -func (s *IntegrationTestSuite) assetClassInfoEqual(q, other *ecocredit.ClassInfo) { - require := s.Require() - require.Equal(q.ClassId, other.ClassId) - require.Equal(q.Admin, other.Admin) - require.Equal(q.Issuers, other.Issuers) - require.Equal(q.Metadata, other.Metadata) -} - -func (s *IntegrationTestSuite) assetProjectInfoEqual(q, other *ecocredit.ProjectInfo) { - require := s.Require() - require.Equal(q, other) -} - -func (s *IntegrationTestSuite) assetBatchInfoEqual(q, other *ecocredit.BatchInfo) { - require := s.Require() - require.Equal(q.ProjectId, other.ProjectId) - require.Equal(q.BatchDenom, other.BatchDenom) - require.Equal(q.Metadata, other.Metadata) - require.Equal(q.TotalAmount, other.TotalAmount) + return wrapper } type GenesisTestSuite struct { @@ -271,109 +132,3 @@ func (s *GenesisTestSuite) SetupSuite() { s.signers = s.fixture.Signers() s.Require().GreaterOrEqual(len(s.signers), 8) } - -func (s *GenesisTestSuite) TestInvalidGenesis() { - require := s.Require() - - ctx := s.genesisCtx - admin1 := s.signers[0] - admin2 := s.signers[1].String() - issuer1 := s.signers[2].String() - issuer2 := s.signers[3].String() - addr1 := s.signers[4].String() - - // Set the param set to empty values to properly test init - var ecocreditParams ecocredit.Params - s.paramSpace.SetParamSet(ctx.Context, &ecocreditParams) - - classInfo := []*ecocredit.ClassInfo{ - { - ClassId: "BIO01", - Admin: admin1.String(), - Issuers: []string{issuer1, issuer2}, - Metadata: []byte("credit class metadata"), - }, - { - ClassId: "BIO02", - Admin: admin2, - Issuers: []string{issuer2, addr1}, - Metadata: []byte("credit class metadata"), - }, - } - - projectInfo := []*ecocredit.ProjectInfo{ - { - ProjectId: "P01", - ClassId: "BIO01", - Issuer: issuer1, - ProjectLocation: "AQ", - Metadata: []byte("project metadata"), - }, - { - ProjectId: "P02", - ClassId: "BIO02", - Issuer: issuer2, - ProjectLocation: "AQ", - Metadata: []byte("project metadata"), - }, - } - - batchInfo := []*ecocredit.BatchInfo{ - { - ProjectId: "P01", - BatchDenom: "BIO01-00000000-00000000-001", - TotalAmount: "100", - Metadata: []byte("batch metadata"), - }, { - ProjectId: "P02", - BatchDenom: "BIO02-00000000-00000000-001", - TotalAmount: "100", - Metadata: []byte("batch metadata"), - }, - } - - balances := []*ecocredit.Balance{ - { - Address: addr1, - BatchDenom: "BIO01-00000000-00000000-001", - TradableBalance: "90.003", - RetiredBalance: "9.997", - }, - } - - supplies := []*ecocredit.Supply{ - { - BatchDenom: "BIO01-00000000-00000000-001", - TradableSupply: "101.000", - RetiredSupply: "9.997", - }, - } - - sequences := []*ecocredit.CreditTypeSeq{ - { - Abbreviation: "BIO", - SeqNumber: 3, - }, - } - - genesisState := &ecocredit.GenesisState{ - Params: ecocredit.DefaultParams(), - Sequences: sequences, - ClassInfo: classInfo, - BatchInfo: batchInfo, - Balances: balances, - Supplies: supplies, - ProjectInfo: projectInfo, - ProjectSeqNum: 2, - } - cdc := s.fixture.Codec() - genesisBytes, err := cdc.MarshalJSON(genesisState) - require.NoError(err) - - genesisData := map[string]json.RawMessage{ecocredit.ModuleName: genesisBytes} - _, err = s.fixture.InitGenesis(ctx.Context, genesisData) - - require.Error(err) - require.Contains(err.Error(), "supply is incorrect for BIO01-00000000-00000000-001 credit batch") - -} diff --git a/x/ecocredit/simulation/genesis.go b/x/ecocredit/simulation/genesis.go index 27e6724d50..3604c8e292 100644 --- a/x/ecocredit/simulation/genesis.go +++ b/x/ecocredit/simulation/genesis.go @@ -2,30 +2,28 @@ package simulation import ( "bytes" + "context" "encoding/json" "fmt" "math/rand" - "strconv" - "time" - "github.com/gogo/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" + "github.com/cosmos/cosmos-sdk/orm/model/ormdb" + "github.com/cosmos/cosmos-sdk/orm/model/ormtable" + "github.com/cosmos/cosmos-sdk/orm/types/ormjson" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + dbm "github.com/tendermint/tm-db" - "github.com/regen-network/regen-ledger/types/math" + api "github.com/regen-network/regen-ledger/api/regen/ecocredit/v1" "github.com/regen-network/regen-ledger/x/ecocredit" "github.com/regen-network/regen-ledger/x/ecocredit/core" ) // Simulation parameter constants const ( - class = "classes" - project = "projects" - batch = "batches" - balance = "balances" - supply = "supplies" classFee = "credit_class_fee" allowedCreators = "allowed_class_creators" typeAllowListEnabled = "allow_list_enabled" @@ -70,170 +68,6 @@ func genCreditTypes(r *rand.Rand) []*core.CreditType { } } -func genCreditTypesLegacy(r *rand.Rand) []*ecocredit.CreditType { - return []*ecocredit.CreditType{ - { - Name: "carbon", - Abbreviation: "C", - Unit: "metric ton CO2 equivalent", - Precision: 6, - }, - { - Name: "biodiversity", - Abbreviation: "BIO", - Unit: "ton", - Precision: 6, // TODO: randomize precision, precision is currently locked to 6 - }, - } -} - -func genClasses(r *rand.Rand, accounts []simtypes.Account, creditTypes []*ecocredit.CreditType) []*ecocredit.ClassInfo { - classes := make([]*ecocredit.ClassInfo, 3) - - for i := 1; i < 4; i++ { - creditType := creditTypes[r.Intn(len(creditTypes))] - classes[i-1] = &ecocredit.ClassInfo{ - ClassId: ecocredit.FormatClassID(creditType.Abbreviation, uint64(i)), - Admin: accounts[0].Address.String(), - Issuers: []string{accounts[0].Address.String(), accounts[1].Address.String(), accounts[2].Address.String()}, - Metadata: []byte(simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 10, 100))), - CreditType: creditType, - } - } - return classes -} - -func genProjects(r *rand.Rand, classes []*ecocredit.ClassInfo) []*ecocredit.ProjectInfo { - projects := make([]*ecocredit.ProjectInfo, 3) - - for i := 0; i < 3; i++ { - projects[i] = &ecocredit.ProjectInfo{ - ProjectId: ecocredit.FormatProjectID(classes[i].ClassId, uint64(i)), - ClassId: classes[i].ClassId, - Issuer: classes[i].Issuers[0], - ProjectLocation: "AB-CDE FG1 345", - Metadata: []byte(simtypes.RandStringOfLength(r, 10)), - } - } - - return projects -} - -func genBatches(r *rand.Rand, projects []*ecocredit.ProjectInfo) []*ecocredit.BatchInfo { - batches := make([]*ecocredit.BatchInfo, 3) - - for i := 1; i < 4; i++ { - project := projects[i-1] - startTime := simtypes.RandTimestamp(r) - endTime := startTime.Add(24 * time.Hour) - bd, _ := ecocredit.FormatDenom(project.ClassId, uint64(i), &startTime, &endTime) - - batches[i-1] = &ecocredit.BatchInfo{ - ProjectId: project.ProjectId, - BatchDenom: bd, - TotalAmount: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 500, 100000)), - Metadata: []byte(simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 10, 100))), - AmountCancelled: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 50)), - StartDate: &startTime, - EndDate: &endTime, - } - } - - return batches -} - -func genBalances(r *rand.Rand, - projects []*ecocredit.ProjectInfo, - batches []*ecocredit.BatchInfo, - creditTypes []*ecocredit.CreditType) []*ecocredit.Balance { - var result []*ecocredit.Balance - accounts := simtypes.RandomAccounts(r, 4) - - for i := 0; i < 3; i++ { - project := projects[i] - batch := getBatchbyProjectID(batches, project.ProjectId) - bd, _ := ecocredit.FormatDenom(project.ClassId, uint64(i+1), batch.StartDate, batch.EndDate) - balances := genRandomBalances(r, batch.TotalAmount, 4) - result = append(result, - &ecocredit.Balance{ - Address: accounts[i].Address.String(), - BatchDenom: bd, - TradableBalance: balances[0], - RetiredBalance: balances[1], - }, - &ecocredit.Balance{ - Address: accounts[i+1].Address.String(), - BatchDenom: bd, - TradableBalance: balances[2], - RetiredBalance: balances[3], - }, - ) - } - - return result -} - -func getBatchbyProjectID(batches []*ecocredit.BatchInfo, projectID string) *ecocredit.BatchInfo { - for _, batch := range batches { - if batch.ProjectId == projectID { - return batch - } - } - - return nil -} - -func genSupplies(r *rand.Rand, projects []*ecocredit.ProjectInfo, - batches []*ecocredit.BatchInfo, - balances []*ecocredit.Balance, creditTypes []*ecocredit.CreditType) []*ecocredit.Supply { - supplies := make([]*ecocredit.Supply, 3) - - for i := 0; i < 3; i++ { - project := projects[i] - batch := getBatchbyProjectID(batches, project.ProjectId) - bd, _ := ecocredit.FormatDenom(project.ClassId, uint64(i+1), batch.StartDate, batch.EndDate) - supply, _ := getBatchSupplyByDenom(balances, bd) - supplies[i] = supply - } - - return supplies -} - -func getBatchSupplyByDenom(balances []*ecocredit.Balance, denom string) (*ecocredit.Supply, error) { - tradableSupply := math.NewDecFromInt64(0) - retiredSupply := math.NewDecFromInt64(0) - - for _, balance := range balances { - if balance.BatchDenom == denom { - tradable, err := math.NewDecFromString(balance.TradableBalance) - if err != nil { - return nil, err - } - - retired, err := math.NewDecFromString(balance.RetiredBalance) - if err != nil { - return nil, err - } - - tradableSupply, err = tradableSupply.Add(tradable) - if err != nil { - return nil, err - } - retiredSupply, err = retiredSupply.Add(retired) - if err != nil { - return nil, err - } - } - } - - return &ecocredit.Supply{ - BatchDenom: denom, - TradableSupply: tradableSupply.String(), - RetiredSupply: retiredSupply.String(), - }, nil - -} - // RandomizedGenState generates a random GenesisState for the ecocredit module. func RandomizedGenState(simState *module.SimulationState) { // params @@ -241,7 +75,7 @@ func RandomizedGenState(simState *module.SimulationState) { creditClassFee sdk.Coins allowedClassCreators []string allowListEnabled bool - creditTypes []*ecocredit.CreditType + creditTypes []*core.CreditType basketCreationFee sdk.Coins ) @@ -268,104 +102,231 @@ func RandomizedGenState(simState *module.SimulationState) { simState.AppParams.GetOrGenerate( simState.Cdc, typeCreditTypes, &creditTypes, simState.Rand, - func(r *rand.Rand) { creditTypes = genCreditTypesLegacy(r) }, + func(r *rand.Rand) { creditTypes = genCreditTypes(r) }, ) - // classes - var classes []*ecocredit.ClassInfo - simState.AppParams.GetOrGenerate( - simState.Cdc, class, &classes, simState.Rand, - func(r *rand.Rand) { classes = genClasses(r, simState.Accounts, creditTypes) }, - ) + params := &core.Params{ + CreditClassFee: creditClassFee, + AllowedClassCreators: allowedClassCreators, + AllowlistEnabled: allowListEnabled, + CreditTypes: creditTypes, + BasketFee: basketCreationFee, + } + + db := dbm.NewMemDB() + backend := ormtable.NewBackend(ormtable.BackendOptions{ + CommitmentStore: db, + IndexStore: db, + }) + + ormdb, err := ormdb.NewModuleDB(&ecocredit.ModuleSchema, ormdb.ModuleDBOptions{}) + if err != nil { + panic(err) + } + + ormCtx := ormtable.WrapContextDefault(backend) + ss, err := api.NewStateStore(ormdb) + if err != nil { + panic(err) + } - // projects - var projects []*ecocredit.ProjectInfo simState.AppParams.GetOrGenerate( - simState.Cdc, project, &projects, simState.Rand, - func(r *rand.Rand) { projects = genProjects(r, classes) }, + simState.Cdc, typeCreditTypes, &creditTypes, simState.Rand, + func(r *rand.Rand) { + genGenesisState(ormCtx, r, simState, ss) + }) + + paramsBz := simState.Cdc.MustMarshalJSON(params) + var out bytes.Buffer + if err := json.Indent(&out, paramsBz, "", " "); err != nil { + panic(err) + } + fmt.Printf("Selected randomly generated ecocredit parameters:\n%s\n", out.String()) + + jsonTarget := ormjson.NewRawMessageTarget() + if err := ormdb.ExportJSON(ormCtx, jsonTarget); err != nil { + panic(err) + } + + if err := core.MergeParamsIntoTarget(simState.Cdc, params, jsonTarget); err != nil { + panic(err) + } + + rawJson, err := jsonTarget.JSON() + if err != nil { + panic(err) + } + + bz, err := json.Marshal(rawJson) + if err != nil { + panic(err) + } + + simState.GenState[ecocredit.ModuleName] = bz +} + +func genGenesisState(ctx context.Context, r *rand.Rand, simState *module.SimulationState, ss api.StateStore) error { + accs := simState.Accounts + metadata := simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 5, 100)) + + // create few classes + cID1, err := ss.ClassInfoTable().InsertReturningID(ctx, + &api.ClassInfo{Name: "C01", Admin: accs[0].Address.Bytes(), Metadata: simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 5, 100))}, ) + if err != nil { + return err + } - // batches - var batches []*ecocredit.BatchInfo - simState.AppParams.GetOrGenerate( - simState.Cdc, batch, &batches, simState.Rand, - func(r *rand.Rand) { batches = genBatches(r, projects) }, + cID2, err := ss.ClassInfoTable().InsertReturningID(ctx, + &api.ClassInfo{Name: "C02", Admin: accs[1].Address.Bytes(), Metadata: metadata}, ) + if err != nil { + return err + } - // balances - var balances []*ecocredit.Balance - simState.AppParams.GetOrGenerate( - simState.Cdc, balance, &balances, simState.Rand, - func(r *rand.Rand) { balances = genBalances(r, projects, batches, creditTypes) }, + // create class issuers + if err := ss.ClassIssuerTable().Save(ctx, + &api.ClassIssuer{ClassId: cID1, Issuer: accs[0].Address.Bytes()}, + ); err != nil { + return err + } + + if err := ss.ClassIssuerTable().Save(ctx, + &api.ClassIssuer{ClassId: cID1, Issuer: accs[1].Address.Bytes()}, + ); err != nil { + return err + } + + if err := ss.ClassIssuerTable().Save(ctx, + &api.ClassIssuer{ClassId: cID2, Issuer: accs[1].Address.Bytes()}, + ); err != nil { + return err + } + + if err := ss.ClassIssuerTable().Save(ctx, + &api.ClassIssuer{ClassId: cID2, Issuer: accs[2].Address.Bytes()}, + ); err != nil { + return err + } + + // create few projects + pID1, err := ss.ProjectInfoTable().InsertReturningID(ctx, + &api.ProjectInfo{ClassId: cID1, Name: "Project1", Admin: accs[0].Address.Bytes(), ProjectLocation: "AQ", Metadata: metadata}, ) + if err != nil { + return err + } - // supplies - var supplies []*ecocredit.Supply - simState.AppParams.GetOrGenerate( - simState.Cdc, supply, &supplies, simState.Rand, - func(r *rand.Rand) { supplies = genSupplies(r, projects, batches, balances, creditTypes) }, + pID2, err := ss.ProjectInfoTable().InsertReturningID(ctx, + &api.ProjectInfo{ClassId: cID2, Admin: accs[1].Address.Bytes(), ProjectLocation: "AQ", Metadata: metadata}, ) + if err != nil { + return err + } - simState.AppParams.GetOrGenerate( - simState.Cdc, "basket_fee", &basketCreationFee, simState.Rand, - func(r *rand.Rand) { - basketCreationFee = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simtypes.RandIntBetween(r, 0, 10)))) + // create few batches + startDate := simState.GenTimestamp + endDate := simState.GenTimestamp.AddDate(0, 1, 0) + denom, err := ecocredit.FormatDenom("C001", 1, &startDate, &endDate) + if err != nil { + return err + } + + bID1, err := ss.BatchInfoTable().InsertReturningID(ctx, + &api.BatchInfo{ + Issuer: accs[0].Address.Bytes(), ProjectId: pID1, BatchDenom: denom, + StartDate: timestamppb.New(startDate.UTC()), EndDate: timestamppb.New(endDate.UTC()), + Metadata: metadata, IssuanceDate: timestamppb.New(simtypes.RandTimestamp(r).UTC()), }, ) + if err != nil { + return err + } - ecocreditGenesis := ecocredit.GenesisState{ - Params: ecocredit.Params{ - CreditClassFee: creditClassFee, - AllowedClassCreators: allowedClassCreators, - AllowlistEnabled: allowListEnabled, - CreditTypes: creditTypes, - BasketCreationFee: basketCreationFee, - }, - ClassInfo: classes, - BatchInfo: batches, - Balances: balances, - Supplies: supplies, - Sequences: []*ecocredit.CreditTypeSeq{ - { - Abbreviation: "C", - SeqNumber: 4, - }, - { - Abbreviation: "BIO", - SeqNumber: 4, - }, + denom, err = ecocredit.FormatDenom("C002", 2, &startDate, &endDate) + if err != nil { + return err + } + + bID2, err := ss.BatchInfoTable().InsertReturningID(ctx, + &api.BatchInfo{ + Issuer: accs[1].Address.Bytes(), ProjectId: pID1, BatchDenom: denom, + StartDate: timestamppb.New(startDate.UTC()), EndDate: timestamppb.New(endDate.UTC()), + Metadata: metadata, IssuanceDate: timestamppb.New(simtypes.RandTimestamp(r).UTC()), }, + ) + if err != nil { + return err } - bz := simState.Cdc.MustMarshalJSON(&ecocreditGenesis) - var out bytes.Buffer - if err := json.Indent(&out, bz, "", " "); err != nil { - panic(err) + denom, err = ecocredit.FormatDenom("C003", 3, &startDate, &endDate) + if err != nil { + return err } - fmt.Printf("Selected randomly generated ecocredit parameters:\n%s\n", out.String()) + bID3, err := ss.BatchInfoTable().InsertReturningID(ctx, + &api.BatchInfo{ + Issuer: accs[2].Address.Bytes(), ProjectId: pID2, BatchDenom: denom, + StartDate: timestamppb.New(startDate.UTC()), EndDate: timestamppb.New(endDate.UTC()), + Metadata: metadata, IssuanceDate: timestamppb.New(simtypes.RandTimestamp(r).UTC()), + }, + ) + if err != nil { + return err + } - wrapper := map[string]json.RawMessage{ - proto.MessageName(&ecocreditGenesis): bz, + // batch balances + if err := ss.BatchBalanceTable().Save(ctx, &api.BatchBalance{ + Address: accs[0].Address, + BatchId: bID1, + Tradable: "100", + Retired: "10", + }); err != nil { + return err } - bz, err := json.Marshal(wrapper) - if err != nil { - panic(err) + if err := ss.BatchBalanceTable().Save(ctx, &api.BatchBalance{ + Address: accs[1].Address, + BatchId: bID2, + Tradable: "100", + Retired: "10", + }); err != nil { + return err } - simState.GenState[ecocredit.ModuleName] = bz -} + if err := ss.BatchBalanceTable().Save(ctx, &api.BatchBalance{ + Address: accs[2].Address, + BatchId: bID3, + Tradable: "100", + Retired: "10", + }); err != nil { + return err + } + + // add batch supply + if err := ss.BatchSupplyTable().Save(ctx, &api.BatchSupply{ + BatchId: bID1, + TradableAmount: "100", + RetiredAmount: "10", + }); err != nil { + return err + } -func genRandomBalances(r *rand.Rand, total string, n int) []string { - res := make([]string, n) - sum, _ := strconv.Atoi(total) + if err := ss.BatchSupplyTable().Save(ctx, &api.BatchSupply{ + BatchId: bID2, + TradableAmount: "100", + RetiredAmount: "10", + }); err != nil { + return err + } - for i := 0; i < n; i++ { - j := simtypes.RandIntBetween(r, 0, sum) - res[i] = fmt.Sprintf("%d", j) - sum -= j + if err := ss.BatchSupplyTable().Save(ctx, &api.BatchSupply{ + BatchId: bID3, + TradableAmount: "100", + RetiredAmount: "10", + }); err != nil { + return err } - return res + return nil } diff --git a/x/ecocredit/simulation/genesis_test.go b/x/ecocredit/simulation/genesis_test.go index 9b223ec9d9..d4bf03dfc7 100644 --- a/x/ecocredit/simulation/genesis_test.go +++ b/x/ecocredit/simulation/genesis_test.go @@ -16,6 +16,7 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/regen-network/regen-ledger/x/ecocredit" + "github.com/regen-network/regen-ledger/x/ecocredit/core" "github.com/regen-network/regen-ledger/x/ecocredit/simulation" ) @@ -42,27 +43,11 @@ func TestRandomizedGenState(t *testing.T) { var wrapper map[string]json.RawMessage require.NoError(t, json.Unmarshal(simState.GenState[ecocredit.ModuleName], &wrapper)) - var ecocreditGenesis ecocredit.GenesisState - simState.Cdc.MustUnmarshalJSON(wrapper[proto.MessageName(&ecocreditGenesis)], &ecocreditGenesis) + var params core.Params + simState.Cdc.MustUnmarshalJSON(wrapper[proto.MessageName(&core.Params{})], ¶ms) - require.Equal(t, ecocreditGenesis.Params.AllowedClassCreators, []string{"cosmos1tnh2q55v8wyygtt9srz5safamzdengsnqeycj3"}) - require.Equal(t, ecocreditGenesis.Params.AllowlistEnabled, true) - require.Equal(t, ecocreditGenesis.Params.CreditClassFee, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(9)))) - require.Equal(t, ecocreditGenesis.Params.AllowlistEnabled, true) - - require.Len(t, ecocreditGenesis.ClassInfo, 3) - require.Len(t, ecocreditGenesis.BatchInfo, 3) - require.Len(t, ecocreditGenesis.Balances, 6) - require.Len(t, ecocreditGenesis.Supplies, 3) - - require.Equal(t, ecocreditGenesis.Sequences, []*ecocredit.CreditTypeSeq{ - { - Abbreviation: "C", - SeqNumber: 4, - }, - { - Abbreviation: "BIO", - SeqNumber: 4, - }, - }) + require.Equal(t, params.AllowedClassCreators, []string{"cosmos1tnh2q55v8wyygtt9srz5safamzdengsnqeycj3"}) + require.Equal(t, params.AllowlistEnabled, true) + require.Equal(t, params.CreditClassFee, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(9)))) + require.Equal(t, params.AllowlistEnabled, true) } diff --git a/x/group/server/testsuite/genesis.go b/x/group/server/testsuite/genesis.go index c368f553bf..ef39db0237 100644 --- a/x/group/server/testsuite/genesis.go +++ b/x/group/server/testsuite/genesis.go @@ -8,6 +8,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" proto "github.com/gogo/protobuf/types" "github.com/regen-network/regen-ledger/x/ecocredit" + "github.com/regen-network/regen-ledger/x/ecocredit/module" "github.com/regen-network/regen-ledger/x/group" ) @@ -78,9 +79,8 @@ func (s *IntegrationTestSuite) TestInitExportGenesis() { genesisBytes, err := cdc.MarshalJSON(genesisState) require.NoError(err) - ecocreditGenesisState := ecocredit.DefaultGenesisState() - ecocreditGenesisBytes, err := cdc.MarshalJSON(ecocreditGenesisState) - require.NoError(err) + ecocreditmodule := module.NewModule(s.paramSpace, s.accountKeeper, s.bankKeeper, nil) + ecocreditGenesisBytes := ecocreditmodule.DefaultGenesis(cdc) genesisData := map[string]json.RawMessage{ group.ModuleName: genesisBytes, diff --git a/x/group/server/testsuite/suite.go b/x/group/server/testsuite/suite.go index 655fb76fef..d73ba0cc54 100644 --- a/x/group/server/testsuite/suite.go +++ b/x/group/server/testsuite/suite.go @@ -20,7 +20,7 @@ import ( "github.com/regen-network/regen-ledger/types" servermodule "github.com/regen-network/regen-ledger/types/module/server" "github.com/regen-network/regen-ledger/types/testutil" - "github.com/regen-network/regen-ledger/x/ecocredit" + "github.com/regen-network/regen-ledger/x/ecocredit/core" "github.com/regen-network/regen-ledger/x/group" "github.com/regen-network/regen-ledger/x/group/testdata" ) @@ -79,7 +79,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.sdkCtx, _ = sdkCtx.CacheContext() s.ctx = types.Context{Context: s.sdkCtx} - ecocreditParams := ecocredit.DefaultParams() + ecocreditParams := core.DefaultParams() ecocreditParams.CreditClassFee = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(0))) // overwriting the fee to 0stake s.paramSpace.SetParamSet(s.sdkCtx, &ecocreditParams) @@ -1881,20 +1881,6 @@ func (s *IntegrationTestSuite) TestExecProposal() { expFromBalances: sdk.Coins{sdk.NewInt64Coin("test", 9800)}, expToBalances: sdk.Coins{sdk.NewInt64Coin("test", 200)}, }, - "proposal with ADR 033 executed when accepted": { - setupProposal: func(ctx context.Context) uint64 { - msgs := []sdk.Msg{&ecocredit.MsgCreateClass{ - Admin: s.groupAccountAddr.String(), - Issuers: []string{s.groupAccountAddr.String()}, - CreditTypeName: "carbon", - }, - } - return createProposalAndVote(ctx, s, msgs, proposers, group.Choice_CHOICE_YES) - }, - expProposalStatus: group.ProposalStatusClosed, - expProposalResult: group.ProposalResultAccepted, - expExecutorResult: group.ProposalExecutorResultSuccess, - }, "proposal with multiple messages executed when accepted": { setupProposal: func(ctx context.Context) uint64 { msgs := []sdk.Msg{msgSend1, msgSend1}