以太坊客户端
以太坊客户端用于接入以太坊网络,进行账户管理、交易、挖矿、智能合约相关的操作。目前有多种语言实现的客户端,常用的有 Go 语言实现的 go-ethereum 客户端 Geth,支持接入以太坊网络并成为一个完整节点,也可作为一个 HTTP-RPC 服务器对外提供 JSON-RPC 接口。
其他的客户端有:
智能合约编译器
以太坊支持两种智能合约的编程语言:Solidity 和 Serpent。Serpent 语言面临一些安全问题,现在已经不推荐使用了。Solidity 语法类似 JavaScript,它编译器 solc 可以把智能合约源码编译成以太坊虚拟机 EVM 可以执行的二进制码。
现在以太坊提供更方便的在线 IDE —— Remix https://remix.ethereum.org 使用 Remix,免去了安装 solc 和编译过程,它可以直接提供部署合约所需的二进制码和 ABI。
以太坊钱包
以太坊提供了图形界面的钱包 Ethereum Wallet 和 Mist Dapp 浏览器。钱包的功能是 Mist 的一个子集,可用于管理账户和交易;Mist 在钱包基础上,还能操作智能合约。为了演示合约部署过程,本文使用了 Geth console 操作,没有用到 Mist,当然,使用 Mist 会更简单。
环境说明:
操作系统:Ubuntu16.4
Go环境:1.9.2
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
# 下载最新版本
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
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)章节所描述的条件。.
0x
开头初始化命令如下。/root/chain
【{dataDir}】目录存放区块链数据(可为其他目录)
geth --datadir "/root/chain" init genesis.json
出现如下内容就成功了
Successfully wrote genesis state database=lightchaindata hash=84e71d…97246e
初始化成功后,会在数据目录{dataDir} 中生成 geth
和 keystore
(存储加密后的账户信息)两个文件夹,目录结构如下:
.(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
参数说明如下:
注意:如果想将Ubuntu作为永久区块链节点使用,当使用
nohup
命令时,Geth启动参数console
必须去掉,否则Geth会自动停止。
启动完成之后进入控制台,这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 >
是命令提示符。在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以直接使用这些对象。这些对象主要包括:
> 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、如果使用的服务器或者虚拟机需要注意防火墙和端口的配置
以太坊
以太坊私有链搭建指南
码农的区块链:搭建一个私有区块链环境