node、npm安装(apt-get安装的版本不对)
通过 https://nodejs.org 下载最新/稳定的nodejs、npm版本(需要nodejs 5.0+);
Truffle、ganache-cli安装
Truffle 是目前最流行的以太坊开发框架,采用JavaScript编写,支持智能合约的编译、部署和测试。通过以下指令安装Truffle:1
$ npm install -g truffle
ganache是truffle推出的一个可视化私有链客户端,方便开发,与testrpc类似。
可以下载命令行的ganache-cli1
npm install -g ganache-cli
也可以下载图形化的ganache1
2
3wget https://github.com/trufflesuite/ganache/releases/download/v1.1.0/ganache-1.1.0-x86_64.AppImage
chmod +x ganache-1.1.0-x86_64.AppImage //修改权限
sudo ./ganache-1.1.0-x86_64.AppImage //启动ganache
启动后操作界面如下图如示,其中ganache默认生成了10个Account账户,我们可以清晰的看到钱包地址及账户余额(右侧钥匙为私钥):
可以通过修改hostname和port改变私有私访问地址(端口默认为7545):
基本使用
1、随意建立代码文件夹
mkdir -p ~/blockchain/test_truffle
2、进入刚刚建立的文件夹并执行初始化命令
cd ~/blockchain/test_truffle && truffle init
3、在contracts目录中新建一个HelloWorld.sol文件,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14pragma solidity ^0.4.17;
contract HelloWorld {
//say hello world
function say() public pure returns (string) {
return "Hello world";
}
//print name
function print(string name) public pure returns (string) {
return name;
}
}
4、在migrations目录下新建部署脚本,文件名自定义,比如2_deploy_contracts.js,将我们刚才创建的HelloWorld.sol文件添加到发布配置文件中,内容如下:1
2
3
4
5var HelloWorld = artifacts.require("./HelloWorld.sol");
module.exports = function(deployer) {
deployer.deploy(HelloWorld);
};
5、编译合约
truffle compile
6、编辑truffle.js
编辑truffle.js(注ganache-cli默认使用8545,ganache图型化客户端默认使用7545),内容如下:1
2
3
4
5
6
7
8
9module.exports = {
networks: {
development: {
host: "localhost",
port: 8545,
network_id: "*"
}
}
};
7、部署智能合约
truffle migrate
8、功能验证
输入truffle console
命令打开truffle控制台,测试刚才我们部署的HelloWorld合约1
2
3
4
5
6
7
8
9
10
11truffle(development)> var contract;
undefined
truffle(development)> HelloWorld.deployed().then(function(instance){contract= instance;});
undefined
truffle(development)> contract.say()
'Hello world'
truffle(development)> contract.print("hi")
'hi'
安装geth客户端
Geth又名Go Ethereum,由Go语言开发,完全开源的项目。它是一个命令行工具,提供很多命令和选项,可以运行以太坊节点、创建和管理账户、发送交易、挖矿、部署智能合约等。1
2
3
4sudo apt-get install software-properties-common
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum
搭建以太坊私有链
1、准备创世区块配置文件
以太坊支持自定义创世区块,要运行私有链,我们就需要定义自己的创世区块,创世区块信息写在一个json格式的配置文件中。首先将下面的内容保存到一个json文件中,例如genesis.json。创建blockchain文件夹,并将genesis.json放入。
1 | { |
各参数的作用如下:
1 | mixhash:与nonce配合用于挖矿,由上一个区块的一部分生成的hash。 |
2、写入创世区块
此时genesis.json保存在~/blockchain中,准备好创世区块配置文件后,需要初始化区块链,将上面的创世区块信息写入到区块链中。创建node目录,然后执行下列指令:1
geth --datadir './node' init genesis.json
命令的主体是geth init,表示初始化区块链,命令可以带有选项和参数,其中–datadir选项后面跟一个目录名,这里为node,表示指定数据存放目录为node,genesis.json是init命令的参数。运行上面的命令,会读取genesis.json文件,根据其中的内容,将创世区块写入到区块链中。此时目录结构如下:
blockchain
├── node
│ ├── geth
│ │ ├── chaindata
│ │ └── …
│ └── keystore
└── genesis.json
其中geth/chaindata中存放的是区块数据,keystore中存放的是账户数据。
3、启动私有链节点
初始化完成后,就有了一条自己的私有链,之后就可以启动自己的私有链节点并做一些操作,在终端中输入以下命令即可启动节点。1
nohup geth --rpc --rpcaddr="0.0.0.0" --rpccorsdomain="*" --rpcapi "db,eth,net,web3" --networkid '54001' --datadir '~/blockchain/node' &
–datadir选项指定使用node作为数据目录,–networkid选项后面跟一个数字,这里是54001,表示指定这个私有链的网络id为54001。网络id在连接到其他节点的时候会用到,以太坊公网的网络id是1,为了不与公有链网络冲突,运行私有链节点的时候要指定自己的网络id。
执行以下命令,即可进入区块链的console1
geth attach ~/blockchain/node/geth.ipc
运行上面的命令后,就启动了区块链节点并进入了Javascript Console。这是一个交互式的Javascript执行环境,在这里面可以执行Javascript代码,其中>是命令提示符。在这个环境里也内置了一些用来操作以太坊的Javascript对象,可以直接使用这些对象。
- eth:包含一些跟操作区块链相关的方法
- net:包含以下查看p2p网络状态的方法
- admin:包含一些与管理节点相关的方法
- miner:包含启动&停止挖矿的一些方法
- personal:主要包含一些管理账户的方法
- txpool:包含一些查看交易内存池的方法
- web3:包含了以上对象,还包含一些单位换算的方法
4、探索Javascript Console
进入以太坊Javascript Console后,就可以使用里面的内置对象做一些操作,这些内置对象提供的功能很丰富,比如查看区块和交易、创建账户、挖矿、发送交易、部署智能合约等。
(注:命令都可以按Tab键自动补全。)
1、创建账户
前面只是搭建了私有链,并没有自己的账户,可以在js console中输入eth.accounts来验证:
1 | > eth.accounts |
通过使用personal对象来创建账户:1
2
3Passphrase:
Repeat passphrase:
"0xbe38bf86bb9837cd60c86f70cb344c59c91f9b7f"
接下来就可以查看到刚才创建的账户了:1
2> eth.accounts
["0xbe38bf86bb9837cd60c86f70cb344c59c91f9b7f"]
2、查看余额1
2
3eth对象提供了查看账户余额的方法:
> eth.getBalance(eth.accounts[0])
0
3、启动&停止挖矿
通过miner.start()来启动挖矿:1
> miner.start(1)
其中start的参数表示挖矿使用的线程数。第一次启动挖矿会先生成挖矿所需的DAG文件,这个过程有点慢,等进度达到100%后,就会开始挖矿,此时屏幕会被挖矿信息刷屏。
如果想停止挖矿,在js console中输入miner.stop():1
> miner.stop()
挖到一个区块会奖励5个以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做coinbase,默认情况下coinbase是本地账户中的第一个账户:1
2> eth.coinbase
"0xbe38bf86bb9837cd60c86f70cb344c59c91f9b7f"
要想使挖矿奖励进入其他账户,通过miner.setEtherbase()将其他账户设置成coinbase即可。
getBalance()返回值的单位是wei,wei是以太币的最小单位,1个以太币=10的18次方个wei。要查看有多少个以太币,可以用web3.fromWei()将返回值换算成以太币:1
> web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')
4、发送交易
通过eth.sendTransaction
可以通过发送一笔交易,从账户0转移5个以太币到账户11
2
3
4
5
6> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(3,'ether')})
Error: authentication needed: password or unlock
at web3.js:3119:20
at web3.js:6023:15
at web3.js:4995:36
at <anonymous>:1:1
这里报错是因为账户每隔一段时间就会被锁住,要发送交易需要先解锁账户,由于我们要从账户0发送交易,所以要解锁账户0:1
2
3
4> personal.unlockAccount(eth.accounts[0])
Unlock account 0xbe38bf86bb9837cd60c86f70cb344c59c91f9b7f
Passphrase:
true
输入创建账户时设置的密码,就可以成功解锁账户。然后再发送交易:1
2> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(3, 'ether')})
"0xd2947d185056a3952d1f1641cae0eb4f89347f1f88770f5e2a75f978414351d0"
此时交易已经提交到区块链,返回了交易的hash,但还未被处理,这可以通过查看txpool来验证:1
2
3
4
5> txpool.status
{
pending: 1,
queued: 0
}
其中有一条pending的交易,pending表示已提交但还未被处理的交易。要使交易被处理,必须要挖矿。这里我们启动挖矿,然后等待挖到一个区块之后就停止挖矿。当txpool中pending的交易数量应该为0了,说明交易已经被处理了:1
2
3
4
5
6
7
8> txpool.status
{
pending: 0,
queued: 0
}
> eth.getBalance(eth.accounts[1])
3000000000000000000
5、查看交易和区块
eth对象封装了查看交易和区块信息的方法。
查看当前区块总数:1
2> eth.blockNumber
33
通过交易hash查看交易:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17> eth.getTransaction("0xd2947d185056a3952d1f1641cae0eb4f89347f1f88770f5e2a75f978414351d0")
{
blockHash: "0x0f00b3a4f8599ebe5867bf793a4ba463dc47211815e20f8d7a1593ac18ff872c",
blockNumber: 634359,
from: "0xf16bae16adb39a886e04c728863812fa23141b8b",
gas: 90000,
gasPrice: 1000000000,
hash: "0xd2947d185056a3952d1f1641cae0eb4f89347f1f88770f5e2a75f978414351d0",
input: "0x",
nonce: 22,
r: "0x64204d18a947be6bb7033248166f06c6b97129077d9b895ed67f3e9610718a07",
s: "0x21e2a1c101c72d36d5b450dc44fb41d56c095306ff48ac666b2e7a14a035223b",
to: "0xbe38bf86bb9837cd60c86f70cb344c59c91f9b7f",
transactionIndex: 0,
v: "0x1a606",
value: 3000000000000000000
}
通过区块号查看区块:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23> eth.getBlock(634359)
{
difficulty: 1278282,
extraData: "0xd783010703846765746887676f312e392e32856c696e7578",
gasLimit: 4712388,
gasUsed: 21000,
hash: "0x0f00b3a4f8599ebe5867bf793a4ba463dc47211815e20f8d7a1593ac18ff872c",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0xf16bae16adb39a886e04c728863812fa23141b8b",
mixHash: "0x9ad2c2c50c3c223078d17853860a1e60dbf1ce4d773ccf22c92db92dee91d866",
nonce: "0x6f1fc6c4e0f51c12",
number: 634359,
parentHash: "0xafe36f1d414fc95100fff815149246c3a449bbfafda897732b235e548f4b513c",
receiptsRoot: "0x299e65dd0d084faf2ae29b3abcc14ab7b99029e3629bbcaeef3a69c14a9e39f5",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 654,
stateRoot: "0x832f5fde59c6de9304a50831d8b9d1caa0107b9ec495484d52af6106ee0de856",
timestamp: 1523329711,
totalDifficulty: 1042016387960,
transactions: ["0xd2947d185056a3952d1f1641cae0eb4f89347f1f88770f5e2a75f978414351d0"],
transactionsRoot: "0x668edf6f5eadce730ac49224553a9f0cf761fe518d7a66d89cba0398e6d23b08",
uncles: []
}
6、连接到其他节点
可以通过admin.addPeer()方法连接到其他节点,两个节点要想联通,必须保证网络是相通的,并且要指定相同的networkid。
假设有两个节点:节点一和节点二,networkid都是54001,通过下面的步骤就可以从节点二连接到节点一。
首先要知道节点一的enode信息,在节点一的js console中执行下面的命令查看enode信息:1
2> admin.nodeInfo.enode
"enode://07f36d1c6ee18aa231dfac161913f0a3d533108505883418735b838b9453a7e5321f69bbc08a526695313554e9e325ca3eec12242b1b079c246a07d20a4e33e5@[::]:30303"
然后在节点二的js console中执行admin.addPeer(),就可以连接到节点一:1
> admin.addPeer("enode://07f36d1c6ee18aa231dfac161913f0a3d533108505883418735b838b9453a7e5321f69bbc08a526695313554e9e325ca3eec12242b1b079c246a07d20a4e33e5@ip:30303")
addPeer()的参数就是节点一的enode信息,注意要把enode中的[::]替换成节点二的IP地址。连接成功后,节点二就会开始同步节点一的区块,同步完成后,任意一个节点开始挖矿,另一个节点会自动同步区块,向任意一个节点发送交易,另一个节点也会收到该笔交易。
通过admin.peers可以查看连接到的其他节点信息,通过net.peerCount可以查看已连接到的节点数量。
除了上面的方法,也可以在启动节点的时候指定–bootnodes选项连接到其他节点。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19> net.peerCount
1
> admin.peers
[{
caps: ["eth/62", "eth/63"],
id: "07f36d1c6ee18aa231dfac161913f0a3d533108505883418735b838b9453a7e5321f69bbc08a526695313554e9e325ca3eec12242b1b079c246a07d20a4e33e5",
name: "Geth/v1.7.3-stable-4bb3c89d/linux-amd64/go1.9.2",
network: {
localAddress: "10.104.28.16:58870",
remoteAddress: "111.230.144.116:30303"
},
protocols: {
eth: {
difficulty: 1042104536363,
head: "0xb7a8c1e47797a06760959935f3d72076398f2244cf12ef2de63e13ac1bd4cce9",
version: 63
}
}
}]
安装MetaMask
MetaMask是一款在谷歌浏览器Chrome上使用的插件类型的以太坊钱包,该钱包不需要下载,只需要在谷歌浏览器添加对应的扩展程序即可,非常轻量级,使用起来也非常方便。
MetaMask安装
这款插件的官方地址为 https://metamask.io/ ,Chrome网上应用商店的下载地址是: https://chrome.google.com/webstore/detail/nkbihfbeogaeaoehlefnkodbefgpgknn ,如果无法访问,可以直接点击下载
MetaMask使用
根据提示同意条款并输入钱包密码:
保存好这些助记词之后,点击下面的按钮,进入钱包页面,如下图所示:
点击左上角的Private Network->Custom RPC即可添加自己的以太坊私链地址:
点击右上角图标可以切换或导入新Account:
参考资料
CRYPTOZOMBIES
Truffle Framework
ETHEREUM PET SHOP
BUILDING ROBUST SMART CONTRACTS WITH OPENZEPPELIN
以太坊学习笔记:私有链搭建操作指南
zeppelin-solidity
GO EthEREUM