From b75323a51a28d3976b51aa18953cbe661ab71114 Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Mon, 14 Aug 2017 15:21:22 -0600 Subject: [PATCH] cmd/ethermint: use default Genesis when necessary Fixes https://github.com/tendermint/ethermint/issues/244 Act like `tendermint init` so that if we don't have a genesis-path, and also move to $HOME/.ethermint/keystore, the files that are currently contained in $GOPATH/src/github.com/tendermint/ethermint/setup/keystore Therefore now `ethermint init` should be one step e.g ```shell $ ethermint --datadir ~/.ethermint init ``` instead of the formerly tedious ```shell $ cd $GOPATH/src/github.com/tendermint/ethermint $ ethermint --datadir ~/.ethermint init setup/genesis.json $ cp -r setup/keystore ~/.ethermint ``` --- README.md | 11 ++-- cmd/ethermint/init.go | 61 +++++++++++++++++------ cmd/utils/parse.go | 66 ++++++++++++++++++++++++ cmd/utils/parse_test.go | 72 +++++++++++++++++++++++++++ cmd/utils/testdata/blank-genesis.json | 0 cmd/utils/testdata/genesis1.json | 8 +++ cmd/utils/testdata/non-genesis.json | 4 ++ docs/getting-started.rst | 12 ++--- 8 files changed, 207 insertions(+), 27 deletions(-) create mode 100644 cmd/utils/parse.go create mode 100644 cmd/utils/parse_test.go create mode 100644 cmd/utils/testdata/blank-genesis.json create mode 100644 cmd/utils/testdata/genesis1.json create mode 100644 cmd/utils/testdata/non-genesis.json diff --git a/README.md b/README.md index 31ef5401f2..54e3e31a27 100644 --- a/README.md +++ b/README.md @@ -106,13 +106,14 @@ these instructions. ```bash tendermint init --home ~/.ethermint/tendermint -cd $GOPATH/src/github.com/tendermint/ethermint - -ethermint --datadir ~/.ethermint init setup/genesis.json +ethermint --datadir ~/.ethermint init +``` -cp -r setup/keystore ~/.ethermint +* Note: +You can optionally copy a keystore to the Ethereum folder that you used in the steps above i.e `~/.ethermint` e.g +```bash +cp -r keystore ~/.ethermint ``` -In the last step we copy the private key from the initialisation folder into the actual ethereum folder. ### Running diff --git a/cmd/ethermint/init.go b/cmd/ethermint/init.go index 519588cdaa..10b738aaf8 100644 --- a/cmd/ethermint/init.go +++ b/cmd/ethermint/init.go @@ -1,7 +1,6 @@ package main import ( - "encoding/json" "os" "path/filepath" @@ -17,25 +16,14 @@ import ( // nolint: vetshadow func initCmd(ctx *cli.Context) error { - - // ethereum genesis.json genesisPath := ctx.Args().First() - if len(genesisPath) == 0 { - ethUtils.Fatalf("must supply path to genesis JSON file") - } - - file, err := os.Open(genesisPath) + genesis, err := emtUtils.ParseGenesisOrDefault(genesisPath) if err != nil { - ethUtils.Fatalf("Failed to read genesis file: %v", err) + ethUtils.Fatalf("genesisJSON err: %v", err) } - defer file.Close() // nolint: errcheck - genesis := new(core.Genesis) - if err := json.NewDecoder(file).Decode(genesis); err != nil { - ethUtils.Fatalf("invalid genesis file: %v", err) - } - - chainDb, err := ethdb.NewLDBDatabase(filepath.Join(emtUtils.MakeDataDir(ctx), "ethermint/chaindata"), 0, 0) + ethermintDataDir := emtUtils.MakeDataDir(ctx) + chainDb, err := ethdb.NewLDBDatabase(filepath.Join(ethermintDataDir, "ethermint/chaindata"), 0, 0) if err != nil { ethUtils.Fatalf("could not open database: %v", err) } @@ -46,5 +34,46 @@ func initCmd(ctx *cli.Context) error { } log.Info("successfully wrote genesis block and/or chain rule set", "hash", hash) + + // As per https://github.com/tendermint/ethermint/issues/244#issuecomment-322024199 + // Let's implicitly add in the respective keystore files + // to avoid manually doing this step: + // $ cp -r $GOPATH/src/github.com/tendermint/ethermint/setup/keystore $(DATADIR) + keystoreDir := filepath.Join(ethermintDataDir, "keystore") + if err := os.MkdirAll(keystoreDir, 0777); err != nil { + ethUtils.Fatalf("mkdirAll keyStoreDir: %v", err) + } + + for filename, content := range keystoreFilesMap { + storeFileName := filepath.Join(keystoreDir, filename) + f, err := os.Create(storeFileName) + if err != nil { + log.Error("create %q err: %v", storeFileName, err) + continue + } + if _, err := f.Write([]byte(content)); err != nil { + log.Error("write content %q err: %v", storeFileName, err) + } + f.Close() + } + return nil } + +var keystoreFilesMap = map[string]string{ + // https://github.com/tendermint/ethermint/blob/edc95f9d47ba1fb7c8161182533b5f5d5c5d619b/setup/keystore/UTC--2016-10-21T22-30-03.071787745Z--7eff122b94897ea5b0e2a9abf47b86337fafebdc + // OR + // $GOPATH/src/github.com/ethermint/setup/keystore/UTC--2016-10-21T22-30-03.071787745Z--7eff122b94897ea5b0e2a9abf47b86337fafebdc + "UTC--2016-10-21T22-30-03.071787745Z--7eff122b94897ea5b0e2a9abf47b86337fafebdc": ` +{ + "address":"7eff122b94897ea5b0e2a9abf47b86337fafebdc", + "id":"f86a62b4-0621-4616-99af-c4b7f38fcc48","version":3, + "crypto":{ + "cipher":"aes-128-ctr","ciphertext":"19de8a919e2f4cbdde2b7352ebd0be8ead2c87db35fc8e4c9acaf74aaaa57dad", + "cipherparams":{"iv":"ba2bd370d6c9d5845e92fbc6f951c792"}, + "kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c7cc2380a96adc9eb31d20bd8d8a7827199e8b16889582c0b9089da6a9f58e84"}, + "mac":"ff2c0caf051ca15d8c43b6f321ec10bd99bd654ddcf12dd1a28f730cc3c13730" + } +} +`, +} diff --git a/cmd/utils/parse.go b/cmd/utils/parse.go new file mode 100644 index 0000000000..e96ccd5c38 --- /dev/null +++ b/cmd/utils/parse.go @@ -0,0 +1,66 @@ +package utils + +import ( + "encoding/json" + "errors" + "io/ioutil" + "os" + "reflect" + + "github.com/ethereum/go-ethereum/core" +) + +// defaultGenesisBlob is the JSON representation of the default +// genesis file in $GOPATH/src/github.com/tendermint/ethermint/setup/genesis.json +var defaultGenesisBlob = []byte(` +{ + "config": { + "chainId": 15, + "homesteadBlock": 0, + "eip155Block": 0, + "eip158Block": 0 + }, + "nonce": "0xdeadbeefdeadbeef", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x40", + "gasLimit": "0x8000000", + "alloc": { + "0x7eff122b94897ea5b0e2a9abf47b86337fafebdc": { "balance": "10000000000000000000000000000000000" }, + "0xc6713982649D9284ff56c32655a9ECcCDA78422A": { "balance": "10000000000000000000000000000000000" } + } +}`) + +var blankGenesis = new(core.Genesis) + +var errBlankGenesis = errors.New("could not parse a valid/non-blank Genesis") + +// ParseGenesisOrDefault tries to read the content from provided +// genesisPath. If the path is empty or doesn't exist, it will +// use defaultGenesisBytes as the fallback genesis source. Otherwise, +// it will open that path and if it encounters an error that doesn't +// satisfy os.IsNotExist, it returns that error. +func ParseGenesisOrDefault(genesisPath string) (*core.Genesis, error) { + var genesisBlob = defaultGenesisBlob[:] + if len(genesisPath) > 0 { + blob, err := ioutil.ReadFile(genesisPath) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + if len(blob) >= 2 { // Expecting atleast "{}" + genesisBlob = blob + } + } + + genesis := new(core.Genesis) + if err := json.Unmarshal(genesisBlob, genesis); err != nil { + return nil, err + } + + if reflect.DeepEqual(blankGenesis, genesis) { + return nil, errBlankGenesis + } + + return genesis, nil +} diff --git a/cmd/utils/parse_test.go b/cmd/utils/parse_test.go new file mode 100644 index 0000000000..c5abc4bf11 --- /dev/null +++ b/cmd/utils/parse_test.go @@ -0,0 +1,72 @@ +package utils + +import ( + "encoding/json" + "fmt" + "log" + "math/big" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" + + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" +) + +var defaultGenesis *core.Genesis = func() *core.Genesis { + g := new(core.Genesis) + if err := json.Unmarshal(defaultGenesisBlob, g); err != nil { + log.Fatalf("parsing defaultGenesis: %v", err) + } + return g +}() + +func bigString(s string) *big.Int { + b, _ := big.NewInt(0).SetString(s, 10) + return b +} + +var genesis1 = &core.Genesis{ + Difficulty: big.NewInt(0x40), + GasLimit: 0x8000000, + Alloc: core.GenesisAlloc{ + ethCommon.HexToAddress("0x7eff122b94897ea5b0e2a9abf47b86337fafebdc"): { + Balance: bigString("10000000000000000000000000000000000"), + }, + ethCommon.HexToAddress("0xc6713982649D9284ff56c32655a9ECcCDA78422A"): { + Balance: bigString("10000000000000000000000000000000000"), + }, + }, +} + +func TestParseGenesisOrDefault(t *testing.T) { + tests := [...]struct { + path string + want *core.Genesis + wantErr bool + }{ + 0: {path: "", want: defaultGenesis}, + 1: {want: defaultGenesis}, + 2: {path: fmt.Sprintf("non-existent-%d", rand.Int()), want: defaultGenesis}, + 3: {path: "./testdata/blank-genesis.json", want: defaultGenesis}, + 4: {path: "./testdata/genesis1.json", want: genesis1}, + 5: {path: "./testdata/non-genesis.json", wantErr: true}, + } + + for i, tt := range tests { + gen, err := ParseGenesisOrDefault(tt.path) + if tt.wantErr { + assert.NotNil(t, err, "#%d: cannot be nil", i) + continue + } + + if err != nil { + t.Errorf("#%d: path=%q unexpected error: %v", i, tt.path, err) + continue + } + + assert.NotEqual(t, blankGenesis, gen, true, "#%d: expecting a non-blank", i) + assert.Equal(t, gen, tt.want, "#%d: expected them to be the same", i) + } +} diff --git a/cmd/utils/testdata/blank-genesis.json b/cmd/utils/testdata/blank-genesis.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cmd/utils/testdata/genesis1.json b/cmd/utils/testdata/genesis1.json new file mode 100644 index 0000000000..080218f041 --- /dev/null +++ b/cmd/utils/testdata/genesis1.json @@ -0,0 +1,8 @@ +{ + "difficulty": "0x40", + "gasLimit": "0x8000000", + "alloc": { + "0x7eff122b94897ea5b0e2a9abf47b86337fafebdc": { "balance": "10000000000000000000000000000000000" }, + "0xc6713982649D9284ff56c32655a9ECcCDA78422A": { "balance": "10000000000000000000000000000000000" } + } +} diff --git a/cmd/utils/testdata/non-genesis.json b/cmd/utils/testdata/non-genesis.json new file mode 100644 index 0000000000..ce005204d4 --- /dev/null +++ b/cmd/utils/testdata/non-genesis.json @@ -0,0 +1,4 @@ +{ + "tendermint": true, + "introduction": "https://tendermint.com" +} diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 6ff2c5ef84..4d96f7587d 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -14,18 +14,18 @@ You can choose where to store the ethermint files with `--datadir`. For this gui Before you can run ethermint you need to initialise tendermint and ethermint with their respective genesis states. Please switch into the folder where you have the initialisation files. If you installed from source you can just follow these instructions. - ```bash tendermint init --home ~/.ethermint/tendermint -cd $GOPATH/src/github.com/tendermint/ethermint - -ethermint --datadir ~/.ethermint init setup/genesis.json +ethermint --datadir ~/.ethermint init +``` -cp -r setup/keystore ~/.ethermint +* Note: +You can optionally copy a keystore to the Ethereum folder that you used in the steps above i.e `~/.ethermint` e.g +```bash +cp -r keystore ~/.ethermint ``` -In the last step we copy the private key from the initialisation folder into the actual ethereum folder. ### Running To execute ethermint we need to start two processes. The first one is for tendermint, which handles the P2P