From 1e308c8dfa5102e23819dba7a02ebed478248233 Mon Sep 17 00:00:00 2001 From: Edwin Date: Fri, 11 Aug 2017 13:42:47 +0800 Subject: [PATCH] core: make a tool to generate test configuration --- core/cluster.go | 166 +++++++++++++++++++++++++++++++++++++++++++ core/cluster_test.go | 34 +++++++++ core/genesis.go | 71 ++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 core/cluster.go create mode 100644 core/cluster_test.go create mode 100644 core/genesis.go diff --git a/core/cluster.go b/core/cluster.go new file mode 100644 index 00000000..6f6e3663 --- /dev/null +++ b/core/cluster.go @@ -0,0 +1,166 @@ +// Copyright 2017 AMIS Technologies +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package core + +import ( + "crypto/ecdsa" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net" + "os" + "path/filepath" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/satori/go.uuid" +) + +const ( + defaultBaseRpcPort = uint16(8545) + defaultHttpPort = uint16(30303) + + defaultLocalDir = "/tmp/gdata" + datadirPrivateKey = "nodekey" + defaultIP = "localhost" + + clientIdentifier = "geth" + staticNodeJson = "static-nodes.json" + genesisJson = "genesis.json" +) + +func GenerateClusterKeys(numbers int) []*ecdsa.PrivateKey { + keys := make([]*ecdsa.PrivateKey, numbers) + for i := 0; i < len(keys); i++ { + key, err := crypto.GenerateKey() + if err != nil { + panic("couldn't generate key: " + err.Error()) + } + keys[i] = key + } + return keys +} + +type Env struct { + GethID int + HttpPort uint16 + RpcPort uint16 + DataDir string + Key *ecdsa.PrivateKey +} + +func SetupEnv(prvKeys []*ecdsa.PrivateKey) []*Env { + envs := make([]*Env, len(prvKeys)) + rpcPort := defaultBaseRpcPort + httpPort := defaultHttpPort + + for i := 0; i < len(envs); i++ { + dataDir, err := saveNodeKey(prvKeys[i]) + if err != nil { + panic("Failed to save node key") + } + + envs[i] = &Env{ + GethID: i, + HttpPort: httpPort, + RpcPort: rpcPort, + DataDir: dataDir, + Key: prvKeys[i], + } + + rpcPort = rpcPort + 1 + httpPort = httpPort + 1 + } + return envs +} + +func SetupNodes(envs []*Env) error { + nodes := transformToStaticNodes(envs) + for _, env := range envs { + if err := saveStaticNode(env.DataDir, nodes); err != nil { + return err + } + } + + addrs := transformToAddress(envs) + genesis := GenerateGenesis(addrs) + for _, env := range envs { + if err := saveGenesis(env.DataDir, genesis); err != nil { + return err + } + } + return nil +} + +func saveNodeKey(key *ecdsa.PrivateKey) (string, error) { + err := os.MkdirAll(filepath.Join(defaultLocalDir), 0700) + if err != nil { + log.Fatal(err) + } + + instanceDir := filepath.Join(defaultLocalDir, fmt.Sprintf("%s%s", clientIdentifier, uuid.NewV4().String())) + if err := os.MkdirAll(instanceDir, 0700); err != nil { + log.Println(fmt.Sprintf("Failed to create instance dir: %v", err)) + return "", err + } + + keyDir := filepath.Join(instanceDir, clientIdentifier) + if err := os.MkdirAll(keyDir, 0700); err != nil { + log.Println(fmt.Sprintf("Failed to create key dir: %v", err)) + return "", err + } + + keyfile := filepath.Join(keyDir, datadirPrivateKey) + if err := crypto.SaveECDSA(keyfile, key); err != nil { + log.Println(fmt.Sprintf("Failed to persist node key: %v", err)) + return "", err + } + return instanceDir, nil +} + +func saveStaticNode(dataDir string, nodes []*discover.Node) error { + filePath := filepath.Join(dataDir, clientIdentifier) + keyPath := filepath.Join(filePath, staticNodeJson) + + raw, err := json.Marshal(nodes) + if err != nil { + return err + } + + return ioutil.WriteFile(keyPath, raw, 0600) +} + +func transformToStaticNodes(envs []*Env) []*discover.Node { + nodes := make([]*discover.Node, len(envs)) + + for i, env := range envs { + nodeID := discover.PubkeyID(&env.Key.PublicKey) + nodes[i] = discover.NewNode(nodeID, net.ParseIP(defaultIP), 0, env.HttpPort) + } + return nodes +} + +func transformToAddress(envs []*Env) []common.Address { + addrs := make([]common.Address, len(envs)) + + for i, env := range envs { + addrs[i] = crypto.PubkeyToAddress(env.Key.PublicKey) + } + return addrs +} diff --git a/core/cluster_test.go b/core/cluster_test.go new file mode 100644 index 00000000..f5088101 --- /dev/null +++ b/core/cluster_test.go @@ -0,0 +1,34 @@ +// Copyright 2017 AMIS Technologies +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package core + +import ( + "fmt" + "testing" +) + +func TestWriteFile(t *testing.T) { + keys := GenerateClusterKeys(4) + envs := SetupEnv(keys) + err := SetupNodes(envs) + if err != nil { + t.Fatal("failed to setup nodes", err) + } + for _, env := range envs { + fmt.Println(fmt.Sprintf("%s%d%s%s", "geth ID:", env.GethID, ", dataDir:", env.DataDir)) + } +} diff --git a/core/genesis.go b/core/genesis.go new file mode 100644 index 00000000..4a9cdf9e --- /dev/null +++ b/core/genesis.go @@ -0,0 +1,71 @@ +// Copyright 2017 AMIS Technologies +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package core + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "math/big" + "path/filepath" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/istanbul" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/getamis/istanbul-tools/cmd/istanbul/extradata" +) + +func GenerateGenesis(addrs []common.Address) *core.Genesis { + extraData, err := extradata.Encode("0x00", addrs) + if err != nil { + panic(fmt.Sprintf("%s%s", "Failed to generate genesis", err)) + } + + return &core.Genesis{ + Timestamp: uint64(time.Now().Unix()), + GasLimit: 4700000, + Difficulty: big.NewInt(1), + Alloc: make(core.GenesisAlloc), + Config: ¶ms.ChainConfig{ + HomesteadBlock: big.NewInt(1), + EIP150Block: big.NewInt(2), + EIP155Block: big.NewInt(3), + EIP158Block: big.NewInt(3), + Istanbul: ¶ms.IstanbulConfig{ + ProposerPolicy: uint64(istanbul.DefaultConfig.ProposerPolicy), + Epoch: istanbul.DefaultConfig.Epoch, + }, + }, + Mixhash: types.IstanbulDigest, + ExtraData: hexutil.MustDecode(extraData), + } +} + +func saveGenesis(dataDir string, genesis *core.Genesis) error { + filePath := filepath.Join(dataDir, genesisJson) + + raw, err := json.Marshal(genesis) + if err != nil { + return err + } + + return ioutil.WriteFile(filePath, raw, 0600) +}