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

fix(network): genesis account ordering #2095

Merged
merged 7 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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