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 feb989e commit b75323a
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 27 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"
}
12 changes: 6 additions & 6 deletions docs/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b75323a

Please sign in to comment.