摘要:Ethereum是Block Chain的一种实现,跟比特币相比,它最大的特点之一就是可以在它的基础上发布Smart Contract的Dapp。一段时间的学习和调查,我从第一步搭建私有的Ethereum BlockChain,直到编写Smart Contract, 发布和调用,一整套流程调通。兴奋之余,把经历的种种记录下来,以便日后回顾。
本文主要介绍区块链从搭建到发布Smart Contract的基本步骤:
- 搭建私有区块链。
- 区块链的基本配置。
- 编写,编译和调用Smart Contract
搭建私有区块链
Ethereum 跟比特币对比,虽然都是区块链的一种,但Ethereum 的特点之一是可以编写发布Dapp[1][2]。在开发Dapp的时候,难免需要一个测试用的Chain。 在公网上,可以直接连上 Ethereum testnet (Ropsten), 或者使用testrpc 。不过在使用testrpc有可能会遇到各种不可预期的地雷。Ropsten testnet则是需要等待同步block。
用于搭建私有区块链集中可行的方案:
- 搭建一个Private Ethereum BlockChain. Ethereum 本身也是支持这种做法。
- 通过Parity提供的模板,搭建一个私有的PoA 区块链也是不错的选择。Paity的PoA模板甚至提供了配置功能WebSite Portal。做的是非常友善了。
- 微软的开源私有区块链 Coco Framework。(打个广告,目前还有没有GA)
- 通过Azure平台提供的模板搭建私有的Private Ethereum BlockChain。
可虑再三,我还是比较喜欢自己手上可以控制的私有区块链。同时也可以进一步熟悉和学习区块链。这里有几个考量:
- 这主要也是为了偷个懒,Azure上搭建的模板,不需要我自己去一台一台的创建服务器。
- 托管在Azure上的服务器,可以配置公开一些站点。其他开发者,在使用这个环境进行开发和测试,不会被限制在一个局域网内。在外网能够接入。(我是一个热爱Work @ Home的工程师)
- 安全方面有保障。Azure Portal上有防火墙设置,可以允许特定的人员接入这个网络,也可以屏蔽掉并不需要的人员。如果自己搭建服务器,就要考虑外网访问的各种风险。我只想搭个测试环境,为什么还要在安全方面花那么多心思。
- 扩容方便。增加Virtual Machine只需要简单的点几下按钮就可以完成操作。
- 还有各种没想到的好处。例如环境发生问题,可以随意上ticket要求微软技术支持介入。(ε=ε=ε=(~ ̄▽ ̄)~) 一脸坏笑。
在学习的过程中,我选择了最后一种方式,在Azure上面搭建Private Ethereum BlockChain。喜欢的朋友可以参考这篇文章 如何在Azure上快速创建一个Ethereum Consortium Network模板 .
如何快速测试私有链的连接
私有链的模板搭设好之后,最想做的事情就是想赶快验证一下这个私有链能不能从客户端连上。最简单直接的方法,就是借助现有的一些区块链工具,连上去。现在比较流行的Dapp Browsers有以下几个[3]
- Mist – official GUI dapp browser developed by the foundation, alpha stage. Mist as Wallet dapp is in beta.
- Status – Mobile Ethereum browser (alpha)
- MetaMask – Aaron Kumavis Davis’s in-browser GUI. Epicenter Bitcoin interview on github – supported by DEVgrants
- AlethZero – C++ eth client GUI, (discontinued).
- Supernova – (discontinued).
我挑选了一个比较轻量级的工具MetaMask[4].
- MetaMask是一个可以安装在Chrome的插件。(当然它也可以安装在Brave Browser上)。
- 点击 “Add to Chrome”将会进行这个插件的安装。
- 安装好之后,重启Chrome,在导航栏的右侧会出现一个狐狸头的图标。点击这个图标,可以弹出MetaMask。注册账号之后,默认的,MetaMask会连入以太网的公网。
- 点击右上角的图标。点Settings,进入设置。
- 在里面输入私有链创建好之后,所监听的Ethereum-RPC-EndPoint.
- 设置好之后,点击左上角的
图标。切换到刚刚设定好的私有网络中。如果能够正常显示数据,那么就是连接成功了。
- 点击
图标。找到自己的账号的Address, 也就是一把公钥。
- 在浏览器中访问自己公布出来的Admin Site. 填入自己的Address, 点击submit, 就可以给自己的account发布1000个以太币作为测试使用。给自己的账号转以太币之后,一般间隔10多秒,就能看到以太币到账。
用web3.js连接到私有链上
使用工具验证了私有链部署成功。下一步,需要通过program的方式连接私有链了。web3.js是一个库的集合,它允许我们使用HTTP或IPC连接与本地或远程Ethereum的节点 进行交互。它为我们提供了JavaScript API来与geth进行通信。 它在内部使用JSON-RPC与geth进行通信,geth是一个轻量级的远程过程调用。(RPC)协议。
前期准备
在web server上面,选择使用node.js[5]来host webpage. 首先需要在Windows上面安装NPM和Node.JS.
在开发的IDE方面,我选择的Visual Studio Code[6]. 在开发工具IDE这个方面微软的Visual Studio Code做的还是非常不错的。关键是Visual Studio Code还免费,真心的一个大福利。
动手建项目
环境搭建好之后,可以使用npm创建一个项目的模板。
- 打开CMD, 转到要创建项目文件的路径
- 输入下面的命令行,一路ENTER到底,项目创建完成。
mkdir deploy_contract
cd deploy_contract
npm init #一路enter到底
安装web.js
Npm install web3到目前为止, 项目模板已经创建成功了。可以使用Visual Studio Code 进行编程。
- 打开Visual Studio Code, File -> Open Workspace. 指定到刚才模板创建的路径上。
- 点导航栏左上角的+创建一个文件, index.js
贴入下面的代码,就可以通过web3.js连入到私有链上。按下F5,可以进入运行模式查看结果。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const Web3 = require('web3');
/*
* connect to ethereum node
*/
const ethereumUri = 'http://mynodes.centralus.cloudapp.azure.com:8540/';
let web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider(ethereumUri));
if(!web3.isConnected()){
throw new Error('unable to connect to ethereum node at ' + ethereumUri);
}else{
console.log('connected to ehterum node at ' + ethereumUri);
let coinbase = web3.eth.coinbase;
console.log('coinbase:' + coinbase);
let balance = web3.eth.getBalance(coinbase);
console.log('balance:' + web3.fromWei(balance, 'ether') + " ETH");
let accounts = web3.eth.accounts;
console.log(accounts);ethereumUri指定的是私有链提供的地址. 网上能查询到的大多数的案例都是使用本机的地址http://localhost:8450. 但是我在这个测试的例子中,是将私有链部署在Azure上,可以在Azure Portal上面查看到对应的JSON RPC URL信息。把ethereumUri指定到对应的URL上面。
- 调用isConnected() 可以检查连接到私有链上是否成功。如果调用这个方法失败,最常见的原因就是在之前的步骤中安装的web3 的版本不对,太新或者太旧。可以在上面3#安装web3.js的时候指定版本号
- coinbase 就是 私有链上node的Authority account位址。这个account在创世块的文件中能够找到。
编译智能合约
- 要部署智能合约,首先要在项目上安装solc.js.
npm install solc 在Visual Studio Code中创建一个项目文件夹 Contracts. 创建一个智能合约文件Test.sol, 代码如下:
1
2
3
4
5
6
7
8
9
10
11pragma solidity ^0.4.11;
contract sample {
string public name = "ZeonLab";
function set(string _name) {
name = _name;
}
function get() constant returns (string) {
return name;
}
}在index.js文件中,加载 fs 和 solc模块。加入smart contract的编译部分。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42const Web3 = require('web3');
const fs = require('fs');
const solc = require('solc');
/*
* connect to ethereum node
*/
const ethereumUri = 'http://mynodes.centralus.cloudapp.azure.com:8540/';
const address = '0x35849250780dc951adadf138492bec762784f208'; // user
let web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider(ethereumUri));
if(!web3.isConnected()){
throw new Error('unable to connect to ethereum node at ' + ethereumUri);
}else{
if (web3.personal.unlockAccount(address, 'M!crosoft20120731')) {
console.log(`${address} is unlocaked`);
}else{
console.log(`unlock failed, ${address}`);
}
let balance = web3.fromWei(web3.eth.getBalance(address));
console.log(balance);
}
/*
* Compile Contract and Fetch ABI
*/
let source = fs.readFileSync("./contracts/Test.sol", 'utf8');
console.log('compiling contract...');
let compiledContract = solc.compile(source);
console.log('done');
for (let contractName in compiledContract.contracts) {
// code and ABI that are needed by web3
var bytecode = compiledContract.contracts[contractName].bytecode;
var abi = JSON.parse(compiledContract.contracts[contractName].interface);
}
console.log(JSON.stringify(abi, undefined, 2));- fs.readFileSync是用来读取test.sol文件里面的内容
- solc.compile(source) 是对smart contract进行编译,最后生成ABI。
- ABI里面有test.sol的各种定义
- 相同的代码,执行完编译之后应该是获得相同的bytecode以及ABI。我们可以用这两个object来验证其他人deploy的smart contract的code的真伪。
关于ABI (Application Binary Interface)的描述,看这里 https://solidity.readthedocs.io/en/develop/abi-spec.html
部署智能合约
编译智能合约是在开发环境中对代码进行编译并且转换成为bytecode和ABI。这个步骤并不需要涉及到node上的操作。部署智能合约,就是将一段代码发布到node上面,就跟在node上面做一个transaction 是一样的性质。为了发布smart contract就需要付交易的手续费(gas). 所以要求一个有足够ETH的账号,在发布的时候需要用这个账号来发布。在上面的步骤中,通过portal已经给自己的账号发了一些ETH, 所以ETH应该不是问题。
因为在默认的情况下,账户是锁定状态,这就意味着不能从这个账号发送交易,智能进行查询。接下来需要调用web3.personal.unlockAccount方面解锁这个账号才能做到提供交易所需要的手续费。为了解锁账户,需要提供密码,这个密码就是与账户关联的私钥,从而运行用账户来签署交易。
代码如下:
1 | const Web3 = require('web3'); |
在部署智能合约的时候, 如果只传入bytecode,执行的时候会发送下面的invalid params 错误。这是因为按照JSON RPC 2.0的规范,数值要以0x开头。Solc.js产生的bytecode并没有包含0x的开头,所以需要手工加入。
在unlock account的时候有可能会碰到 The method personal_unlockAccount does not exist/is not available 的错误。可以参考这篇文章FIX – The method personal_unlockAccount does not exist/is not available
调用智能合约
在部署完智能合约以后,会获得一个contract address. 在调用smart contract的时候这个地址作为参数送过去。代码如下:
1 | const Web3 = require('web3'); |
参考
[1]. The General Theory of Decentralized Applications, Dapps
[2]. What is a DApp
[3]. Ethereum Homestead – Dapp browsers
[4]. How to install Metamask
[5]. How to install Node.js and NPM on Windows
[6]. Solidity Integration with Visual Studio
Sonic Guo