转载博文:https://www.jianshu.com/p/8af386ec5f9e

https://www.jianshu.com/p/7994db7a2b89?from=singlemessage

https://blog.csdn.net/hqzxsc2006/article/details/79526911

阅读完本文,你将可以在一台物理机上搭建起一个完整的以太坊私链,并且部署自己的合约。用以开发、调试、学习以太坊。

本文涉及的知识和技术有:

  • Docker:一种时下流行的容器
  • geth:以太坊客户端的go实现
  • truffle:以太坊合约

Docker环境搭建

关于如何搭建Docker环境,可以参考我之前的一篇文章。以下的内容都是基于该文搭建的环境。如果你已经有了可以运行的Docker环境,可以忽略。

文章地址:https://www.jianshu.com/p/7ca57e4f66c5

主机配置

此处需要补充一点的是,如果您使用的是虚拟机、云主机或者老破小机器,需要确保分配给主机的内存至少2GB或以上。因为以太坊为了抵御比特大陆这样的ASIC矿机对算力的垄断,采用了和比特币完全不同的PoW算法——ethash。该算法的特点是算力不敏感,内存敏感。该算法目前需要在内存创建大约1GB的DAG用来做PoW运算,且DAG会随着区块的增加呈阶梯状增长,因此建议至少给挖矿节点的宿主机器分配至少2GB的内存,且保留扩大内存容量的灵活性。

获取geth镜像

docker hub上有现成的geth镜像。直接获取。

docker pull ethereum/client-go:v1.8.12

试运行一下

docker run -it --rm -v /workspace:/workspace --entrypoint /bin/sh ethereum/client-go:v1.8.12

此处修改镜像默认的entrypoint是为了不让节点自动运行。我们稍后会对节点进行自定义配置使其成为私有链节点。
-v将本地的/workspace目录挂载成容器的/workspace目录,用来在容器和宿主机器之间共享文件

创建Docker网络

旧版本的docker容器相互之间是依靠link建立关系。
新版本docker推荐创建自有网路,再将需要互联的容器配置到相同的网络中。
于是,我们创建一个名为“ethnet“的网络。该网络配置如下:

  • 子网172.18.0.0/16

    • IP段172.18.0.0
    • 掩码255.255.0.0
    • IP范围172.18.0.1~172.18.255.254
    • IP广播172.18.255.255
docker network create -d bridge --subnet=172.18.0.0/ ethnet
docker network ls

配置以太坊网络

运行如下命令进入一个容器:

docker run -it --rm --network ethnet --ip 172.18.0.40 -v /workspace:/workspace --entrypoint /bin/sh ethereum/client-go:v1.8.12

--network ethnet参数指定了该容器加入刚才创建的ethnet网络
--ip 172.18.0.5指定了一个固定IP给该容器。

创建账户

首先,在容器内的/workspace目录创建如下目录结构和文件:

dapp\
dapp\miner\
dapp\data\
dapp\genesis.json

然后运行如下命令创建账户:

cd /workspace/dapp/miner
geth -datadir ./data account new

输入两次password,获得地址。将地址记录下来,后面要用到。

重复如上步骤可以创建多个账户。

创建4个账户:

Address0: {6da7e585f389c24010445bd1578362dc1c6be44d}
Address1: {97cb4a1f2a3748df3de2ad1e0ca32d66639da852}
Address2: {2d7b7417447ae079255dee15d3fc8c41d06bdb72}
Address3: {edf470defd86bbd2bf7ca9320f19d327c86ba1c6}

创建创世区块

编辑刚才创建的文件dapp\genesis.json

