以太坊私有链搭建指南

go-ethereum 私有链搭建指南

前言

工具
  1. 以太坊客户端

    以太坊客户端用于接入以太坊网络,进行账户管理、交易、挖矿、智能合约相关的操作。目前有多种语言实现的客户端,常用的有 Go 语言实现的 go-ethereum 客户端 Geth,支持接入以太坊网络并成为一个完整节点,也可作为一个 HTTP-RPC 服务器对外提供 JSON-RPC 接口。

    其他的客户端有:

    • Parity:Rust 语言实现;
    • cpp-ethereum:C++ 语言实现;
    • ethereumjs-lib:JavaScript 语言实现;
    • Ethereum(J):Java 语言实现;
    • ethereumH:Haskell 语言实现;
    • pyethapp: Python 语言实现;
    • ruby-ethereum:Ruby 语言实现;
  2. 智能合约编译器
    以太坊支持两种智能合约的编程语言:Solidity 和 Serpent。Serpent 语言面临一些安全问题,现在已经不推荐使用了。Solidity 语法类似 JavaScript,它编译器 solc 可以把智能合约源码编译成以太坊虚拟机 EVM 可以执行的二进制码。
    现在以太坊提供更方便的在线 IDE —— Remix https://remix.ethereum.org 使用 Remix,免去了安装 solc 和编译过程,它可以直接提供部署合约所需的二进制码和 ABI。

  3. 以太坊钱包
    以太坊提供了图形界面的钱包 Ethereum Wallet 和 Mist Dapp 浏览器。钱包的功能是 Mist 的一个子集,可用于管理账户和交易;Mist 在钱包基础上,还能操作智能合约。为了演示合约部署过程,本文使用了 Geth console 操作,没有用到 Mist,当然,使用 Mist 会更简单。

环境说明

操作系统:Ubuntu16.4
Go环境:1.9.2

安装 ethereum

1、PPA 直接安装

# 安装必要的工具包
apt install software-properties-common
# 添加以太坊源
add-apt-repository -y ppa:ethereum/ethereum
apt update
# 安装 go-ethereum
apt install ethereum

安装完成可以通过geth version 命令查看是否安装成功

2、源码安装,源码安装需要安装Go环境

参考官方文档 https://golang.org/doc/install

  • 配置Go环境,版本1.9.2
# 下载最新版本
curl -O https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz
# 解压
tar -C /usr/local -xzf go1.9.2.linux-amd64.tar.gz
# 卸载
apt-get purge golang-go
# 查看版本
go version
  • 设置GOPATH和PATH

    1、设置一个去文件夹 mkdir -p ~/go; echo "export GOPATH=$HOME/go" >> ~/.bashrc

    2、更新你的路径 echo "export PATH=$PATH:$HOME/go/bin:/usr/local/go/bin" >> ~/.bashrc

    3、将环境变量读入当前会话: source ~/.bashrc

  • 安装ethereum

  sudo apt-get install software-properties-common
  sudo add-apt-repository -y ppa:ethereum/ethereum
  sudo add-apt-repository -y ppa:ethereum/ethereum-dev
  sudo apt-get update
  sudo apt-get install ethereum
  • 安装 solc 编译器
  sudo add-apt-repository ppa:ethereum/ethereum-qt
  sudo add-apt-repository ppa:ethereum/ethereum
  sudo apt-get update
  sudo apt-get install cpp-ethereum

至此环境已经安装完成

私有链搭建

一、配置初始状态

​ 要运行以太坊私有链,需要定义自己的创世区块,创世区块信息写在一个 JSON 格式的配置文件中。首先将下面的内容保存到一个 JSON 文件中,例如 genesis.json

