github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/cmd/puppeth/module_wallet.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2017 Go Ethereum作者
    10  //此文件是Go以太坊的一部分。
    11  //
    12  //Go以太坊是免费软件:您可以重新发布和/或修改它
    13  //根据GNU通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊的分布希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU通用公共许可证了解更多详细信息。
    21  //
    22  //你应该已经收到一份GNU通用公共许可证的副本
    23  //一起去以太坊吧。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package main
    26  
    27  import (
    28  	"bytes"
    29  	"fmt"
    30  	"html/template"
    31  	"math/rand"
    32  	"path/filepath"
    33  	"strconv"
    34  	"strings"
    35  
    36  	"github.com/ethereum/go-ethereum/log"
    37  )
    38  
    39  //
    40  var walletDockerfile = `
    41  FROM puppeth/wallet:latest
    42  
    43  ADD genesis.json /genesis.json
    44  
    45  RUN \
    46    echo 'node server.js &'                     > wallet.sh && \
    47  	echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
    48  	echo $'exec geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh
    49  
    50  RUN \
    51  	sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
    52  	sed -i 's/PuppethNetwork/{{.Network}}/g'     dist/js/etherwallet-master.js && \
    53  	sed -i 's/PuppethDenom/{{.Denom}}/g'         dist/js/etherwallet-master.js && \
    54  	sed -i 's/PuppethHost/{{.Host}}/g'           dist/js/etherwallet-master.js && \
    55  	sed -i 's/PuppethRPCPort/{{.RPCPort}}/g'     dist/js/etherwallet-master.js
    56  
    57  ENTRYPOINT ["/bin/sh", "wallet.sh"]
    58  `
    59  
    60  //
    61  //
    62  var walletComposefile = `
    63  version: '2'
    64  services:
    65    wallet:
    66      build: .
    67      image: {{.Network}}/wallet
    68      ports:
    69        - "{{.NodePort}}:{{.NodePort}}"
    70        - "{{.NodePort}}:{{.NodePort}}/udp"
    71        - "{{.RPCPort}}:8545"{{if not .VHost}}
    72        - "{{.WebPort}}:80"{{end}}
    73      volumes:
    74        - {{.Datadir}}:/root/.ethereum
    75      environment:
    76        - NODE_PORT={{.NodePort}}/tcp
    77        - STATS={{.Ethstats}}{{if .VHost}}
    78        - VIRTUAL_HOST={{.VHost}}
    79        - VIRTUAL_PORT=80{{end}}
    80      logging:
    81        driver: "json-file"
    82        options:
    83          max-size: "1m"
    84          max-file: "10"
    85      restart: always
    86  `
    87  
    88  //
    89  //Docker和Docker组合。如果具有指定网络名称的实例
    90  //已经存在,将被覆盖!
    91  func deployWallet(client *sshClient, network string, bootnodes []string, config *walletInfos, nocache bool) ([]byte, error) {
    92  //生成要上载到服务器的内容
    93  	workdir := fmt.Sprintf("%d", rand.Int63())
    94  	files := make(map[string][]byte)
    95  
    96  	dockerfile := new(bytes.Buffer)
    97  	template.Must(template.New("").Parse(walletDockerfile)).Execute(dockerfile, map[string]interface{}{
    98  		"Network":   strings.ToTitle(network),
    99  		"Denom":     strings.ToUpper(network),
   100  		"NetworkID": config.network,
   101  		"NodePort":  config.nodePort,
   102  		"RPCPort":   config.rpcPort,
   103  		"Bootnodes": strings.Join(bootnodes, ","),
   104  		"Ethstats":  config.ethstats,
   105  		"Host":      client.address,
   106  	})
   107  	files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes()
   108  
   109  	composefile := new(bytes.Buffer)
   110  	template.Must(template.New("").Parse(walletComposefile)).Execute(composefile, map[string]interface{}{
   111  		"Datadir":  config.datadir,
   112  		"Network":  network,
   113  		"NodePort": config.nodePort,
   114  		"RPCPort":  config.rpcPort,
   115  		"VHost":    config.webHost,
   116  		"WebPort":  config.webPort,
   117  		"Ethstats": config.ethstats[:strings.Index(config.ethstats, ":")],
   118  	})
   119  	files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes()
   120  
   121  	files[filepath.Join(workdir, "genesis.json")] = config.genesis
   122  
   123  //将部署文件上载到远程服务器(然后清理)
   124  	if out, err := client.Upload(files); err != nil {
   125  		return out, err
   126  	}
   127  	defer client.Run("rm -rf " + workdir)
   128  
   129  //
   130  	if nocache {
   131  		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
   132  	}
   133  	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
   134  }
   135  
   136  //
   137  //各种配置参数。
   138  type walletInfos struct {
   139  	genesis  []byte
   140  	network  int64
   141  	datadir  string
   142  	ethstats string
   143  	nodePort int
   144  	rpcPort  int
   145  	webHost  string
   146  	webPort  int
   147  }
   148  
   149  //报表将类型化结构转换为纯字符串->字符串映射,其中包含
   150  //大多数(但不是全部)字段用于向用户报告。
   151  func (info *walletInfos) Report() map[string]string {
   152  	report := map[string]string{
   153  		"Data directory":         info.datadir,
   154  		"Ethstats username":      info.ethstats,
   155  		"Node listener port ":    strconv.Itoa(info.nodePort),
   156  		"RPC listener port ":     strconv.Itoa(info.rpcPort),
   157  		"Website address ":       info.webHost,
   158  		"Website listener port ": strconv.Itoa(info.webPort),
   159  	}
   160  	return report
   161  }
   162  
   163  //
   164  //
   165  func checkWallet(client *sshClient, network string) (*walletInfos, error) {
   166  //
   167  	infos, err := inspectContainer(client, fmt.Sprintf("%s_wallet_1", network))
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	if !infos.running {
   172  		return nil, ErrServiceOffline
   173  	}
   174  //从主机或反向代理解析端口
   175  	webPort := infos.portmap["80/tcp"]
   176  	if webPort == 0 {
   177  		if proxy, _ := checkNginx(client, network); proxy != nil {
   178  			webPort = proxy.port
   179  		}
   180  	}
   181  	if webPort == 0 {
   182  		return nil, ErrNotExposed
   183  	}
   184  //
   185  	host := infos.envvars["VIRTUAL_HOST"]
   186  	if host == "" {
   187  		host = client.server
   188  	}
   189  //
   190  	nodePort := infos.portmap[infos.envvars["NODE_PORT"]]
   191  	if err = checkPort(client.server, nodePort); err != nil {
   192  		log.Warn(fmt.Sprintf("Wallet devp2p port seems unreachable"), "server", client.server, "port", nodePort, "err", err)
   193  	}
   194  	rpcPort := infos.portmap["8545/tcp"]
   195  	if err = checkPort(client.server, rpcPort); err != nil {
   196  		log.Warn(fmt.Sprintf("Wallet RPC port seems unreachable"), "server", client.server, "port", rpcPort, "err", err)
   197  	}
   198  //收集并返回有用的信息
   199  	stats := &walletInfos{
   200  		datadir:  infos.volumes["/root/.ethereum"],
   201  		nodePort: nodePort,
   202  		rpcPort:  rpcPort,
   203  		webHost:  host,
   204  		webPort:  webPort,
   205  		ethstats: infos.envvars["STATS"],
   206  	}
   207  	return stats, nil
   208  }