2018-04-25 21:27:40 -07:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2018-08-01 12:15:37 -07:00
|
|
|
"fmt"
|
2018-10-19 11:00:27 -07:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-09-13 11:17:32 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
2018-04-25 21:27:40 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/server"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
2018-09-18 21:42:05 -07:00
|
|
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
2018-08-20 03:47:04 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
2018-10-19 11:36:00 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
2018-08-31 02:03:43 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
2018-04-25 21:27:40 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
2018-08-01 12:15:37 -07:00
|
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
2018-04-25 21:27:40 -07:00
|
|
|
)
|
|
|
|
|
2018-06-13 17:30:16 -07:00
|
|
|
var (
|
|
|
|
// bonded tokens given to genesis validators/accounts
|
2018-06-26 19:00:12 -07:00
|
|
|
freeFermionVal = int64(100)
|
2018-10-19 11:00:27 -07:00
|
|
|
freeFermionsAcc = sdk.NewInt(150)
|
2018-06-13 17:30:16 -07:00
|
|
|
)
|
|
|
|
|
2018-04-25 21:27:40 -07:00
|
|
|
// State to Unmarshal
|
|
|
|
type GenesisState struct {
|
2018-08-31 02:03:43 -07:00
|
|
|
Accounts []GenesisAccount `json:"accounts"`
|
|
|
|
StakeData stake.GenesisState `json:"stake"`
|
2018-10-19 11:36:00 -07:00
|
|
|
MintData mint.GenesisState `json:"mint"`
|
2018-10-14 23:43:36 -07:00
|
|
|
DistrData distr.GenesisState `json:"distr"`
|
2018-08-31 02:03:43 -07:00
|
|
|
GovData gov.GenesisState `json:"gov"`
|
|
|
|
SlashingData slashing.GenesisState `json:"slashing"`
|
2018-10-19 11:00:27 -07:00
|
|
|
GenTxs []json.RawMessage `json:"gentxs"`
|
2018-04-25 21:27:40 -07:00
|
|
|
}
|
|
|
|
|
2018-10-19 11:36:00 -07:00
|
|
|
func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mintData mint.GenesisState,
|
|
|
|
distrData distr.GenesisState, govData gov.GenesisState, slashingData slashing.GenesisState) GenesisState {
|
|
|
|
|
|
|
|
return GenesisState{
|
|
|
|
Accounts: accounts,
|
|
|
|
StakeData: stakeData,
|
|
|
|
MintData: mintData,
|
|
|
|
DistrData: distrData,
|
|
|
|
GovData: govData,
|
|
|
|
SlashingData: slashingData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 21:27:40 -07:00
|
|
|
// GenesisAccount doesn't need pubkey or sequence
|
|
|
|
type GenesisAccount struct {
|
2018-07-06 00:06:53 -07:00
|
|
|
Address sdk.AccAddress `json:"address"`
|
|
|
|
Coins sdk.Coins `json:"coins"`
|
2018-04-25 21:27:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
|
|
|
return GenesisAccount{
|
2018-07-09 01:47:38 -07:00
|
|
|
Address: acc.Address,
|
2018-04-25 21:27:40 -07:00
|
|
|
Coins: acc.Coins,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-23 19:26:54 -07:00
|
|
|
func NewGenesisAccountI(acc auth.Account) GenesisAccount {
|
2018-04-27 17:00:33 -07:00
|
|
|
return GenesisAccount{
|
2018-07-09 01:47:38 -07:00
|
|
|
Address: acc.GetAddress(),
|
2018-04-27 17:00:33 -07:00
|
|
|
Coins: acc.GetCoins(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 21:27:40 -07:00
|
|
|
// convert GenesisAccount to auth.BaseAccount
|
|
|
|
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
|
|
|
|
return &auth.BaseAccount{
|
2018-07-09 01:47:38 -07:00
|
|
|
Address: ga.Address,
|
2018-04-25 21:27:40 -07:00
|
|
|
Coins: ga.Coins.Sort(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get app init parameters for server init command
|
|
|
|
func GaiaAppInit() server.AppInit {
|
|
|
|
|
|
|
|
return server.AppInit{
|
2018-10-19 11:00:27 -07:00
|
|
|
AppGenState: GaiaAppGenStateJSON,
|
2018-04-25 21:27:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the core parameters for genesis initialization for gaia
|
|
|
|
// note that the pubkey input is this machines pubkey
|
2018-09-13 11:17:32 -07:00
|
|
|
func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisState GenesisState, err error) {
|
2018-04-25 21:27:40 -07:00
|
|
|
if len(appGenTxs) == 0 {
|
|
|
|
err = errors.New("must provide at least genesis transaction")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// start with the default staking genesis state
|
2018-04-30 23:07:06 -07:00
|
|
|
stakeData := stake.DefaultGenesisState()
|
2018-09-10 04:59:05 -07:00
|
|
|
slashingData := slashing.DefaultGenesisState()
|
2018-08-31 02:03:43 -07:00
|
|
|
|
2018-04-25 21:27:40 -07:00
|
|
|
// get genesis flag account information
|
|
|
|
genaccs := make([]GenesisAccount, len(appGenTxs))
|
|
|
|
|
2018-10-19 11:00:27 -07:00
|
|
|
for i, genTx := range appGenTxs {
|
|
|
|
var tx auth.StdTx
|
|
|
|
err = cdc.UnmarshalJSON(genTx, &tx)
|
2018-04-25 21:27:40 -07:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-10-19 11:00:27 -07:00
|
|
|
msgs := tx.GetMsgs()
|
|
|
|
if len(msgs) != 1 {
|
|
|
|
err = errors.New("must provide genesis StdTx with exactly 1 CreateValidator message")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
msg := msgs[0].(stake.MsgCreateValidator)
|
2018-04-25 21:27:40 -07:00
|
|
|
|
2018-04-30 16:24:46 -07:00
|
|
|
// create the genesis account, give'm few steaks and a buncha token with there name
|
2018-10-19 11:00:27 -07:00
|
|
|
genaccs[i] = genesisAccountFromMsgCreateValidator(msg, freeFermionsAcc)
|
2018-08-27 15:18:18 -07:00
|
|
|
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
2018-04-25 21:27:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// create the final app state
|
2018-05-25 07:17:49 -07:00
|
|
|
genesisState = GenesisState{
|
2018-08-31 02:03:43 -07:00
|
|
|
Accounts: genaccs,
|
|
|
|
StakeData: stakeData,
|
2018-10-19 11:36:00 -07:00
|
|
|
MintData: mint.DefaultGenesisState(),
|
2018-10-14 23:43:36 -07:00
|
|
|
DistrData: distr.DefaultGenesisState(),
|
2018-08-31 02:03:43 -07:00
|
|
|
GovData: gov.DefaultGenesisState(),
|
|
|
|
SlashingData: slashingData,
|
2018-10-19 11:00:27 -07:00
|
|
|
GenTxs: appGenTxs,
|
2018-04-25 21:27:40 -07:00
|
|
|
}
|
2018-10-07 09:57:52 -07:00
|
|
|
|
2018-05-25 07:17:49 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-10-19 11:00:27 -07:00
|
|
|
func genesisAccountFromMsgCreateValidator(msg stake.MsgCreateValidator, amount sdk.Int) GenesisAccount {
|
|
|
|
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddr))
|
|
|
|
accAuth.Coins = []sdk.Coin{
|
|
|
|
{msg.Description.Moniker + "Token", sdk.NewInt(1000)},
|
|
|
|
{"steak", amount},
|
2018-09-08 02:29:34 -07:00
|
|
|
}
|
|
|
|
return NewGenesisAccount(&accAuth)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GaiaValidateGenesisState ensures that the genesis state obeys the expected invariants
|
2018-09-14 11:52:23 -07:00
|
|
|
// TODO: No validators are both bonded and jailed (#2088)
|
2018-09-08 02:29:34 -07:00
|
|
|
// 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
|
|
|
|
}
|
2018-10-19 11:00:27 -07:00
|
|
|
// skip stakeData validation as genesis is created from txs
|
|
|
|
if len(genesisState.GenTxs) > 0 {
|
|
|
|
return nil
|
2018-09-09 08:23:51 -07:00
|
|
|
}
|
2018-10-19 11:00:27 -07:00
|
|
|
return stake.ValidateGenesis(genesisState.StakeData)
|
2018-09-09 08:23:51 -07:00
|
|
|
}
|
|
|
|
|
2018-09-08 02:29:34 -07:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2018-05-25 07:17:49 -07:00
|
|
|
// GaiaAppGenState but with JSON
|
2018-09-13 11:17:32 -07:00
|
|
|
func GaiaAppGenStateJSON(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
2018-05-25 07:17:49 -07:00
|
|
|
// create the final app state
|
|
|
|
genesisState, err := GaiaAppGenState(cdc, appGenTxs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-09-13 11:17:32 -07:00
|
|
|
appState, err = codec.MarshalJSONIndent(cdc, genesisState)
|
2018-04-25 21:27:40 -07:00
|
|
|
return
|
|
|
|
}
|
2018-10-19 11:00:27 -07:00
|
|
|
|
|
|
|
// CollectStdTxs processes and validates application's genesis StdTxs and returns the list of validators,
|
|
|
|
// appGenTxs, and persistent peers required to generate genesis.json.
|
|
|
|
func CollectStdTxs(moniker string, genTxsDir string, cdc *codec.Codec) (
|
|
|
|
validators []tmtypes.GenesisValidator, appGenTxs []auth.StdTx, persistentPeers string, err error) {
|
|
|
|
var fos []os.FileInfo
|
|
|
|
fos, err = ioutil.ReadDir(genTxsDir)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var addresses []string
|
|
|
|
for _, fo := range fos {
|
|
|
|
filename := filepath.Join(genTxsDir, fo.Name())
|
|
|
|
if !fo.IsDir() && (filepath.Ext(filename) != ".json") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the genStdTx
|
|
|
|
var jsonRawTx []byte
|
|
|
|
jsonRawTx, err = ioutil.ReadFile(filename)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var genStdTx auth.StdTx
|
|
|
|
err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
appGenTxs = append(appGenTxs, genStdTx)
|
|
|
|
|
|
|
|
nodeAddr := genStdTx.GetMemo()
|
|
|
|
if len(nodeAddr) == 0 {
|
|
|
|
err = fmt.Errorf("couldn't find node's address in %s", fo.Name())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
msgs := genStdTx.GetMsgs()
|
|
|
|
if len(msgs) != 1 {
|
|
|
|
err = errors.New("each genesis transaction must provide a single genesis message")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: this could be decoupled from stake.MsgCreateValidator
|
|
|
|
// TODO: and we likely want to do it for real world Gaia
|
|
|
|
msg := msgs[0].(stake.MsgCreateValidator)
|
|
|
|
validators = append(validators, tmtypes.GenesisValidator{
|
|
|
|
PubKey: msg.PubKey,
|
|
|
|
Power: freeFermionVal,
|
|
|
|
Name: msg.Description.Moniker,
|
|
|
|
})
|
|
|
|
|
|
|
|
// exclude itself from persistent peers
|
|
|
|
if msg.Description.Moniker != moniker {
|
|
|
|
addresses = append(addresses, nodeAddr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(addresses)
|
|
|
|
persistentPeers = strings.Join(addresses, ",")
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
|
|
|
|
accAuth := auth.NewBaseAccountWithAddress(addr)
|
|
|
|
accAuth.Coins = []sdk.Coin{
|
|
|
|
{"fooToken", sdk.NewInt(1000)},
|
|
|
|
{"steak", freeFermionsAcc},
|
|
|
|
}
|
|
|
|
return NewGenesisAccount(&accAuth)
|
|
|
|
}
|