以太坊开发(三)使用 Go-Ethereum 1.8.1搭建以太
什么是 Go-Ethereum
Go-Ethereum是由以太坊基金会提供的官方客户端软件。它是用Go编程语言编写的,简称Geth。
Geth是以太坊协议的具体落地实现,通过Geth,你可以实现以太坊的各种功能,如账户的新建编辑删除,开启挖矿,ether币的转移,智能合约的部署和执行等等。
Geth官网:https://geth.ethereum.org/
Geth的Github地址:https://github.com/ethereum/go-ethereum
本文环境:
Mac OS 10.13.3
Homebrew v1.5.4
Geth v1.8.1
Geth的安装
这里使用Homebrew演示在Mac OS上的下载安装
首先安装Homebrew
Homebrew是一款Mac OS平台下的软件包管理工具,拥有安装、卸载、更新、查看、搜索等很多实用的功能。简单的一条指令,就可以实现包管理,而不用你关心各种依赖和文件路径的情况,十分方便快捷。
Homebrew官网:https://brew.sh
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
安装完成后查看版本信息,确认是否安装成功
yuyangdeMacBook-Pro:~ yuyang$ brew -v
Homebrew 1.5.4
Homebrew/homebrew-core (git revision 68c5; last commit 2018-02-19)
安装Geth
brew tap ethereum/ethereum
brew install ethereum
安装完成后,查看版本后确认安装是否成功
yuyangdeMacBook-Pro:~ yuyang$ geth version
Geth
Version: 1.8.1-stable
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.10
Operating System: darwin
GOPATH=
GOROOT=/usr/local/opt/go/libexec
如果安装失败
我当时安装一直失败,忘了截图错误原因了。后来查了很久,找到了一篇可能的解决方法(但我不确定我当时就是文中的错误信息)。用了文中方法失败,然后我又尝试运行安装Geth的两条指令,结果安装成功。
Got an error while installing cpp-ethereum using brew.
https://github.com/ethereum/homebrew-ethereum/issues/116
<Install Xcode or the CLI from developer.apple.com/xcode>
brew update
brew upgrade
brew tap ethereum/ethereum
brew reinstall llvm
<At this point, close the terminal, and relaunch it.>
brew install leveldb libmicrohttpd cryptopp
brew install cpp-ethereum --devel --successful --verbose
简单理解就是:
- 安装Xcode或者CLI(我是把两个都安装了)
-
Xcode直接去AppStore安装。
-
CLI一款能用命令行自由操作各种软件获取各种系统信息的工具。
安装命令:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/guarinogabriel/mac-cli/master/mac-cli/tools/install)
安装完成后查看是否成功:
yuyangdeMacBook-Pro:~ yuyang$ Mac list
mac CLI – OS X command line tools for developers
关于CLI的使用可以查看这篇文章
-
-
执行以下命令:
brew update
brew upgrade
brew tap ethereum/ethereum
brew reinstall llvm -
完成后重启命令行
-
执行以下命令:
brew install leveldb libmicrohttpd cryptopp brew install cpp-ethereum --devel --successful --verbose
这是解决办法提供者对此的解释:
Running all those commands will install the latest version of the C++ Ethereum client using the develop branch that has successfully passed CI.
创建以太坊私有链
初始化一个创世区块
初始化创世区块时,要先创建一个genesis.json文件,内容如下:
{
"config": {
"chainId": 10,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0xffffffff",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"alloc" : {},
}
参数名称 | 参数描述 |
---|---|
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 | 附加信息,随便填,可以填你的个性信息 |
gasLimit | 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们是私有链,所以填最大 |
接下来,创建项目目录,然后使用geth init ./genesis.json --datadir "./chain"
命令,来进行创世区块的初始化,当前区块链网络数据存放的位置会保存在chain目录中:
yuyangdeMacBook-Pro:~ yuyang$ mkdir TestGeth
yuyangdeMacBook-Pro:~ yuyang$ cd TestGeth
yuyangdeMacBook-Pro:TestGeth yuyang$ geth init ./genesis.json --datadir "./chain"
INFO [02-24|11:08:41] Maximum peer count ETH=25 LES=0 total=25
INFO [02-24|11:08:41] Allocated cache and file handles database=/Users/yuyang/TestGeth/chain/geth/chaindata cache=16 handles=16
INFO [02-24|11:08:41] Writing custom genesis block
INFO [02-24|11:08:41] Persisted trie from memory database nodes=0 size=0.00B time=10.106µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-24|11:08:41] Successfully wrote genesis state database=chaindata hash=5e1fc7…d790e0
INFO [02-24|11:08:41] Allocated cache and file handles database=/Users/yuyang/TestGeth/chain/geth/lightchaindata cache=16 handles=16
INFO [02-24|11:08:41] Writing custom genesis block
INFO [02-24|11:08:41] Persisted trie from memory database nodes=0 size=0.00B time=1.743µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-24|11:08:41] Successfully wrote genesis state database=lightchaindata hash=5e1fc7…d790e0
启用私有链
使用以下命令,启用私有链,并创建log日志文件:
geth \
--datadir "./chain" \
--nodiscover \
console 2>>eth_output.log
启动后的效果如下:
yuyangdeMacBook-Pro:TestGeth yuyang$ geth \
> --datadir "./chain" \
> --nodiscover \
> console 2>>eth_output.log
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.1-stable/darwin-amd64/go1.10
modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
参数名称 | 参数描述 |
---|---|
datadir | 设置当前区块链网络数据存放的位置 |
console | 启动命令行模式,可以在Geth中执行命令 |
nodiscover | 私有链地址,不会被网上看到 |
在当前目录执行tail -f eth_output.log,可以看到输出日志(需要新开命令行)。
yuyangdeMacBook-Pro:~ yuyang$ cd /Users/yuyang/TestGeth
yuyangdeMacBook-Pro:TestGeth yuyang$ tail -f eth_output.log
INFO [02-24|12:03:49] Disk storage enabled for ethash caches dir=/Users/yuyang/TestGeth/chain/geth/ethash count=3
INFO [02-24|12:03:49] Disk storage enabled for ethash DAGs dir=/Users/yuyang/.ethash count=2
INFO [02-24|12:03:49] Initialising Ethereum protocol versions="[63 62]" network=1
INFO [02-24|12:03:49] Loaded most recent local header number=0 hash=5e1fc7…d790e0 td=131072
INFO [02-24|12:03:49] Loaded most recent local full block number=0 hash=5e1fc7…d790e0 td=131072
INFO [02-24|12:03:49] Loaded most recent local fast block number=0 hash=5e1fc7…d790e0 td=131072
INFO [02-24|12:03:49] Regenerated local transaction journal transactions=0 accounts=0
INFO [02-24|12:03:49] Starting P2P networking
INFO [02-24|12:03:49] RLPx listener up self="enode://f49cd7741cb1e91624d284aa7896a3dca1bedfcc36a6a99f05e2f0bdd1c6f830c59391b2c47493eeafd7d9ca6fff0720a1ab5ebc20627b1314cdbc1dfc86c351@[::]:30303?discport=0"
INFO [02-24|12:03:49] IPC endpoint opened url=/Users/yuyang/TestGeth/chain/geth.ipc
在私有链中进行操作
帐户的添加和查看
查看帐户,可以看到当前帐户是空的
> web3.eth.accounts
[]
创建帐户的方式有两种,第一种创建帐户时直接初始化密码
> web3,personal.newAccount("123456")
"0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe"
其中返回的0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe是帐户,123456是帐户的密码
第二种方法是先创建账户,然后输入密码
> web3.personal.newAccount()
Passphrase:
Repeat passphrase:
"0x69c9e2942557b25e4967672a72ee7b8f8c531a1c"
这时我们再查看帐户,能够看到刚才创建的两个帐户已经存在了
> web3.eth.accounts
["0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe", "0x69c9e2942557b25e4967672a72ee7b8f8c531a1c"]
开始挖矿和停止挖矿
挖矿执行以下命令:
> miner.start()
null
执行以后,通过刚才查看日志的方法tail -f eth_output.log,能够看到类似下面的日志,说明挖矿已经在进行。
INFO [02-24|12:33:12] Commit new mining work number=83 txs=0 uncles=0 elapsed=2.005s
INFO [02-24|12:33:13] Successfully sealed new block number=83 hash=b72b9d…c117b8
INFO [02-24|12:33:13] 🔗 block reached canonical chain number=78 hash=85741d…4330d5
INFO [02-24|12:33:13] 🔨 mined potential block number=83 hash=b72b9d…c117b8
INFO [02-24|12:33:13] Commit new mining work number=84 txs=0 uncles=0 elapsed=165.913µs
INFO [02-24|12:33:13] Successfully sealed new block number=84 hash=46555c…078e21
INFO [02-24|12:33:13] 🔗 block reached canonical chain number=79 hash=2d948b…ea81da
INFO [02-24|12:33:13] 🔨 mined potential block number=84 hash=46555c…078e21
挖矿会默认保存到创建的第一个帐户0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe中。
block number=79,说明我们已经创建了79个区块。
在以太坊官方的网络上,平均每15秒产生一个区块。
停止挖矿执行以下命令:
> miner.stop()
true
停止挖矿后,以太币则不会产生,同样智能合约、转帐等操作也不会起作用。
查看账户余额
查看帐户余额的方法如下:
> web3.eth.getBalance("0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe")
425000000000000000000
> web3.eth.getBalance("0x69c9e2942557b25e4967672a72ee7b8f8c531a1c")
0
每次记一长串的地址很麻烦,我们可以通过设置变量来acc0表示帐户1
0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe,acc1表示帐户2
0x69c9e2942557b25e4967672a72ee7b8f8c531a1c。
> acc0 = web3.eth.accounts[0]
"0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe"
> acc1 = web3.eth.accounts[1]
"0x69c9e2942557b25e4967672a72ee7b8f8c531a1c"
> web3.eth.getBalance(acc0)
425000000000000000000
> web3.eth.getBalance(acc1)
0
使用下面方法可以查看格式化的以太币:
> web3.fromWei(web3.eth.getBalance(acc0))
425
以太币最小的单位是wei(18个0)
因为geth javascript console是基于javascript的,所以也可以创建js函数,查看所有帐户余额。
> function checkAllBalances() {
... var totalBal = 0;
... for (var acctNum in eth.accounts) {
...... var acct = eth.accounts[acctNum];
...... var acctBal = web3.fromWei(eth.getBalance(acct), "ether");
...... totalBal += parseFloat(acctBal);
...... console.log(" eth.accounts[" + acctNum + "]: \t" + acct + " \tbalance: " + acctBal + " ether");
...... }
... console.log(" Total balance: " + totalBal + " ether");
... };
undefined
> checkAllBalances()
eth.accounts[0]: 0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe balance: 425 ether
eth.accounts[1]: 0x69c9e2942557b25e4967672a72ee7b8f8c531a1c balance: 0 ether
Total balance: 425 ether
undefined
转帐操作
从帐户0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe转3个以太币到0x69c9e2942557b25e4967672a72ee7b8f8c531a1c,如果不指定单位ether,默认转的是wei。
> web3.eth.sendTransaction({from:acc0,to:acc1,value:web3.toWei(3,"ether")})
Error: authentication needed: password or unlock
at web3.js:3143:20
at web3.js:6347:15
at web3.js:5081:36
at <anonymous>:1:1
当直接执行此方法时会抛出异常,显示帐号被锁。
解锁转帐帐户:
> web3.personal.unlockAccount(acc0,"123456")
true
解锁完成之后,即可执行转账操作:
> web3.eth.sendTransaction({from:acc0,to:acc1,value:web3.toWei(3,"ether")})
"0x23d65dd8c4d8b26b820013fff0f1c70fd50f2e471ea58b3041389f6746ed02e2"
但此时查看时会发现接收账户依旧为原来数值。此时需要执行挖矿命令,才会把转账真正完成。
> checkAllBalances()
eth.accounts[0]: 0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe balance: 425 ether
eth.accounts[1]: 0x69c9e2942557b25e4967672a72ee7b8f8c531a1c balance: 0 ether
Total balance: 425 ether
undefined
> miner.start()
null
> checkAllBalances()
eth.accounts[0]: 0xf2e4cf8222e79b579543a5708ff0dfd1e6e37cfe balance: 547 ether
eth.accounts[1]: 0x69c9e2942557b25e4967672a72ee7b8f8c531a1c balance: 3 ether
Total balance: 550 ether
undefined
> miner.stop()
true
acc1余额增加是因为启动挖矿后又有以太币进账。
fromWei和toWei
-
web3.fromWei
把 wei 转为如下种类的以太坊单位(还有其他代币token单位)- kwei/ada
- mwei/babbage
- gwei/shannon
- szabo
- finney
- ether
- kether/grand/einstein
- mether
- gether
- tether
> web3.fromWei("425000000000000000000", "ether")
"425"
- web3.toWei
把以太坊单位(包含代币单位)转为 wei
> web3.toWei("1", "ether")
"1000000000000000000"
参考: