环境:
? ? 1. centos 7.3
? ? 2. etheruem 1.7.3
? ? 3. go-etheruem
? ? 4. golang
安装
? ? ?1. ?golang环境
? ??
yum -y install golang
2. ? ?安装git 工具
yum -y install git
3. ?下载go-etheruem源码包并且安装
git clone https://github.com/ethereum/go-ethereum.git
cd go-ethereum
git checkout v1.7.2 git checkout v1.7.3
make geth
make all
4. 查看是否安装成功
??
# build/bin/geth version
5. 设置 geth 环境变了
export PATH=/eth/go-ethereum/build/bin:$PATH
[root@lt-test-mongodb eth]# geth version
Geth
Version: 1.7.2-stable
Git Commit: 1db4ecdc0b9e828ff65777fb466fc7c1d04e0de9
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.8.3
Operating System: linux
GOPATH=
GOROOT=/usr/lib/golang
[root@lt-test-mongodb eth]#
以上 geth环境就安装好了
创建以太坊私有链
? 初始化一个创世区块,首先创建一个 ?genesis.json文件 内容如下
{
"config": {
"chainId": 10,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"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目录中:
? ? 初始化 只要在第一次执行就好了
[root@lt-test-mongodb eth]# geth init ./genesis.json --datadir ./chain
WARN [01-19|11:20:28] No etherbase set and no accounts found as default
INFO [01-19|11:20:28] Allocated cache and file handles database=/eth/chain/geth/chaindata cache=16 handles=16
INFO [01-19|11:20:28] Writing custom genesis block
INFO [01-19|11:20:28] Successfully wrote genesis state database=chaindata hash=5e1fc7…d790e0
INFO [01-19|11:20:28] Allocated cache and file handles database=/eth/chain/geth/lightchaindata cache=16 handles=16
INFO [01-19|11:20:28] Writing custom genesis block
INFO [01-19|11:20:28] Successfully wrote genesis state database=lightchaindata hash=5e1fc7…d790e0
启用私有链
? ? geth是一个以太坊客户端,现在利用geth启动一个以太坊网络节点
注意: ?在使用go-wallet前 需要先启动 get节点
geth --datadir "./chain" --nodiscover console 2>>eth_output.log //启动了 30303端口
还可以自定义一些参数来启动 启动了 30304和 8545 其他rpc启动相关 https://github.com/ethereum/wiki/wiki/JSON-RPC
geth --datadir "./chain" --networkid 9999 --port 30304 --rpc --rpccorsdomain "*" --rpcapi "db,eth,net,web3" console
[root@lt-test-mongodb eth]# geth \
> --datadir "./chain" \
> --nodiscover \
> console 2>>eth_output.log
Welcome to the Geth JavaScript console!
instance: Geth/v1.7.2-stable-1db4ecdc/linux-amd64/go1.8.3
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
主网同步数据 列子:
mkdir ./eth
nohup geth --datadir ./eth --syncmode "fast" --cache=512 --rpc --rpcaddr "0.0.0.0" --rpcport 8545 --rpcapi "db,eth,net,web3" --port 30303 --rpccorsdomain "*" >> "./eth/eth-main-geth.log"
?主网同步数据的时候 如果内存配置小于8G , 最好不要加上 ethbase 和 mine 等参数,否则进程容易挂掉。 以上主网测试基本没什么问题(4H 8G) CPU %50? 内存 40%左右
参数名称 | 参数描述 |
---|
datadir | 设置当前区块链网络数据存放的位置 | console | 启动命令行模式,可以在Geth中执行命令 | nodiscover | 私有链地址,不会被网上看到 | gcmode | full or archive. 默认是 full.? ?若要及时写道磁盘使用 "archive" |
?添加--dev 参数,则运行的是POA共识机制,并且不需要先进行geth init了
geth --datadir "./chain" --dev --networkid 9999 --port 30304 --rpc --rpccorsdomain "*" --rpcapi "db,eth,net,web3" console
? window启动节点 注意路径 和linux 有点不一样
geth --datadir 'chain' console 2>> eth_output.log
注意:? 以上启动方式 可能存在 区块的数据不能及时写道本地磁盘,当geth程序关闭后,可能发现区块高度为0,
我们需要在启动的时候 加上参数??--gcmode "archive"
查看日志输出 ?
tail -f eth_output.log
INFO [01-19|12:15:40] Successfully sealed new block number=379 hash=0dbe3c…7b2d4f
INFO [01-19|12:15:40] block reached canonical chain number=374 hash=f17121…536dbe
INFO [01-19|12:15:40] mined potential block number=379 hash=0dbe3c…7b2d4f
INFO [01-19|12:15:40] Commit new mining work number=380 txs=0 uncles=0 elapsed=157.01μs
INFO [01-19|12:15:42] Successfully sealed new block number=380 hash=ae2d83…bb0eb6
INFO [01-19|12:15:42] block reached canonical chain number=375 hash=f62016…409432
INFO [01-19|12:15:42] mined potential block number=380 hash=ae2d83…bb0eb6
INFO [01-19|12:15:42] Commit new mining work number=381 txs=0 uncles=0 elapsed=151.898μs
INFO [01-19|12:15:43] Successfully sealed new block number=381 hash=7d185e…9b6893
INFO [01-19|12:15:43] block reached canonical chain number=376 hash=62d7eb…06e0d2
INFO [01-19|12:15:43] mined potential block number=381 hash=7d185e…9b6893
INFO [01-19|12:15:43] Commit new mining work number=382 txs=0 uncles=0 elapsed=158.401μs
INFO [01-19|12:15:43] Successfully sealed new block number=382 hash=a1fa15…043c0d
INFO [01-19|12:15:43] block reached canonical chain number=377 hash=2c36b1…1a493e
INFO [01-19|12:15:43] mined potential block number=382 hash=a1fa15…043c0d
INFO [01-19|12:15:43] Commit new mining work number=383 txs=0 uncles=0 elapse
挖矿会默认保存到创建的第一个帐户0xfdbd0fb13c4a7c14e72fa0fe490f3c3c3b7f7fab中。
block number=383,说明我们已经创建了383个区块
在以太坊官方的网络上,平均每15秒产生一个区块
账户操作
? 账户查看、新建
> eth.accounts
[]
> web3.eth.accounts
[]
> personal.newAccount("star") --star是密码
"0xfdbd0fb13c4a7c14e72fa0fe490f3c3c3b7f7fab" --返回账户
> eth.accounts
["0xfdbd0fb13c4a7c14e72fa0fe490f3c3c3b7f7fab"]
启动挖矿
? ? 启动后开始挖矿 ?miner.start(1) -> 1:表示一个CPU
> miner.start()
查看日志就开始自动挖矿了 ?我们查看下余额 , 以太币最小的单位是wei(18个0)
> eth.getBalance(eth.accounts[0])
10000000000000000000
新建一个账户
??
> eth.accounts
["0xfdbd0fb13c4a7c14e72fa0fe490f3c3c3b7f7fab"]
> personal.newAccount('star2')
"0xbb2b0e20937bdff666a85cd723c18250e50c469a"
> eth.accounts
["0xfdbd0fb13c4a7c14e72fa0fe490f3c3c3b7f7fab", "0xbb2b0e20937bdff666a85cd723c18250e50c469a"]
> eth.getBalance(eth.accounts[1])
0
> eth.getBalance(eth.accounts[0])
90000000000000000000
第一个账户往第二个账户转账
? ?从帐户 第一个账户 转10个以太币到第二个账户,如果不指定单位 ether,默认转的是 wei。备注: ? value:web3.toWei(10,"ether")
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:10})
? ?如果出现以下错误, ?那么账号需要先解锁
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
> personal.unlockAccount(eth.accounts[0],"star")
true
再查看余额
> eth.getBalance(eth.accounts[0])
114999999999999999980
> eth.getBalance(eth.accounts[1])
20
停止 go-etheruem?
??停止挖矿后,以太币则不会产生,同样智能合约、转帐等操作也不会起作用。
>miner.stop()
Hello World 智能合约开发
? ?Solidity安装
强烈建议新手使用Browser-Solidity来进行开发。
Browser-Solidity是一个基于浏览器的Solidity,就可以不用安装Solidity,本文的Hello World教程也将基于Browser-Solidity来进行。
如果你想自己安装请参考Solidity安装指引。
? ?本地安装
git clone https://github.com/ethereum/browser-solidity
cd browser-solidity
npm install
npm run prepublish
npm start
然后打开浏览器,在地址栏输入:http://127.0.0.1:8080 ?
? 编写合约代码
? ? ??现在我们来开始编写第一个智能合约代码,solidity代码如下:
??
pragma solidity ^0.4.20;
contract hello {
? ??
? ??
? ? string ?greeting="hello world";
? ??
? ?
? ?function hello(string _greeting) public{
? ? ? ?greeting =_greeting;
? ?}
? ??
? ? function setHello(string _greeting) payable public {
? ? ? ? greeting =_greeting;
? ? }
? ??
? ? function sayHello() view public returns(string){
? ? ? ? return greeting;
? ? ? ??
? ? }
? ??
}
简单解释下,我们定义了一个名为hello的合约,在合约初始化时保存了一个字符串(我们会传入hello world),每次调用say返回字符串。 把这段代码写(拷贝)到Browser-Solidity,如果没有错误,点击Details获取部署代码,如:
在弹出的对话框中找到WEB3DEPLOY部分,点拷贝,粘贴到编辑器后,修改初始化字符串为hello world。
solidity,版本为0.4.18,solidity发展非常快,solidity版本之间有可能不能兼容,这是你可以在Browser-Solidity的Settings里选择对应的编译器版本。 Browser-Solidity也不停的更新中,截图可能和你看到的界面不一样。
部署合约
??
var _greeting ="hello,world";
var helloContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"_greeting","type":"string"}],"name":"setHello","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"sayHello","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_greeting","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
var hello = helloContract.new(
? ?_greeting,
? ?{
? ? ?from: web3.eth.accounts[0],?
? ? ?data: '0x60606040526040805190810160405280600b81526020017f68656c6c6f20776f726c640000000000000000000000000000000000000000008152506000908051906020019061004f929190610094565b50341561005b57600080fd5b60405161042038038061042083398101604052808051820191905050806000908051906020019061008d929190610094565b5050610139565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100d557805160ff1916838001178555610103565b82800160010185558215610103579182015b828111156101025782518255916020019190600101906100e7565b5b5090506101109190610114565b5090565b61013691905b8082111561013257600081600090555060010161011a565b5090565b90565b6102d8806101486000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063435ffe9414610051578063ef5fb05b146100a3575b600080fd5b6100a1600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610131565b005b34156100ae57600080fd5b6100b661014b565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101479291906101f3565b5050565b610153610273565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101e95780601f106101be576101008083540402835291602001916101e9565b820191906000526020600020905b8154815290600101906020018083116101cc57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061023457805160ff1916838001178555610262565b82800160010185558215610262579182015b82811115610261578251825591602001919060010190610246565b5b50905061026f9190610287565b5090565b602060405190810160405280600081525090565b6102a991905b808211156102a557600081600090555060010161028d565b5090565b905600a165627a7a72305820416b762e5c484970552c447f5e80665d36d2730f97820b306dbdcb9d62bdf7cc0029',?
? ? ?gas: '300000'
? ?}, function (e, contract){
? ? console.log(e, contract);
? ? if (typeof contract.address !== 'undefined') {
? ? ? ? ?console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
? ? }
?})
第1行:修改字符串为Hello World 第2行:修改合约变量名 第3行:修改合约实例变量名,之后可以直接用实例调用函数。 第6行:修改部署账户为新账户索引,即使用新账户来部署合约。 第8行:准备付的gas费用,IDE已经帮我们预估好了 ?需要gas 到300000(若错误Error: exceeds block gas limit undefined )。 第9行:设置部署回调函数。
拷贝会geth控制台里,回车后,看到输出如: ?注意: 有可能在 geth客户端比较慢 可能在 miner.start()后 一段时间才能被打包到区块
? 请耐心等待 。还可以 这样写 ? miner.start(2);admin.sleepBlocks(1);miner.stop() 表示挖到一个区块就停止
Contract mined! address: 0x6d9abea47d43fbc425160f9515ac4dd41c7f1a07 transactionHash: 0xc07ae58e654ae9d8a2d6506e1f341134ec53d4ff796fba99a8f55d6a74cbc06a
同时 ?日志部分也有相关信息
INFO [01-19|12:58:06] Submitted contract creation fullhash=0xc07ae58e654ae9d8a2d6506e1f341134ec53d4ff796fba99a8f55d6a74cbc06a contract=0x6D9abeA47D43fBc425160f9515AC4DD41C7F1a07
说明合约已经部署成功。 如果没有成功。 看看有没有启动 私有链 ?miner.start()
输入合约名称 ?hello 如果出现?
> hello
{
? abi: [{
? ? ? constant: false,
? ? ? inputs: [{...}],
? ? ? name: "setHello",
? ? ? outputs: [],
? ? ? payable: true,
? ? ? stateMutability: "payable",
? ? ? type: "function"
? }, {
? ? ? constant: true,
? ? ? inputs: [],
? ? ? name: "sayHello",
? ? ? outputs: [{...}],
? ? ? payable: false,
? ? ? stateMutability: "view",
? ? ? type: "function"
? }, {
? ? ? inputs: [{...}],
? ? ? payable: false,
? ? ? stateMutability: "nonpayable",
? ? ? type: "constructor"
? }],
? address: "0x595d69c7bacc1c6d37588810fe6f2f10da2795c2",
? transactionHash: "0x5f0a5f2b3c3d9409b4179b99ce0a4639838496a3814
eed3c5",
? allEvents: function(),
? sayHello: function(),
? setHello: function()
}
出现最后的3行 ?表示已经写到区块
注意 节点启动最好启用 --rpc ?--rpcaip "eth.net.web3"
web3方式调用合约:
> hello.sayHello() # 合约查询
"hello,world"
> hello.sayHello.call() #合约查询
"hello,world"
> hello.setHello.sendTransaction("hello,andrew",{from:web3.eth.accounts[0]});
Error: authentication needed: password or unlock
? ? at web3.js:3143:20
? ? at web3.js:6347:15
? ? at web3.js:5081:36
? ? at web3.js:4137:16
? ? at <anonymous>:1:1
> personal.unlockAccount(eth.accounts[0],'andrew')
true
> hello.setHello.sendTransaction("hello,andrew",{from:web3.eth.accounts[0]}); //修改区块数据
INFO [03-11|15:28:57] Submitted transaction ? ? ? ? ? ? ? ? ? ?fullhash=0xc97b58
77708362ffafe5faa0829e8045f23b5658f99c6584fc072cc1f9a911e3 recipient=0x595d69C7B
Acc1c6d37588810fE6F2f10da2795C2
"0xc97b5877708362ffafe5faa0829e8045f23b5658f99c6584fc072cc1f9a911e3"
> hello.sayHello.call()
"hello,world"
> miner.start(1);admin.sleepBlocks(1);miner.stop()
INFO [03-11|15:29:39] Updated mining threads ? ? ? ? ? ? ? ? ? threads=1
INFO [03-11|15:29:39] Transaction pool price threshold updated price=18000000000
INFO [03-11|15:29:39] Starting mining operation
INFO [03-11|15:29:39] Commit new mining work ? ? ? ? ? ? ? ? ? number=56 ?txs=1
uncles=0 elapsed=0s
INFO [03-11|15:29:40] Successfully sealed new block ? ? ? ? ? ?number=56 ?hash=0
84b05…0377a0
INFO [03-11|15:29:40]
|