Skip to content

Commit

Permalink
Merge PR cosmos#2275: genesis: Ensure there are no duplicate accounts…
Browse files Browse the repository at this point in the history
… in genesis file

This also contains a light refactor of genesis state parsing, so that
the tests file didn't duplicate a lot of this code.
  • Loading branch information
ValarDragon authored and cwgoes committed Sep 8, 2018
1 parent 4448d17 commit 1a70020
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 28 deletions.
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ IMPROVEMENTS
* [x/auth] Signature verification's gas cost now accounts for pubkey type. [#2046](https://github.com/tendermint/tendermint/pull/2046)
* [x/stake] [x/slashing] Ensure delegation invariants to jailed validators [#1883](https://github.com/cosmos/cosmos-sdk/issues/1883).
* [x/stake] Improve speed of GetValidator, which was shown to be a performance bottleneck. [#2046](https://github.com/tendermint/tendermint/pull/2200)
* [genesis] \#2229 Ensure that there are no duplicate accounts in the genesis state.
* SDK
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
* [spec] Added simple piggy bank distribution spec
Expand Down
5 changes: 5 additions & 0 deletions cmd/gaia/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.StakeData)

gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
err = GaiaValidateGenesisState(genesisState)
if err != nil {
// TODO find a way to do this w/o panics
panic(err)
}

return abci.ResponseInitChain{
Validators: validators,
Expand Down
90 changes: 62 additions & 28 deletions cmd/gaia/app/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,38 +180,12 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
}

// create the genesis account, give'm few steaks and a buncha token with there name
accAuth := auth.NewBaseAccountWithAddress(genTx.Address)
accAuth.Coins = sdk.Coins{
{genTx.Name + "Token", sdk.NewInt(1000)},
{"steak", freeFermionsAcc},
}
acc := NewGenesisAccount(&accAuth)
genaccs[i] = acc
genaccs[i] = genesisAccountFromGenTx(genTx)
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply

// add the validator
if len(genTx.Name) > 0 {
desc := stake.NewDescription(genTx.Name, "", "", "")
validator := stake.NewValidator(
sdk.ValAddress(genTx.Address), sdk.MustGetConsPubKeyBech32(genTx.PubKey), desc,
)

stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply

// add some new shares to the validator
var issuedDelShares sdk.Dec
validator, stakeData.Pool, issuedDelShares = validator.AddTokensFromDel(stakeData.Pool, sdk.NewInt(freeFermionVal))
stakeData.Validators = append(stakeData.Validators, validator)

// create the self-delegation from the issuedDelShares
delegation := stake.Delegation{
DelegatorAddr: sdk.AccAddress(validator.OperatorAddr),
ValidatorAddr: validator.OperatorAddr,
Shares: issuedDelShares,
Height: 0,
}

stakeData.Bonds = append(stakeData.Bonds, delegation)
stakeData = addValidatorToStakeData(genTx, stakeData)
}
}

Expand All @@ -224,6 +198,66 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
return
}

func addValidatorToStakeData(genTx GaiaGenTx, stakeData stake.GenesisState) stake.GenesisState {
desc := stake.NewDescription(genTx.Name, "", "", "")
validator := stake.NewValidator(
sdk.ValAddress(genTx.Address), sdk.MustGetConsPubKeyBech32(genTx.PubKey), desc,
)

stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply

// add some new shares to the validator
var issuedDelShares sdk.Dec
validator, stakeData.Pool, issuedDelShares = validator.AddTokensFromDel(stakeData.Pool, sdk.NewInt(freeFermionVal))
stakeData.Validators = append(stakeData.Validators, validator)

// create the self-delegation from the issuedDelShares
delegation := stake.Delegation{
DelegatorAddr: sdk.AccAddress(validator.OperatorAddr),
ValidatorAddr: validator.OperatorAddr,
Shares: issuedDelShares,
Height: 0,
}

stakeData.Bonds = append(stakeData.Bonds, delegation)
return stakeData
}

func genesisAccountFromGenTx(genTx GaiaGenTx) GenesisAccount {
accAuth := auth.NewBaseAccountWithAddress(genTx.Address)
accAuth.Coins = sdk.Coins{
{genTx.Name + "Token", sdk.NewInt(1000)},
{"steak", freeFermionsAcc},
}
return NewGenesisAccount(&accAuth)
}

// GaiaValidateGenesisState ensures that the genesis state obeys the expected invariants
// TODO: No validators are both bonded and revoked (#2088)
// TODO: Error if there is a duplicate validator (#1708)
// TODO: Ensure all state machine parameters are in genesis (#1704)
func GaiaValidateGenesisState(genesisState GenesisState) (err error) {
err = validateGenesisStateAccounts(genesisState.Accounts)
if err != nil {
return
}
return
}

// Ensures that there are no duplicate accounts in the genesis state,
func validateGenesisStateAccounts(accs []GenesisAccount) (err error) {
addrMap := make(map[string]bool, len(accs))
for i := 0; i < len(accs); i++ {
acc := accs[i]
strAddr := string(acc.Address)
if _, ok := addrMap[strAddr]; ok {
return fmt.Errorf("Duplicate account in genesis state: Address %v", acc.Address)
}
addrMap[strAddr] = true
}
return
}

// GaiaAppGenState but with JSON
func GaiaAppGenStateJSON(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {

Expand Down
39 changes: 39 additions & 0 deletions cmd/gaia/app/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,36 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov"
stake "github.com/cosmos/cosmos-sdk/x/stake"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
)

func makeGenesisState(genTxs []GaiaGenTx) GenesisState {
// start with the default staking genesis state
stakeData := stake.DefaultGenesisState()

// get genesis flag account information
genaccs := make([]GenesisAccount, len(genTxs))
for i, genTx := range genTxs {
genaccs[i] = genesisAccountFromGenTx(genTx)
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply

// add the validator
if len(genTx.Name) > 0 {
stakeData = addValidatorToStakeData(genTx, stakeData)
}
}

// create the final app state
return GenesisState{
Accounts: genaccs,
StakeData: stakeData,
GovData: gov.DefaultGenesisState(),
}
}

func TestToAccount(t *testing.T) {
priv := ed25519.GenPrivKey()
addr := sdk.AccAddress(priv.PubKey().Address())
Expand All @@ -34,3 +60,16 @@ func TestGaiaAppGenState(t *testing.T) {
// TODO test with both one and two genesis transactions:
// TODO correct: genesis account created, canididates created, pool token variance
}

func TestGaiaGenesisValidation(t *testing.T) {
genTxs := make([]GaiaGenTx, 2)
privKey := ed25519.GenPrivKey()
pubKey := privKey.PubKey()
addr := pubKey.Address()
// Test duplicate accounts fails
genTxs[0] = GaiaGenTx{"", sdk.AccAddress(addr), ""}
genTxs[1] = GaiaGenTx{"", sdk.AccAddress(addr), ""}
genesisState := makeGenesisState(genTxs)
err := GaiaValidateGenesisState(genesisState)
require.NotNil(t, err)
}

0 comments on commit 1a70020

Please sign in to comment.