github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/cmd/puppeth/module_wallet.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bytes" 21 "fmt" 22 "html/template" 23 "math/rand" 24 "path/filepath" 25 "strconv" 26 "strings" 27 28 "github.com/vntchain/go-vnt/log" 29 ) 30 31 // walletDockerfile is the Dockerfile required to run a web wallet. 32 var walletDockerfile = ` 33 FROM puppeth/wallet:latest 34 35 ADD genesis.json /genesis.json 36 37 RUN \ 38 echo 'node server.js &' > wallet.sh && \ 39 echo 'gvnt --cache 512 init /genesis.json' >> wallet.sh && \ 40 echo $'gvnt --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --vntstats \'{{.Vntstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh 41 42 ENTRYPOINT ["/bin/sh", "wallet.sh"] 43 ` 44 45 // walletComposefile is the docker-compose.yml file required to deploy and 46 // maintain a web wallet. 47 var walletComposefile = ` 48 version: '2' 49 services: 50 wallet: 51 build: . 52 image: {{.Network}}/wallet 53 ports: 54 - "{{.NodePort}}:{{.NodePort}}" 55 - "{{.NodePort}}:{{.NodePort}}/udp" 56 - "{{.RPCPort}}:8545"{{if not .VHost}} 57 - "{{.WebPort}}:80"{{end}} 58 volumes: 59 - {{.Datadir}}:/root/.vntchain 60 environment: 61 - NODE_PORT={{.NodePort}}/tcp 62 - STATS={{.Vntstats}}{{if .VHost}} 63 - VIRTUAL_HOST={{.VHost}} 64 - VIRTUAL_PORT=80{{end}} 65 logging: 66 driver: "json-file" 67 options: 68 max-size: "1m" 69 max-file: "10" 70 restart: always 71 ` 72 73 // deployWallet deploys a new web wallet container to a remote machine via SSH, 74 // docker and docker-compose. If an instance with the specified network name 75 // already exists there, it will be overwritten! 76 func deployWallet(client *sshClient, network string, bootnodes []string, config *walletInfos, nocache bool) ([]byte, error) { 77 // Generate the content to upload to the server 78 workdir := fmt.Sprintf("%d", rand.Int63()) 79 files := make(map[string][]byte) 80 81 dockerfile := new(bytes.Buffer) 82 template.Must(template.New("").Parse(walletDockerfile)).Execute(dockerfile, map[string]interface{}{ 83 "Network": strings.ToTitle(network), 84 "Denom": strings.ToUpper(network), 85 "NetworkID": config.network, 86 "NodePort": config.nodePort, 87 "RPCPort": config.rpcPort, 88 "Bootnodes": strings.Join(bootnodes, ","), 89 "Vntstats": config.vntstats, 90 "Host": client.address, 91 }) 92 files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() 93 94 composefile := new(bytes.Buffer) 95 template.Must(template.New("").Parse(walletComposefile)).Execute(composefile, map[string]interface{}{ 96 "Datadir": config.datadir, 97 "Network": network, 98 "NodePort": config.nodePort, 99 "RPCPort": config.rpcPort, 100 "VHost": config.webHost, 101 "WebPort": config.webPort, 102 "Vntstats": config.vntstats[:strings.Index(config.vntstats, ":")], 103 }) 104 files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() 105 106 files[filepath.Join(workdir, "genesis.json")] = config.genesis 107 108 // Upload the deployment files to the remote server (and clean up afterwards) 109 if out, err := client.Upload(files); err != nil { 110 return out, err 111 } 112 defer client.Run("rm -rf " + workdir) 113 114 // Build and deploy the boot or seal node service 115 if nocache { 116 return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate", workdir, network, network)) 117 } 118 return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network)) 119 } 120 121 // walletInfos is returned from a web wallet status check to allow reporting 122 // various configuration parameters. 123 type walletInfos struct { 124 genesis []byte 125 network int64 126 datadir string 127 vntstats string 128 nodePort int 129 rpcPort int 130 webHost string 131 webPort int 132 } 133 134 // Report converts the typed struct into a plain string->string map, containing 135 // most - but not all - fields for reporting to the user. 136 func (info *walletInfos) Report() map[string]string { 137 report := map[string]string{ 138 "Data directory": info.datadir, 139 "Vntstats username": info.vntstats, 140 "Node listener port ": strconv.Itoa(info.nodePort), 141 "RPC listener port ": strconv.Itoa(info.rpcPort), 142 "Website address ": info.webHost, 143 "Website listener port ": strconv.Itoa(info.webPort), 144 } 145 return report 146 } 147 148 // checkWallet does a health-check against web wallet server to verify whether 149 // it's running, and if yes, whether it's responsive. 150 func checkWallet(client *sshClient, network string) (*walletInfos, error) { 151 // Inspect a possible web wallet container on the host 152 infos, err := inspectContainer(client, fmt.Sprintf("%s_wallet_1", network)) 153 if err != nil { 154 return nil, err 155 } 156 if !infos.running { 157 return nil, ErrServiceOffline 158 } 159 // Resolve the port from the host, or the reverse proxy 160 webPort := infos.portmap["80/tcp"] 161 if webPort == 0 { 162 if proxy, _ := checkNginx(client, network); proxy != nil { 163 webPort = proxy.port 164 } 165 } 166 if webPort == 0 { 167 return nil, ErrNotExposed 168 } 169 // Resolve the host from the reverse-proxy and the config values 170 host := infos.envvars["VIRTUAL_HOST"] 171 if host == "" { 172 host = client.server 173 } 174 // Run a sanity check to see if the devp2p and RPC ports are reachable 175 nodePort := infos.portmap[infos.envvars["NODE_PORT"]] 176 if err = checkPort(client.server, nodePort); err != nil { 177 log.Warn(fmt.Sprintf("Wallet devp2p port seems unreachable"), "server", client.server, "port", nodePort, "err", err) 178 } 179 rpcPort := infos.portmap["8545/tcp"] 180 if err = checkPort(client.server, rpcPort); err != nil { 181 log.Warn(fmt.Sprintf("Wallet RPC port seems unreachable"), "server", client.server, "port", rpcPort, "err", err) 182 } 183 // Assemble and return the useful infos 184 stats := &walletInfos{ 185 datadir: infos.volumes["/root/.vntchain"], 186 nodePort: nodePort, 187 rpcPort: rpcPort, 188 webHost: host, 189 webPort: webPort, 190 vntstats: infos.envvars["STATS"], 191 } 192 return stats, nil 193 }