2017-01-28 09:29:32 -08:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2017-05-22 04:10:25 -07:00
|
|
|
"bytes"
|
2017-01-28 09:29:32 -08:00
|
|
|
"encoding/json"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2017-05-13 17:04:53 -07:00
|
|
|
|
2017-03-14 00:11:49 -07:00
|
|
|
"github.com/tendermint/basecoin/types"
|
2017-05-22 04:10:25 -07:00
|
|
|
crypto "github.com/tendermint/go-crypto"
|
|
|
|
"github.com/tendermint/go-wire/data"
|
2017-04-25 22:08:31 -07:00
|
|
|
cmn "github.com/tendermint/tmlibs/common"
|
2017-01-28 09:29:32 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
func (app *Basecoin) LoadGenesis(path string) error {
|
2017-03-14 10:55:46 -07:00
|
|
|
genDoc, err := loadGenesis(path)
|
2017-01-28 09:29:32 -08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-03-14 00:11:49 -07:00
|
|
|
|
2017-03-14 10:55:46 -07:00
|
|
|
// set chain_id
|
|
|
|
app.SetOption("base/chain_id", genDoc.ChainID)
|
|
|
|
|
|
|
|
// set accounts
|
|
|
|
for _, acc := range genDoc.AppOptions.Accounts {
|
2017-03-14 00:11:49 -07:00
|
|
|
accBytes, err := json.Marshal(acc)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r := app.SetOption("base/account", string(accBytes))
|
|
|
|
// TODO: SetOption returns an error
|
2017-05-01 07:03:54 -07:00
|
|
|
app.logger.Info("Done setting Account via SetOption", "result", r)
|
2017-03-14 10:55:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// set plugin options
|
|
|
|
for _, kv := range genDoc.AppOptions.pluginOptions {
|
|
|
|
r := app.SetOption(kv.Key, kv.Value)
|
2017-05-01 07:03:54 -07:00
|
|
|
app.logger.Info("Done setting Plugin key-value pair via SetOption", "result", r, "k", kv.Key, "v", kv.Value)
|
2017-01-28 09:29:32 -08:00
|
|
|
}
|
2017-06-05 05:11:46 -07:00
|
|
|
|
2017-01-28 09:29:32 -08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type keyValue struct {
|
|
|
|
Key string `json:"key"`
|
|
|
|
Value string `json:"value"`
|
|
|
|
}
|
|
|
|
|
2017-03-14 00:11:49 -07:00
|
|
|
// includes tendermint (in the json, we ignore here)
|
|
|
|
type FullGenesisDoc struct {
|
2017-03-14 10:55:46 -07:00
|
|
|
ChainID string `json:"chain_id"`
|
2017-03-14 00:11:49 -07:00
|
|
|
AppOptions *GenesisDoc `json:"app_options"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type GenesisDoc struct {
|
2017-05-22 04:10:25 -07:00
|
|
|
Accounts []GenesisAccount `json:"accounts"`
|
2017-03-14 10:55:46 -07:00
|
|
|
PluginOptions []json.RawMessage `json:"plugin_options"`
|
|
|
|
|
|
|
|
pluginOptions []keyValue // unmarshaled rawmessages
|
2017-03-14 00:11:49 -07:00
|
|
|
}
|
|
|
|
|
2017-03-14 10:55:46 -07:00
|
|
|
func loadGenesis(filePath string) (*FullGenesisDoc, error) {
|
2017-01-28 09:29:32 -08:00
|
|
|
bytes, err := cmn.ReadFile(filePath)
|
|
|
|
if err != nil {
|
2017-03-14 10:55:46 -07:00
|
|
|
return nil, errors.Wrap(err, "loading genesis file")
|
2017-01-28 09:29:32 -08:00
|
|
|
}
|
2017-03-14 00:11:49 -07:00
|
|
|
|
2017-04-25 22:08:31 -07:00
|
|
|
// the basecoin genesis go-wire/data :)
|
2017-03-14 10:55:46 -07:00
|
|
|
genDoc := new(FullGenesisDoc)
|
|
|
|
err = json.Unmarshal(bytes, genDoc)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "unmarshaling genesis file")
|
|
|
|
}
|
|
|
|
|
2017-06-05 05:11:46 -07:00
|
|
|
if genDoc.AppOptions == nil {
|
|
|
|
genDoc.AppOptions = new(GenesisDoc)
|
|
|
|
}
|
|
|
|
|
2017-03-14 10:55:46 -07:00
|
|
|
pluginOpts, err := parseGenesisList(genDoc.AppOptions.PluginOptions)
|
2017-01-28 09:29:32 -08:00
|
|
|
if err != nil {
|
2017-03-14 10:55:46 -07:00
|
|
|
return nil, err
|
2017-01-28 09:29:32 -08:00
|
|
|
}
|
2017-03-14 10:55:46 -07:00
|
|
|
genDoc.AppOptions.pluginOptions = pluginOpts
|
|
|
|
return genDoc, nil
|
2017-03-14 00:11:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseGenesisList(kvz_ []json.RawMessage) (kvz []keyValue, err error) {
|
2017-01-28 09:29:32 -08:00
|
|
|
if len(kvz_)%2 != 0 {
|
|
|
|
return nil, errors.New("genesis cannot have an odd number of items. Format = [key1, value1, key2, value2, ...]")
|
|
|
|
}
|
2017-02-24 14:25:48 -08:00
|
|
|
|
2017-01-28 09:29:32 -08:00
|
|
|
for i := 0; i < len(kvz_); i += 2 {
|
2017-02-24 14:25:48 -08:00
|
|
|
kv := keyValue{}
|
|
|
|
rawK := []byte(kvz_[i])
|
|
|
|
err := json.Unmarshal(rawK, &(kv.Key))
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Errorf("Non-string key: %s", string(rawK))
|
2017-01-28 09:29:32 -08:00
|
|
|
}
|
2017-02-24 14:25:48 -08:00
|
|
|
// convert value to string if possible (otherwise raw json)
|
|
|
|
rawV := kvz_[i+1]
|
|
|
|
err = json.Unmarshal(rawV, &(kv.Value))
|
|
|
|
if err != nil {
|
|
|
|
kv.Value = string(rawV)
|
2017-01-28 09:29:32 -08:00
|
|
|
}
|
2017-02-24 14:25:48 -08:00
|
|
|
kvz = append(kvz, kv)
|
2017-01-28 09:29:32 -08:00
|
|
|
}
|
|
|
|
return kvz, nil
|
|
|
|
}
|
2017-05-22 04:10:25 -07:00
|
|
|
|
|
|
|
/**** code to parse accounts from genesis docs ***/
|
|
|
|
|
|
|
|
type GenesisAccount struct {
|
|
|
|
Address data.Bytes `json:"address"`
|
|
|
|
// this from types.Account (don't know how to embed this properly)
|
|
|
|
PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known.
|
|
|
|
Sequence int `json:"sequence"`
|
|
|
|
Balance types.Coins `json:"coins"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g GenesisAccount) ToAccount() *types.Account {
|
|
|
|
return &types.Account{
|
|
|
|
PubKey: g.PubKey,
|
|
|
|
Sequence: g.Sequence,
|
|
|
|
Balance: g.Balance,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g GenesisAccount) GetAddr() ([]byte, error) {
|
|
|
|
noAddr, noPk := len(g.Address) == 0, g.PubKey.Empty()
|
|
|
|
|
|
|
|
if noAddr {
|
|
|
|
if noPk {
|
|
|
|
return nil, errors.New("No address given")
|
|
|
|
}
|
|
|
|
return g.PubKey.Address(), nil
|
|
|
|
}
|
|
|
|
if noPk { // but is addr...
|
|
|
|
return g.Address, nil
|
|
|
|
}
|
|
|
|
// now, we have both, make sure they check out
|
|
|
|
if bytes.Equal(g.Address, g.PubKey.Address()) {
|
|
|
|
return g.Address, nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("Address and pubkey don't match")
|
|
|
|
}
|