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 8077e39be4..f0381977e0 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -22,16 +22,16 @@ Please switch into the folder where you have the initialisation files. If you in these instructions. :: - tendermint init --home ~/.ethermint/tendermint - - cd $GOPATH/src/github.com/tendermint/ethermint - - ethermint --datadir ~/.ethermint init setup/genesis.json - - cp -r setup/keystore ~/.ethermint -In the last step we copy the private key from the initialisation folder into the actual ethereum folder. + ethermint --datadir ~/.ethermint init + +* Note: +You can optionally copy a keystore to the Ethereum folder that you used in the steps above i.e `~/.ethermint` e.g + +:: + cp -r keystore ~/.ethermint + Run Ethermint -------------