{
"config": {
"chainId": ,
"homesteadBlock": ,
"eip155Block": ,
"eip158Block":
},
"alloc" : {
"0x6da7e585f389c24010445bd1578362dc1c6be44d": {"balance": "100000000000000000000"},
"0x97cb4a1f2a3748df3de2ad1e0ca32d66639da852": {"balance": "1000000000000000000"},
"0x2d7b7417447ae079255dee15d3fc8c41d06bdb72": {"balance": "1000000000000000000"},
"0xedf470defd86bbd2bf7ca9320f19d327c86ba1c6": {"balance": "1000000000000000000"}
},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x400",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000000",
"mixhash" :
"0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" :
"0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}
  • genesis.json是用来创建创世区块的配置文件
  • 加入同一私链的节点必须使用同一配置文件
  • chainid是私链网络的标识,可以是任意数字。
  • 即使chainid相同,如果genesis.json配置不一样,也将是两个不兼容的网络
  • alloc下面列举了4个账户地址,分别是上一步骤创建并记录下来的地址。
  • balance是创世区块为每个账户分配的初始以太币。这里看似分配了很多,其实单位是wei。1eth=10^18wei。也就是除了第一个账户给了100eth外,其它几个账户分别只拥有1eth。这里给第一个账户多分点,是因为我们之后需要用它来部署合约。

完成以太坊网络配置

此时可以退出刚才的容器。由于我们运行容器是加了--rm参数,刚才的容器会被删除,但宿主机的/workspace下的文件会被保存下来。

挖矿

上述步骤只是配置好了一个以太坊私有网络,并没有真正创建网络。我们知道,以太坊网络是一个分布式的网络,有了矿工,才有的网络。于是,我们首先得有一个矿工。

创建“主”矿工节点

我们接下来打算创建的矿工节点,成为“主”矿工,因为它需要拥有如下特性:

  • 它是一个容器,并且是持久的容器
  • 它会自动读取genesis.json文件,并初始化以太坊网络
  • 它能够连接其它节点(容器)
  • 它能够接受各种rpc调用,并能够部署合约
  • 它已经配置好挖矿账户,可以一键挖矿

于是,我们按照这个要求,开始一步步创建矿工节点。

创建entrypoint脚本

创建一个文件:/workspace/dapp/init.sh
文件内容如下:

#!/bin/sh
geth -datadir ~/data/ init /workspace/traceability/genesis.json if [ $# -lt ]; then
exec "/bin/sh"
else
exec /bin/sh -c "$@"
fi

给init.sh赋予执行权限:

chmod  init.sh

该脚本的功能是让以太坊节点(容器)自动初始化以太坊网络,并且接受一个自动运行脚本作为输入。

创建自动运行脚本

创建一个文件:/workspace/dapp/mine.sh
内容如下:

#!/bin/sh
cp -r /workspace/dapp/miner/data/keystore/* ~/data/keystore/
geth -datadir ~/data/ --networkid 88 --rpc --rpcaddr "172.18.0.50" --rpcapi admin,eth,miner,web3,personal,net,txpool --unlock "0x6da7e585f389c24010445bd1578362dc1c6be44d" --etherbase "0x6da7e585f389c24010445bd1578362dc1c6be44d" console

给mine.sh赋予执行权限:

chmod  mine.sh
  • 第一行命令是将刚才生成的账户私钥文件拷贝到容器的home目录下。因为/workspace是宿主目录挂载的,并不是linux文件系统,直接将datadir指定到该目录会导致geth报错。
  • 第二行命令是启动以太坊节点的命令。
    • --networkid 88指定了networkid,这个必须与genesis.json内设置保持一致
    • --rpc --rpcaddr "172.18.0.50" --rpcapi .... 这些参数表示该节点接受rpc,并且指定了rpc的协议
    • --unlock "0x..." 加入该参数会需要用户输入账户密码。密码校验后会解锁该账户。账户解锁后,该节点就能使用此账户的私钥进行签名加密等动作,用以进行交易、发布合约等。
    • --etherbase 参数指定了挖矿收益账户

创建容器

docker run -it --name=miner --network ethnet --ip 172.18.0.50 --hostname node -v /workspace:/workspace --entrypoint /workspace/dapp/init.sh ethereum/client-go:v1.8.12 /workspace/dapp/mine.sh

该命令会创建一个持久化的容器。容器的entrypoint和自动运行脚本指定为我们刚创建的那两个脚本。

创建“从”矿工节点

只有一个节点的网络,怎么看都不像“分布式”网络。所以我们需要创建更多的节点来形成一个“分布式网络”。我们称这些节点叫做“从”矿工。
这类矿工不需要交易,不需要发布合约,因此不需要unlock账户,也不需要接受rpc。它们只知道埋头挖矿。

创建自动运行脚本

“从”矿工节点和“主”矿工节点共享entrypoint,以保证它们创建出完全相同的网络。
只有自动运行脚本不太一样,/workspace/dapp/node.sh:

#!/bin/sh
cp -r /workspace/dapp/miner/data/keystore/* ~/data/keystore/
geth -datadir ~/data/ --networkid 88 console

给node.sh赋予执行权限:

chmod  node.sh

创建容器

节点1:

docker run -it --name=node1 --network ethnet --ip 172.18.0.51 --hostname node1 -v /workspace:/workspace --entrypoint /workspace/dapp/init.sh ethereum/client-go:v1.8.12 /workspace/dapp/node.sh

节点2:

docker run -it --name=node2 --network ethnet --ip 172.18.0.52 --hostname node2 -v /workspace:/workspace --entrypoint /workspace/dapp/init.sh ethereum/client-go:v1.8.12 /workspace/dapp/node.sh

操作节点

以上创建出了多个以太坊节点,运行在同一网络下。每个节点都可以执行如下操作。供参考。

节点发现

查看节点信息

geth -datadir ~/data/ --networkid  console
>admin.nodeInfo.enode

配置静态节点文件

~/data/geth/static-nodes.json
[
//miner:
"enode://9c4cd381d661cae558b18416b90a4c61e870519f55bde9688fd43b0e1047e1e577bb92ddcf664086e13c761fd9074dc2ee38f1988e1b2d0ac7c7d6c182a0b002@[::]:30303",
//node1:
"enode://863ce25a410afe973cfb2efd866b2c7726f8fc6134866cdaec86a9a5c13fa1ef414b05df95f3f0f2460d7f0d30608165c7146d9b229fa7120adf0d8c5b857d22@[::]:30303",
//node2:
"enode://85c55fd02de2231f3750f910002861e9f16651fc0dd0d18d7e1672954166be2b8092d6f52e3dd25c94c453fb1f4545ac1bc089edcec8e4411aa7dc0ff8f51cbc@[::]:30303"
]

查看连接上的节点

geth -datadir ~/data/ --networkid  console
>admin.peers

动态添加节点

>admin.addPeer("enode://<node public key>@<node IP address>:<node port>")

挖矿

启动miner容器

>miner.start()
  • 参数1指定了挖矿的线程数。
  • 首次启动节点会消耗大约20~30分钟产生DAG
  • 某开始挖矿后,其它节点将会收到新区块并打印

交易:https://blog.csdn.net/u013096666/article/details/72639906

部署合约

可参考博文:http://www.cnblogs.com/sumingk/articles/9030469.html

创建truffle镜像

由于没有找到好用的truffle镜像,我自己创建了一个。Dockerfile内容如下:

FROM alpine:3.8
MAINTAINER Cary Tan tx-cary@.com
ENV PS1='[truffle@docker $PWD]\$ '
RUN echo "http://mirrors.tuna.tsinghua.edu.cn/alpine/v3.8/main" > /etc/apk/repositories \
&& echo "http://mirrors.tuna.tsinghua.edu.cn/alpine/v3.8/community" >> /etc/apk/repositories \
&& apk update \
&& apk add npm \
&& mkdir -p /workspace \
&& npm config set registry https://registry.npm.taobao.org \
&& npm install -g truffle
WORKDIR /workspace
CMD /bin/sh

该镜像我已经上传到dockerhub了,您也可以直接下载使用:

docker pull txcary/truffle:

启动truffle容器

docker run -it --rm -v /workspace:/workspace --network ethnet txcary/truffle:

测试节点RPC

curl 172.18.0.50: -X POST --data '{"id":1,"jsonrpc":"2.0","method":"eth_accounts", "params":[]}' -H "Content-Type: application/json"
curl 172.18.0.50: -X POST --data '{"id":1,"jsonrpc":"2.0","method":"eth_getBalance", "params":["0x4c2832
87839fd441b8c8d18771321bc06a81edae","latest"]}' -H "Content-Type: application/json"
  • 第一条命令获取节点上的账户
  • 第二条命令获取账户余额
  • 如果这两条命令成功了,说明以太坊私有网络搭建成功,并且节点rpc调用成功

新建truffle工程

truffle init

修改truffle.js

module.exports = {
networks: {
development: {
host: "172.18.0.50",
port: ,
network_id: ,
gas: ,
gasPrice:
}
}
};
  • gas使用默认值会导致超限错误,研究半天不知道为什么。要是搞明白的可以给我留言,谢谢!
  • gasPrice为默认值

编写合约Yourname.sol

  • 合约名称必须和文件名一致,不然会部署失败
    如果你还没有自己的合约,可以上truffle官网下载一个做练习。
    我也做了一个供应链追踪的合约放在github上:https://github.com/txcary/traceability。该合约通过remix调试并成功部署在我的私链上,供参考。

新建部署脚本

2_deploy_contracts.js

var Yourname = artifacts.require("./Yourname.sol");

module.exports = function(deployer) {
deployer.deploy(Yourname);
};

编译合约

truffle compile

部署合约

truffle migrate --network development --verbose-rpc

作者:大洋一生
链接:https://www.jianshu.com/p/7994db7a2b89
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

基于docker的以太坊集群的私有链开发环境的更多相关文章

  1. 庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群

    庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群 一.简介      前面的两篇文章,我们已经介绍了Net Core项目基于Docker容器部署在Linux服 ...

  2. 基于docker虚拟化创建hadoop集群

    最近想用hadoop做一个测试,与性能无关的测试,但是可与屌丝的命,手头没有太多机器,也租不起云主机.这里使用docker进行虚拟化,并搭建hadoop集群,在这里将过程记录如下. 首先安装docke ...

  3. 喵星之旅-狂奔的兔子-基于docker的redis分布式集群

    一.docker安装(略) 二.下载redis安装包(redis-4.0.8.tar.gz) 以任何方式获取都可以.自行官网下载. 三.拉取centos7的docker镜像 命令:docker pul ...

  4. 基于Docker UI 配置ceph集群

    前言 前一篇介绍了docker在命令行下面进行的ceph部署,本篇用docker的UI进行ceph的部署,目前来说市面上还没有一款能够比较简单就能直接在OS上面去部署Ceph的管理平台,这是因为OS的 ...

  5. 基于docker快速搭建hbase集群

    一.概述 HBase是一个分布式的.面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文"Bigtable:一个结构化数据的分布式存储系统".就像Bigt ...

  6. 暑假第二弹:基于docker的hadoop分布式集群系统的搭建和测试

    早在四月份的时候,就已经开了这篇文章.当时是参加数据挖掘的比赛,在计科院大佬的建议下用TensorFlow搞深度学习,而且要在自己的hadoop分布式集群系统下搞. 当时可把我们牛逼坏了,在没有基础的 ...

  7. 基于docker的spark-hadoop分布式集群之一: 环境搭建

    一.软件准备 1.基础docker镜像:ubuntu,目前最新的版本是18 2.需准备的环境软件包: (1) spark-2.3.0-bin-hadoop2.7.tgz (2) hadoop-2.7. ...

  8. 基于Docker方式实现Elasticsearch集群

    采用docker容器,搭建两个es集群,可根据步骤自行扩展n+集群 1.创建es挂载目录 cd /usr/localmkdir -p es/config 2.创建es存放数据目录 cd esmkdir ...

  9. 搭建基于docker 的redis分布式集群在docker for windows

    https://blog.csdn.net/xielinrui123/article/details/85104446 首先在docker中下载使用 docker pull redis:3.0.7do ...

随机推荐

  1. php设计模式之简单工厂模式代码实例

    <?php header("Content-type:text/html;charset=utf-8"); /** * 共同接口 */ interface db { func ...

  2. 题解【洛谷P3884】[JLOI2009]二叉树问题

    题面 题解 这道题目可以用很多方法解决,这里我使用的是树链剖分. 关于树链剖分,可以看一下我的树链剖分学习笔记. 大致思路是这样的: 第\(1\)次\(dfs\)记录出每个点的父亲.重儿子.深度.子树 ...

  3. Custom LED Keychain, Small And Surefire Gifts

    The    LED Keychain    makes it easy for people to carry their keys with them and carry them with th ...

  4. scrapy 框架基本使用

    scrapy简介: Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 ...

  5. (原)Vue 单文件组件安装 (创建vue-cli 项目)

    更新于20200220 题外话:久违了我的博客园 正题: 1.准备工作,安装环境 1.安装node 官网下载安装即可  -- 配置环境变量 2.安装npm (基于node.js 包管理器) 3.安装c ...

  6. think PHP5中,模板、控制器、JavaScript的url跳转重定向方法

    php控制器中的跳转: 1, header()函数是PHP中进行页面跳转的一种十分简单的方法.主要功能是将HTTP协议标头(header)输出到浏览器. header("Location: ...

  7. AcWing 853. 有边数限制的最短路 bellman-ford 结构体

    //存在负权值 处理负环 //如果能求出来 一般是不存在负权回路 //如果有负回路 那最小距离可能是负无穷 #include <cstring> #include <iostream ...

  8. Codeforces Round #598 (Div. 3) D. Binary String Minimizing

    You are given a binary string of length nn (i. e. a string consisting of nn characters '0' and '1'). ...

  9. FileOutputStream,BufferedOutputStream,FileWriter 效率比较

    测试代码: /** * 写文件 * FileOutputStream, BufferedOutputStream, FileWriter * 三个流 效率比较 */ @Test public void ...

  10. yii2时区语言设置

    main.php return [ 'charset' => 'utf-8', 'language' => 'zh-CN', 'timeZone' => 'Asia/Shanghai ...