mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 11:27:27 +00:00 
			
		
		
		
	add genesis init/export/validation
This commit is contained in:
		
							parent
							
								
									62da823314
								
							
						
					
					
						commit
						18dfcd2a3d
					
				@ -4,6 +4,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/kava-labs/kava/x/committee/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// InitGenesis initializes the store state from a genesis state.
 | 
			
		||||
@ -14,11 +15,44 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, gs GenesisState) {
 | 
			
		||||
 | 
			
		||||
	keeper.SetNextProposalID(ctx, gs.NextProposalID)
 | 
			
		||||
 | 
			
		||||
	// TODO set votes, committee, proposals
 | 
			
		||||
	for _, com := range gs.Committees {
 | 
			
		||||
		keeper.SetCommittee(ctx, com)
 | 
			
		||||
	}
 | 
			
		||||
	for _, p := range gs.Proposals {
 | 
			
		||||
		keeper.SetProposal(ctx, p)
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range gs.Votes {
 | 
			
		||||
		keeper.SetVote(ctx, v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExportGenesis returns a GenesisState for a given context and keeper.
 | 
			
		||||
func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState {
 | 
			
		||||
	// TODO
 | 
			
		||||
	return GenesisState{}
 | 
			
		||||
 | 
			
		||||
	nextID, err := keeper.GetNextProposalID(ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	committees := []types.Committee{}
 | 
			
		||||
	keeper.IterateCommittees(ctx, func(com types.Committee) bool {
 | 
			
		||||
		committees = append(committees, com)
 | 
			
		||||
		return false
 | 
			
		||||
	})
 | 
			
		||||
	proposals := []types.Proposal{}
 | 
			
		||||
	votes := []types.Vote{}
 | 
			
		||||
	keeper.IterateProposals(ctx, func(p types.Proposal) bool {
 | 
			
		||||
		proposals = append(proposals, p)
 | 
			
		||||
		keeper.IterateVotes(ctx, p.ID, func(v types.Vote) bool {
 | 
			
		||||
			votes = append(votes, v)
 | 
			
		||||
			return false
 | 
			
		||||
		})
 | 
			
		||||
		return false
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return types.NewGenesisState(
 | 
			
		||||
		nextID,
 | 
			
		||||
		committees,
 | 
			
		||||
		proposals,
 | 
			
		||||
		votes,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										75
									
								
								x/committee/genesis_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								x/committee/genesis_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
package committee_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/suite"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/committee"
 | 
			
		||||
	"github.com/kava-labs/kava/x/committee/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GenesisTestSuite struct {
 | 
			
		||||
	suite.Suite
 | 
			
		||||
 | 
			
		||||
	app    app.TestApp
 | 
			
		||||
	ctx    sdk.Context
 | 
			
		||||
	keeper committee.Keeper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *GenesisTestSuite) TestGenesis() {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		name       string
 | 
			
		||||
		genState   types.GenesisState
 | 
			
		||||
		expectPass bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name:       "normal",
 | 
			
		||||
			genState:   types.DefaultGenesisState(),
 | 
			
		||||
			expectPass: true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "invalid",
 | 
			
		||||
			genState: types.NewGenesisState(
 | 
			
		||||
				2,
 | 
			
		||||
				[]types.Committee{},
 | 
			
		||||
				[]types.Proposal{{ID: 1, CommitteeID: 57}},
 | 
			
		||||
				[]types.Vote{},
 | 
			
		||||
			),
 | 
			
		||||
			expectPass: false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range testCases {
 | 
			
		||||
		suite.Run(tc.name, func() {
 | 
			
		||||
			// Setup (note: suite.SetupTest is not run before every suite.Run)
 | 
			
		||||
			suite.app = app.NewTestApp()
 | 
			
		||||
			suite.keeper = suite.app.GetCommitteeKeeper()
 | 
			
		||||
			suite.ctx = suite.app.NewContext(true, abci.Header{})
 | 
			
		||||
 | 
			
		||||
			// Run
 | 
			
		||||
			var exportedGenState types.GenesisState
 | 
			
		||||
			run := func() {
 | 
			
		||||
				committee.InitGenesis(suite.ctx, suite.keeper, tc.genState)
 | 
			
		||||
				exportedGenState = committee.ExportGenesis(suite.ctx, suite.keeper)
 | 
			
		||||
			}
 | 
			
		||||
			if tc.expectPass {
 | 
			
		||||
				suite.NotPanics(run)
 | 
			
		||||
			} else {
 | 
			
		||||
				suite.Panics(run)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Check
 | 
			
		||||
			if tc.expectPass {
 | 
			
		||||
				suite.Equal(tc.genState, exportedGenState)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGenesisTestSuite(t *testing.T) {
 | 
			
		||||
	suite.Run(t, new(GenesisTestSuite))
 | 
			
		||||
}
 | 
			
		||||
@ -2,6 +2,7 @@ package types
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DefaultNextProposalID is the starting poiint for proposal IDs.
 | 
			
		||||
@ -10,18 +11,18 @@ const DefaultNextProposalID uint64 = 1
 | 
			
		||||
// GenesisState is state that must be provided at chain genesis.
 | 
			
		||||
type GenesisState struct {
 | 
			
		||||
	NextProposalID uint64
 | 
			
		||||
	Votes          []Vote
 | 
			
		||||
	Proposals      []Proposal
 | 
			
		||||
	Committees     []Committee
 | 
			
		||||
	Proposals      []Proposal
 | 
			
		||||
	Votes          []Vote
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewGenesisState returns a new genesis state object for the module.
 | 
			
		||||
func NewGenesisState(nextProposalID uint64, votes []Vote, proposals []Proposal, committees []Committee) GenesisState {
 | 
			
		||||
func NewGenesisState(nextProposalID uint64, committees []Committee, proposals []Proposal, votes []Vote) GenesisState {
 | 
			
		||||
	return GenesisState{
 | 
			
		||||
		NextProposalID: nextProposalID,
 | 
			
		||||
		Votes:          votes,
 | 
			
		||||
		Proposals:      proposals,
 | 
			
		||||
		Committees:     committees,
 | 
			
		||||
		Proposals:      proposals,
 | 
			
		||||
		Votes:          votes,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -29,9 +30,9 @@ func NewGenesisState(nextProposalID uint64, votes []Vote, proposals []Proposal,
 | 
			
		||||
func DefaultGenesisState() GenesisState {
 | 
			
		||||
	return NewGenesisState(
 | 
			
		||||
		DefaultNextProposalID,
 | 
			
		||||
		[]Vote{},
 | 
			
		||||
		[]Proposal{},
 | 
			
		||||
		[]Committee{},
 | 
			
		||||
		[]Proposal{},
 | 
			
		||||
		[]Vote{},
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -48,4 +49,62 @@ func (data GenesisState) IsEmpty() bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Validate performs basic validation of genesis data.
 | 
			
		||||
func (gs GenesisState) Validate() error { return nil }
 | 
			
		||||
func (gs GenesisState) Validate() error {
 | 
			
		||||
	// validate committees
 | 
			
		||||
	committeeMap := make(map[uint64]bool, len(gs.Committees))
 | 
			
		||||
	for _, com := range gs.Committees {
 | 
			
		||||
		// check there are no duplicate IDs
 | 
			
		||||
		if _, ok := committeeMap[com.ID]; ok {
 | 
			
		||||
			return fmt.Errorf("duplicate committee ID found in genesis state; id: %d", com.ID)
 | 
			
		||||
		}
 | 
			
		||||
		committeeMap[com.ID] = true
 | 
			
		||||
 | 
			
		||||
		// validate committee
 | 
			
		||||
		if len(com.Members) == 0 {
 | 
			
		||||
			return fmt.Errorf("committee %d invalid: cannot have zero members", com.ID)
 | 
			
		||||
		}
 | 
			
		||||
		for _, m := range com.Members {
 | 
			
		||||
			if m.Empty() {
 | 
			
		||||
				return fmt.Errorf("committee %d invalid: found empty member address", com.ID)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// validate proposals - pp.Val, no duplicate IDs, no ids >= nextID, committee needs to exist
 | 
			
		||||
	proposalMap := make(map[uint64]bool, len(gs.Proposals))
 | 
			
		||||
	for _, p := range gs.Proposals {
 | 
			
		||||
		// check there are no duplicate IDs
 | 
			
		||||
		if _, ok := proposalMap[p.ID]; ok {
 | 
			
		||||
			return fmt.Errorf("duplicate proposal ID found in genesis state; id: %d", p.ID)
 | 
			
		||||
		}
 | 
			
		||||
		proposalMap[p.ID] = true
 | 
			
		||||
 | 
			
		||||
		// validate next proposal ID
 | 
			
		||||
		if p.ID >= gs.NextProposalID {
 | 
			
		||||
			return fmt.Errorf("NextProposalID is not greater than all proposal IDs; id: %d", p.ID)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check committee exists
 | 
			
		||||
		if !committeeMap[p.CommitteeID] {
 | 
			
		||||
			return fmt.Errorf("proposal refers to non existant committee; proposal: %+v", p)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// validate pubProposal
 | 
			
		||||
		if err := p.PubProposal.ValidateBasic(); err != nil {
 | 
			
		||||
			return fmt.Errorf("proposal %d invalid: %w", p.ID, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// validate votes
 | 
			
		||||
	for _, v := range gs.Votes {
 | 
			
		||||
		// check proposal exists
 | 
			
		||||
		if !proposalMap[v.ProposalID] {
 | 
			
		||||
			return fmt.Errorf("vote refers to non existant proposal; vote: %+v", v)
 | 
			
		||||
		}
 | 
			
		||||
		// validate address
 | 
			
		||||
		if v.Voter.Empty() {
 | 
			
		||||
			return fmt.Errorf("found empty voter address; vote: %+v", v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								x/committee/types/genesis_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								x/committee/types/genesis_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
package types
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestGenesisState_Validate(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		name       string
 | 
			
		||||
		genState   GenesisState
 | 
			
		||||
		expectPass bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name:       "normal",
 | 
			
		||||
			genState:   DefaultGenesisState(),
 | 
			
		||||
			expectPass: true,
 | 
			
		||||
		},
 | 
			
		||||
		// TODO test failure cases
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range testCases {
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
			err := tc.genState.Validate()
 | 
			
		||||
 | 
			
		||||
			if tc.expectPass {
 | 
			
		||||
				require.NoError(t, err)
 | 
			
		||||
			} else {
 | 
			
		||||
				require.Error(t, err)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user