环境:

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.gitcdgo-ethereumgit checkout v1.7.2 git checkout v1.7.3make gethmake all

4. 查看是否安装成功

#build/bin/geth version

5. 设置 geth 环境变了

export PATH=/eth/go-ethereum/build/bin:$PATH
[root@lt-test-mongodb eth]# geth versionGethVersion: 1.7.2-stableGit Commit: 1db4ecdc0b9e828ff65777fb466fc7c1d04e0de9Architecture: amd64Protocol Versions: [63 62]Network Id: 1Go Version: go1.8.3Operating System: linuxGOPATH=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)章节所描述的条件。
noncenonce就是一个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=16INFO [01-19|11:20:28] Writing custom genesis block INFO [01-19|11:20:28] Successfully wrote genesis state database=chaindata hash=5e1fc7…d790e0INFO [01-19|11:20:28] Allocated cache and file handles database=/eth/chain/geth/lightchaindata cache=16 handles=16INFO [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-RPCgeth --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.logWelcome 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 ./ethnohup 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

私有链地址,不会被网上看到

gcmodefull 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 blocknumber=379 hash=0dbe3c…7b2d4fINFO [01-19|12:15:40]block reached canonical chainnumber=374 hash=f17121…536dbeINFO [01-19|12:15:40]mined potential blocknumber=379 hash=0dbe3c…7b2d4fINFO [01-19|12:15:40] Commit new mining work number=380 txs=0 uncles=0 elapsed=157.01µsINFO [01-19|12:15:42] Successfully sealed new blocknumber=380 hash=ae2d83…bb0eb6INFO [01-19|12:15:42]block reached canonical chainnumber=375 hash=f62016…409432INFO [01-19|12:15:42]mined potential blocknumber=380 hash=ae2d83…bb0eb6INFO [01-19|12:15:42] Commit new mining work number=381 txs=0 uncles=0 elapsed=151.898µsINFO [01-19|12:15:43] Successfully sealed new blocknumber=381 hash=7d185e…9b6893INFO [01-19|12:15:43]block reached canonical chainnumber=376 hash=62d7eb…06e0d2INFO [01-19|12:15:43]mined potential blocknumber=381 hash=7d185e…9b6893INFO [01-19|12:15:43] Commit new mining work number=382 txs=0 uncles=0 elapsed=158.401µsINFO [01-19|12:15:43] Successfully sealed new blocknumber=382 hash=a1fa15…043c0dINFO [01-19|12:15:43]block reached canonical chainnumber=377 hash=2c36b1…1a493eINFO [01-19|12:15:43]mined potential blocknumber=382 hash=a1fa15…043c0dINFO [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 unlockat web3.js:3143:20at web3.js:6347:15at web3.js:5081:36at :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-soliditycd browser-soliditynpm installnpm run prepublishnpm 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 creationfullhash=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: "0x5f0a5f2b3c3d9409b4179b99ce0a4639838496a3814eed3c5", 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 unlockat web3.js:3143:20at web3.js:6347:15at web3.js:5081:36at web3.js:4137:16at :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 transactionfullhash=0xc97b5877708362ffafe5faa0829e8045f23b5658f99c6584fc072cc1f9a911e3 recipient=0x595d69C7BAcc1c6d37588810fE6F2f10da2795C2"0xc97b5877708362ffafe5faa0829e8045f23b5658f99c6584fc072cc1f9a911e3"> hello.sayHello.call()"hello,world"> miner.start(1);admin.sleepBlocks(1);miner.stop()INFO [03-11|15:29:39] Updated mining threadsthreads=1INFO [03-11|15:29:39] Transaction pool price threshold updated price=18000000000INFO [03-11|15:29:39] Starting mining operationINFO [03-11|15:29:39] Commit new mining worknumber=56 txs=1uncles=0 elapsed=0sINFO [03-11|15:29:40] Successfully sealed new blocknumber=56 hash=084b05…0377a0INFO [03-11|15:29:40]