{
   "config": {
        "chainId": 1024,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
  "alloc": {},
  "nonce": "0x0000000000000042",
  "difficulty": "0x020000",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "timestamp": "0x00",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData": "0x6d6f7475692d32",
  "gasLimit": "0xffffffff"
}

各个参数的含义如下:

  • chainId :指定了独立的区块链网络 ID。网络 ID 在连接到其他节点的时候会用到,以太坊公网的网络 ID 是 1,为了不与公有链网络冲突,运行私有链节点的时候要指定自己的网络 ID。不同 ID 网络的节点无法相互连接。

  • mixhash:与nonce配合用于挖矿,由上一个区块的一部分生成的hash。注意他和nonce的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。.

  • nonce: nonce就是一个64位随机数,用于挖矿,注意他和mixhash的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。
  • difficulty: 设置当前区块的难度,如果难度过大,cpu挖矿就很难,这里设置较小难度
  • alloc: 用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以我们不需要预置有币的账号,需要的时候自己创建即可以。默认为空即可
  • coinbase: 矿工的账号,随便填
  • timestamp: 设置创世块的时间戳
  • parentHash: 上一个区块的hash值,因为是创世块,所以这个值是0
  • extraData: 附加信息。【注意】新版本该值需要为16进制数据,以0x 开头
  • gasLimit: 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们是私有链,所以填最大。

二、初始化:写入创世区块

初始化命令如下。/root/chain 【{dataDir}】目录存放区块链数据(可为其他目录)

geth  --datadir "/root/chain" init genesis.json 

出现如下内容就成功了

Successfully wrote genesis state         database=lightchaindata         hash=84e71d…97246e

初始化成功后,会在数据目录{dataDir} 中生成 gethkeystore (存储加密后的账户信息)两个文件夹,目录结构如下:

.(root)
├── chain
│   ├── geth
│   │   ├── chaindata
│   │   │   ├── 000001.log
│   │   │   ├── CURRENT
│   │   │   ├── LOCK
│   │   │   ├── LOG
│   │   │   └── MANIFEST-000000
│   │   └── lightchaindata
│   │       ├── 000001.log
│   │       ├── CURRENT
│   │       ├── LOCK
│   │       ├── LOG
│   │       └── MANIFEST-000000
│   └── keystore
└── genesis.json

三、启动私有链节点

初始化完成后,就有了一条自己的私有链,之后就可以启动自己的私有链节点并做一些操作,在终端中输入以下命令即可启动节点:

geth --identity "motui"  --rpc  --rpccorsdomain "*" --datadir "/root/chain" --port "30303"  --rpcapi "db,eth,net,web3" --networkid 89898 console

参数说明如下:

  • identity :指定节点 用于标示目前网络的名字;
  • rpc :表示开启 HTTP-RPC 服务;
  • init :指定创世块文件的位置,并创建初始块
  • rpcport :指定 HTTP-RPC 服务监听端口号(默认为 8545);
  • rpcapi: 设置允许连接的rpc的客户端,一般为db,eth,net,web3
  • datadir :指定区块链数据的存储位置;
  • port :指定和其他节点连接所用的端口号(默认为 30303);
  • networkid: 设置当前区块链的网络ID,用于区分不同的网络,是一个数字
  • nodiscover :关闭节点发现机制,防止加入有同样初始配置的陌生节点。
  • maxpeers : 如果你不希望其他人连接到你的测试链,可以使用maxpeers 0。反之,如果你确切知道希望多少人连接到你的节点,你也可以通过调整数字来实现。
  • rpccorsdomain : 这个可以指示什么URL能连接到你的节点来执行RPC定制端任务。务必谨慎,输入一个特定的URL而不是wildcard ( * ),后者会使所有的URL都能连接到你的RPC实例。
  • console:启动命令行模式,可以在Geth中执行命令

注意:如果想将Ubuntu作为永久区块链节点使用,当使用nohup命令时,Geth启动参数console必须去掉,否则Geth会自动停止。

​ 启动完成之后进入控制台,这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符。在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以直接使用这些对象。这些对象主要包括:

  • eth:包含一些跟操作区块链相关的方法;
  • net:包含一些查看p2p网络状态的方法;
  • admin:包含一些与管理节点相关的方法;
  • miner:包含启动&停止挖矿的一些方法;
  • personal:主要包含一些管理账户的方法;
  • txpool:包含一些查看交易内存池的方法;
  • web3:包含了以上对象,还包含一些单位换算的方法。
> eth.accounts
["0x6594cc2f72908c0fea54d5c9dd297ce68f735411", "0x442aa25d86f30c3ed1cdee8cb787dccac680abdd"]
> 

3、查看账户余额

> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0
> 

查询余额有多种方式,可以通过创建时的16进制码,也可以通过账户下标查询,下标默认从0开始

启动&停止挖矿

启动挖矿

> miner.start(1)

其中 start 的参数表示挖矿使用的线程数。第一次启动挖矿会先生成挖矿所需的 DAG 文件,这个过程有点慢,等进度达到 100% 后,就会开始挖矿,此时屏幕会被挖矿信息刷屏。

停止挖矿

> miner.stop()

挖到一个区块会奖励n个以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做 coinbase,默认情况下 coinbase 是本地账户中的第一个账户,可以通过 miner.setEtherbase() 将其他账户设置成 coinbase。

交易

假如0账户向1账户转账,需要先把0账户锁定,然后才能进行交易

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x6594cc2f72908c0fea54d5c9dd297ce68f735411
Passphrase: 
true
> 

转账 账户0 –> 账户1

> amount = web3.toWei(5,'ether')
"5000000000000000000"
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount})
INFO [01-18|17:56:14] Submitted transaction                    fullhash=0x065c698cceaf996ab9ab06c6eddc8b035704defbcff0d65227d32c06a5b17637 recipient=0x4BD9F7b3c365D35C50757AF4CC7Bdb1307A083C0
"0x065c698cceaf996ab9ab06c6eddc8b035704defbcff0d65227d32c06a5b17637
>

