cmd/istanbul, docker, genesis: add docker-compose and quorum flags
This commit is contained in:
parent
a72a4b5633
commit
8ff6abd0e7
12
README.md
12
README.md
|
@ -99,7 +99,7 @@ seal: 0x000000000000000000000000000000000000000000000000000000000000000000000000
|
|||
<details>
|
||||
<summary>Click here to expand</summary>
|
||||
|
||||
When `--nodes --verbose` flags are given, a `static-nodes.json` template as well as the validators' node keys, public keys, and addresses are generated. When `--save` flag is given, the generated configs will be saved.
|
||||
When `--nodes --verbose` flags are given, a `static-nodes.json` template as well as the validators' node keys, public keys, and addresses are generated. When `--docker-compose` is given, a `docker-compose.yml` for the validators is generated. When `--save` flag is given, all generated configs will be saved. Use Quorum when `--quorum` flag is given.
|
||||
|
||||
**Note**: the generated `static-nodes.json` template are set with IP `0.0.0.0`, please make according change to match your environment.
|
||||
|
||||
|
@ -201,10 +201,12 @@ DESCRIPTION:
|
|||
|
||||
|
||||
OPTIONS:
|
||||
--num value Number of validators (default: 0)
|
||||
--nodes Print static nodes template
|
||||
--verbose Print validator details
|
||||
--save Save to files
|
||||
--num value Number of validators (default: 0)
|
||||
--nodes Print static nodes template
|
||||
--verbose Print validator details
|
||||
--quorum Use quorum
|
||||
--docker-compose Print docker compose file
|
||||
--save Save to files
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
|
@ -25,13 +25,14 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
istcommon "github.com/getamis/istanbul-tools/common"
|
||||
"github.com/getamis/istanbul-tools/docker/compose"
|
||||
"github.com/getamis/istanbul-tools/genesis"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type validatorInfo struct {
|
||||
|
@ -57,6 +58,8 @@ var (
|
|||
numOfValidatorsFlag,
|
||||
staticNodesFlag,
|
||||
verboseFlag,
|
||||
quorumFlag,
|
||||
dockerComposeFlag,
|
||||
saveFlag,
|
||||
},
|
||||
}
|
||||
|
@ -113,12 +116,22 @@ func gen(ctx *cli.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
genesis := genesis.New(
|
||||
var jsonBytes []byte
|
||||
isQuorum := ctx.Bool(quorumFlag.Name)
|
||||
g := genesis.New(
|
||||
genesis.Validators(addrs...),
|
||||
genesis.Alloc(addrs, new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil)),
|
||||
)
|
||||
|
||||
jsonBytes, _ := json.MarshalIndent(genesis, "", " ")
|
||||
jsonBytes, _ = json.MarshalIndent(g, "", " ")
|
||||
fmt.Println("--Old genesis.json")
|
||||
fmt.Println(string(jsonBytes))
|
||||
|
||||
if isQuorum {
|
||||
jsonBytes, _ = json.MarshalIndent(genesis.ToQuorum(g, true), "", " ")
|
||||
} else {
|
||||
jsonBytes, _ = json.MarshalIndent(g, "", " ")
|
||||
}
|
||||
fmt.Println("genesis.json")
|
||||
fmt.Println(string(jsonBytes))
|
||||
|
||||
|
@ -126,5 +139,31 @@ func gen(ctx *cli.Context) error {
|
|||
ioutil.WriteFile("genesis.json", jsonBytes, os.ModePerm)
|
||||
}
|
||||
|
||||
if ctx.Bool(dockerComposeFlag.Name) {
|
||||
fmt.Print("\n\n\n")
|
||||
compose := compose.New(
|
||||
"172.16.239",
|
||||
num,
|
||||
"bb98a0b6442386d0cdf8a31b267892c1",
|
||||
nodekeys,
|
||||
removeSpacesAndLines(jsonBytes),
|
||||
removeSpacesAndLines(staticNodes),
|
||||
isQuorum)
|
||||
fmt.Println("docker-compose.yml")
|
||||
fmt.Println(compose.String())
|
||||
|
||||
if ctx.Bool(saveFlag.Name) {
|
||||
ioutil.WriteFile("docker-compose.yml", []byte(compose.String()), os.ModePerm)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeSpacesAndLines(b []byte) string {
|
||||
out := string(b)
|
||||
out = strings.Replace(out, " ", "", -1)
|
||||
out = strings.Replace(out, "\t", "", -1)
|
||||
out = strings.Replace(out, "\n", "", -1)
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -34,6 +34,16 @@ var (
|
|||
Usage: "Print static nodes template",
|
||||
}
|
||||
|
||||
dockerComposeFlag = cli.BoolFlag{
|
||||
Name: "docker-compose",
|
||||
Usage: "Print docker compose file",
|
||||
}
|
||||
|
||||
quorumFlag = cli.BoolFlag{
|
||||
Name: "quorum",
|
||||
Usage: "Use Quorum",
|
||||
}
|
||||
|
||||
saveFlag = cli.BoolFlag{
|
||||
Name: "save",
|
||||
Usage: "Save to files",
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/getamis/istanbul-tools/docker/service"
|
||||
)
|
||||
|
||||
type Compose interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
type istanbul struct {
|
||||
IPPrefix string
|
||||
EthStats *service.EthStats
|
||||
Services []*service.Validator
|
||||
}
|
||||
|
||||
func New(ipPrefix string, number int, secret string, nodeKeys []string,
|
||||
genesis string, staticNodes string, quorum bool) Compose {
|
||||
ist := &istanbul{
|
||||
IPPrefix: ipPrefix,
|
||||
EthStats: service.NewEthStats(fmt.Sprintf("%v.9", ipPrefix), secret),
|
||||
}
|
||||
ist.init(number, nodeKeys, genesis, staticNodes)
|
||||
if quorum {
|
||||
return newQuorum(ist, number)
|
||||
}
|
||||
return ist
|
||||
}
|
||||
|
||||
func (ist *istanbul) init(number int, nodeKeys []string, genesis string, staticNodes string) {
|
||||
for i := 0; i < number; i++ {
|
||||
s := service.NewValidator(i,
|
||||
genesis,
|
||||
nodeKeys[i],
|
||||
"",
|
||||
30303+i,
|
||||
8545+i,
|
||||
ist.EthStats.Host(),
|
||||
// from subnet ip 10
|
||||
fmt.Sprintf("%v.%v", ist.IPPrefix, i+10),
|
||||
)
|
||||
|
||||
staticNodes = strings.Replace(staticNodes, "0.0.0.0", s.IP, 1)
|
||||
ist.Services = append(ist.Services, s)
|
||||
}
|
||||
|
||||
// update static nodes
|
||||
for i := range ist.Services {
|
||||
ist.Services[i].StaticNodes = staticNodes
|
||||
}
|
||||
}
|
||||
|
||||
func (ist istanbul) String() string {
|
||||
tmpl, err := template.New("istanbul").Parse(istanbulTemplate)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
result := new(bytes.Buffer)
|
||||
err = tmpl.Execute(result, ist)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to render template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
var istanbulTemplate = `version: '3'
|
||||
services:
|
||||
{{ .EthStats }}
|
||||
{{- range .Services }}
|
||||
{{ . }}
|
||||
{{- end }}
|
||||
networks:
|
||||
app_net:
|
||||
driver: bridge
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: {{ .IPPrefix }}.0/24`
|
|
@ -0,0 +1,110 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/getamis/istanbul-tools/docker/service"
|
||||
)
|
||||
|
||||
type quorum struct {
|
||||
*istanbul
|
||||
Number int
|
||||
QuorumServices []*service.Quorum
|
||||
}
|
||||
|
||||
func newQuorum(ist *istanbul, number int) Compose {
|
||||
q := &quorum{
|
||||
istanbul: ist,
|
||||
Number: number,
|
||||
}
|
||||
q.init()
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *quorum) init() {
|
||||
// set constellations
|
||||
var constellations []*service.Constellation
|
||||
for i := 0; i < q.Number; i++ {
|
||||
constellations = append(constellations,
|
||||
service.NewConstellation(q.Services[i].Identity,
|
||||
// from subnet ip 100
|
||||
fmt.Sprintf("%v.%v", q.IPPrefix, i+100),
|
||||
10000+i,
|
||||
),
|
||||
)
|
||||
}
|
||||
for i := 0; i < q.Number; i++ {
|
||||
// set othernodes
|
||||
var nodes []string
|
||||
for j := 0; j < q.Number; j++ {
|
||||
if i != j {
|
||||
nodes = append(nodes, constellations[j].Host())
|
||||
}
|
||||
}
|
||||
constellations[i].SetOtherNodes(nodes)
|
||||
|
||||
// update quorum service
|
||||
q.QuorumServices = append(q.QuorumServices,
|
||||
service.NewQuorum(q.Services[i], constellations[i]))
|
||||
}
|
||||
}
|
||||
|
||||
func (q *quorum) String() string {
|
||||
tmpl, err := template.New("quorum").Funcs(template.FuncMap(
|
||||
map[string]interface{}{
|
||||
"PrintVolumes": func() (result string) {
|
||||
for i := 0; i < q.Number; i++ {
|
||||
result += fmt.Sprintf(" \"%v\":\n", i)
|
||||
}
|
||||
return
|
||||
},
|
||||
})).Parse(quorumTemplate)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
result := new(bytes.Buffer)
|
||||
err = tmpl.Execute(result, q)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to render template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
var quorumTemplate = `version: '3'
|
||||
services:
|
||||
{{ .EthStats }}
|
||||
{{- range .QuorumServices }}
|
||||
{{ . }}
|
||||
{{- end }}
|
||||
networks:
|
||||
app_net:
|
||||
driver: bridge
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: {{ .IPPrefix }}.0/24
|
||||
volumes:
|
||||
{{ PrintVolumes }}
|
||||
`
|
|
@ -0,0 +1,110 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type Constellation struct {
|
||||
Identity int
|
||||
Name string
|
||||
IP string
|
||||
Port int
|
||||
OtherNodes string
|
||||
PublicKey string
|
||||
PrivateKey string
|
||||
SocketPath string
|
||||
ConfigPath string
|
||||
Folder string
|
||||
KeyPath string
|
||||
}
|
||||
|
||||
func NewConstellation(identity int, ip string, port int) *Constellation {
|
||||
folder := "/constellation"
|
||||
keyPath := fmt.Sprintf("%v/tm", folder)
|
||||
return &Constellation{
|
||||
Identity: identity,
|
||||
Name: fmt.Sprintf("constellation-%v", identity),
|
||||
IP: ip,
|
||||
Port: port,
|
||||
PublicKey: fmt.Sprintf("%v.pub", keyPath),
|
||||
PrivateKey: fmt.Sprintf("%v.key", keyPath),
|
||||
SocketPath: fmt.Sprintf("%v.ipc", keyPath),
|
||||
ConfigPath: fmt.Sprintf("%v.conf", keyPath),
|
||||
Folder: folder,
|
||||
KeyPath: keyPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Constellation) SetOtherNodes(nodes []string) {
|
||||
c.OtherNodes = strings.Join(nodes, ",")
|
||||
}
|
||||
|
||||
func (c Constellation) Host() string {
|
||||
return fmt.Sprintf("http://%v:%v/", c.IP, c.Port)
|
||||
}
|
||||
|
||||
func (c Constellation) String() string {
|
||||
tmpl, err := template.New("constellation").Parse(constellationTemplate)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
result := new(bytes.Buffer)
|
||||
err = tmpl.Execute(result, c)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to render template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
var constellationTemplate = `{{ .Name }}:
|
||||
hostname: {{ .Name }}
|
||||
image: quay.io/amis/constellation:latest
|
||||
ports:
|
||||
- '{{ .Port }}:{{ .Port }}'
|
||||
volumes:
|
||||
- {{ .Identity }}:{{ .Folder }}:z
|
||||
- .:/tmp/
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
mkdir -p {{ .Folder }}
|
||||
echo "socket=\"{{ .SocketPath }}\"\npublickeys=[\"{{ .PublicKey }}\"]\n" > {{ .ConfigPath }}
|
||||
constellation-node --generatekeys={{ .KeyPath }}
|
||||
cp {{ .KeyPath }}.pub /tmp/tm{{ .Identity }}.pub
|
||||
constellation-node \
|
||||
--url={{ .Host }} \
|
||||
--port={{ .Port }} \
|
||||
--socket={{ .SocketPath }} \
|
||||
--othernodes={{ .OtherNodes }} \
|
||||
--publickeys={{ .PublicKey }} \
|
||||
--privatekeys={{ .PrivateKey }} \
|
||||
--storage={{ .Folder }} \
|
||||
--verbosity=4
|
||||
networks:
|
||||
app_net:
|
||||
ipv4_address: {{ .IP }}
|
||||
restart: always`
|
|
@ -0,0 +1,67 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type EthStats struct {
|
||||
Secret string
|
||||
IP string
|
||||
}
|
||||
|
||||
func NewEthStats(ip string, secret string) *EthStats {
|
||||
return &EthStats{
|
||||
IP: ip,
|
||||
Secret: secret,
|
||||
}
|
||||
}
|
||||
|
||||
func (c EthStats) Host() string {
|
||||
return fmt.Sprintf("%v@%v:3000", c.Secret, c.IP)
|
||||
}
|
||||
|
||||
func (c EthStats) String() string {
|
||||
tmpl, err := template.New("eth_stats").Parse(ethStatsTemplate)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
result := new(bytes.Buffer)
|
||||
err = tmpl.Execute(result, c)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to render template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
var ethStatsTemplate = `eth-stats:
|
||||
image: quay.io/amis/ethstats:latest
|
||||
ports:
|
||||
- '3000:3000'
|
||||
environment:
|
||||
- WS_SECRET={{ .Secret }}
|
||||
restart: always
|
||||
networks:
|
||||
app_net:
|
||||
ipv4_address: {{ .IP }}`
|
|
@ -0,0 +1,95 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type Quorum struct {
|
||||
*Validator
|
||||
Constellation *Constellation
|
||||
}
|
||||
|
||||
func NewQuorum(v *Validator, c *Constellation) *Quorum {
|
||||
return &Quorum{
|
||||
Validator: v,
|
||||
Constellation: c,
|
||||
}
|
||||
}
|
||||
func (q Quorum) String() string {
|
||||
tmpl, err := template.New("quorum").Parse(quorumTemplate)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
result := new(bytes.Buffer)
|
||||
err = tmpl.Execute(result, q)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to render template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
var quorumTemplate = `{{ .Name }}:
|
||||
hostname: {{ .Name }}
|
||||
image: quay.io/amis/quorum:feature_istanbul
|
||||
ports:
|
||||
- '{{ .Port }}:30303'
|
||||
- '{{ .RPCPort }}:8545'
|
||||
volumes:
|
||||
- {{ .Identity }}:{{ .Constellation.Folder }}:z
|
||||
depends_on:
|
||||
- {{ .Constellation.Name }}
|
||||
environment:
|
||||
- PRIVATE_CONFIG={{ .Constellation.ConfigPath }}
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
mkdir -p /eth/geth
|
||||
echo '{{ .Genesis }}' > /eth/genesis.json
|
||||
echo '{{ .StaticNodes }}' > /eth/geth/static-nodes.json
|
||||
geth --datadir "/eth" init "/eth/genesis.json"
|
||||
geth \
|
||||
--identity "{{ .Name }}" \
|
||||
--rpc \
|
||||
--rpcaddr "0.0.0.0" \
|
||||
--rpcport "8545" \
|
||||
--rpccorsdomain "*" \
|
||||
--datadir "/eth" \
|
||||
--port "30303" \
|
||||
--rpcapi "db,eth,net,web3,istanbul,personal" \
|
||||
--networkid "2017" \
|
||||
--nat "any" \
|
||||
--nodekeyhex "{{ .NodeKey }}" \
|
||||
--mine \
|
||||
--debug \
|
||||
--metrics \
|
||||
--syncmode "full" \
|
||||
--ethstats "{{ .Name }}:{{ .EthStats }}" \
|
||||
--gasprice 0
|
||||
networks:
|
||||
app_net:
|
||||
ipv4_address: {{ .IP }}
|
||||
restart: always
|
||||
{{ .Constellation }}`
|
|
@ -0,0 +1,102 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type Validator struct {
|
||||
Identity int
|
||||
Genesis string
|
||||
NodeKey string
|
||||
StaticNodes string
|
||||
Port int
|
||||
RPCPort int
|
||||
IP string
|
||||
EthStats string
|
||||
Name string
|
||||
}
|
||||
|
||||
func NewValidator(identity int, genesis string, nodeKey string, staticNodes string, port int, rpcPort int, ethStats string, ip string) *Validator {
|
||||
return &Validator{
|
||||
Identity: identity,
|
||||
Genesis: genesis,
|
||||
NodeKey: nodeKey,
|
||||
Port: port,
|
||||
RPCPort: rpcPort,
|
||||
EthStats: ethStats,
|
||||
IP: ip,
|
||||
Name: fmt.Sprintf("validator-%v", identity),
|
||||
}
|
||||
}
|
||||
|
||||
func (v Validator) String() string {
|
||||
tmpl, err := template.New("validator").Parse(validatorTemplate)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
result := new(bytes.Buffer)
|
||||
err = tmpl.Execute(result, v)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to render template, %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
var validatorTemplate = `{{ .Name }}:
|
||||
hostname: {{ .Name }}
|
||||
image: quay.io/amis/geth:latest
|
||||
ports:
|
||||
- '{{ .Port }}:30303'
|
||||
- '{{ .RPCPort }}:8545'
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
mkdir -p /eth/geth
|
||||
echo '{{ .Genesis }}' > /eth/genesis.json
|
||||
echo '{{ .StaticNodes }}' > /eth/geth/static-nodes.json
|
||||
geth --datadir "/eth" init "/eth/genesis.json"
|
||||
geth \
|
||||
--identity "{{ .Name }}" \
|
||||
--rpc \
|
||||
--rpcaddr "0.0.0.0" \
|
||||
--rpcport "8545" \
|
||||
--rpccorsdomain "*" \
|
||||
--datadir "/eth" \
|
||||
--port "30303" \
|
||||
--rpcapi "db,eth,net,web3,istanbul,personal" \
|
||||
--networkid "2017" \
|
||||
--nat "any" \
|
||||
--nodekeyhex "{{ .NodeKey }}" \
|
||||
--mine \
|
||||
--debug \
|
||||
--metrics \
|
||||
--syncmode "full" \
|
||||
--ethstats "{{ .Name }}:{{ .EthStats }}" \
|
||||
--gasprice 0
|
||||
networks:
|
||||
app_net:
|
||||
ipv4_address: {{ .IP }}
|
||||
restart: always`
|
|
@ -0,0 +1,116 @@
|
|||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package genesis
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/getamis/go-ethereum/common/math"
|
||||
)
|
||||
|
||||
var _ = (*genesisSpecMarshaling)(nil)
|
||||
|
||||
func (q QuorumGenesis) MarshalJSON() ([]byte, error) {
|
||||
type QuorumGenesis struct {
|
||||
Config *QuorumChainConfig `json:"config"`
|
||||
Nonce math.HexOrDecimal64 `json:"nonce"`
|
||||
Timestamp math.HexOrDecimal64 `json:"timestamp"`
|
||||
ExtraData hexutil.Bytes `json:"extraData"`
|
||||
GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"`
|
||||
Mixhash common.Hash `json:"mixHash"`
|
||||
Coinbase common.Address `json:"coinbase"`
|
||||
Alloc map[common.UnprefixedAddress]core.GenesisAccount `json:"alloc" gencodec:"required"`
|
||||
Number math.HexOrDecimal64 `json:"number"`
|
||||
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
}
|
||||
var enc QuorumGenesis
|
||||
enc.Config = q.Config
|
||||
enc.Nonce = math.HexOrDecimal64(q.Nonce)
|
||||
enc.Timestamp = math.HexOrDecimal64(q.Timestamp)
|
||||
enc.ExtraData = q.ExtraData
|
||||
enc.GasLimit = math.HexOrDecimal64(q.GasLimit)
|
||||
enc.Difficulty = (*math.HexOrDecimal256)(q.Difficulty)
|
||||
enc.Mixhash = q.Mixhash
|
||||
enc.Coinbase = q.Coinbase
|
||||
if q.Alloc != nil {
|
||||
enc.Alloc = make(map[common.UnprefixedAddress]core.GenesisAccount, len(q.Alloc))
|
||||
for k, v := range q.Alloc {
|
||||
enc.Alloc[common.UnprefixedAddress(k)] = v
|
||||
}
|
||||
}
|
||||
enc.Number = math.HexOrDecimal64(q.Number)
|
||||
enc.GasUsed = math.HexOrDecimal64(q.GasUsed)
|
||||
enc.ParentHash = q.ParentHash
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
func (q *QuorumGenesis) UnmarshalJSON(input []byte) error {
|
||||
type QuorumGenesis struct {
|
||||
Config *QuorumChainConfig `json:"config"`
|
||||
Nonce *math.HexOrDecimal64 `json:"nonce"`
|
||||
Timestamp *math.HexOrDecimal64 `json:"timestamp"`
|
||||
ExtraData hexutil.Bytes `json:"extraData"`
|
||||
GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"`
|
||||
Mixhash *common.Hash `json:"mixHash"`
|
||||
Coinbase *common.Address `json:"coinbase"`
|
||||
Alloc map[common.UnprefixedAddress]core.GenesisAccount `json:"alloc" gencodec:"required"`
|
||||
Number *math.HexOrDecimal64 `json:"number"`
|
||||
GasUsed *math.HexOrDecimal64 `json:"gasUsed"`
|
||||
ParentHash *common.Hash `json:"parentHash"`
|
||||
}
|
||||
var dec QuorumGenesis
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.Config != nil {
|
||||
q.Config = dec.Config
|
||||
}
|
||||
if dec.Nonce != nil {
|
||||
q.Nonce = uint64(*dec.Nonce)
|
||||
}
|
||||
if dec.Timestamp != nil {
|
||||
q.Timestamp = uint64(*dec.Timestamp)
|
||||
}
|
||||
if dec.ExtraData != nil {
|
||||
q.ExtraData = dec.ExtraData
|
||||
}
|
||||
if dec.GasLimit == nil {
|
||||
return errors.New("missing required field 'gasLimit' for QuorumGenesis")
|
||||
}
|
||||
q.GasLimit = uint64(*dec.GasLimit)
|
||||
if dec.Difficulty == nil {
|
||||
return errors.New("missing required field 'difficulty' for QuorumGenesis")
|
||||
}
|
||||
q.Difficulty = (*big.Int)(dec.Difficulty)
|
||||
if dec.Mixhash != nil {
|
||||
q.Mixhash = *dec.Mixhash
|
||||
}
|
||||
if dec.Coinbase != nil {
|
||||
q.Coinbase = *dec.Coinbase
|
||||
}
|
||||
if dec.Alloc == nil {
|
||||
return errors.New("missing required field 'alloc' for QuorumGenesis")
|
||||
}
|
||||
q.Alloc = make(core.GenesisAlloc, len(dec.Alloc))
|
||||
for k, v := range dec.Alloc {
|
||||
q.Alloc[common.Address(k)] = v
|
||||
}
|
||||
if dec.Number != nil {
|
||||
q.Number = uint64(*dec.Number)
|
||||
}
|
||||
if dec.GasUsed != nil {
|
||||
q.GasUsed = uint64(*dec.GasUsed)
|
||||
}
|
||||
if dec.ParentHash != nil {
|
||||
q.ParentHash = *dec.ParentHash
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -18,11 +18,9 @@ package genesis
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/istanbul"
|
||||
|
@ -84,17 +82,15 @@ func NewFile(isQuorum bool, options ...Option) string {
|
|||
func Save(dataDir string, genesis *core.Genesis, isQuorum bool) error {
|
||||
filePath := filepath.Join(dataDir, FileName)
|
||||
|
||||
raw, err := json.Marshal(genesis)
|
||||
var raw []byte
|
||||
var err error
|
||||
if isQuorum {
|
||||
raw, err = json.Marshal(ToQuorum(genesis, true))
|
||||
} else {
|
||||
raw, err = json.Marshal(genesis)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Quorum hack: add isQuorum field
|
||||
if isQuorum {
|
||||
jsonStr := string(raw)
|
||||
idx := strings.Index(jsonStr, ",\"istanbul\"")
|
||||
jsonStr = fmt.Sprintf("%s,\"isQuorum\":true%s", jsonStr[:idx], jsonStr[idx:])
|
||||
raw = []byte(jsonStr)
|
||||
}
|
||||
return ioutil.WriteFile(filePath, raw, 0600)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package genesis
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/getamis/go-ethereum/common/math"
|
||||
)
|
||||
|
||||
//go:generate gencodec -type QuorumGenesis -field-override genesisSpecMarshaling -out gen_quorum_genesis.go
|
||||
|
||||
// field type overrides for gencodec
|
||||
type genesisSpecMarshaling struct {
|
||||
Nonce math.HexOrDecimal64
|
||||
Timestamp math.HexOrDecimal64
|
||||
ExtraData hexutil.Bytes
|
||||
GasLimit math.HexOrDecimal64
|
||||
GasUsed math.HexOrDecimal64
|
||||
Number math.HexOrDecimal64
|
||||
Difficulty *math.HexOrDecimal256
|
||||
Alloc map[common.UnprefixedAddress]core.GenesisAccount
|
||||
}
|
||||
|
||||
type QuorumChainConfig struct {
|
||||
*params.ChainConfig
|
||||
IsQuorum bool `json:"isQuorum,omitempty"`
|
||||
}
|
||||
|
||||
type QuorumGenesis struct {
|
||||
Config *QuorumChainConfig `json:"config"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
Timestamp uint64 `json:"timestamp"`
|
||||
ExtraData []byte `json:"extraData"`
|
||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
||||
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
|
||||
Mixhash common.Hash `json:"mixHash"`
|
||||
Coinbase common.Address `json:"coinbase"`
|
||||
Alloc core.GenesisAlloc `json:"alloc" gencodec:"required"`
|
||||
|
||||
// These fields are used for consensus tests. Please don't use them
|
||||
// in actual genesis blocks.
|
||||
Number uint64 `json:"number"`
|
||||
GasUsed uint64 `json:"gasUsed"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
}
|
||||
|
||||
// ToQuorum converts standard genesis to quorum genesis
|
||||
func ToQuorum(g *core.Genesis, isQuorum bool) *QuorumGenesis {
|
||||
return &QuorumGenesis{
|
||||
Config: &QuorumChainConfig{
|
||||
ChainConfig: g.Config,
|
||||
IsQuorum: isQuorum,
|
||||
},
|
||||
Nonce: g.Nonce,
|
||||
Timestamp: g.Timestamp,
|
||||
ExtraData: g.ExtraData,
|
||||
GasLimit: g.GasLimit,
|
||||
Difficulty: g.Difficulty,
|
||||
Mixhash: g.Mixhash,
|
||||
Coinbase: g.Coinbase,
|
||||
Alloc: g.Alloc,
|
||||
Number: g.Number,
|
||||
GasUsed: g.GasUsed,
|
||||
ParentHash: g.ParentHash,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue