Skip to content

Commit

Permalink
cmd/ethermint: use default Genesis when necessary
Browse files Browse the repository at this point in the history
Fixes cosmos#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
```
  • Loading branch information
odeke-em committed Aug 24, 2017
1 parent ac865eb commit af9948b
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 29 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
61 changes: 45 additions & 16 deletions cmd/ethermint/init.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"encoding/json"
"os"
"path/filepath"

Expand All @@ -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)
}
Expand All @@ -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"
}
}
`,
}
66 changes: 66 additions & 0 deletions cmd/utils/parse.go
Original file line number Diff line number Diff line change
@@ -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
}
72 changes: 72 additions & 0 deletions cmd/utils/parse_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
Empty file.
8 changes: 8 additions & 0 deletions cmd/utils/testdata/genesis1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"difficulty": "0x40",
"gasLimit": "0x8000000",
"alloc": {
"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc": { "balance": "10000000000000000000000000000000000" },
"0xc6713982649D9284ff56c32655a9ECcCDA78422A": { "balance": "10000000000000000000000000000000000" }
}
}
4 changes: 4 additions & 0 deletions cmd/utils/testdata/non-genesis.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"tendermint": true,
"introduction": "https://tendermint.com"
}
16 changes: 8 additions & 8 deletions docs/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------------
Expand Down

0 comments on commit af9948b

Please sign in to comment.