cmd/puppeth: v4/v5 boot separation, signer gas configs (#14453)
This commit is contained in:
parent
b0d0fafd68
commit
ef7b9fb7d0
@ -40,7 +40,7 @@ ADD genesis.json /genesis.json
|
|||||||
RUN \
|
RUN \
|
||||||
echo '/geth init /genesis.json' > geth.sh && \{{if .Unlock}}
|
echo '/geth init /genesis.json' > geth.sh && \{{if .Unlock}}
|
||||||
echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}}
|
echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}}
|
||||||
echo $'/geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine{{end}}{{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}}' >> geth.sh
|
echo $'/geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .BootV4}}--bootnodesv4 {{.BootV4}}{{end}} {{if .BootV5}}--bootnodesv5 {{.BootV5}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine{{end}}{{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --targetgaslimit {{.GasTarget}} --gasprice {{.GasPrice}}' >> geth.sh
|
||||||
|
|
||||||
ENTRYPOINT ["/bin/sh", "geth.sh"]
|
ENTRYPOINT ["/bin/sh", "geth.sh"]
|
||||||
`
|
`
|
||||||
@ -66,17 +66,20 @@ services:
|
|||||||
- LIGHT_PEERS={{.LightPeers}}
|
- LIGHT_PEERS={{.LightPeers}}
|
||||||
- STATS_NAME={{.Ethstats}}
|
- STATS_NAME={{.Ethstats}}
|
||||||
- MINER_NAME={{.Etherbase}}
|
- MINER_NAME={{.Etherbase}}
|
||||||
|
- GAS_TARGET={{.GasTarget}}
|
||||||
|
- GAS_PRICE={{.GasPrice}}
|
||||||
restart: always
|
restart: always
|
||||||
`
|
`
|
||||||
|
|
||||||
// deployNode deploys a new Ethereum node container to a remote machine via SSH,
|
// deployNode deploys a new Ethereum node container to a remote machine via SSH,
|
||||||
// docker and docker-compose. If an instance with the specified network name
|
// docker and docker-compose. If an instance with the specified network name
|
||||||
// already exists there, it will be overwritten!
|
// already exists there, it will be overwritten!
|
||||||
func deployNode(client *sshClient, network string, bootnodes []string, config *nodeInfos) ([]byte, error) {
|
func deployNode(client *sshClient, network string, bootv4, bootv5 []string, config *nodeInfos) ([]byte, error) {
|
||||||
kind := "sealnode"
|
kind := "sealnode"
|
||||||
if config.keyJSON == "" && config.etherbase == "" {
|
if config.keyJSON == "" && config.etherbase == "" {
|
||||||
kind = "bootnode"
|
kind = "bootnode"
|
||||||
bootnodes = make([]string, 0)
|
bootv4 = make([]string, 0)
|
||||||
|
bootv5 = make([]string, 0)
|
||||||
}
|
}
|
||||||
// Generate the content to upload to the server
|
// Generate the content to upload to the server
|
||||||
workdir := fmt.Sprintf("%d", rand.Int63())
|
workdir := fmt.Sprintf("%d", rand.Int63())
|
||||||
@ -92,9 +95,12 @@ func deployNode(client *sshClient, network string, bootnodes []string, config *n
|
|||||||
"Port": config.portFull,
|
"Port": config.portFull,
|
||||||
"Peers": config.peersTotal,
|
"Peers": config.peersTotal,
|
||||||
"LightFlag": lightFlag,
|
"LightFlag": lightFlag,
|
||||||
"Bootnodes": strings.Join(bootnodes, ","),
|
"BootV4": strings.Join(bootv4, ","),
|
||||||
|
"BootV5": strings.Join(bootv5, ","),
|
||||||
"Ethstats": config.ethstats,
|
"Ethstats": config.ethstats,
|
||||||
"Etherbase": config.etherbase,
|
"Etherbase": config.etherbase,
|
||||||
|
"GasTarget": uint64(1000000 * config.gasTarget),
|
||||||
|
"GasPrice": uint64(1000000000 * config.gasPrice),
|
||||||
"Unlock": config.keyJSON != "",
|
"Unlock": config.keyJSON != "",
|
||||||
})
|
})
|
||||||
files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes()
|
files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes()
|
||||||
@ -111,6 +117,8 @@ func deployNode(client *sshClient, network string, bootnodes []string, config *n
|
|||||||
"LightPeers": config.peersLight,
|
"LightPeers": config.peersLight,
|
||||||
"Ethstats": config.ethstats[:strings.Index(config.ethstats, ":")],
|
"Ethstats": config.ethstats[:strings.Index(config.ethstats, ":")],
|
||||||
"Etherbase": config.etherbase,
|
"Etherbase": config.etherbase,
|
||||||
|
"GasTarget": config.gasTarget,
|
||||||
|
"GasPrice": config.gasPrice,
|
||||||
})
|
})
|
||||||
files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes()
|
files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes()
|
||||||
|
|
||||||
@ -147,6 +155,8 @@ type nodeInfos struct {
|
|||||||
etherbase string
|
etherbase string
|
||||||
keyJSON string
|
keyJSON string
|
||||||
keyPass string
|
keyPass string
|
||||||
|
gasTarget float64
|
||||||
|
gasPrice float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the stringer interface.
|
// String implements the stringer interface.
|
||||||
@ -155,7 +165,8 @@ func (info *nodeInfos) String() string {
|
|||||||
if info.peersLight > 0 {
|
if info.peersLight > 0 {
|
||||||
discv5 = fmt.Sprintf(", portv5=%d", info.portLight)
|
discv5 = fmt.Sprintf(", portv5=%d", info.portLight)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("port=%d%s, datadir=%s, peers=%d, lights=%d, ethstats=%s", info.portFull, discv5, info.datadir, info.peersTotal, info.peersLight, info.ethstats)
|
return fmt.Sprintf("port=%d%s, datadir=%s, peers=%d, lights=%d, ethstats=%s, gastarget=%0.3f MGas, gasprice=%0.3f GWei",
|
||||||
|
info.portFull, discv5, info.datadir, info.peersTotal, info.peersLight, info.ethstats, info.gasTarget, info.gasPrice)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkNode does a health-check against an boot or seal node server to verify
|
// checkNode does a health-check against an boot or seal node server to verify
|
||||||
@ -176,6 +187,8 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
|
|||||||
// Resolve a few types from the environmental variables
|
// Resolve a few types from the environmental variables
|
||||||
totalPeers, _ := strconv.Atoi(infos.envvars["TOTAL_PEERS"])
|
totalPeers, _ := strconv.Atoi(infos.envvars["TOTAL_PEERS"])
|
||||||
lightPeers, _ := strconv.Atoi(infos.envvars["LIGHT_PEERS"])
|
lightPeers, _ := strconv.Atoi(infos.envvars["LIGHT_PEERS"])
|
||||||
|
gasTarget, _ := strconv.ParseFloat(infos.envvars["GAS_TARGET"], 64)
|
||||||
|
gasPrice, _ := strconv.ParseFloat(infos.envvars["GAS_PRICE"], 64)
|
||||||
|
|
||||||
// Container available, retrieve its node ID and its genesis json
|
// Container available, retrieve its node ID and its genesis json
|
||||||
var out []byte
|
var out []byte
|
||||||
@ -213,6 +226,8 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
|
|||||||
etherbase: infos.envvars["MINER_NAME"],
|
etherbase: infos.envvars["MINER_NAME"],
|
||||||
keyJSON: keyJSON,
|
keyJSON: keyJSON,
|
||||||
keyPass: keyPass,
|
keyPass: keyPass,
|
||||||
|
gasTarget: gasTarget,
|
||||||
|
gasPrice: gasPrice,
|
||||||
}
|
}
|
||||||
stats.enodeFull = fmt.Sprintf("enode://%s@%s:%d", id, client.address, stats.portFull)
|
stats.enodeFull = fmt.Sprintf("enode://%s@%s:%d", id, client.address, stats.portFull)
|
||||||
if stats.portLight != 0 {
|
if stats.portLight != 0 {
|
||||||
|
@ -162,6 +162,48 @@ func (w *wizard) readDefaultInt(def int) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readFloat reads a single line from stdin, trimming if from spaces, enforcing it
|
||||||
|
// to parse into a float.
|
||||||
|
func (w *wizard) readFloat() float64 {
|
||||||
|
for {
|
||||||
|
fmt.Printf("> ")
|
||||||
|
text, err := w.in.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("Failed to read user input", "err", err)
|
||||||
|
}
|
||||||
|
if text = strings.TrimSpace(text); text == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val, err := strconv.ParseFloat(strings.TrimSpace(text), 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Invalid input, expected float", "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// readDefaultFloat reads a single line from stdin, trimming if from spaces, enforcing
|
||||||
|
// it to parse into a float. If an empty line is entered, the default value is returned.
|
||||||
|
func (w *wizard) readDefaultFloat(def float64) float64 {
|
||||||
|
for {
|
||||||
|
fmt.Printf("> ")
|
||||||
|
text, err := w.in.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("Failed to read user input", "err", err)
|
||||||
|
}
|
||||||
|
if text = strings.TrimSpace(text); text == "" {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
val, err := strconv.ParseFloat(strings.TrimSpace(text), 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Invalid input, expected float", "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// readPassword reads a single line from stdin, trimming it from the trailing new
|
// readPassword reads a single line from stdin, trimming it from the trailing new
|
||||||
// line and returns it. The input will not be echoed.
|
// line and returns it. The input will not be echoed.
|
||||||
func (w *wizard) readPassword() string {
|
func (w *wizard) readPassword() string {
|
||||||
|
@ -39,7 +39,7 @@ func (w *wizard) networkStats(tips bool) {
|
|||||||
// Iterate over all the specified hosts and check their status
|
// Iterate over all the specified hosts and check their status
|
||||||
stats := tablewriter.NewWriter(os.Stdout)
|
stats := tablewriter.NewWriter(os.Stdout)
|
||||||
stats.SetHeader([]string{"Server", "IP", "Status", "Service", "Details"})
|
stats.SetHeader([]string{"Server", "IP", "Status", "Service", "Details"})
|
||||||
stats.SetColWidth(128)
|
stats.SetColWidth(100)
|
||||||
|
|
||||||
for server, pubkey := range w.conf.Servers {
|
for server, pubkey := range w.conf.Servers {
|
||||||
client := w.servers[server]
|
client := w.servers[server]
|
||||||
|
@ -50,7 +50,7 @@ func (w *wizard) deployNode(boot bool) {
|
|||||||
if boot {
|
if boot {
|
||||||
infos = &nodeInfos{portFull: 30303, peersTotal: 512, peersLight: 256}
|
infos = &nodeInfos{portFull: 30303, peersTotal: 512, peersLight: 256}
|
||||||
} else {
|
} else {
|
||||||
infos = &nodeInfos{portFull: 30303, peersTotal: 50, peersLight: 0}
|
infos = &nodeInfos{portFull: 30303, peersTotal: 50, peersLight: 0, gasTarget: 4.7, gasPrice: 18}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
infos.genesis, _ = json.MarshalIndent(w.conf.genesis, "", " ")
|
infos.genesis, _ = json.MarshalIndent(w.conf.genesis, "", " ")
|
||||||
@ -136,9 +136,17 @@ func (w *wizard) deployNode(boot bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Establish the gas dynamics to be enforced by the signer
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("What gas limit should empty blocks target (MGas)? (default = %0.3f)\n", infos.gasTarget)
|
||||||
|
infos.gasTarget = w.readDefaultFloat(infos.gasTarget)
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("What gas price should the signer require (GWei)? (default = %0.3f)\n", infos.gasPrice)
|
||||||
|
infos.gasPrice = w.readDefaultFloat(infos.gasPrice)
|
||||||
}
|
}
|
||||||
// Try to deploy the full node on the host
|
// Try to deploy the full node on the host
|
||||||
if out, err := deployNode(client, w.network, w.conf.bootFull, infos); err != nil {
|
if out, err := deployNode(client, w.network, w.conf.bootFull, w.conf.bootLight, infos); err != nil {
|
||||||
log.Error("Failed to deploy Ethereum node container", "err", err)
|
log.Error("Failed to deploy Ethereum node container", "err", err)
|
||||||
if len(out) > 0 {
|
if len(out) > 0 {
|
||||||
fmt.Printf("%s\n", out)
|
fmt.Printf("%s\n", out)
|
||||||
|
Loading…
Reference in New Issue
Block a user