6分钟以太坊实战系列-以太坊私有链搭建及智能合约部署

本文是由链博科技 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 ./

生成四个文件,如下:


image.png

因为合约中的 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 数量。如下图

image.png

(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实战经验感兴趣的朋友和手里有行业资源准备布局区块链的大佬关注我们的公众号并和我们取得联系:(原创文章,转载请注明出处,欢迎读者分享到朋友圈)

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269