参考来自《区块链开发实战这本书
首先来了解下以太坊的一些知识
比特币的设计只适合虚拟货币场景,由于存在非图灵完备、缺少保存状态的账户概念以及pow挖矿机制带来的资源浪费和效率问题,需要一个新的基于区块链的具有图灵完备性、高效共识机制、支持更多应用场景的智能合约开发平台。
以太坊是平台和编程语言
1)以太坊虚拟机(EVM),以太坊智能合约运行的环境,是基于栈的虚拟机
2)账户:外部账户(密钥对控制),合约账户;包含4个部分:nonce(发送过的交易数或创建过的合约数),balance(账户拥有的余额,1Ether=10^18Wei),storageRoot(存储内容的merkle patricia树根节点),codeHash(空的字符串哈希值或EVM code的哈希值)
3)消息
4)交易:存储从外部账户发出的消息的签名数据包
5)gas:无论执行到什么位置,gas耗尽就会触发out-of-gas,所有状态回滚,交易执行过程中消耗的gas不会退回,还是支付交易费用添加到矿工账户
6)存储、主存和栈:1.存储,永久的内存区域,key-value(256-256);2.主存,合约执行每次消息有一块新的被清除的主存
7)指令集:
8)消息调用
9)代码调用和库
目前有4种语言编写的以太坊客户端,go语言实现的Geth,C++实现的Eth,Python实现的Pyethapp和java实现的EthereumJ,go是以太坊官方一直维护并推荐使用的客户端。
parity声称是世界上最快最轻便的以太坊客户端,用rust语言编写。
以太坊有一个专用的客户端浏览器,mist
以太坊有四种专用语言:Serpent,Solidity,Mutan,LLL,其中Solitity是以太坊的首选语言,语法类似于javascript
以太坊的网络类型:主网络的networkid=1,公开的测试网有4个,目前仍在运行的有3个。morden(已退役,2),ropsten(pow,3),kovan(poa,仅parity钱包客户端可用),rinkeby(poa,4)
运行在区块链网络上的程序,称为智能合约(smart contract)
这个程序就像一个可以被信任的人,可以临时保管资产,总是按照事先的规则执行和操作。
以太坊的发展分成4个阶段,Frontier(前沿),Homestead(家园),Metropolis(大都会),Serenity(宁静),在前三个阶段采用工作量证明机制,在第四阶段会切换到权益证明机制,阶段之间的转换通过硬分叉的方式实现
2015.7.30 发布Frontier阶段
2016.3.14 发布Homestead阶段,提供图形界面的钱包
Metropolis分为两个阶段,Byzantium(拜占庭)和Constantinople(君士坦丁堡)
2017.10.16 Byzantium硬分叉成功
安装部分有参考下面内容
https://blog.csdn.net/u013137970/article/details/52255001#commentBox
https://blog.csdn.net/weixin_40345905/article/details/81041748
sudo apt-get install git
sudo apt-get install curl
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install -y npm
上述步骤如果不行就编译源码,相对耗时,在官网下载
tar -zxvf node-v8.12.0.tar.gz
cd node-v8.12.0/
sudo ./configure
sudo make
sudo make install
solidity是以太坊智能合约的开发语言,测试智能合约、开发Dapp都需要安装
sudo npm install -g solc solc-cli --save-dev
运行solcjs --help报错
parallels@parallels-vm:~$ solcjs --help
/usr/bin/env: ‘node’: No such file or directory
可能是solc与solc-cli的版本不匹配,未解决,走下面的步骤
sudo ln -s /usr/bin/nodejs /usr/local/bin/node
如果需要在geth控制台使用solc编译器,需要以下步骤,添加以太坊官方apt源
sudo add-apt-repository ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install -y solc
3)源码编译
git clone https://github.com/ethereum/go-ethereum.git
cd go-ethereum/
sudo make geth
最后一步有问题,需要安装go语言环境,报错如下
parallels@parallels-vm:~/go-ethereum$ sudo make geth
build/env.sh go run build/ci.go install ./cmd/geth
build/env.sh: 30: exec: go: not found
Makefile:15: recipe for target 'geth' failed
make: *** [geth] Error 127
4)快速安装
不想用源码的话可以跳过3)通过添加以太坊官网apt源,并安装以太坊客户端
sudo apt-get install software-properties-common
sudo apt-get-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get -y ethereum
下面是安装后的部分日志,就当记录了
Setting up abigen (1.8.16+build15490+xenial) ...
Setting up bootnode (1.8.16+build15490+xenial) ...
Setting up evm (1.8.16+build15490+xenial) ...
Setting up geth (1.8.16+build15490+xenial) ...
Setting up puppeth (1.8.16+build15490+xenial) ...
Setting up rlpdump (1.8.16+build15490+xenial) ...
Setting up wnode (1.8.16+build15490+xenial) ...
Setting up ethereum (1.8.16+build15490+xenial) ...
5)docker安装
还可以通过docker拉取镜像,docker之前安装好了
sudo apt install docker.io
sudo apt install docker-compose
拉取ethereum/client-go:alpine镜像,然后启动
docker pull ethereum/client-go:alpine
docker run -d --name ethereum-node -v /Users/alice/ethereum:/root -p 8545:8545 -p 30303:30303 ethereum/client-go --fast --cache=512
在同步的数据的时候可以指定–datadir参数设置区块数据存放位置,–fast启动快速区块同步模式,在同步到最新区块后,转为正常区块同步模式,–fast貌似不可用
1)公有链上运行一个全节点
geth --cache=512 --datadir "/home/parallels/gethblock" console
2)testnet上
geth --testnet --cache=512 --datadir "/home/parallels/gethblock" console
打印内容
instance: Geth/v1.8.16-stable-477eb093/linux-amd64/go1.10
modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
> INFO [10-08|15:50:41.385] Block synchronisation started
INFO [10-08|15:51:04.099] Imported new block headers count=192 elapsed=699.139ms number=192 hash=9d4976…cf6e5b age=1y10mo3w
INFO [10-08|15:51:04.100] Imported new block receipts
···
1)新建一个geth工作目录,不需要sudo
mkdir geth
cd geth
touch gensis.json
2)创世区块配置文件
创世(Genesis)区块是区块链的起点,这点能确保没有其它节点和你的节点的区块链版本一致,除非创世区块一致。因此我们可一创建任意多的私有区块链
{
"config":{
"chainId":15,
"homesteadBlock":0,
"eip155Block":0,
"eip158Block":0
},
"alloc":{
"0xeb680f30715f347d4eb5cd03ac5eced297ac5046":{"balance":"1000000000000000000000000000000"}
},
"coinbase":"0x0000000000000000000000000000000000000000",
"difficulty":"0x01",
"extraData":"0x0000111122223333",
"gasLimit":"0xffffffff",
"nonce":"0x0000000000000001",
"mixhash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp":"0x00"
}
各个参数的介绍
参数名称 | 参数详解 |
---|---|
chainId | 指定了独立的区块链网络id,网络id在连接到其它节点的时候会用到,以太坊公网id是1,不同的id网络的节点无法相互连接 |
homesteadBlock | HomesteadBlock是以太坊的第二个主要版本,第一个是Frontier,这个值设置为“0”表示目前正在使用Homestead版本 |
eip155Block | eip是ethereum improvement proposal的缩写,我们的链不会提议分叉,所以设置为“0”即可 |
eip158Block | 同上 |
minhash | 与nonce配合用于挖矿,由上一个区块的一部分生成的哈希,注意它和nonce的设置需要满足以太坊的yellow paper |
nonce | 一个用于挖矿的64位随机数 |
difficulty | 设置当前区块的难度,如果难度过大,cpu挖矿就很难,这里设置较小难度 |
alloc | 给某个账户预分配以太币 |
coinbase | 矿工的账号(随便填) |
timestamp | 设置创世区块的时间戳 |
parentHash | 上一个区块的哈希值,因为是创世区块,所以这个值是0 |
extraData | 可以写入32byte大小的任意数据,每个block都会有,由挖出block的miner来决定要不要写点什么 |
gasLimit | 该值设置对gas的消耗总量限制,用来限制区块能包含的交易信息和,因为我们是私有链,所以填最大 |
写入之后可以使用jq来看json内容
parallels@parallels-vm:~/geth$ jq . gensis.json
{
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc": {
"0xeb680f30715f347d4eb5cd03ac5eced297ac5046": {
"balance": "1000000000000000000000000000000"
}
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x01",
"extraData": "0x0000111122223333",
"gasLimit": "0xffffffff",
"nonce": "0x0000000000000001",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}
3)初始化
新建一个目录存放区块链数据,然后在geth目录下执行初始化命令
sudo mkdir db
geth --datadir "./db" init gensis.json
报错1
Fatal: invalid genesis file: json: cannot unmarshal hex string of odd length into Go struct field Genesis.coinbase of type common.Address
应该是输入问题无法解析奇数位的十六进制,发现是我的coinbase少打一位
查看日志打印
parallels@parallels-vm:~/geth$ geth --datadir "./db" init gensis.json
WARN [10-09|09:25:22.161] Sanitizing cache to Go's GC limits provided=1024 updated=328
INFO [10-09|09:25:22.162] Maximum peer count ETH=25 LES=0 total=25
INFO [10-09|09:25:22.162] Allocated cache and file handles database=/home/parallels/geth/db/geth/chaindata cache=16 handles=16
INFO [10-09|09:25:22.170] Writing custom genesis block
INFO [10-09|09:25:22.170] Persisted trie from memory database nodes=1 size=153.00B time=47.625µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [10-09|09:25:22.170] Successfully wrote genesis state database=chaindata hash=e6d323…1fa434
INFO [10-09|09:25:22.170] Allocated cache and file handles database=/home/parallels/geth/db/geth/lightchaindata cache=16 handles=16
INFO [10-09|09:25:22.173] Writing custom genesis block
INFO [10-09|09:25:22.173] Persisted trie from memory database nodes=1 size=153.00B time=34.398µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [10-09|09:25:22.173] Successfully wrote genesis state database=lightchaindata hash=e6d323…1fa434
初始化成功后,会在数据目录db中生成geth和keystore两个文件夹
parallels@parallels-vm:~/geth$ tree
.
├── db
│ ├── geth
│ │ ├── chaindata
│ │ │ ├── 000001.log
│ │ │ ├── CURRENT
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000000
│ │ └── lightchaindata
│ │ ├── 000001.log
│ │ ├── CURRENT
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000000
│ └── keystore
└── gensis.json
5 directories, 11 files
其中的db/geth/chaindata存放区块数据,db/keysotre存放账户数据
4)启动节点
geth --datadir "./db" --rpc --rpcaddr=0.0.0.0 --rpcport 8545 --rpccorsdomain "*" --rpcapi "eth,net,web3,personl,admin,shh,txpool,debug,miner" --nodiscover --maxpeers 30 --networkid 1981 --port 30303 --mine --miner.threads 1 --etherbase "0xeb680f30715f347d4eb5cd03ac5eced297ac5046" console
启动节点的参数
参数 | 参数详解 |
---|---|
datadir | 指明当前区块链私钥和网络数据存放的位置 |
rpc | 开启http-rpc服务,可以进行智能合约的部署和调试 |
rpcaddr | 指定http-rpc服务监听地址,默认为"localhost" |
rpcport | 指定http-rpc服务监听端口,默认为8545 |
rpccorsdomain | |
rpcapi | 设置允许连接的rpc的客户端,一般为db,eth,net,web3 |
nodiscover | 关闭自动连接节点,但是可以手动添加节点,在搭建私有链的时候,为避免其他节点连入私有链,可以使用该命令 |
maxpeers | 设置允许最大连节点数,默认25 |
networkid | 指定以太坊网络id,共有链为1,测试链为3,默认启动1 |
port | 指定以太坊网络监听端口,默认为30303 |
mine | 开启挖矿,默认为cpu挖矿 |
minerthreads | 挖矿占用cpu线程数,默认为4,现命名为miner.threads |
etherbase | 指定矿工账号 |
console | 启动命令行模式,可以在geth中执行命令 |
来看启动后
parallels@parallels-vm:~/geth$ geth --datadir "./db" --rpc --rpcaddr=0.0.0.0 --rpcport 8545 --rpccorsdomain "*" --rpcapi "eth,net,web3,personl,admin,shh,txpool,debug,miner" --nodiscover --maxpeers 30 --networkid 1981 --port 30303 --mine --miner.threads 1 --etherbase "0xeb680f30715f347d4eb5cd03ac5eced297ac5046" console
WARN [10-09|10:03:47.100] Sanitizing cache to Go's GC limits provided=1024 updated=328
INFO [10-09|10:03:47.101] Maximum peer count ETH=30 LES=0 total=30
INFO [10-09|10:03:47.102] Starting peer-to-peer node instance=Geth/v1.8.16-stable-477eb093/linux-amd64/go1.10
INFO [10-09|10:03:47.102] Allocated cache and file handles database=/home/parallels/geth/db/geth/chaindata cache=246 handles=512
INFO [10-09|10:03:47.111] Initialised chain configuration config="{ChainID: 15 Homestead: 0 DAO: DAOSupport: false EIP150: EIP155: 0 EIP158: 0 Byzantium: Constantinople: Engine: unknown}"
INFO [10-09|10:03:47.111] Disk storage enabled for ethash caches dir=/home/parallels/geth/db/geth/ethash count=3
INFO [10-09|10:03:47.111] Disk storage enabled for ethash DAGs dir=/home/parallels/.ethash count=2
INFO [10-09|10:03:47.111] Initialising Ethereum protocol versions="[63 62]" network=1981
INFO [10-09|10:03:47.111] Loaded most recent local header number=0 hash=e6d323…1fa434 td=1 age=49y5mo3w
INFO [10-09|10:03:47.111] Loaded most recent local full block number=0 hash=e6d323…1fa434 td=1 age=49y5mo3w
INFO [10-09|10:03:47.111] Loaded most recent local fast block number=0 hash=e6d323…1fa434 td=1 age=49y5mo3w
INFO [10-09|10:03:47.111] Regenerated local transaction journal transactions=0 accounts=0
INFO [10-09|10:03:47.112] Starting P2P networking
INFO [10-09|10:03:47.113] RLPx listener up self="enode://6a838e31cb369d6823f8737013f8609cec10ee1d6dc6275db1d8faed644f8a5773a9f182167b1b8d88bc06bb683f170dea5cf1281039b2a666108c53d2eb3364@[::]:30303?discport=0"
INFO [10-09|10:03:47.118] IPC endpoint opened url=/home/parallels/geth/db/geth.ipc
INFO [10-09|10:03:47.119] HTTP endpoint opened url=http://0.0.0.0:8545 cors=* vhosts=localhost
INFO [10-09|10:03:47.119] Transaction pool price threshold updated price=1000000000
INFO [10-09|10:03:47.119] Updated mining threads threads=1
INFO [10-09|10:03:47.119] Transaction pool price threshold updated price=1000000000
INFO [10-09|10:03:47.120] Commit new mining work number=1 sealhash=9b6ee0…a5293b uncles=0 txs=0 gas=0 fees=0 elapsed=138.878µs
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.16-stable-477eb093/linux-amd64/go1.10
coinbase: 0xeb680f30715f347d4eb5cd03ac5eced297ac5046
at block: 0 (Thu, 01 Jan 1970 08:00:00 CST)
datadir: /home/parallels/geth/db
modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
> INFO [10-09|10:03:49.703] Generating DAG in progress epoch=0 percentage=0 elapsed=1.837s
INFO [10-09|10:03:51.668] Generating DAG in progress epoch=0 percentage=1 elapsed=3.802s
INFO [10-09|10:03:53.590] Generating DAG in progress epoch=0 percentage=2 elapsed=5.724s
INFO [10-09|10:03:55.497] Generating DAG in progress epoch=0 percentage=3 elapsed=7.631s
INFO [10-09|10:03:57.279] Generating DAG in progress epoch=0 percentage=4 elapsed=9.413s
INFO [10-09|10:03:59.186] Generating DAG in progress epoch=0 percentage=5 elapsed=11.320s
INFO [10-09|10:04:01.077] Generating DAG in progress epoch=0 percentage=6 elapsed=13.211s
INFO [10-09|10:04:02.938] Generating DAG in progress epoch=0 percentage=7 elapsed=15.071s
INFO [10-09|10:04:04.712] Generating DAG in progress
···
可以看到后面不是挖矿,是生成dag,是虚拟机分配的内存太小的原因,应该是出现锤子,后面有
5)进入javascript控制台
另开一个终端,通过attach命令,连接一个已经启动节点,启动js命令环境
parallels@parallels-vm:~$ cd geth
parallels@parallels-vm:~/geth$ geth --datadir './db' attach ipc:./db/geth.ipc
WARN [10-09|10:07:40.514] Sanitizing cache to Go's GC limits provided=1024 updated=328
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.16-stable-477eb093/linux-amd64/go1.10
coinbase: 0xeb680f30715f347d4eb5cd03ac5eced297ac5046
at block: 0 (Thu, 01 Jan 1970 08:00:00 CST)
datadir: /home/parallels/geth/db
modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
>
在启动参数的rpcapi有设置过,这些是以太坊javascript的内置对象
1)eth:提供操作区块链相关的方法
2)net:提供查看p2p网络状态的方法
3)admin:提供管理节点相关的方法
4)miner:提供启动和停止挖矿的方法
5)personal:提供了管理账户的方法
6)txpool:提供查看内存池的方法
7)web3:除了包含以上对象中的方法,还包含一些单位换算的方法
需要在开启节点的情况下,才能在js控制台使用命令
geth --datadir "./db" --rpc --rpcaddr=0.0.0.0 --rpcport 8545 --rpccorsdomain "*" --rpcapi "eth,net,web3,personl,admin,shh,txpool,debug,miner" --nodiscover --maxpeers 30 --networkid 1981 --port 30303 console
上述步骤开启节点不挖矿
> personal.newAccount("123456")
Error: write unix @->/home/parallels/geth/db/geth.ipc: use of closed network connection
> personal.newAccount("123456")
"0x0f9fea676cad4b86d157179d77d038982614104b"
personal.newAccount(“passwd”)用来生成账户,传入的参数是账户密码,执行后会返回账户公钥,生成的账户文件在keystore下
│ └── keystore
│ └── UTC--2018-10-09T02-40-07.234932244Z--0f9fea676cad4b86d157179d77d038982614104b
查看我们刚生成的两个账户,执行两次
> eth.accounts
["0x0f9fea676cad4b86d157179d77d038982614104b", "0x3262f586a0c0b7e82a357c42fb57a0d1b9083d57"]
> balance=web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
0
> balance=web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")
0
eth.accounts[index]会按传入的索引返回已有的账户,eth.getBalance(address)会返回账户的余额,余额是以wei为单位,传入的参数是账户的公钥,可以看到新建的这两个账户的余额都是0,需要通过挖矿获取
在挖矿前,先设置挖矿奖励地址
> miner.setEtherbase(eth.accounts[0])
true
> eth.coinbase
"0x0f9fea676cad4b86d157179d77d038982614104b"
设置成功后,我们就开始挖矿,调大虚拟机内存
> miner.start(1)
INFO [10-09|11:23:18.475] Updated mining threads threads=1
INFO [10-09|11:23:18.475] Transaction pool price threshold updated price=1000000000
null
> INFO [10-09|11:23:18.475] Commit new mining work number=1 sealhash=5ee453…d43b2f uncles=0 txs=0 gas=0 fees=0 elapsed=188.516µs
> INFO [10-09|11:23:32.327] Successfully sealed new block number=1 sealhash=5ee453…d43b2f hash=3a7693…ac82f9 elapsed=13.852s
INFO [10-09|11:23:32.329] mined potential block number=1 hash=3a7693…ac82f9
INFO [10-09|11:23:32.329] Commit new mining work number=2 sealhash=4a9541…3f58a4 uncles=0 txs=0 gas=0 fees=0 elapsed=705.055µs
INFO [10-09|11:23:32.770] Successfully sealed new block number=2 sealhash=4a9541…3f58a4 hash=d522c7…b6b0ba elapsed=440.109ms
INFO [10-09|11:23:32.770] mined potential block number=2 hash=d522c7…b6b0ba
INFO [10-09|11:23:32.770] Commit new mining work number=3 sealhash=28cbd5…160883 uncles=0 txs=0 gas=0 fees=0 elapsed=135.475µs
···
INFO [10-09|11:24:07.320] Successfully sealed new block number=11 sealhash=9ffeca…eab784 hash=8f021e…b07669 elapsed=1.803s
INFO [10-09|11:24:07.320] block reached canonical chain number=4 hash=5b856d…0b87e3
INFO [10-09|11:24:07.320] mined potential block number=11 hash=8f021e…b07669
INFO [10-09|11:24:07.320] Commit new mining work number=12 sealhash=1dbbe1…99fdc7 uncles=0 txs=0 gas=0 fees=0 elapsed=105.843µs
INFO [10-09|11:24:07.471] Successfully sealed new block number=12 sealhash=1dbbe1…99fdc7 hash=253223…a70f75 elapsed=151.429ms
INFO [10-09|11:24:07.471] block reached canonical chain number=5 hash=66b687…c722a6
INFO [10-09|11:24:07.471] mined potential block number=12 hash=253223…a70f75
INFO [10-09|11:24:07.471] Commit new mining work number=13 sealhash=f0e378…bcb36a uncles=0 txs=0 gas=0 fees=0 elapsed=105.459µs
INFO [10-09|11:24:11.512] Successfully sealed new block number=13 sealhash=f0e378…bcb36a hash=1f7b2e…2f0d16 elapsed=4.040s
···
出现锤子了,并且块会达到标准链中
现在来余额,另外开一个attach,先停止挖矿,返回的不是true有点奇怪
> miner.stop()
null
> balance=web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
425
现在账户上有425个以太币了
在发送转账交易之前需要先解锁账户,否则会报错,600表示600s
> personal.unlockAccount(eth.accounts[0],"123456",600)
true
准备就绪后开始转账操作
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(1,"ether")})
INFO [10-09|11:39:38.775] Setting new local account address=0x0F9fea676cAd4B86d157179d77D038982614104B
INFO [10-09|11:39:38.775] Submitted transaction fullhash=0x03ae416d2817a05a1e2c4720dc6ae8b3c0b06b28943cfe7dd71d31b76e7f58a6 recipient=0x3262f586A0c0b7e82A357c42FB57A0d1b9083D57
"0x03ae416d2817a05a1e2c4720dc6ae8b3c0b06b28943cfe7dd71d31b76e7f58a6"
查看交易池等待被打包的交易
> txpool.status
{
pending: 1,
queued: 0
}
pending表示已提交但还未被处理的交易,下面显示详细信息
> txpool.inspect.pending
{
0x0F9fea676cAd4B86d157179d77D038982614104B: {
0: "0x3262f586A0c0b7e82A357c42FB57A0d1b9083D57: 1000000000000000000 wei + 90000 gas × 1000000000 wei"
}
}
要使交易被处理,需要开启挖矿,我们启动挖矿
> miner.start(1);admin.sleepBlocks(1);miner.stop(1);
INFO [10-09|11:44:43.093] Updated mining threads threads=1
INFO [10-09|11:44:43.093] Transaction pool price threshold updated price=1000000000
INFO [10-09|11:44:43.094] Commit new mining work number=86 sealhash=21e018…ecdfcd uncles=0 txs=0 gas=0 fees=0 elapsed=126.346µs
INFO [10-09|11:44:43.096] Commit new mining work number=86 sealhash=fb70ee…1cacb0 uncles=0 txs=1 gas=21000 fees=2.1e-05 elapsed=2.484ms
INFO [10-09|11:44:54.368] Successfully sealed new block number=86 sealhash=fb70ee…1cacb0 hash=be7528…a5e03f elapsed=11.273s
INFO [10-09|11:44:54.370] block reached canonical chain number=79 hash=fb125b…007941
INFO [10-09|11:44:54.370] mined potential block number=86 hash=be7528…a5e03f
INFO [10-09|11:44:54.370] Commit new mining work number=87 sealhash=ad0d6d…ee831e uncles=0 txs=0 gas=0 fees=0 elapsed=389.275µs
Error: Invalid number of input parameters to RPC method
at web3.js:3133:20
at web3.js:5008:15
at web3.js:5051:5
at web3.js:5075:23
···
并没有限制住,后面还有区块被挖出来,所以不止一个区块,先来查看余额
> balance=web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
644
> balance=web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")
1
644=5*129-1
转账成功的
转账交易时返回的交易hash可以用来查询发起转账交易时的详情
> eth.getTransaction("0x03ae416d2817a05a1e2c4720dc6ae8b3c0b06b28943cfe7dd71d31b76e7f58a6")
{
blockHash: "0xbe752881732690580d24cdeb1362a081c93aa57ca883003f911ba7ea35a5e03f",//交易所在区块的hash值
blockNumber: 86,//交易所在区块的块号
from: "0x0f9fea676cad4b86d157179d77d038982614104b",
gas: 90000,
gasPrice: 1000000000,
hash: "0x03ae416d2817a05a1e2c4720dc6ae8b3c0b06b28943cfe7dd71d31b76e7f58a6",
input: "0x",//交易附带的数据
nonce: 0,//交易发起者在之前发起过的交易
r: "0xe8877ecaed9777a4767d737a99f6905d6c0ad3e6ea077e215bb0f41011490283",
s: "0x6c28c426d99353e3b19816e6da871bbbdcd9e3b85430adbfd4321740eaf28cf4",
to: "0x3262f586a0c0b7e82a357c42fb57a0d1b9083d57",
transactionIndex: 0,//交易在区块中的序号,区块处于pending返回null
v: "0x42",
value: 1000000000000000000
}
>
还有另外一个命令,可以查看交易被打包进区块时的命令
> eth.getTransactionReceipt("0x03ae416d2817a05a1e2c4720dc6ae8b3c0b06b28943cfe7dd71d31b76e7f58a6")
{
blockHash: "0xbe752881732690580d24cdeb1362a081c93aa57ca883003f911ba7ea35a5e03f",
blockNumber: 86,
contractAddress: null,//创建的合约地址,如果是一个合约创建交易,则返回合约地址,其他情况返回null
cumulativeGasUsed: 21000,//当前交易执行后累积花费的gas总值
from: "0x0f9fea676cad4b86d157179d77d038982614104b",
gasUsed: 21000,//执行当前这个交易单独花费的gas
logs: [],//这个交易产生的日志对象数组
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",//由logs中的address和topics共同决定
root: "0x08b18b0bd13b3ce809a5e26795a3c0d554311542bbd7cd15cebed74dde2e26e7",//交易执行后的stateroot
to: "0x3262f586a0c0b7e82a357c42fb57a0d1b9083d57",//交易接收者的地址
transactionHash: "0x03ae416d2817a05a1e2c4720dc6ae8b3c0b06b28943cfe7dd71d31b76e7f58a6",
transactionIndex: 0
}
下面还有一些常用的查询区块命令:
*查看当前区块总数
> eth.blockNumber
129
*查询最新区块
> eth.getBlock('latest')
{
difficulty: 133705,
extraData: "0xd683010810846765746886676f312e3130856c696e7578",
gasLimit: 3786362799,
gasUsed: 0,
hash: "0x4367222de32a091e9366d32c9c0f92e294500350dacec50b347b22be5fbb33f7",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0x0f9fea676cad4b86d157179d77d038982614104b",
mixHash: "0x40b821fe4ea919ef1647bd7dee575392e5c80bd4b660e7f6945a48ba41808735",
nonce: "0x216d305d26aa65a5",
number: 129,
parentHash: "0x025649a36c8d91b9d5d36ca59b2ea00f0df46a1973e3f675c32678b59d72c968",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 536,
stateRoot: "0xa9e986c2104ae06f45dfbe208097eadce679001f2585c280ff14051cafca58b2",
timestamp: 1539056840,
totalDifficulty: 17173277,
transactions: [],
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
uncles: []
}
eth.getBlock(blockNumber|blockHash)根据区块Number或Hash查询区块
> eth.getBlock(0)
{
difficulty: 1,
extraData: "0x0000111122223333",
gasLimit: 4294967295,
gasUsed: 0,
hash: "0xe6d323f9071b7765f4cf1b22f7516b271b8c5825d546667d29179dd2c81fa434",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0x0000000000000000000000000000000000000000",
mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: "0x0000000000000001",//工作量证明
number: 0,//当前区块高度
parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",//区块receipt trie的根
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",//对叔区块的进行hash运算的结果
size: 513,//区块大小,字节
stateRoot: "0xf4963e586b9cd62eb4c47233af0b49b9841b0737baf0872e02c29ea03165e599",//块的状态树根结果
timestamp: 0,
totalDifficulty: 1,//达到该区块的难度总数
transactions: [],//交易数组
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",//交易的merkle树根
uncles: []//当前区块引用的叔父区块的哈希值
}
这个是我们自己写的创世区块,大部分内容都熟悉的
目前为止,我们的以太坊私有链还是在单机上运行的,接下来看怎么和其他节点通信,唔,我只能尝试两台虚拟了
*查看节点信息
> admin.nodeInfo
{
enode: "enode://6a838e31cb369d6823f8737013f8609cec10ee1d6dc6275db1d8faed644f8a5773a9f182167b1b8d88bc06bb683f170dea5cf1281039b2a666108c53d2eb3364@[::]:30303?discport=0",
id: "6a838e31cb369d6823f8737013f8609cec10ee1d6dc6275db1d8faed644f8a5773a9f182167b1b8d88bc06bb683f170dea5cf1281039b2a666108c53d2eb3364",
ip: "::",
listenAddr: "[::]:30303",
name: "Geth/v1.8.16-stable-477eb093/linux-amd64/go1.10",
ports: {
discovery: 0,
listener: 30303
},
protocols: {
eth: {
config: {
chainId: 15,
eip150Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
eip155Block: 0,
eip158Block: 0,
homesteadBlock: 0
},
difficulty: 17173277,
genesis: "0xe6d323f9071b7765f4cf1b22f7516b271b8c5825d546667d29179dd2c81fa434",
head: "0x4367222de32a091e9366d32c9c0f92e294500350dacec50b347b22be5fbb33f7",
network: 1981
}
}
}
*添加节点(我没尝试)
admin.nodeInfo.enode//获取节点二的encode
admin.addPeer("")//上面获取的encode
*创建新账号
parallels@parallels-vm:~/geth$ geth --datadir './db' account new
WARN [10-09|14:18:05.723] Sanitizing cache to Go's GC limits provided=1024 updated=664
INFO [10-09|14:18:05.724] Maximum peer count ETH=25 LES=0 total=25
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat passphrase:
Address: {27d56169b474f570c58c37a39a6433630be58d09}
*列举已存在账号
parallels@parallels-vm:~/geth$ geth --datadir './db' account list
WARN [10-09|14:20:49.310] Sanitizing cache to Go's GC limits provided=1024 updated=664
INFO [10-09|14:20:49.310] Maximum peer count ETH=25 LES=0 total=25
Account #0: {0f9fea676cad4b86d157179d77d038982614104b} keystore:///home/parallels/geth/db/keystore/UTC--2018-10-09T02-40-07.234932244Z--0f9fea676cad4b86d157179d77d038982614104b
Account #1: {3262f586a0c0b7e82a357c42fb57a0d1b9083d57} keystore:///home/parallels/geth/db/keystore/UTC--2018-10-09T02-45-56.804969723Z--3262f586a0c0b7e82a357c42fb57a0d1b9083d57
Account #2: {27d56169b474f570c58c37a39a6433630be58d09} keystore:///home/parallels/geth/db/keystore/UTC--2018-10-09T06-18-17.187006663Z--27d56169b474f570c58c37a39a6433630be58d09
*修改账户密码
parallels@parallels-vm:~/geth$ geth --datadir './db' account update 27d56169b474f570c58c37a39a6433630be58d09
WARN [10-09|14:23:30.021] Sanitizing cache to Go's GC limits provided=1024 updated=664
INFO [10-09|14:23:30.022] Maximum peer count ETH=25 LES=0 total=25
Unlocking account 27d56169b474f570c58c37a39a6433630be58d09 | Attempt 1/3
Passphrase:
INFO [10-09|14:23:39.512] Unlocked account address=0x27d56169B474F570C58C37A39a6433630Be58d09
Please give a new password. Do not forget this password.
Passphrase:
Repeat passphrase:
*导入密钥文件
geth --datadir './db' account import ecc.key
ecc.key是ECDSA的私钥,这里不尝试了
*导出区块数据
将db目录中的区块数据导出到bak文件
parallels@parallels-vm:~/geth$ geth --datadir './db' export ./bak
WARN [10-09|14:35:09.825] Sanitizing cache to Go's GC limits provided=1024 updated=664
INFO [10-09|14:35:09.825] Maximum peer count ETH=25 LES=0 total=25
INFO [10-09|14:35:09.826] Allocated cache and file handles database=/home/parallels/geth/db/geth/chaindata cache=498 handles=1024
INFO [10-09|14:35:09.833] Disk storage enabled for ethash caches dir=/home/parallels/geth/db/geth/ethash count=3
INFO [10-09|14:35:09.833] Disk storage enabled for ethash DAGs dir=/home/parallels/.ethash count=2
WARN [10-09|14:35:09.833] Head state missing, repairing chain number=129 hash=436722…bb33f7
INFO [10-09|14:35:09.839] Rewound blockchain to past state number=0 hash=e6d323…1fa434
INFO [10-09|14:35:09.839] Loaded most recent local header number=129 hash=436722…bb33f7 td=17173277 age=2h47m49s
INFO [10-09|14:35:09.839] Loaded most recent local full block number=0 hash=e6d323…1fa434 td=1 age=49y5mo3w
INFO [10-09|14:35:09.839] Loaded most recent local fast block number=129 hash=436722…bb33f7 td=17173277 age=2h47m49s
INFO [10-09|14:35:09.839] Exporting blockchain file=./bak
INFO [10-09|14:35:09.840] Exporting batch of blocks count=1
INFO [10-09|14:35:09.840] Exported blockchain file=./bak
Export done in 103.155µs
导出成功后会有bak文件
parallels@parallels-vm:~/geth$ ll
total 20
drwxrwxr-x 3 parallels parallels 4096 Oct 9 14:35 ./
drwxr-xr-x 21 parallels parallels 4096 Oct 9 13:58 ../
-rwxrwxr-x 1 parallels parallels 513 Oct 9 14:35 bak*
drwxrwxr-x 4 parallels parallels 4096 Oct 9 13:58 db/
-rw-rw-r-- 1 parallels parallels 0 Oct 9 10:45 eth.accounts
-rw-rw-r-- 1 parallels parallels 630 Oct 9 09:24 gensis.json
*移除区块数据
parallels@parallels-vm:~/geth$ geth --datadir './db' removedb
WARN [10-09|14:39:40.167] Sanitizing cache to Go's GC limits provided=1024 updated=664
INFO [10-09|14:39:40.167] Maximum peer count ETH=25 LES=0 total=25
/home/parallels/geth/db/geth/chaindata
Remove this database? [y/N] y
Remove this database? [y/N] y
INFO [10-09|14:39:46.755] Database successfully deleted database=chaindata elapsed=259.121µs
/home/parallels/geth/db/geth/lightchaindata
Remove this database? [y/N] y
Remove this database? [y/N] y
INFO [10-09|14:39:48.971] Database successfully deleted database=lightchaindata elapsed=537.34µs
*导入区块数据
在导入前需要先用gensis.json文件执行初始化操作
geth --datadir './db' init gensis.json
初始化后可以开始导入区块
parallels@parallels-vm:~/geth$ geth --datadir './db' import ./bak
WARN [10-09|14:42:43.095] Sanitizing cache to Go's GC limits provided=1024 updated=664
INFO [10-09|14:42:43.096] Maximum peer count ETH=25 LES=0 total=25
INFO [10-09|14:42:43.096] Allocated cache and file handles database=/home/parallels/geth/db/geth/chaindata cache=498 handles=1024
INFO [10-09|14:42:43.103] Disk storage enabled for ethash caches dir=/home/parallels/geth/db/geth/ethash count=3
INFO [10-09|14:42:43.103] Disk storage enabled for ethash DAGs dir=/home/parallels/.ethash count=2
INFO [10-09|14:42:43.103] Loaded most recent local header number=0 hash=e6d323…1fa434 td=1 age=49y5mo3w
INFO [10-09|14:42:43.103] Loaded most recent local full block number=0 hash=e6d323…1fa434 td=1 age=49y5mo3w
INFO [10-09|14:42:43.103] Loaded most recent local fast block number=0 hash=e6d323…1fa434 td=1 age=49y5mo3w
INFO [10-09|14:42:43.103] Importing blockchain file=./bak
INFO [10-09|14:42:43.103] Blockchain manager stopped
Import done in 150.15µs.
Compactions
Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)
-------+------------+---------------+---------------+---------------+---------------
0 | 1 | 0.00070 | 0.00000 | 0.00000 | 0.00000
Read(MB):0.00216 Write(MB):0.00097
Trie cache misses: 0
Trie cache unloads: 0
Object memory: 126.225 MB current, 126.217 MB peak
System memory: 263.530 MB current, 263.530 MB peak
Allocations: 0.017 million
GC pause: 391.196µs
Compacting entire database...
Compaction done in 37.935811ms.
Compactions
Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)
-------+------------+---------------+---------------+---------------+---------------
0 | 0 | 0.00000 | 0.00218 | 0.00000 | 0.00021
1 | 1 | 0.00070 | 0.00148 | 0.00091 | 0.00070
Read(MB):0.00235 Write(MB):0.00207
INFO [10-09|14:42:43.142] Database closed database=/home/parallels/geth/db/geth/chaindata
*更新db目录中的区块数据
parallels@parallels-vm:~/geth$ geth --datadir './db' upgradedb
WARN [10-09|14:44:52.823] Sanitizing cache to Go's GC limits provided=1024 updated=664
invalid command: "upgradedb"
emmmm…无效的指令,根据geth help来看,确实没有这个指令
*dump(未尝试)
从区块链中抛弃某一区块数据
geth --datadir './db' number/blockHash
testrpc是一个基于node.js开发的以太坊客户端,使用ethereumjs模拟以太坊完整客户端的行为,帮助快速开发
前面我们已经安装过nodejs了,不过很尴尬的是版本不够
parallels@parallels-vm:~$ nodejs --version
v4.2.6
首先卸载,然后再装
sudo apt-get --purge remove nodejs
tar -zxvf node-v8.12.0.tar.gz
cd node-v8.12.0/
sudo ./configure
sudo make
sudo make install
然后安装testrpc
sudo npm install -g ethereumjs-testrpc
···//日志
+ ethereumjs-testrpc@6.0.3
added 331 packages from 281 contributors in 11.262s
testrpc客户端的基本使用方法如下
testrpc -a 1//-a或--accounts指定在启动时生成多少个账户
parallels@parallels-vm:~$ testrpc -a 1
EthereumJS TestRPC v6.0.3 (ganache-core: 2.0.2)
Available Accounts
==================
(0) 0xfc277a31bacb72c35dc7cbcda0dbda3e36779979
Private Keys
==================
(0) 263dcf64aea1c34d99f5870b5e47c3be40d3c447c7f66d42a36f9e98398f2a6d
HD Wallet
==================
Mnemonic: double hint anger erosion exile easy index vintage city ecology harvest glad
Base HD Path: m/44'/60'/0'/0/{account_index}
Listening on localhost:8545
testrpc -b 1//-b或--blocktime设置每隔多少秒产生一个区块,用于自动挖矿。默认0,不挖矿
testrpc -n//-n或--secure默认锁上所有可用的账户
testrpc -a 1 -m "squirrel shield mass ···"//-m或--mnemonic使用一个指定分层确定性钱包助记符来生成初始地址
testrpc -a 1 -d -p 8888//-p或--port用于监听的端口,默认8545
testrpc -a 1 -s "11"//-s或--seed使用任意的数据生成分层确定钱包助记符
-h或–hostname 用于设置监听的域名
-g或–gasPrice 自定义gas价格(默认200000000000)
-l或–gasLimit 自定义gas限额(默认0x47E7C4)
···