Skip to content

Commit

Permalink
fix(network): genesis account ordering (ignite#2095)
Browse files Browse the repository at this point in the history
* fix genesis account ordering

* fix tests

* fix tests again

* apply review fixes

* Update starport/services/network/networktypes/genesisinformation.go

* make format

Co-authored-by: Petr Ivanov <petr.ivanov@tendermint.com>
Co-authored-by: İlker G. Öztürk <ilkergoktugozturk@gmail.com>
  • Loading branch information
3 people authored Feb 17, 2022
1 parent c66ad0f commit 193c080
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 60 deletions.
12 changes: 9 additions & 3 deletions starport/services/network/networkchain/prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ func (c Chain) buildGenesis(ctx context.Context, gi networktypes.GenesisInformat
}

// apply genesis information to the genesis
if err := c.applyGenesisAccounts(ctx, gi.GetGenesisAccounts(), addressPrefix); err != nil {
if err := c.applyGenesisAccounts(ctx, gi.GenesisAccounts, addressPrefix); err != nil {
return errors.Wrap(err, "error applying genesis accounts to genesis")
}
if err := c.applyVestingAccounts(ctx, gi.GetVestingAccounts(), addressPrefix); err != nil {
if err := c.applyVestingAccounts(ctx, gi.VestingAccounts, addressPrefix); err != nil {
return errors.Wrap(err, "error applying vesting accounts to genesis")
}
if err := c.applyGenesisValidators(ctx, gi.GetGenesisValidators()); err != nil {
if err := c.applyGenesisValidators(ctx, gi.GenesisValidators); err != nil {
return errors.Wrap(err, "error applying genesis validators to genesis")
}

Expand Down Expand Up @@ -244,6 +244,12 @@ func (c Chain) updateConfigFromGenesisValidators(genesisVals []networktypes.Gene
return err
}

// if there are tunneled peers they will be connected with tunnel clients via localhost,
// so we need to allow to have few nodes with the same ip
if len(tunnelAddresses) > 0 {
configToml.Set("p2p.allow_duplicate_ip", true)
}

// save config.toml file
configTomlFile, err := os.OpenFile(configPath, os.O_RDWR|os.O_TRUNC, 0644)
if err != nil {
Expand Down
115 changes: 73 additions & 42 deletions starport/services/network/networktypes/genesisinformation.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ import (
// GenesisInformation represents all information for a chain to construct the genesis.
// This structure indexes accounts and validators by their address for better performance
type GenesisInformation struct {
GenesisAccounts map[string]GenesisAccount
VestingAccounts map[string]VestingAccount
GenesisValidators map[string]GenesisValidator
// make sure to use slices for the following because slices are ordered.
// they later used to create a Genesis so, having them ordered is important to
// be able to produce a deterministic Genesis.

GenesisAccounts []GenesisAccount
VestingAccounts []VestingAccount
GenesisValidators []GenesisValidator
}

// GenesisAccount represents an account with initial coin allocation for the chain for the chain genesis
Expand Down Expand Up @@ -77,45 +81,72 @@ func NewGenesisInformation(
vestingAccs []VestingAccount,
genVals []GenesisValidator,
) (gi GenesisInformation) {
return GenesisInformation{
GenesisAccounts: genAccs,
VestingAccounts: vestingAccs,
GenesisValidators: genVals,
}
}

// convert account arrays into maps
gi.GenesisAccounts = make(map[string]GenesisAccount)
for _, genAcc := range genAccs {
gi.GenesisAccounts[genAcc.Address] = genAcc
func (gi GenesisInformation) ContainsGenesisAccount(address string) bool {
for _, account := range gi.GenesisAccounts {
if account.Address == address {
return true
}
}
gi.VestingAccounts = make(map[string]VestingAccount)
for _, vestingAcc := range vestingAccs {
gi.VestingAccounts[vestingAcc.Address] = vestingAcc
return false
}
func (gi GenesisInformation) ContainsVestingAccount(address string) bool {
for _, account := range gi.VestingAccounts {
if account.Address == address {
return true
}
}
gi.GenesisValidators = make(map[string]GenesisValidator)
for _, genVal := range genVals {
gi.GenesisValidators[genVal.Address] = genVal
return false
}
func (gi GenesisInformation) ContainsGenesisValidator(address string) bool {
for _, account := range gi.GenesisValidators {
if account.Address == address {
return true
}
}
return gi
return false
}

// GetGenesisAccounts converts into array and returns genesis accounts
func (gi GenesisInformation) GetGenesisAccounts() (accs []GenesisAccount) {
for _, genAcc := range gi.GenesisAccounts {
accs = append(accs, genAcc)
func (gi *GenesisInformation) AddGenesisAccount(acc GenesisAccount) {
gi.GenesisAccounts = append(gi.GenesisAccounts, acc)
}

func (gi *GenesisInformation) AddVestingAccount(acc VestingAccount) {
gi.VestingAccounts = append(gi.VestingAccounts, acc)
}

func (gi *GenesisInformation) AddGenesisValidator(val GenesisValidator) {
gi.GenesisValidators = append(gi.GenesisValidators, val)
}

func (gi *GenesisInformation) RemoveGenesisAccount(address string) {
for i, account := range gi.GenesisAccounts {
if account.Address == address {
gi.GenesisAccounts = append(gi.GenesisAccounts[:i], gi.GenesisAccounts[i+1:]...)
}
}
return accs
}

// GetVestingAccounts converts into array and returns vesting accounts
func (gi GenesisInformation) GetVestingAccounts() (accs []VestingAccount) {
for _, vestingAcc := range gi.VestingAccounts {
accs = append(accs, vestingAcc)
func (gi *GenesisInformation) RemoveVestingAccount(address string) {
for i, account := range gi.VestingAccounts {
if account.Address == address {
gi.VestingAccounts = append(gi.VestingAccounts[:i], gi.VestingAccounts[i+1:]...)
}
}
return accs
}

// GetGenesisValidators converts into array and returns genesis validators
func (gi GenesisInformation) GetGenesisValidators() (vals []GenesisValidator) {
for _, genVal := range gi.GenesisValidators {
vals = append(vals, genVal)
func (gi *GenesisInformation) RemoveGenesisValidator(address string) {
for i, account := range gi.GenesisValidators {
if account.Address == address {
gi.GenesisValidators = append(gi.GenesisValidators[:i], gi.GenesisValidators[i+1:]...)
}
}
return vals
}

// ApplyRequest applies to the genesisInformation the changes implied by the approval of a request
Expand All @@ -124,12 +155,12 @@ func (gi GenesisInformation) ApplyRequest(request launchtypes.Request) (GenesisI
case *launchtypes.RequestContent_GenesisAccount:
// new genesis account in the genesis
ga := ToGenesisAccount(*requestContent.GenesisAccount)
_, genExist := gi.GenesisAccounts[ga.Address]
_, vestingExist := gi.VestingAccounts[ga.Address]
genExist := gi.ContainsGenesisAccount(ga.Address)
vestingExist := gi.ContainsVestingAccount(ga.Address)
if genExist || vestingExist {
return gi, NewWrappedErrInvalidRequest(request.RequestID, "genesis account already in genesis")
}
gi.GenesisAccounts[ga.Address] = ga
gi.AddGenesisAccount(ga)

case *launchtypes.RequestContent_VestingAccount:
// new vesting account in the genesis
Expand All @@ -141,36 +172,36 @@ func (gi GenesisInformation) ApplyRequest(request launchtypes.Request) (GenesisI
return gi, err
}

_, genExist := gi.GenesisAccounts[va.Address]
_, vestingExist := gi.VestingAccounts[va.Address]
genExist := gi.ContainsGenesisAccount(va.Address)
vestingExist := gi.ContainsVestingAccount(va.Address)
if genExist || vestingExist {
return gi, NewWrappedErrInvalidRequest(request.RequestID, "vesting account already in genesis")
}
gi.VestingAccounts[va.Address] = va
gi.AddVestingAccount(va)

case *launchtypes.RequestContent_AccountRemoval:
// account removed from the genesis
ar := requestContent.AccountRemoval
_, genExist := gi.GenesisAccounts[ar.Address]
_, vestingExist := gi.VestingAccounts[ar.Address]
genExist := gi.ContainsGenesisAccount(ar.Address)
vestingExist := gi.ContainsVestingAccount(ar.Address)
if !genExist && !vestingExist {
return gi, NewWrappedErrInvalidRequest(request.RequestID, "account can't be removed because it doesn't exist")
}
delete(gi.GenesisAccounts, ar.Address)
delete(gi.VestingAccounts, ar.Address)
gi.RemoveGenesisAccount(ar.Address)
gi.RemoveVestingAccount(ar.Address)

case *launchtypes.RequestContent_GenesisValidator:
// new genesis validator in the genesis
gv := ToGenesisValidator(*requestContent.GenesisValidator)
if _, ok := gi.GenesisValidators[gv.Address]; ok {
if gi.ContainsGenesisValidator(gv.Address) {
return gi, NewWrappedErrInvalidRequest(request.RequestID, "genesis validator already in genesis")
}
gi.GenesisValidators[gv.Address] = gv
gi.AddGenesisValidator(gv)

case *launchtypes.RequestContent_ValidatorRemoval:
// validator removed from the genesis
vr := requestContent.ValidatorRemoval
if _, ok := gi.GenesisValidators[vr.ValAddress]; !ok {
if !gi.ContainsGenesisValidator(vr.ValAddress) {
return gi, NewWrappedErrInvalidRequest(request.RequestID, "genesis validator can't be removed because it doesn't exist")
}
}
Expand Down
36 changes: 21 additions & 15 deletions starport/services/network/networktypes/genesisinformation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,32 +314,38 @@ func TestGenesisInformation_ApplyRequest(t *testing.T) {
switch rc := tt.r.Content.Content.(type) {
case *launchtypes.RequestContent_GenesisAccount:
ga := networktypes.ToGenesisAccount(*rc.GenesisAccount)
got, ok := newGi.GenesisAccounts[ga.Address]
require.True(t, ok)
require.EqualValues(t, ga, got)
require.True(t, newGi.ContainsGenesisAccount(ga.Address))
for _, account := range newGi.GenesisAccounts {
if account.Address == ga.Address {
require.EqualValues(t, ga, account)
}
}

case *launchtypes.RequestContent_VestingAccount:
va, err := networktypes.ToVestingAccount(*rc.VestingAccount)
require.NoError(t, err)
got, ok := newGi.VestingAccounts[va.Address]
require.True(t, ok)
require.EqualValues(t, va, got)
require.True(t, newGi.ContainsVestingAccount(va.Address))
for _, account := range newGi.VestingAccounts {
if account.Address == va.Address {
require.EqualValues(t, va, account)
}
}

case *launchtypes.RequestContent_AccountRemoval:
_, ok := newGi.GenesisAccounts[rc.AccountRemoval.Address]
require.False(t, ok)
_, ok = newGi.VestingAccounts[rc.AccountRemoval.Address]
require.False(t, ok)
require.False(t, newGi.ContainsGenesisAccount(rc.AccountRemoval.Address))
require.False(t, newGi.ContainsVestingAccount(rc.AccountRemoval.Address))

case *launchtypes.RequestContent_GenesisValidator:
gv := networktypes.ToGenesisValidator(*rc.GenesisValidator)
got, ok := newGi.GenesisValidators[gv.Address]
require.True(t, ok)
require.EqualValues(t, gv, got)
require.True(t, newGi.ContainsGenesisValidator(gv.Address))
for _, val := range newGi.GenesisValidators {
if val.Address == gv.Address {
require.EqualValues(t, gv, val)
}
}

case *launchtypes.RequestContent_ValidatorRemoval:
_, ok := newGi.GenesisAccounts[rc.ValidatorRemoval.ValAddress]
require.False(t, ok)
require.False(t, newGi.ContainsGenesisAccount(rc.ValidatorRemoval.ValAddress))
}
})
}
Expand Down

0 comments on commit 193c080

Please sign in to comment.