Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(ecocredit): update genesis import & export to use v1 api #977

Merged
merged 26 commits into from
Apr 15, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
86009b7
wip: migrate genesis
aleem1314 Apr 4, 2022
1f86fa4
fix: tests
aleem1314 Apr 8, 2022
a3ff33b
cleanup genesis sims
aleem1314 Apr 8, 2022
aa1b135
Merge branch 'master' into aleem/ecocredit-genesis-migration
aleem1314 Apr 8, 2022
2561ded
Update x/ecocredit/module/module_test.go
aleem1314 Apr 8, 2022
235d9b9
chore: disable ecocredit tests
aleem1314 Apr 8, 2022
ead088b
remove legacy genesis
aleem1314 Apr 8, 2022
c572105
Merge branch 'aleem/ecocredit-genesis-migration' of https://github.co…
aleem1314 Apr 8, 2022
6460cb1
wip: use memdb for genesis validation
aleem1314 Apr 9, 2022
840549d
wip: add tests
aleem1314 Apr 10, 2022
d0d46ea
migrate core sims to v1
aleem1314 Apr 10, 2022
e8e6ad9
update genesis tests
aleem1314 Apr 11, 2022
0b89b4d
chore: add todo for commented code
aleem1314 Apr 11, 2022
016f0c6
Merge branch 'master' into aleem/ecocredit-genesis-migration
aleem1314 Apr 11, 2022
44948ec
remove test
aleem1314 Apr 11, 2022
e31a6aa
Merge branch 'aleem/ecocredit-genesis-migration' of https://github.co…
aleem1314 Apr 11, 2022
eb63b2c
chore: cleanup
aleem1314 Apr 11, 2022
7fe26b6
Update x/ecocredit/core/genesis.go
aleem1314 Apr 12, 2022
90d0872
chore: review changes
aleem1314 Apr 12, 2022
dd2d7f0
Merge branch 'master' into aleem/ecocredit-genesis-migration
aleem1314 Apr 12, 2022
c6e0839
chore: add core state types validation
aleem1314 Apr 13, 2022
c3e3d17
Merge branch 'aleem/ecocredit-genesis-migration' of https://github.co…
aleem1314 Apr 13, 2022
a583f4e
Merge branch 'master' of https://github.com/regen-network/regen-ledge…
aleem1314 Apr 13, 2022
5180f2b
Update x/ecocredit/core/genesis.go
aleem1314 Apr 14, 2022
1c66a72
chore: review changes
aleem1314 Apr 14, 2022
5f50723
Merge branch 'master' into aleem/ecocredit-genesis-migration
ryanchristo Apr 15, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions x/ecocredit/client/testsuite/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
tmcli "github.com/tendermint/tendermint/libs/cli"

Expand Down Expand Up @@ -47,15 +46,16 @@ const (
var validMetadataBytes = []byte{0x1}

func RunCLITests(t *testing.T, cfg network.Config) {
suite.Run(t, NewIntegrationTestSuite(cfg))
// 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.
genesisState := ecocredit.DefaultGenesisState()
genesisState.Params.AllowlistEnabled = true
bz, err := cfg.Codec.MarshalJSON(genesisState)
require.NoError(t, err)
cfg.GenesisState[ecocredit.ModuleName] = bz
suite.Run(t, NewAllowListEnabledTestSuite(cfg))
// genesisState := ecocredit.DefaultGenesisState()
// genesisState.Params.AllowlistEnabled = true
// bz, err := cfg.Codec.MarshalJSON(genesisState)
// require.NoError(t, err)
// cfg.GenesisState[ecocredit.ModuleName] = bz
// suite.Run(t, NewAllowListEnabledTestSuite(cfg))
aleem1314 marked this conversation as resolved.
Show resolved Hide resolved
}

func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite {
Expand Down
267 changes: 267 additions & 0 deletions x/ecocredit/core/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
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"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/gogo/protobuf/proto"
dbm "github.com/tendermint/tm-db"
"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/x/ecocredit"
)

// ValidateGenesis performs basic validation for the following:
// - params are valid param types with valid properties
aleem1314 marked this conversation as resolved.
Show resolved Hide resolved
// - 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{})
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
}

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() {
aleem1314 marked this conversation as resolved.
Show resolved Hide resolved
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 and retired 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 calculateSupply(ctx context.Context, decimalPlaces map[uint64]uint32, ss api.StateStore, calSupply map[uint64]math.Dec) error {
aleem1314 marked this conversation as resolved.
Show resolved Hide resolved
bbItr, err := ss.BatchBalanceTable().List(ctx, api.BatchBalancePrimaryKey{})
if err != nil {
return err
}
defer bbItr.Close()

for bbItr.Next() {
tBalance := math.NewDecFromInt64(0)
rBalance := math.NewDecFromInt64(0)

balance, err := bbItr.Value()
if err != nil {
return err
}

if _, ok := decimalPlaces[balance.BatchId]; !ok {
return sdkerrors.ErrInvalidType.Wrapf("credit type not exist for %d batch", balance.BatchId)
}

if balance.Tradable != "" {
tBalance, err = math.NewNonNegativeFixedDecFromString(balance.Tradable, decimalPlaces[balance.BatchId])
if err != nil {
return err
}
}

if balance.Retired != "" {
rBalance, err = math.NewNonNegativeFixedDecFromString(balance.Retired, decimalPlaces[balance.BatchId])
if err != nil {
aleem1314 marked this conversation as resolved.
Show resolved Hide resolved
return err
}
}

total, err := math.Add(tBalance, rBalance)
if err != nil {
return err
}

if supply, ok := calSupply[balance.BatchId]; ok {
result, err := math.SafeAddBalance(supply, total)
if err != nil {
return err
}
calSupply[balance.BatchId] = result
} else {
calSupply[balance.BatchId] = total
}
}

return nil
}

func validateSupply(calSupply, supply map[uint64]math.Dec) error {
for denom, cs := range calSupply {
if s, ok := supply[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 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()
}
Loading