From 193c080a59e1a7fd397e8feff90935f9e7e400c7 Mon Sep 17 00:00:00 2001 From: Petr Ivanov Date: Thu, 17 Feb 2022 20:47:27 +0300 Subject: [PATCH] fix(network): genesis account ordering (#2095) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 Co-authored-by: İlker G. Öztürk --- .../services/network/networkchain/prepare.go | 12 +- .../networktypes/genesisinformation.go | 115 +++++++++++------- .../networktypes/genesisinformation_test.go | 36 +++--- 3 files changed, 103 insertions(+), 60 deletions(-) diff --git a/starport/services/network/networkchain/prepare.go b/starport/services/network/networkchain/prepare.go index 59098296fe..7cc44dbde3 100644 --- a/starport/services/network/networkchain/prepare.go +++ b/starport/services/network/networkchain/prepare.go @@ -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") } @@ -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 { diff --git a/starport/services/network/networktypes/genesisinformation.go b/starport/services/network/networktypes/genesisinformation.go index d7755a7a9f..35bbcb7783 100644 --- a/starport/services/network/networktypes/genesisinformation.go +++ b/starport/services/network/networktypes/genesisinformation.go @@ -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 @@ -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 @@ -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 @@ -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") } } diff --git a/starport/services/network/networktypes/genesisinformation_test.go b/starport/services/network/networktypes/genesisinformation_test.go index 79eeb19a6c..c9743f9444 100644 --- a/starport/services/network/networktypes/genesisinformation_test.go +++ b/starport/services/network/networktypes/genesisinformation_test.go @@ -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)) } }) }