From a5e020c4fec6fb69d4bda099110f9c4f4d3a9731 Mon Sep 17 00:00:00 2001 From: Alan Chen Date: Thu, 17 Aug 2017 18:04:35 +0800 Subject: [PATCH] container, core, tests: add blockchain struct for testing and refactoring --- container/blockchain.go | 135 ++++++++++ .../blockchain_test.go | 34 ++- container/ethereum.go | 58 +++-- container/ethereum_test.go | 63 ++--- container/options.go | 50 +++- container/utils.go | 64 +++++ core/cluster.go | 233 ------------------ genesis/genesis.go | 75 ++++++ tests/integration_test.go | 64 ++--- 9 files changed, 422 insertions(+), 354 deletions(-) create mode 100644 container/blockchain.go rename core/cluster_test.go => container/blockchain_test.go (63%) create mode 100644 container/utils.go delete mode 100644 core/cluster.go create mode 100644 genesis/genesis.go diff --git a/container/blockchain.go b/container/blockchain.go new file mode 100644 index 00000000..22199cae --- /dev/null +++ b/container/blockchain.go @@ -0,0 +1,135 @@ +// 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 container + +import ( + "crypto/ecdsa" + "log" + "os" + "path/filepath" + + "github.com/docker/docker/client" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/phayes/freeport" + + "github.com/getamis/istanbul-tools/genesis" +) + +type Blockchain interface { + Start() error + Stop() error + Validators() []Ethereum + Finalize() +} + +func NewBlockchain(numOfValidators int, options ...Option) (bc *blockchain) { + var keys []*ecdsa.PrivateKey + var addrs []common.Address + + bc = &blockchain{} + + for i := 0; i < numOfValidators; i++ { + key, err := crypto.GenerateKey() + if err != nil { + log.Fatalf("couldn't generate key: " + err.Error()) + } + keys = append(keys, key) + + addr := crypto.PubkeyToAddress(key.PublicKey) + addrs = append(addrs, addr) + } + + setupDir, err := generateRandomDir() + if err != nil { + log.Fatal("Failed to create setup dir", err) + } + err = genesis.Save(setupDir, genesis.New(addrs)) + if err != nil { + log.Fatal("Failed to save genesis", err) + } + bc.genesisFile = filepath.Join(setupDir, genesis.FileName) + + dockerClient, err := client.NewEnvClient() + if err != nil { + log.Fatalf("Cannot connect to Docker daemon, err: %v", err) + } + + for i := 0; i < numOfValidators; i++ { + opts := make([]Option, len(options)) + copy(opts, options) + + // Host data directory + dataDir, err := generateRandomDir() + if err != nil { + log.Fatal("Failed to create data dir", err) + } + opts = append(opts, HostDataDir(dataDir)) + opts = append(opts, HostPort(freeport.GetPort())) + opts = append(opts, HostWebSocketPort(freeport.GetPort())) + opts = append(opts, Key(keys[i])) + + geth := NewEthereum( + dockerClient, + opts..., + ) + + err = geth.Init(bc.genesisFile) + if err != nil { + log.Fatal("Failed to init genesis", err) + } + + bc.validators = append(bc.validators, geth) + } + + return bc +} + +// ---------------------------------------------------------------------------- + +type blockchain struct { + genesisFile string + validators []Ethereum +} + +func (bc *blockchain) Start() error { + for _, v := range bc.validators { + if err := v.Start(); err != nil { + return err + } + } + + return nil +} + +func (bc *blockchain) Stop() error { + for _, v := range bc.validators { + if err := v.Stop(); err != nil { + return err + } + } + + return nil +} + +func (bc *blockchain) Finalize() { + os.RemoveAll(filepath.Dir(bc.genesisFile)) +} + +func (bc *blockchain) Validators() []Ethereum { + return bc.validators +} diff --git a/core/cluster_test.go b/container/blockchain_test.go similarity index 63% rename from core/cluster_test.go rename to container/blockchain_test.go index ffb1cea4..fe800017 100644 --- a/core/cluster_test.go +++ b/container/blockchain_test.go @@ -14,21 +14,37 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +package container import ( - "fmt" "testing" + "time" ) -func TestWriteFile(t *testing.T) { - envs := SetupEnv(4) - err := SetupNodes(envs, NewGenesis(envs)) +func TestEthereumBlockchain(t *testing.T) { + chain := NewBlockchain( + 4, + ImageRepository("quay.io/amis/geth"), + ImageTag("istanbul_develop"), + DataDir("/data"), + WebSocket(), + WebSocketAddress("0.0.0.0"), + WebSocketAPI("eth,net,web3,personal"), + WebSocketOrigin("*"), + NoDiscover(), + Logging(true), + ) + defer chain.Finalize() + + err := chain.Start() if err != nil { - t.Fatal("failed to setup nodes", err) + t.Error(err) } - defer Teardown(envs) - for _, env := range envs { - fmt.Println(fmt.Sprintf("%s%d%s%s", "geth ID:", env.GethID, ", dataDir:", env.DataDir)) + + time.Sleep(5 * time.Second) + + err = chain.Stop() + if err != nil { + t.Error(err) } } diff --git a/container/ethereum.go b/container/ethereum.go index 495cffd8..3f90b02a 100644 --- a/container/ethereum.go +++ b/container/ethereum.go @@ -18,7 +18,9 @@ package container import ( "context" + "crypto/ecdsa" "errors" + "fmt" "io" "io/ioutil" "log" @@ -32,9 +34,10 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" - "github.com/getamis/go-ethereum/cmd/utils" - "github.com/getamis/go-ethereum/ethclient" - "github.com/getamis/istanbul-tools/core" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/ethclient" + + "github.com/getamis/istanbul-tools/genesis" ) const ( @@ -86,7 +89,6 @@ func NewEthereum(c *client.Client, options ...Option) *ethereum { type ethereum struct { ok bool flags []string - hostDataDir string dataDir string port string rpcPort string @@ -97,26 +99,35 @@ type ethereum struct { imageRepository string imageTag string + key *ecdsa.PrivateKey logging bool client *client.Client } func (eth *ethereum) Init(genesisFile string) error { + if err := saveNodeKey(eth.key, eth.dataDir); err != nil { + log.Fatal("Failed to save nodekey", err) + return err + } + + binds := []string{ + genesisFile + ":" + filepath.Join("/", genesis.FileName), + } + if eth.dataDir != "" { + binds = append(binds, eth.dataDir+":"+utils.DataDirFlag.Value.Value) + } resp, err := eth.client.ContainerCreate(context.Background(), &container.Config{ Image: eth.Image(), Cmd: []string{ "init", "--" + utils.DataDirFlag.Name, - eth.dataDir, - filepath.Join("/", core.GenesisFile), + utils.DataDirFlag.Value.Value, + filepath.Join("/", genesis.FileName), }, }, &container.HostConfig{ - Binds: []string{ - genesisFile + ":" + filepath.Join("/", core.GenesisFile), - eth.hostDataDir + ":" + eth.dataDir, - }, + Binds: binds, }, nil, "") if err != nil { log.Printf("Failed to create container, err: %v", err) @@ -158,8 +169,9 @@ func (eth *ethereum) Start() error { portBindings := nat.PortMap{} if eth.port != "" { - exposedPorts[nat.Port(eth.port)] = struct{}{} - portBindings[nat.Port(eth.port)] = []nat.PortBinding{ + port := fmt.Sprintf("%d", utils.ListenPortFlag.Value) + exposedPorts[nat.Port(port)] = struct{}{} + portBindings[nat.Port(port)] = []nat.PortBinding{ { HostIP: "0.0.0.0", HostPort: eth.port, @@ -168,8 +180,9 @@ func (eth *ethereum) Start() error { } if eth.rpcPort != "" { - exposedPorts[nat.Port(eth.rpcPort)] = struct{}{} - portBindings[nat.Port(eth.rpcPort)] = []nat.PortBinding{ + port := fmt.Sprintf("%d", utils.RPCPortFlag.Value) + exposedPorts[nat.Port(port)] = struct{}{} + portBindings[nat.Port(port)] = []nat.PortBinding{ { HostIP: "0.0.0.0", HostPort: eth.rpcPort, @@ -178,8 +191,9 @@ func (eth *ethereum) Start() error { } if eth.wsPort != "" { - exposedPorts[nat.Port(eth.wsPort)] = struct{}{} - portBindings[nat.Port(eth.wsPort)] = []nat.PortBinding{ + port := fmt.Sprintf("%d", utils.WSPortFlag.Value) + exposedPorts[nat.Port(port)] = struct{}{} + portBindings[nat.Port(port)] = []nat.PortBinding{ { HostIP: "0.0.0.0", HostPort: eth.wsPort, @@ -187,6 +201,11 @@ func (eth *ethereum) Start() error { } } + binds := []string{} + if eth.dataDir != "" { + binds = append(binds, eth.dataDir+":"+utils.DataDirFlag.Value.Value) + } + resp, err := eth.client.ContainerCreate(context.Background(), &container.Config{ Hostname: "geth-" + eth.hostName, @@ -195,9 +214,7 @@ func (eth *ethereum) Start() error { ExposedPorts: exposedPorts, }, &container.HostConfig{ - Binds: []string{ - eth.hostDataDir + ":" + eth.dataDir, - }, + Binds: binds, PortBindings: portBindings, }, nil, "") if err != nil { @@ -247,6 +264,8 @@ func (eth *ethereum) Stop() error { return err } + os.RemoveAll(eth.dataDir) + return eth.client.ContainerRemove(context.Background(), eth.containerID, types.ContainerRemoveOptions{ Force: true, @@ -289,7 +308,6 @@ func (eth *ethereum) NewClient() *ethclient.Client { } client, err := ethclient.Dial(scheme + eth.Host() + ":" + port) if err != nil { - log.Printf("Failed to dial to geth, err: %v", err) return nil } return client diff --git a/container/ethereum_test.go b/container/ethereum_test.go index f40c2396..f9ebad3c 100644 --- a/container/ethereum_test.go +++ b/container/ethereum_test.go @@ -17,54 +17,43 @@ package container import ( - "fmt" - "path/filepath" "testing" - "github.com/getamis/istanbul-tools/core" + "github.com/docker/docker/client" + "github.com/phayes/freeport" ) func TestEthereumContainer(t *testing.T) { - envs := core.SetupEnv(1) - defer core.Teardown(envs) - err := core.SetupNodes(envs, core.NewGenesis(envs)) + dockerClient, err := client.NewEnvClient() if err != nil { t.Error(err) } - for _, env := range envs { - geth := NewEthereum( - env.Client, - ImageRepository("quay.io/amis/geth"), - ImageTag("istanbul_develop"), - HostDataDir(env.DataDir), - DataDir("/data"), - Port(fmt.Sprintf("%d", env.P2PPort)), - WebSocket(), - WebSocketAddress("0.0.0.0"), - WebSocketAPI("eth,net,web3,personal"), - WebSocketPort(fmt.Sprintf("%d", env.RpcPort)), - WebSocketOrigin("*"), - NoDiscover(), - ) + geth := NewEthereum( + dockerClient, + ImageRepository("quay.io/amis/geth"), + ImageTag("istanbul_develop"), + DataDir("/data"), + HostPort(freeport.GetPort()), + WebSocket(), + WebSocketAddress("0.0.0.0"), + WebSocketAPI("eth,net,web3,personal"), + HostWebSocketPort(freeport.GetPort()), + WebSocketOrigin("*"), + NoDiscover(), + ) - err := geth.Init(filepath.Join(env.DataDir, core.GenesisFile)) - if err != nil { - t.Error(err) - } + err = geth.Start() + if err != nil { + t.Error(err) + } - err = geth.Start() - if err != nil { - t.Error(err) - } + if !geth.Running() { + t.Error("geth should be running") + } - if !geth.Running() { - t.Error("geth should be running") - } - - err = geth.Stop() - if err != nil { - t.Error(err) - } + err = geth.Stop() + if err != nil { + t.Error(err) } } diff --git a/container/options.go b/container/options.go index c2c97c23..c62a3804 100644 --- a/container/options.go +++ b/container/options.go @@ -17,6 +17,7 @@ package container import ( + "crypto/ecdsa" "fmt" "github.com/getamis/go-ethereum/cmd/utils" @@ -44,7 +45,25 @@ func HostName(hostName string) Option { func HostDataDir(path string) Option { return func(eth *ethereum) { - eth.hostDataDir = path + eth.dataDir = path + } +} + +func HostPort(port int) Option { + return func(eth *ethereum) { + eth.port = fmt.Sprintf("%d", port) + } +} + +func HostRPCPort(port int) Option { + return func(eth *ethereum) { + eth.rpcPort = fmt.Sprintf("%d", port) + } +} + +func HostWebSocketPort(port int) Option { + return func(eth *ethereum) { + eth.wsPort = fmt.Sprintf("%d", port) } } @@ -56,11 +75,20 @@ func Logging(enabled bool) Option { // ---------------------------------------------------------------------------- +func Key(key *ecdsa.PrivateKey) Option { + return func(eth *ethereum) { + eth.key = key + } +} + func DataDir(dir string) Option { return func(eth *ethereum) { + utils.DataDirFlag.Value = utils.DirectoryString{ + Value: dir, + } eth.flags = append(eth.flags, "--"+utils.DataDirFlag.Name) eth.flags = append(eth.flags, dir) - eth.dataDir = dir + } } @@ -133,11 +161,11 @@ func NoDiscover() Option { } } -func Port(port string) Option { +func Port(port int) Option { return func(eth *ethereum) { + utils.ListenPortFlag.Value = port eth.flags = append(eth.flags, "--"+utils.ListenPortFlag.Name) - eth.flags = append(eth.flags, port) - eth.port = port + eth.flags = append(eth.flags, fmt.Sprintf("%d", port)) } } @@ -161,11 +189,11 @@ func RPCAPI(apis string) Option { } } -func RPCPort(port string) Option { +func RPCPort(port int) Option { return func(eth *ethereum) { + utils.RPCPortFlag.Value = port eth.flags = append(eth.flags, "--"+utils.RPCPortFlag.Name) - eth.flags = append(eth.flags, port) - eth.rpcPort = port + eth.flags = append(eth.flags, fmt.Sprintf("%d", port)) } } @@ -189,11 +217,11 @@ func WebSocketAPI(apis string) Option { } } -func WebSocketPort(port string) Option { +func WebSocketPort(port int) Option { return func(eth *ethereum) { + utils.WSPortFlag.Value = port eth.flags = append(eth.flags, "--"+utils.WSPortFlag.Name) - eth.flags = append(eth.flags, port) - eth.wsPort = port + eth.flags = append(eth.flags, fmt.Sprintf("%d", port)) } } diff --git a/container/utils.go b/container/utils.go new file mode 100644 index 00000000..883671bc --- /dev/null +++ b/container/utils.go @@ -0,0 +1,64 @@ +// 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 container + +import ( + "crypto/ecdsa" + "fmt" + "log" + "os" + "path/filepath" + + "github.com/getamis/go-ethereum/crypto" + uuid "github.com/satori/go.uuid" +) + +const ( + defaultLocalDir = "/tmp/gdata" + clientIdentifier = "geth" + nodekeyFileName = "nodekey" +) + +func generateRandomDir() (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 + } + + return instanceDir, nil +} + +func saveNodeKey(key *ecdsa.PrivateKey, dataDir string) error { + keyDir := filepath.Join(dataDir, 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, nodekeyFileName) + if err := crypto.SaveECDSA(keyfile, key); err != nil { + log.Println(fmt.Sprintf("Failed to persist node key: %v", err)) + return err + } + return nil +} diff --git a/core/cluster.go b/core/cluster.go deleted file mode 100644 index e1e13580..00000000 --- a/core/cluster.go +++ /dev/null @@ -1,233 +0,0 @@ -// 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" - "math/big" - "net" - "net/url" - "os" - "path/filepath" - "time" - - "github.com/docker/docker/client" - "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/crypto" - "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/params" - "github.com/getamis/istanbul-tools/cmd/istanbul/extradata" - "github.com/phayes/freeport" - "github.com/satori/go.uuid" -) - -const ( - defaultLocalDir = "/tmp/gdata" - datadirPrivateKey = "nodekey" - - clientIdentifier = "geth" - staticNodeJson = "static-nodes.json" - - GenesisFile = "genesis.json" -) - -type Env struct { - GethID int - P2PPort uint16 - RpcPort uint16 - DataDir string - Key *ecdsa.PrivateKey - Client *client.Client -} - -// TODO: need to refactor with ethereum/container -func (e *Env) Address() common.Address { - addrs := toAddress([]*Env{e}) - return addrs[0] -} - -// TODO: need to refactor with ethereum/container -func (e *Env) NodeURL() string { - nodeID := discover.PubkeyID(&e.Key.PublicKey) - daemonHost := e.Client.DaemonHost() - url, err := url.Parse(daemonHost) - if err != nil { - log.Fatalf("Failed to parse daemon host, err: %v", err) - } - - var host string - if url.Scheme == "unix" { - host = "127.0.0.1" - } else { - host, _, err = net.SplitHostPort(url.Host) - if err != nil { - log.Fatalf("Failed to split host and port, err: %v", err) - } - } - return discover.NewNode(nodeID, net.ParseIP(host), 0, e.P2PPort).String() -} - -func Teardown(envs []*Env) { - for _, env := range envs { - os.RemoveAll(env.DataDir) - } -} - -func SetupEnv(numbers int) []*Env { - envs := make([]*Env, numbers) - rpcPort := uint16(freeport.GetPort()) - p2pPort := uint16(freeport.GetPort()) - - for i := 0; i < len(envs); i++ { - client, err := client.NewEnvClient() - if err != nil { - log.Fatalf("Cannot connect to Docker daemon, err: %v", err) - } - - key, err := crypto.GenerateKey() - if err != nil { - log.Fatalf("couldn't generate key: " + err.Error()) - } - - envs[i] = &Env{ - GethID: i, - P2PPort: p2pPort, - RpcPort: rpcPort, - DataDir: filepath.Join(defaultLocalDir, fmt.Sprintf("%s%s", clientIdentifier, uuid.NewV4().String())), - Key: key, - Client: client, - } - - rpcPort = uint16(freeport.GetPort()) - p2pPort = uint16(freeport.GetPort()) - } - return envs -} - -func SetupNodes(envs []*Env, g *core.Genesis) error { - nodes := toStaticNodes(envs) - - for _, env := range envs { - if err := saveNodeKey(env.DataDir, env.Key); err != nil { - log.Fatalf("Failed to save node key") - } - - if err := saveStaticNode(env.DataDir, nodes); err != nil { - return err - } - - if err := saveGenesis(env.DataDir, g); err != nil { - return err - } - } - return nil -} - -func NewGenesis(envs []*Env) *core.Genesis { - extraData, err := extradata.Encode("0x00", toAddress(envs)) - if err != nil { - log.Fatalf("Failed to generate genesis, err:%s", 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 saveNodeKey(dataDir string, key *ecdsa.PrivateKey) error { - err := os.MkdirAll(dataDir, 0700) - if err != nil { - log.Fatal(err) - } - - keyDir := filepath.Join(dataDir, 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 nil -} - -func saveStaticNode(dataDir string, nodes []string) 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 saveGenesis(dataDir string, genesis *core.Genesis) error { - filePath := filepath.Join(dataDir, GenesisFile) - - raw, err := json.Marshal(genesis) - if err != nil { - return err - } - - return ioutil.WriteFile(filePath, raw, 0600) -} - -func toStaticNodes(envs []*Env) []string { - nodes := make([]string, len(envs)) - - for i, env := range envs { - nodes[i] = env.NodeURL() - } - return nodes -} - -func toAddress(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/genesis/genesis.go b/genesis/genesis.go new file mode 100644 index 00000000..724cccbd --- /dev/null +++ b/genesis/genesis.go @@ -0,0 +1,75 @@ +// 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 genesis + +import ( + "encoding/json" + "io/ioutil" + "math/big" + "path/filepath" + "time" + "log" + + "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" +) + +const ( + FileName = "genesis.json" +) + +func New(addrs []common.Address) *core.Genesis { + extraData, err := extradata.Encode("0x00", addrs) + if err != nil { + log.Fatalf("Failed to generate genesis, err:%s", 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 Save(dataDir string, genesis *core.Genesis) error { + filePath := filepath.Join(dataDir, FileName) + + raw, err := json.Marshal(genesis) + if err != nil { + return err + } + + return ioutil.WriteFile(filePath, raw, 0600) +} diff --git a/tests/integration_test.go b/tests/integration_test.go index cd3ddfd7..2986ec07 100644 --- a/tests/integration_test.go +++ b/tests/integration_test.go @@ -18,74 +18,50 @@ package tests import ( "context" - "fmt" "math/big" - "path/filepath" "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/getamis/istanbul-tools/container" - "github.com/getamis/istanbul-tools/core" ) -// var geths []container.Ethereum - var _ = Describe("4 validators Istanbul", func() { const ( numberOfValidators = 4 ) var ( - envs []*core.Env - geths []container.Ethereum + blockchain container.Blockchain ) BeforeSuite(func() { - envs = core.SetupEnv(numberOfValidators) - err := core.SetupNodes(envs, core.NewGenesis(envs)) - Expect(err).To(BeNil()) + blockchain = container.NewBlockchain( + numberOfValidators, + container.ImageRepository("quay.io/amis/geth"), + container.ImageTag("istanbul_develop"), + container.DataDir("/data"), + container.WebSocket(), + container.WebSocketAddress("0.0.0.0"), + container.WebSocketAPI("eth,net,web3,personal,miner"), + container.WebSocketOrigin("*"), + container.NAT("any"), + container.NoDiscover(), + container.Etherbase("1a9afb711302c5f83b5902843d1c007a1a137632"), + container.Mine(), + container.Logging(true), + ) - for _, env := range envs { - geth := container.NewEthereum( - env.Client, - container.ImageRepository("quay.io/amis/geth"), - container.ImageTag("istanbul_develop"), - container.HostDataDir(env.DataDir), - container.DataDir("/data"), - container.Port(fmt.Sprintf("%d", env.P2PPort)), - container.WebSocket(), - container.WebSocketAddress("0.0.0.0"), - container.WebSocketAPI("eth,net,web3,personal,miner"), - container.WebSocketPort(fmt.Sprintf("%d", env.RpcPort)), - container.WebSocketOrigin("*"), - container.NAT("any"), - container.NoDiscover(), - container.Etherbase("1a9afb711302c5f83b5902843d1c007a1a137632"), - container.Mine(), - container.Logging(true), - ) - - err := geth.Init(filepath.Join(env.DataDir, core.GenesisFile)) - Expect(err).To(BeNil()) - - geths = append(geths, geth) - - err = geth.Start() - Expect(err).To(BeNil()) - } + Expect(blockchain.Start()).To(BeNil()) }) AfterSuite(func() { - for _, geth := range geths { - geth.Stop() - } - - core.Teardown(envs) + Expect(blockchain.Stop()).To(BeNil()) + blockchain.Finalize() }) It("Blockchain creation", func() { - for _, geth := range geths { + for _, geth := range blockchain.Validators() { client := geth.NewClient() Expect(client).NotTo(BeNil())