通过各方资料了解学习之后,决定自己开始搭建基于以太坊go-ethereum的私有链环境。由于本人的电脑系统为win10,为避免window环境出现过多莫名其妙的问题,特意通过vm搭建了一台ubuntu17.10版本的虚拟系统。以下内容均基于ubuntu17.10系统。
首先,可以查看一下go-ethereum项目在git上的地址:
https://github.com/ethereum/Go-ethereum
可以在点击项目上的wiki标签,也可以通过一下地址访问wiki:
https://github.com/ethereum/Go-ethereum/wiki/Building-Ethereum
在wiki页面选择ubuntu系统的安装说明,也可以直接访问下面链接:
https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Ubuntu
在wiki页面选择mac系统的安装说明,也可以直接访问下面链接:
https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Mac
在wiki页面选择windows系统的安装说明,也可以直接访问下面链接:
https://github.com/ethereum/go-ethereum/wiki/Installation-instructions-for-Windows
可以在点击项目上的wiki标签,也可以通过一下地址访问wiki:
https://github.com/ethereum/go-ethereum/wiki/private-network
更换apt-get
为国内阿里云源
备份系统默认的源(没有root权限的前面加sudo)
cp /etc/apt/sources.list /etc/apt/sources.list.bak
修改/etc/apt/sources.list
# deb cdrom:[Ubuntu 16.04 LTS _Xenial Xerus_ - Release amd64 (20160420.1)]/ xenial main restricted
deb-src http://archive.ubuntu.com/ubuntu xenial main restricted #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse #Added by software-properties
deb http://archive.canonical.com/ubuntu xenial partner
deb-src http://archive.canonical.com/ubuntu xenial partner
deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-security multiverse
执行更新
sudo apt-get update //不执行是不生效的
sudo apt-get install software-properties-common
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum
somnus@ubuntu:~$ geth version
Geth
Version: 1.8.2-stable
Git Commit: b8b9f7f4476a30a0aaf6077daade6ae77f969960
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.9.4
Operating System: linux
GOPATH=
GOROOT=/usr/lib/go-1.9
somnus@ubuntu:~$
sudo apt-get install solc -y
somnus@ubuntu:~$ solc --version
solc, the solidity compiler commandline interface
Version: 0.4.19+commit.c4cbbb05.Linux.g++
访问 https://geth.ethereum.org/downloads/
下载并安装 Geth for Windows
brew tap ethereum/ethereum
brew install ethereum
创建一个文件夹来存储你的私链数据
mkdir -p ethereum && cd ethereum
{
"nonce": "0x0000000000000042",
"difficulty": "0x0f0000",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x4c4b40",
"config": { "chainId": 15, "homesteadBlock": 0, "eip155Block": 0, "eip158Block": 0 },
"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的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们是私有链,所以填最大。 |
初始化创世区块
默认目录是root/ethereum/
你可以通过--datadir
参数指定目录
somnus@ubuntu:~/ethereum$ geth --datadir data init genesis.json
INFO [04-01|19:53:03] Maximum peer count ETH=25 LES=0 total=25
INFO [04-01|19:53:03] Allocated cache and file handles database=/home/somnus/ethereum/data/geth/chaindata cache=16 handles=16
INFO [04-01|19:53:03] Writing custom genesis block
INFO [04-01|19:53:03] Persisted trie from memory database nodes=0 size=0.00B time=2.123µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [04-01|19:53:03] Successfully wrote genesis state database=chaindata hash=611596…424d04
INFO [04-01|19:53:03] Allocated cache and file handles database=/home/somnus/ethereum/data/geth/lightchaindata cache=16 handles=16
INFO [04-01|19:53:03] Writing custom genesis block
INFO [04-01|19:53:03] Persisted trie from memory database nodes=0 size=0.00B time=2.565µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [04-01|19:53:03] Successfully wrote genesis state database=lightchaindata hash=611596…424d04
somnus@ubuntu:~/ethereum$ find data
data
data/keystore
data/geth
data/geth/chaindata
data/geth/chaindata/LOCK
data/geth/chaindata/LOG
data/geth/chaindata/MANIFEST-000000
data/geth/chaindata/CURRENT
data/geth/chaindata/000001.log
data/geth/lightchaindata
data/geth/lightchaindata/LOCK
data/geth/lightchaindata/LOG
data/geth/lightchaindata/MANIFEST-000000
data/geth/lightchaindata/CURRENT
data/geth/lightchaindata/000001.log
目录结构
data
├── geth
│ ├── chaindata
│ │ ├── 000001.log
│ │ ├── CURRENT
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000000
│ └── lightchaindata
│ ├── 000001.log
│ ├── CURRENT
│ ├── LOCK
│ ├── LOG
│ └── MANIFEST-000000
└── keystore
somnus@ubuntu:~/ethereum$ geth --networkid 15 --datadir data --rpc --rpcaddr 172.16.61.17 --rpcport 8545 --rpcapi web3,eth,personal --nodiscover console
INFO [04-01|20:00:31] Maximum peer count ETH=25 LES=0 total=25
INFO [04-01|20:00:31] Starting peer-to-peer node instance=Geth/v1.8.2-stable-b8b9f7f4/linux-amd64/go1.9.4
INFO [04-01|20:00:31] Allocated cache and file handles database=/home/somnus/.ethereum/geth/chaindata cache=768 handles=512
INFO [04-01|20:00:31] Writing default main-net genesis block
INFO [04-01|20:00:31] Persisted trie from memory database nodes=12356 size=2.34mB time=41.622179ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [04-01|20:00:31] Initialised chain configuration config="{ChainID: 1 Homestead: 1150000 DAO: 1920000 DAOSupport: true EIP150: 2463000 EIP155: 2675000 EIP158: 2675000 Byzantium: 4370000 Constantinople: <nil> Engine: ethash}"
INFO [04-01|20:00:31] Disk storage enabled for ethash caches dir=/home/somnus/.ethereum/geth/ethash count=3
INFO [04-01|20:00:31] Disk storage enabled for ethash DAGs dir=/home/somnus/.ethash count=2
INFO [04-01|20:00:31] Initialising Ethereum protocol versions="[63 62]" network=123456
INFO [04-01|20:00:31] Loaded most recent local header number=0 hash=d4e567…cb8fa3 td=17179869184
INFO [04-01|20:00:31] Loaded most recent local full block number=0 hash=d4e567…cb8fa3 td=17179869184
INFO [04-01|20:00:31] Loaded most recent local fast block number=0 hash=d4e567…cb8fa3 td=17179869184
INFO [04-01|20:00:31] Regenerated local transaction journal transactions=0 accounts=0
INFO [04-01|20:00:31] Starting P2P networking
INFO [04-01|20:00:31] HTTP endpoint opened url=http://127.0.0.1:8545 cors=* vhosts=localhost
INFO [04-01|20:00:31] RLPx listener up self="enode://50e818e4a6ecaba459ebb3edacaaab170e206d16410a52ea67e41324228382ec91dbfea1e324ade4708fc32fa8b952b15b75b0b87cdb307ed8b9629b4d42640d@[::]:30303?discport=0"
INFO [04-01|20:00:31] IPC endpoint opened url=/home/somnus/.ethereum/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.2-stable-b8b9f7f4/linux-amd64/go1.9.4
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
>
启动私有节点所需参数
参数名称 | 参数描述 |
---|---|
identity | 区块链的标示,随便填写,用于标示目前网络的名字 |
init | 指定创世块文件的位置,并创建初始块 |
datadir | 设置当前区块链网络数据存放的位置 |
port | 网络监听端口 |
rpc | 启动rpc通信,可以进行智能合约的部署和调试 |
rpcapi | 设置允许连接的rpc的客户端,一般为db,eth,net,web3 |
rpcaddr | HTTP-RPC 服务ip地址(默认127.0.0.1) |
rpcport | 指定 HTTP-RPC 服务监听端口号(默认为 8545); |
networkid | 设置当前区块链的网络ID,用于区分不同的网络,是一个数字,如果在默认模式下启动,网络ID为1,代码会自动连接到以太坊主链 |
console | 启动命令行模式,可以在Geth中执行命令 |
nodiscover | 关闭节点发现机制,防止加入有同样初始配置的陌生节点。 |
请注意,在我们的genesis.json
文件里networkid(15)
和“chainid”
必须是相同的。
//在需要日志文件的情况下
geth --networkid 15 --datadir data --rpc --rpcaddr 172.16.61.17 --rpcport 8545 --rpcapi web3,eth,personal --nodiscover console 2>>geth.log
在已启动的情况下如何进入终端
geth attach ipc:/usr/local/ethereum/data/geth.ipc
在其它服务器中如何进入终端
geth attach http://121.43.162.28:8545
这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符。在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以直接使用这些对象。这些对象主要包括:
eth
:包含一些跟操作区块链相关的方法;net
:包含一些查看p2p网络状态的方法;admin
:包含一些与管理节点相关的方法;miner
:包含启动&停止挖矿的一些方法;personal
:主要包含一些管理账户的方法;txpool
:包含一些查看交易内存池的方法;web3
:包含了以上对象,还包含一些单位换算的方法。如跳过这一步骤,进入挖矿会报如下错误,需要设置一个挖矿的账号
Error: etherbase missing: etherbase address must be explicitly specified
at web3.js:3104:20
at web3.js:6191:15
at web3.js:5004:36
at <anonymous>:1:1
//方式一
somnus@ubuntu:~/ethereum$ personal.listAccounts
//方式二
somnus@ubuntu:~/ethereum$ eth.accounts
//方式三
somnus@ubuntu:~/ethereum$ geth account list
Account #0: {83fda0ba7e6cfa8d7319d78fa0e6b753a2bcb5a6} keystore:///home/neo/.ethereum/keystore/UTC--2018-01-20T04-04-06.786586541Z--83fda0ba7e6cfa8d7319d78fa0e6b753a2bcb5a6
Account #1: {e8abf98484325fd6afc59b804ac15804b978e607} keystore:///home/neo/.ethereum/keystore/UTC--2018-01-20T06-11-23.608902164Z--e8abf98484325fd6afc59b804ac15804b978e607
//方式一(参数为此账户的密码)
personal.newAccount("123456")
//方式二(也可以先创建账户,然后输入密码:)
personal.newAccount()
默认挖矿账号就是第一个设置的账号,当然也可以自行设置
eth.coinbase
miner.setEtherbase(eth.accounts[0])
查看区块数据
eth.blockNumber
> eth.getBalance(eth.accounts[0])
70000000000000000000
eth.getBalance()返回的余额是以太币的最小面额wei,将wei转换为以太币ether。
//primary = eth.accounts[0]
//balance = web3.fromWei(eth.getBalance(primary), "ether");
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
70
备注eth单位解释:
kwei (1000 Wei)
mwei (1000 KWei)
gwei (1000 mwei)
szabo (1000 gwei)
finney (1000 szabo)
ether (1000 finney)
也就是说ether =wei * 10^18
,也就是说精度可以达到18位。
//wei转ether
> web3.fromWei(1000000000000000000,"ether")
"1"
//ether转wei
> web3.toWei(1)
"1000000000000000000"
ps:web3命令
https://ethereumbuilders.gitbooks.io/guide/content/en/ethereum_javascript_api.html
miner.start(1)
这里的1表示只使用一个线程运行,第一次运行时将开始创建DAG文件
,只需等待进度条到100,则将开始挖矿。 实际你看到的挖矿速度很快,这是因为我们已经在初始化创世区块时配置为:"nonce": "0x0000000000000042"
。 “0x42”难度能让你在私有测试网链上快速挖以太币。
提示
挖矿时必然有矿工账户,而系统默认使用创建的第一个账号。
> miner.start(1)
INFO [01-19|21:06:43] Updated mining threads threads=1
INFO [01-19|21:06:43] Transaction pool price threshold updated price=18000000000
INFO [01-19|21:06:43] Starting mining operation
null
> INFO [01-19|21:06:43] Commit new mining work number=1 txs=0 uncles=0 elapsed=717.552µs
INFO [01-19|21:06:46] Generating ethash verification cache epoch=0 percentage=91 elapsed=3.000s
INFO [01-19|21:06:46] Generated ethash verification cache epoch=0 elapsed=3.273s
INFO [01-19|21:06:51] Generating DAG in progress epoch=0 percentage=0 elapsed=5.056s
INFO [01-19|21:06:56] Generating DAG in progress epoch=0 percentage=1 elapsed=10.140s
INFO [01-19|21:07:01] Generating DAG in progress epoch=0 percentage=2 elapsed=15.119s
INFO [01-19|21:07:06] Generating DAG in progress epoch=0 percentage=3 elapsed=19.924s
INFO [01-19|21:07:11] Generating DAG in progress epoch=0 percentage=4 elapsed=24.739s
INFO [01-19|21:07:16] Generating DAG in progress epoch=0 percentage=5 elapsed=29.473s
INFO [01-19|21:07:22] Generating DAG in progress epoch=0 percentage=6 elapsed=35.641s
INFO [01-19|21:07:26] Generating DAG in progress epoch=0 percentage=7 elapsed=40.374s
INFO [01-19|21:07:31] Generating DAG in progress epoch=0 percentage=8 elapsed=45.134s
INFO [01-19|21:07:36] Generating DAG in progress epoch=0 percentage=9 elapsed=49.908s
INFO [01-19|21:07:41] Generating DAG in progress epoch=0 percentage=10 elapsed=54.633s
......
......
......
INFO [01-19|21:22:43] Generated ethash verification cache epoch=0 elapsed=15m57.328s
INFO [01-19|21:22:47] Generating ethash verification cache epoch=1 percentage=17 elapsed=3.031s
INFO [01-19|21:22:50] Generating ethash verification cache epoch=1 percentage=34 elapsed=6.056s
INFO [01-19|21:22:53] Generating ethash verification cache epoch=1 percentage=49 elapsed=9.562s
INFO [01-19|21:22:57] Generating ethash verification cache epoch=1 percentage=70 elapsed=13.115s
INFO [01-19|21:23:00] Generating ethash verification cache epoch=1 percentage=90 elapsed=16.123s
INFO [01-19|21:23:01] Generated ethash verification cache epoch=1 elapsed=17.576s
INFO [01-19|21:23:19] Generating DAG in progress epoch=1 percentage=0 elapsed=18.198s
INFO [01-19|21:23:32] Successfully sealed new block number=1 hash=e2b5b9…9b1bfe
INFO [01-19|21:23:32] ? mined potential block number=1 hash=e2b5b9…9b1bfe
INFO [01-19|21:23:32] Commit new mining work number=2 txs=0 uncles=0 elapsed=1.188ms
INFO [01-19|21:23:37] Generating DAG in progress epoch=1 percentage=1 elapsed=35.913s
INFO [01-19|21:23:41] Successfully sealed new block number=2 hash=62db3f…e27b50
INFO [01-19|21:23:41] ? mined potential block number=2 hash=62db3f…e27b50
INFO [01-19|21:23:41] Commit new mining work number=3 txs=0 uncles=0 elapsed=772.239µs
INFO [01-19|21:23:43] Successfully sealed new block number=3 hash=34384b…c387f2
INFO [01-19|21:23:43] ? mined potential block number=3 hash=34384b…c387f2
INFO [01-19|21:23:43] Commit new mining work number=4 txs=0 uncles=0 elapsed=1.002ms
INFO [01-19|21:23:55] Generating DAG in progress epoch=1 percentage=2 elapsed=53.757s
INFO [01-19|21:24:13] Generating DAG in progress epoch=1 percentage=3 elapsed=1m11.561s
INFO [01-19|21:24:30] Generating DAG in progress epoch=1 percentage=4 elapsed=1m28.986s
INFO [01-19|21:24:30] Successfully sealed new block number=4 hash=681970…462135
INFO [01-19|21:24:30] ? mined potential block number=4 hash=681970…462135
INFO [01-19|21:24:30] Commit new mining work number=5 txs=0 uncles=0 elapsed=833.629µs
INFO [01-19|21:24:36] Successfully sealed new block number=5 hash=7b058b…d2f07a
INFO [01-19|21:24:36] ? mined potential block number=5 hash=7b058b…d2f07a
INFO [01-19|21:24:36] Commit new mining work number=6 txs=0 uncles=0 elapsed=897.815µs
INFO [01-19|21:24:43] Successfully sealed new block number=6 hash=a5fc3d…b1221e
INFO [01-19|21:24:43] ? block reached canonical chain number=1 hash=e2b5b9…9b1bfe
INFO [01-19|21:24:43] ? mined potential block number=6 hash=a5fc3d…b1221e
INFO [01-19|21:24:43] Commit new mining work number=7 txs=0 uncles=0 elapsed=758.061µs
INFO [01-19|21:24:47] Successfully sealed new block number=7 hash=003b02…e886fd
INFO [01-19|21:24:47] ? block reached canonical chain number=2 hash=62db3f…e27b50
INFO [01-19|21:24:47] ? mined potential block number=7 hash=003b02…e886fd
INFO [01-19|21:24:47] Commit new mining work number=8 txs=0 uncles=0 elapsed=920.862µs
INFO [01-19|21:24:48] Generating DAG in progress epoch=1 percentage=5 elapsed=1m46.827s
INFO [01-19|21:25:06] Generating DAG in progress epoch=1 percentage=6 elapsed=2m4.338s
INFO [01-19|21:25:23] Successfully sealed new block number=8 hash=fd23c9…361c65
INFO [01-19|21:25:23] ? block reached canonical chain number=3 hash=34384b…c387f2
INFO [01-19|21:25:23] ? mined potential block number=8 hash=fd23c9…361c65
INFO [01-19|21:25:23] Commit new mining work number=9 txs=0 uncles=0 elapsed=825.737µs
INFO [01-19|21:25:23] Generating DAG in progress epoch=1 percentage=7 elapsed=2m22.061s
> miner.stop()
true
>
> eth.getBalance(eth.accounts[0])
7000000000000000000
这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符。在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以直接使用这些对象。这些对象主要包括:
eth
:包含一些跟操作区块链相关的方法;net
:包含一些查看p2p网络状态的方法;admin
:包含一些与管理节点相关的方法;miner
:包含启动&停止挖矿的一些方法;personal
:主要包含一些管理账户的方法;txpool
:包含一些查看交易内存池的方法;web3
:包含了以上对象,还包含一些单位换算的方法。转出账号中有10000个以太币
> web3.fromWei(eth.getBalance(eth.accounts[0]))
10000
转入账号目前是 100
> web3.fromWei(eth.getBalance(eth.accounts[1]))
100
解锁传出账号,否则不能转出。personal.unlockAccount(账号)或者personal.unlockAccount(账号,"password", 15000)
> personal.unlockAccount(eth.accounts[0])
true
转账操作
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(10000, "ether")})
INFO [04-19|12:00:35] Submitted transaction fullhash=0xa5572bee3609c772e2f3c0b05df52a0ce5b75e401dc00c6c0365b4f36b93df27 recipient=0x7053133f9C5803a71C1a0FEdAD3E3a3138e2225B
"0xa5572bee3609c772e2f3c0b05df52a0ce5b75e401dc00c6c0365b4f36b93df27"
//查看待确认交易的详情 //使用命令web3.eth.getTransaction:
> web3.eth.getTransaction("0xa5572bee3609c772e2f3c0b05df52a0ce5b75e401dc00c6c0365b4f36b93df27")
{
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
blockNumber: null,
from: "0x4d047e01cd56f878443b11eb2417a936f40d69f7",
gas: 90000,
gasPrice: 18000000000,
hash: "0xa5572bee3609c772e2f3c0b05df52a0ce5b75e401dc00c6c0365b4f36b93df27",
input: "0x",
nonce: 13,
r: "0x4670f7999a0466a80870d8d69a4c0dab2597b055e1c850b063990d431cdb046a",
s: "0x38f5275a006a1b74ef889a73ac096142f294d69505d60239384a706d9a3cc44c",
to: "0x7053133f9c5803a71c1a0fedad3e3a3138e2225b",
transactionIndex: 0,
v: "0x42",
value: 1e+22
}
//由于交易还未确认,所以所属区块为null,blockNumber: null。 //主要参数含义 //gas:需要的gas数量 //gasPrice:交易的gas单价[18,000,000,000(wei)=18(GWei)] //由此可以算出,我们需要交纳的手续费为=90,000*18(GWei)=1620,000(Gwei)=0.00162(ether)
如果你现在查看转入账号,你会发现余额仍然是 0 ,交易还未成功写进区块,写进区块的方式是挖矿,所以你必须执行挖矿
> miner.start(1)
null
> INFO [04-19|12:51:18] Starting mining operation
INFO [04-19|12:51:18] Commit new mining work number=6713 txs=1 uncles=0 elapsed=363.708µs
INFO [04-19|12:51:26] Successfully sealed new block number=6713 hash=260c89…44b141
INFO [04-19|12:51:26] mined potential block number=6713 hash=260c89…44b141
INFO [04-19|12:51:26] Commit new mining work number=6714 txs=0 uncles=0 elapsed=196.425µs
INFO [04-19|12:51:28] Successfully sealed new block number=6714 hash=b690a2…b38e1a
INFO [04-19|12:51:28] mined potential block number=6714 hash=b690a2…b38e1a
INFO [04-19|12:51:28] Commit new mining work number=6715 txs=0 uncles=0 elapsed=115.331µs
第三行第四行显示成功密封了一个新的区块。
稍后几分钟,再次查看转入账号,将会看到有10000个以太币入账。传出账号会减少10000个以太币,同时仍然继续挖矿中。
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
10100
//再次查看交易详情
> web3.eth.getTransaction("0xa5572bee3609c772e2f3c0b05df52a0ce5b75e401dc00c6c0365b4f36b93df27")
{
blockHash: "0x260c89fdcef4783c22b8cf537fa69c22ee9b7c05bae5ca3aa98c8a3b7944b141",
blockNumber: 6713,
from: "0x4d047e01cd56f878443b11eb2417a936f40d69f7",
gas: 90000,
gasPrice: 18000000000,
hash: "0xa5572bee3609c772e2f3c0b05df52a0ce5b75e401dc00c6c0365b4f36b93df27",
input: "0x",
nonce: 13,
r: "0x4670f7999a0466a80870d8d69a4c0dab2597b055e1c850b063990d431cdb046a",
s: "0x38f5275a006a1b74ef889a73ac096142f294d69505d60239384a706d9a3cc44c",
to: "0x7053133f9c5803a71c1a0fedad3e3a3138e2225b",
transactionIndex: 0,
v: "0x42",
value: 1e+22
}
pragma solidity ^0.4.4;
contract calculator {
function multiply(uint a) returns(uint d){
return a * 7;
}
}
> account1 = web3.eth.coinbase
"0x2abf46d8b0d940cdeedd55872bc0648add40227d"
> web3.eth.getBalance(account1)
0
>
如果余额大于0,继续,否则,开始挖矿。
> miner.start();
null
>
如果你觉得差不多了,可以运行下面的命令停止挖矿。
> miner.stop();
true
123456
: 换成你的密码。
> personal.unlockAccount(web3.eth.coinbase, '123456')
true
代码拷贝到https://remix.ethereum.org 或 https://ethereum.github.io/browser-solidity/,编译,然后点击Details
发送部署合约的交易
var calculatorContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]);
var calculator = calculatorContract.new(
{
from: web3.eth.accounts[0],
data: '0x608060405234801561001057600080fd5b5060bb8061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b348015604f57600080fd5b50606c600480360381019080803590602001909291905050506082565b6040518082815260200191505060405180910390f35b60006007820290509190505600a165627a7a72305820f75ed1716facde6a967c214d7920116d5cc4bc2504682f047a95e82183d8c9bd0029',
gas: '4700000'
}, function (e, contract){
console.log(e, contract);
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
})
from
代表合约由哪个账户生成,哪个账户生成,则生成所需的gas
就需要该账户承担,默认为eth.accounts[0]
,因为所有挖矿所得的以太币也默认都存入该账户中。
data
代表的就是bytecode
。是编译后的代码,你的代码越长,这块的字符串越多。
gas
代表的是为了部署该合约最多准备的gas数量,当然实际上可能用不了这么多gas
,具体消耗以实际使用量为准,这里只是设定一个最大量。gas
是调用合约要扣除的gas
单位,可以理解为以太币,gas
和ether
之间有个汇率,汇率受矿机的算率影响会有调整,在公网上,这些gas
用于奖励给挖矿者。最后这段是一个典型的javascript的异步调用的写法,将上面的new方法的结果传递给下一个方法
function(e,contract)
,在下一个方法中处理如果挖矿成功的显示结果。如果合约成功部署在区块上,则在控制台打印出来Contract mined!
、contract address
、transactionHash
等信息。
address
表示已经部署智能合约的帐户地址,智能合约也相当于一个帐户。
transactionHash
表示智能合约产生时的hash值,会永久保存到区块链条里面。
输入calculator
可以看到合约的一些信息
> calculator
{
abi: [{
constant: false,
inputs: [{...}],
name: "multiply",
outputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "function"
}],
address: "0x35be144ae869bf8cc7ab83f5dd956898e3b127aa",
transactionHash: "0x3c5d28ef56f225d7d2d6b02106a628fce5ce5b42c9c2ba6205bb3ee3a9deeeed",
allEvents: function(),
multiply: function()
}
> txpool.status
{ pending: 1, queued: 0 }
可以看到交易池中有一个待确认的交易
使用命令web3.eth.getTransaction
,参数为transactionHash
:
> web3.eth.getTransaction("0x3c5d28ef56f225d7d2d6b02106a628fce5ce5b42c9c2ba6205bb3ee3a9deeeed")
{
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
blockNumber: null,
from: "0x4d047e01cd56f878443b11eb2417a936f40d69f7",
gas: 4700000,
gasPrice: 18000000000,
hash: "0x9bd7fe9080ed20a5fbeaa644ca87614b00fcd15582bff897598d991a680fa5d9",
input: "0x608060405234801561001057600080fd5b5060bb8061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b348015604f57600080fd5b50606c600480360381019080803590602001909291905050506082565b6040518082815260200191505060405180910390f35b60006007820290509190505600a165627a7a72305820f22b1e35f2de2583454229eaa5609b69b3a3628801c59eecb3361299cc2cdc4b0029",
nonce: 20,
r: "0xca66158e7abf3582fedf03dd040083a0838370687569a62badb88089a62f77",
s: "0x140d6bd716ec6d137eced02987eccc952065d371030784b661051d6f3f630428",
to: null,
transactionIndex: 0,
v: "0x41",
value: 0
}
>
由于交易还未确认,所以所属区块为null,blockNumber: null
。
> bytecode = "608060405234801561001057600080fd5b5060bb8061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b348015604f57600080fd5b50606c600480360381019080803590602001909291905050506082565b6040518082815260200191505060405180910390f35b60006007820290509190505600a165627a7a72305820f75ed1716facde6a967c214d7920116d5cc4bc2504682f047a95e82183d8c9bd0029 "
"608060405234801561001057600080fd5b5060bb8061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b348015604f57600080fd5b50606c600480360381019080803590602001909291905050506082565b6040518082815260200191505060405180910390f35b60006007820290509190505600a165627a7a72305820f75ed1716facde6a967c214d7920116d5cc4bc2504682f047a95e82183d8c9bd0029"
> web3.eth.estimateGas({data: bytecode})
Error: invalid argument 0: json: cannot unmarshal hex string without 0x prefix into Go struct field CallArgs.data of type hexutil.Bytes
at web3.js:3104:20
at web3.js:6191:15
at web3.js:5004:36
at <anonymous>:1:1
> bytecode = "0x608060405234801561001057600080fd5b5060bb8061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b348015604f57600080fd5b50606c600480360381019080803590602001909291905050506082565b6040518082815260200191505060405180910390f35b60006007820290509190505600a165627a7a72305820f75ed1716facde6a967c214d7920116d5cc4bc2504682f047a95e82183d8c9bd0029"
"0x608060405234801561001057600080fd5b5060bb8061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b348015604f57600080fd5b50606c600480360381019080803590602001909291905050506082565b6040518082815260200191505060405180910390f35b60006007820290509190505600a165627a7a72305820f75ed1716facde6a967c214d7920116d5cc4bc2504682f047a95e82183d8c9bd0029"
> web3.eth.estimateGas({data: bytecode})
98391
>
备注:字节码前面需要添加0x
。手续费大概为98391gas
。
> miner.start()
null
> Contract mined! Address: 0xbf8b24283f2516360d3a4ba1db0df78ae74689db
[object Object]
> miner.stop()
true
>
> eth.getCode(calculator.address)
"0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
>
> calculator.multiply.call(6)
42
> //本地调用,不会向区块链网络广播任何东西的合约调用,不会被区块所打包,切记、切记!!!
如果换做其他人需要运行你的智能合约,还可以用如下方式,但需要两个信息:(后面提到的truffle部署智能合约成功后,私有链就按此方式调用)
- 智能合约地址
Address
- 智能合约
ABI(Application Binary Interface)
,ABI
其实就是一个有序的用户手册,描述了所有方法的名字和如何调用它们。
> var abi = [{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]
> var calc = eth.contract(abi).at("0x35be144ae869bf8cc7ab83f5dd956898e3b127aa")
> calc.multiply.call(6)
> 42
> web3.eth.getTransaction("0x3c5d28ef56f225d7d2d6b02106a628fce5ce5b42c9c2ba6205bb3ee3a9deeeed")
{
blockHash: "0x23718f944ea863cdae899b7cf85a298e7a3efc70be09364461d0bf4ef90ae4b5",
blockNumber: 5900,
from: "0x4d047e01cd56f878443b11eb2417a936f40d69f7",
gas: 4700000,
gasPrice: 18000000000,
hash: "0x3c5d28ef56f225d7d2d6b02106a628fce5ce5b42c9c2ba6205bb3ee3a9deeeed",
input: "0x608060405234801561001057600080fd5b5060bb8061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b348015604f57600080fd5b50606c600480360381019080803590602001909291905050506082565b6040518082815260200191505060405180910390f35b60006007820290509190505600a165627a7a72305820f75ed1716facde6a967c214d7920116d5cc4bc2504682f047a95e82183d8c9bd0029",
nonce: 21,
r: "0x2c81c8ff57dfeccf393d7db45a4cee2f66653e80019a26fb3992ece650457d30",
s: "0xf5db5ebebaa82b16136a29274bffd2351782c9be6f6e4059addf52e58219f48",
to: null,
transactionIndex: 0,
v: "0x41",
value: 0
}
可以看到已经写到编号为5900
的区块上了blockNumber: 5900
。
都说区块链是去中心化的账本那么可以满足于单机挖矿?说干就干接下来创建一个新节点并将太接入我们的主节点。这里需要注意以下几点:
新节点的 networkid
要与 第一个创建的节点data
一致
需要与 第一个创建的节点data
使用同一个创世区块(也就是同一个genesis.json
文件)
如果多个节点都在一台机器上注意端口区分,避免端口冲突
--port 30304
--rpcport 9545
geth --datadir data2 init genesis.json
geth --networkid 15 --datadir data2 --rpc --port 30304 --rpcaddr 172.16.61.17 --rpcport 9545 --nodiscover console
上面分别是在两个节点上进行的操作,下面我们需要把两个节点之间建立起链接。首先,我们执行以下命令查看以下节点的peers的情况。
> admin.peers
[]
发现节点并没有链接上任何其他节点,这也是我们的nodiscover参数发挥了效果。
下面就通过分享enode地址的方式来让两个节点建立链接。
> admin.nodeInfo.enode
"enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30306?discport=0"
>
通过上面命令,我们获得了节点2的encode信息。这是geth用来连接到不同节点的enode信息,在这些不同的节点它们能够分享交易和成功挖掘信息。
其实这个信息如果留心的话,在启动节点的打印日志中已经打印出每个节点的encode信息。比如:
INFO [12-28|19:23:16] RLPx listener up self="enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30303?discport=0"
现在,我们要告知一个节点,另外一个节点的encode信息。首先复制节点2的日志中self等号后面的信息,在节点1的控制台执行以下命令:
> admin.addPeer("enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30306?discport=0")
true
返回true,说明执行成功。再次验证一下:
> admin.peers
[{
caps: ["eth/63"],
id: "aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c",
name: "Geth/v1.7.3-stable-4bb3c89d/darwin-amd64/go1.9.2",
network: {
localAddress: "[::1]:49426",
remoteAddress: "[::1]:30306"
},
protocols: {
eth: {
difficulty: 16384,
head: "0x942f596f99dc8879b426b59080824662e1f97587353d087487fea0a0e2a2588a",
version: 63
}
}
}]
>
发现节点1
已经有一个peer了,同时我们可以看到remoteAddress: “[::1]:30306”
,正是我们节点2的端口信息。在节点2
执行admin.peers
会发现有类似的信息,指向的peer正是节点1的。
查询余额并挖矿
执行查看余额命令:
> eth.getBalance(eth.coinbase)
0
在节点1
执行miner.start()
进行挖矿,执行miner.stop()
停止挖矿。停止挖矿的时候开业忽略控制台输出,只要正确拼写命令回车即可。
当我们在节点1
执行挖矿时,我们会发现节点2
的控制台出现了这样的日志信息:
> INFO [12-28|20:05:32] Block synchronisation started
INFO [12-28|20:05:33] Imported new state entries count=1 elapsed=47.661µs processed=1 pending=0 retry=0 duplicate=0 unexpected=0
WARN [12-28|20:05:33] Discarded bad propagated block number=1 hash=ab49ba…1cf32f
INFO [12-28|20:05:33] Imported new block headers count=2 elapsed=9.208ms number=2 hash=738225…000e3b ignored=0
INFO [12-28|20:05:33] Imported new chain segment blocks=2 txs=0 mgas=0.000 elapsed=1.724ms mgasps=0.000 number=2 hash=738225…000e3b
INFO [12-28|20:05:33] Fast sync complete, auto disabling
INFO [12-28|20:05:34] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=5.978ms mgasps=0.000 number=3 hash=b069a9…426060
INFO [12-28|20:05:38] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=6.930ms mgasps=0.000 number=4 hash=21217e…526253
INFO [12-28|20:05:41] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=6.419ms mgasps=0.000 number=5 hash=3fa6ff…cf2794
INFO [12-28|20:05:43] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=6.557ms mgasps=0.000 number=6 hash=4c35b9…78b3ec
INFO [12-28|20:05:45] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=6.514ms mgasps=0.000 number=7 hash=328e62…1bd3d3
INFO [12-28|20:05:46] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=6.513ms mgasps=0.000 number=8 hash=12287e…0465b5
INFO [12-28|20:06:19] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=7.048ms mgasps=0.000 number=9 hash=8e844b…b99d6c
INFO [12-28|20:06:22] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=8.156ms mgasps=0.000 number=10 hash=159b36…d4dde5
INFO [12-28|20:06:24] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=6.549ms mgasps=0.000 number=11 hash=969100…5658a5
也就是说,节点1
挖矿,节点2
在同步数据信息。
停止节点1的挖矿,并查看coinbase地址金额:
> miner.stop()
true
> eth.getBalance(eth.coinbase)
140000000000000000000
> eth.coinbase
"0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e"
这里我们知道了节点一种的地址信息和余额信息,那我们拿节点1
的这个地址在节点2
的控制台查询一下信息:
> eth.getBalance("0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e")
140000000000000000000
很显然,节点2
中也能查询到节点1
中地址的余额。以上信息说明,节点1
和节点2
的数据是完全同步的。
并且也可以在不同节点运行eth.blockNumber
可以查到区块数量是保持一致的
[Unit]
Description=Ethereum go client
[Service]
Type=simple
ExecStart=/usr/bin/geth --networkid 15 --datadir /usr/local/ethereum/data --rpc --rpcaddr 172.16.61.17 --rpcport 8545 --nodiscover 2>>/usr/local/ethereum/data/geth.log
[Install]
WantedBy=default.target
systemctl --user enable /usr/local/ethereum/geth.service
systemctl --user start geth.service
netstat -tunpl|grep 8545
geth attach ipc:/usr/local/ethereum/data/geth.ipc