此时如果没有挖矿,用 txpool.status 命令可以看到本地交易池中有一个待确认的交易,可以使用 eth.getBlock("pending", true).transactions 查看当前待确认交易。

查交易和区块

> eth.blockNumber
200

通过交易 Hash 查看交易(Hash 值包含在上面交易返回值中):

> eth.getTransaction("0x65a8278d571d7cf3f2ca36ce721900d61e9d6eadd1ed5f24f39b646c2b194427")
{
  blockHash: "0x0101b5f9e9c50ee45156f0631df18a97176aef5215bde40b3e167195d367ed80",
  blockNumber: 342,
  from: "0x16671cdabbc9b3f0f1b31380d972dcd9725f7d8a",
  gas: 90000,
  gasPrice: 18000000000,
  hash: "0x65a8278d571d7cf3f2ca36ce721900d61e9d6eadd1ed5f24f39b646c2b194427",
  input: "0x",
  nonce: 1,
  r: "0x52b7fce530ebd67527d4fe684cb3b5a4b96909154aeedcc5f371ab27e9e7f1ba",
  s: "0x141268e8fef639b79773f6ab7fb778b958be77bd05944f305dc4f1ec68f21962",
  to: "0x4bd9f7b3c365d35c50757af4cc7bdb1307a083c0",
  transactionIndex: 0,
  v: "0x823",
  value: 5000000000000000000
}
> 

通过区块号查看区块:

> eth.getBlock(0)
{
  difficulty: 131072,
  extraData: "0x6d6f7475692d32",
  gasLimit: 4294967295,
  gasUsed: 0,
  hash: "0x5117726df3040cb5cbd6e8d59cdaacaaa1cd8df4a20072d0e8242e96ea5c893f",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x0000000000000000000000000000000000000000",
  mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  nonce: "0x0000000000000042",
  number: 0,
  parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 515,
  stateRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  timestamp: 0,
  totalDifficulty: 131072,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}
> 

连接到其他节点

所有的节点创建都是一样的。

可以通过 admin.addPeer() 方法连接到其他节点,两个节点要要指定相同的 chainID。

假设有两个节点:节点一和节点二,chainID 都是 1024,通过下面的步骤就可以从节点一连接到节点二。

首先要知道节点二的 enode 信息,在节点二的 JavaScript console 中执行下面的命令查看 enode 信息:

> admin.nodeInfo.enode
"enode://8db747ce768cb5e6ea3dc00bd16fe2bdf56dbeda0b1abfcd2ddcbb5a5cf0fe6bb0123ca341935c2c4348a34c89b0a73e2fac72e8b4fac414006760aa9ab1f613@[::]:30303"
> 

然后在节点一的 JavaScript console 中执行 admin.addPeer(),就可以连接到节点二:

> admin.addPeer("enode://8db747ce768cb5e6ea3dc00bd16fe2bdf56dbeda0b1abfcd2ddcbb5a5cf0fe6bb0123ca341935c2c4348a34c89b0a73e2fac72e8b4fac414006760aa9ab1f613@127.0.0.1:30303")
true
>

addPeer() 的参数就是节点二的 enode 信息,注意要把 enode 中的 [::] 替换成节点二的 IP 地址。连接成功后,节点二就会开始同步节点一的区块,同步完成后,任意一个节点开始挖矿,另一个节点会自动同步区块,向任意一个节点发送交易,另一个节点也会收到该笔交易。

通过 admin.peers 可以查看连接到的其他节点信息,通过 net.peerCount 可以查看已连接到的节点数量。

除了上面的方法,也可以在启动节点的时候指定 --bootnodes 选项连接到其他节点。

注意:

​ 1、对于操作过程中存在的问题网上基本上都有解决方法,可以参考错误信息自己解决

​ 2、如果使用的服务器或者虚拟机需要注意防火墙和端口的配置

参考内容

以太坊

以太坊私有链搭建指南

码农的区块链:搭建一个私有区块链环境

你可能感兴趣的:(区域链)