本文是由链博科技 chainboard.io 给大家准备的6分钟以太坊实践的第三篇,从以太坊的私有链搭建到智能合约的部署。手把手带你在你自己的私有链上部署你自己的智能合约~
一、 搭建私有以太坊
1.安装 Geth(Go-Ethereum) 客户端
(1) 在 Mac 上使用 Homebrew 安装
> brew tap ethereum/ethereum
> brew install ethereum
(2) 在 Ubuntu 上安装
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum
(3) 直接下载
下载地址:https://ethereum.github.io/go-ethereum/downloads/
2.初始化创世区块
初始化创世区块时,要先创建一个 genesis.json
文件,内容如下:
{
"config": {
"chainId": 88,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"nonce": "0x0000000000000000",
"timestamp": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "",
"gasLimit": "0xffffffff",
"difficulty": "0x4000",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": { }
}
然后使用 geth 命令初始化:
> geth init ./genesis.json --datadir "./chain"
--datadir
后跟数据库文件目录位置,自己指定即可
3.启动私有链
启动命令:
> geth --datadir "./chain" --nodediscover --networkid=88 console 2>>ouput.log
参数说明:
参数名称 | 参数描述 |
---|---|
datadir | 设置当前区块链网络数据存放的位置 |
nodiscover | 私有链地址,不会被网上看到 |
console | 启动命令行模式,可以在Geth中执行命令 |
二、部署智能合约
部署前, 需要使用 solc 对Solidity 文件进行编译
1.编译 Solidity 文件
(1) 安装 npm
从 nodejs 官网下载对应版本安装(安装 nodejs 即可)。nodejs 官网地址:https://nodejs.org/en/
(2) 安装 solc
> npm install -g solc
(3) 编译 Solidity 文件
注意,编译的命令不是 solc
而是 solcjs
命令:
> solcjs <Solidity文件地址>.sol --bin --abi --optimize -o <输出文件夹路径>/
(4) 实例
这里我们使用昨天课程中编写的智能合约为例(示例合约见文末)。进入到合约所在目录下:
> solcjs Compute.sol --bin --abi --optimize -o ./
生成四个文件,如下:
因为合约中的 Compute、Owner 两个函数,所以两个函数的文件都会生成出来。但是,由于 Compute 函数继承了 Owner 函数的方法,所以实际上我们只需要用到 Compute_sol_Compute.abi
Compute_sol_Compute.bin
这两个文件。
2.创建账号 & 挖矿
在部署之前,还需要几步操作。
(1) 启动私有链,并进入到 geth 的 console
> geth --datadir "./chain" --nodiscover console 2>>ouput.log
(2) 创建一个账号
> personal.newAccount("passward")
"0x....." // 返回你新建的账户的地址
这时就已经可以查看到你的账户了
> eth.accounts
["0x....."]
> eth.getBalabce(eth.accounts[0])
0
(3) 挖矿
部署前,要挖一下矿,让自己账户上有钱,因为部署是需要 gas 的,需要先钱挣点钱
// 在 miner.start() 的括号中可以填入挖矿的线程数,不填默认为一个线程
> miner.start()
在 output.log 中可以查看到我们的日志信息:
INFO [03-04|22:48:14] Generating DAG in progress epoch=0 percentage=0 elapsed=2.518s
...
NFO [03-04|23:11:55] Commit new mining work number=1 txs=0 uncles=0 elapsed=129.456µs
INFO [03-04|23:11:55] Successfully sealed new block number=1 hash=729b9d…ea7aa5
INFO [03-04|23:11:55] 🔨 mined potential block number=1 hash=729b9d…ea7aa5
注意:第一次挖矿会比较慢,以太坊节点会生成挖矿必需的数据,你会看到Generating DAG的进度,当进度到 100% 后,会正式开始挖矿,就可以看见已经开始产生了区块了。
停止挖矿了:
> miner.stop()
这个时候账户上就有钱了,可以再次查看一下
> eth.getBalabce(eth.accounts[0])
1.245e+21
3.部署合约
部署合约需要用到之前编译生成出来的 Compute_sol_Compute.bin
Compute_sol_Compute.abi
文件
// 获取 .abi 文件内容
// 将Compute_sol_Compute.abi文件的内容复制出来,放到 web3.eth.contract() 中去
> var contractAbi = web3.eth.contract([{"constant":true,..}]);
// 获取 .bin 文件内容
// 将Compute_sol_Compute.bin文件的内容复制出来,注意在内容前面需要加上 '0x'
> var contractBin = '0x' + <.bin文件中的内容>
// 计算需要的 gas
> var gasValue = eth.estimateGas({data:contractBin})
// 部署合约
> var contract = contractAbi.new(
{
from: web3.eth.accounts[0],
data: contractBin,
gas: gasValue
}, function (e, contract){
console.log(e, contract);
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
})
可能会出现以下错误:
1.账户没有解锁
Error: authentication needed: password or unlock undefined
解决办法:解锁账户
> personal.unlockAccount(eth.accounts[0])
Unlock account 0x32314e87346e13338fb11c0acc8e2d51ac4139eb
Passphrase: // 然后输入你账户的密码
2.账户余额不足
Error: insufficient funds for gas * price + value undefined
解决办法:挖矿
注意:需要启动矿工,合约才能部署完成
> miner.start()
// 过一小会
Contract mined! address: 0x4289aec1d7cb79c8b181f37bb9fa5939b2c9e2bb transactionHash: 0x41f4dda5868d21f883fcf41ebeb2bddd3cac737ba2f5e005c2b573d19a9edf33
返回合约地址后,我们的智能合约就正式部署完成了。
三、在 console 中调用智能合约
1.调用 getLCM 方法,将我们需要算最小公倍数的两个数值传入:
> contract.getLCM(2, 3, {from:eth.coinbase, gas:200000})
"0xd52f4fa99f66052078564b123820b84083ede17da789ad8520410fb3c57ec739"
注意:
(1) 因为 getLCM 方法会改变链上的数据,所以调用的时候一定要带上地址{from:eth.coinbase}
,否则会报错Error: invalid address
(2) 在交易参数中,gas 参数的默认值为 90000,但是在这个方法中是不够的,所以需要自己设置大一点。在交易完成后,可以使用 eth.getTransactionReceipt('0x...') 查看实际使用的 gas 数量。如下图
(3) 交易参数详解
参数名 | 类型 | 详情 |
---|---|---|
from | DATA,20字节 | 发起交易的地址 |
to | DATA,20字节 | 可选项,交易转账地址 |
gas | 数字,默认为 90000 | 提供给交易的 gas 数量,未使用的 gas 会返回到账户中 |
gasPrice | 数字 | 可选项,gas 的单价 |
value | 数字 | 可选项,交易转账金额 |
data | DATA | 你方法的参数 |
nonce | 数字 | 可选项,允许覆盖使用相同 nonce 的交易数据 |
2.调用 getRecord 方法:
> contract.getRecord(0)
[2, 3, 6]
通过返回值可以看到,我们的数据已经写入链中,2与3的公倍数计算结果为6。
3.使用其他账户调用合约
在我们的合约中,做了权限限制,只有部署的账户才能够调用该合约,其他账户调用该合约将不能改变合约中的数据。
四、示例合约
pragma solidity ^0.4.19;
contract Owner {
//合约拥有者
address public owner;
//构造函数,将合约的所有权给予发布者
function Owner() public {
owner = msg.sender;
}
//仅有合约的拥有者可以操作
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
//onlyOwner作为函数执行的前置条件,仅有合约拥有者可以更换所属权
function setOwner(address to) public onlyOwner {
if(to != address(0)) {
owner == to;
}
}
}
//通过is使Compute继承Owner合约
contract Compute is Owner {
//建立一个存储于区块链上的二维数组,存储每一次计算的输入以及结果
uint[3][] records;
//比较大小,solidity允许返回两个值
function compare(uint first, uint second) internal pure returns(uint bigOne, uint smallOne) {
if(first > second) {
return (first, second);
}
else {
return (second, first);
}
}
//建立事件去监听每一次计算并记录日志
event GetLCM(uint first, uint second, uint result);
function getLCM(uint first, uint second) external onlyOwner returns(uint) {
if (first == second) {
return first;
}
else {
uint bigOne;uint smallOne;
(bigOne, smallOne) = compare(first, second);
uint i = 1;
while(true) {
uint mul = i * bigOne;
if(mul % smallOne == 0) {
uint index = records.push([first, second, mul]) - 1;
//调用事件
GetLCM(first, second, mul);
return index;
}
i++;
}
}
}
//根据索引获取游戏记录
function getRecord(uint index) external onlyOwner view returns(uint[3]) {
return records[index];
}
}
系列文章地址:
第一篇:智能合约与Solidity高级语言(一)
第二篇:智能合约与Solidity高级语言(二)
第三篇:以太坊私有链搭建及智能合约部署
第四篇:Web3j对智能合约的调用
最后,给大家介绍一下:
ChainBoard 核心团队利用其在区块链技术研发上沉淀的丰富经验,围绕项目的需求持续创新,与合作伙伴开放共赢、深度融合,共同打造在金融科技、游戏、众筹互助、医疗保健、物流等领域的区块链应用。 主要输出智能合约开发、公链开发、联盟链开发及交互应用开发等能力,助力项目迅速取得先发优势。目前团队已经在区块链+游戏及区块链+金融与国内知名游戏运营商和海外金融机构展开深度合作。
欢迎对ChainBoard实战经验感兴趣的朋友和手里有行业资源准备布局区块链的大佬关注我们的公众号并和我们取得联系:(原创文章,转载请注明出处,欢迎读者分享到朋友圈)