diff --git a/app/app.go b/app/app.go index 7b903a5b9..2107dc17e 100644 --- a/app/app.go +++ b/app/app.go @@ -1,6 +1,7 @@ package app import ( + "encoding/hex" "encoding/json" "strings" @@ -77,14 +78,18 @@ func (app *Basecoin) SetOption(key string, value string) string { app.state.SetChainID(value) return "Success" case "account": - var acc types.Account + var acc GenesisAccount err := json.Unmarshal([]byte(value), &acc) if err != nil { return "Error decoding acc message: " + err.Error() } acc.Balance.Sort() - app.state.SetAccount(acc.PubKey.Address(), &acc) - app.logger.Info("SetAccount", "addr", acc.PubKey.Address(), "acc", acc) + addr, err := acc.GetAddr() + if err != nil { + return "Invalid address: " + err.Error() + } + app.state.SetAccount(addr, acc.ToAccount()) + app.logger.Info("SetAccount", "addr", hex.EncodeToString(addr), "acc", acc) return "Success" } diff --git a/app/genesis.go b/app/genesis.go index f1c36914f..fa6a5ac30 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -1,11 +1,14 @@ package app import ( + "bytes" "encoding/json" "github.com/pkg/errors" "github.com/tendermint/basecoin/types" + crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/go-wire/data" cmn "github.com/tendermint/tmlibs/common" ) @@ -49,7 +52,7 @@ type FullGenesisDoc struct { } type GenesisDoc struct { - Accounts []types.Account `json:"accounts"` + Accounts []GenesisAccount `json:"accounts"` PluginOptions []json.RawMessage `json:"plugin_options"` pluginOptions []keyValue // unmarshaled rawmessages @@ -98,3 +101,40 @@ func parseGenesisList(kvz_ []json.RawMessage) (kvz []keyValue, err error) { } return kvz, nil } + +/**** 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") +} diff --git a/app/genesis_test.go b/app/genesis_test.go index 186bb231f..b2a590bcf 100644 --- a/app/genesis_test.go +++ b/app/genesis_test.go @@ -7,12 +7,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/basecoin/types" "github.com/tendermint/go-crypto" eyescli "github.com/tendermint/merkleeyes/client" cmn "github.com/tendermint/tmlibs/common" ) const genesisFilepath = "./testdata/genesis.json" +const genesisAcctFilepath = "./testdata/genesis2.json" func TestLoadGenesis(t *testing.T) { assert, require := assert.New(t), require.New(t) @@ -50,6 +52,51 @@ func TestLoadGenesis(t *testing.T) { } } +// Fix for issue #89, change the parse format for accounts in genesis.json +func TestLoadGenesisAccountAddress(t *testing.T) { + assert, require := assert.New(t), require.New(t) + + eyesCli := eyescli.NewLocalClient("", 0) + app := NewBasecoin(eyesCli) + err := app.LoadGenesis(genesisAcctFilepath) + require.Nil(err, "%+v", err) + + // check the chain id + assert.Equal("addr_accounts_chain", app.GetState().GetChainID()) + + // make sure the accounts were set properly + cases := []struct { + addr string + exists bool + hasPubkey bool + coins types.Coins + }{ + // this comes from a public key, should be stored proper (alice) + {"62035D628DE7543332544AA60D90D3693B6AD51B", true, true, types.Coins{{"one", 111}}}, + // this comes from an address, should be stored proper (bob) + {"C471FB670E44D219EE6DF2FC284BE38793ACBCE1", true, false, types.Coins{{"two", 222}}}, + // this one had a mismatched address and pubkey, should not store under either (carl) + {"1234ABCDD18E8EFE3FFC4B0506BF9BF8E5B0D9E9", false, false, nil}, // this is given addr + {"700BEC5ED18E8EFE3FFC4B0506BF9BF8E5B0D9E9", false, false, nil}, // this is addr of the given pubkey + // this comes from a secp256k1 public key, should be stored proper (sam) + {"979F080B1DD046C452C2A8A250D18646C6B669D4", true, true, types.Coins{{"four", 444}}}, + } + + for _, tc := range cases { + addr, err := hex.DecodeString(tc.addr) + require.Nil(err, tc.addr) + acct := app.GetState().GetAccount(addr) + if !tc.exists { + assert.Nil(acct, tc.addr) + } else if assert.NotNil(acct, tc.addr) { + // it should and does exist... + assert.True(acct.Balance.IsValid()) + assert.Equal(tc.coins, acct.Balance) + assert.Equal(!tc.hasPubkey, acct.PubKey.Empty(), tc.addr) + } + } +} + func TestParseGenesisList(t *testing.T) { assert, require := assert.New(t), require.New(t) diff --git a/app/testdata/genesis2.json b/app/testdata/genesis2.json new file mode 100644 index 000000000..a880b3c64 --- /dev/null +++ b/app/testdata/genesis2.json @@ -0,0 +1,52 @@ +{ + "chain_id": "addr_accounts_chain", + "app_options": { + "accounts": [{ + "name": "alice", + "pub_key": { + "type": "ed25519", + "data": "DBD9A46C45868F0A37C92B53113C09B048FBD87B5FBC2F8B199052973B8FAA36" + }, + "coins": [ + { + "denom": "one", + "amount": 111 + } + ] + }, { + "name": "bob", + "address": "C471FB670E44D219EE6DF2FC284BE38793ACBCE1", + "coins": [ + { + "denom": "two", + "amount": 222 + } + ] + }, { + "name": "carl", + "address": "1234ABCDD18E8EFE3FFC4B0506BF9BF8E5B0D9E9", + "pub_key": { + "type": "ed25519", + "data": "177C0AC45E86257F0708DC085D592AB22AAEECD1D26381B757F7C96135921858" + }, + "coins": [ + { + "denom": "three", + "amount": 333 + } + ] + }, { + "name": "sam", + "pub_key": { + "type": "secp256k1", + "data": "02AA8342F63CCCCE6DDB128525BA048CE0B2993DA3B4308746E1F216361A87651E" + }, + "coins": [ + { + "denom": "four", + "amount": 444 + } + ] + }] + } +}