最近因为国家对区块链又重视起来了,相信今年年底到明年年初会是一个区块链的新的爆发点,也是碰巧学习了一下以太坊构建区块链应用,以前都是简单的了解,并没有实际动手演练。今天趁机会也学习一下区块链,同时也学习了几个新名词。比如账户,私钥,智能合约(smart contract),编译合约(compile),迁移合约(migrate),测试合约(test)。
truffle是一个nodejs的库,他可以构建node版本的以太坊应用,所以我们的机器需要安装node,而且版本需要8以上。truffle,可以直接通过npm install -g truffle的方式来安装,很方便。
安装了node,会默认带上npm包管理工具,我们为了让国内下载包更快,可以更换国内阿里的镜像地址。具体操作如下所示:
npm config set registry=https://registry.npm.taobao.org/
因为我已经提前安装并且设置好了淘宝的镜像,所以这系统里显示如下:
另外,设置了淘宝npm镜像地址,会相应的在本机用户目录下生成一个.npmrc的文件,里面的内容就是registry=https://registry.npm.taobao.org/,所以我们可以手动的设置这个文件,会达到一样的效果。
下面就开始安装truffle了,他的安装很简单,但是为了在所有的命令行下使用,最好使用全局的方式安装。
npm install -g truffle
安装了truffle,我们可以验证一下。
理论上,安装了truffle就可以了,整个实验也就够了,但是有的也推荐安装geth,ganache-cli(老版本叫ethereumjs-testrpc),我觉着没有必要,因为truffle develop命令就可以开启以太坊客户端。我们不妨也安装一下ganache-cli,或者ethereumjs-testrpc,如下所示,当我们安装ethereumjs-testrpc的时候,系统提示ethereumjs-testrpc已经被重命名为ganache-cli了,所以安装ganache-cli就可以了。
npm install -g ganache-cli
当我们安装完了ganache-cli,我们可以直接在命令行下输入命令ganache-cli,就可以开启以太坊的客户端。
启动了客户端,开启了8545端口,这种方式开启以太坊客户端,没有进入一个交互模式,而我们通过truffle develop命令启动,同样会开启类似的客户端,并且打印信息几乎一样,不同的是账户和秘钥每次都不同。但是开启的端口是一样的,而且truffle develop可以进入交互模式,可以在命令行下进行compile编译合约与migrate迁移合约,还可以进行合约调用。前提是需要进入一个truffle构建的以太坊工程。
truffle官方提供了很多truffle的工程盒子box,像webpack,react,metacoin,pet-shop等等,我们可以在官网上看到:
官方说通过命令truffle unbox react或者truffle unbox metacoin可以构建项目,意思是会自动下载这些盒子到本地,但是最近试了,下载失败:
甚至直接通过初始化的方式也不对:
mkdir react
cd react
truffle init
truffle踩坑也是够奔溃的,到此,以为山重水复疑无路,truffle可以放弃了。但是好像可以通过git clone 将github上的react-box下载到本地,因为无论是truffle unbox react还是truffle init得到的工程都是源代码,而且需要人为编译和迁移合约。
克隆下来的代码结构如下,和truffle unbox react的结构还是一样的。
至此,我们的准备工作算是做完了,其实本文helloworld示例才刚刚开始。前面一堆介绍基本都是在踩坑。因为js,甚至node的框架更新太快,而且以太坊本身也在不断迭代,出现问题也可以理解。
到这里,我们可以在项目目录下的命令行中运行truffle develop,进入truffle交互式,来感受一下客户端,并且和ganache-cli做个对比:
开启的端口是8545,同样创建了10个临时账户以及10个秘钥。所以说前面如果仅仅安装了truffle,也可以完成本次实验,没有必要再安装ganache-cli。
我们需要手动增加一个合约helloworld.sol, 我们可以进入contracts目录,然后通过命令创建一个helloworld.sol,而不是直接新建一个helloworld.sol文件。如下所示:
cd contracts
truffle create contract HelloWorld
接着,我们可以手动在notepad++中编辑HelloWorld.sol文件,试着编写一个最简单的sayHello方法。但是这里必须注意使用Solidity的语法。
智能合约编写完毕,我们就需要编译了,我们回到truffle develop的交互式界面中,输入compile,或者直接在react-box目录下的命令行中输入truffle compile,也可以编译合约。
智能合约一下子编译成功,是不是很开心啊,这得益于踩坑啊,这里HelloWorld.sol内容中的sayHello,有几处需要注意,首先是必须声明式public的,而且需要pure修饰,最后返回类型string后面还需要加上memory,比如returns (string memory) 。
接着,我们需要迁移合约即migrate,我们进入migrations目录,按照创建合约的方法新建一个HelloWorld的migration,这里也是有坑的,需要创建一个字母数字即alpha-numeric名称的迁移文件。他会自动在migration文件前面加上数字,构成一个数字开头的文件。这里需要注意一下。
cd migrations
truffle create migration deploy_helloworld_3
我们可以模仿1_initial_migration.js的内容来修改helloworld的迁移文件。
1572713506_deploy_helloworld_3.js的内容如下所示:
var HelloWorld = artifacts.require("./HelloWorld.sol");
module.exports = function(_deployer) {
// Use deployer to state migration tasks.
_deployer.deploy(HelloWorld);
};
接下来,我们就需要执行合约迁移命令了。可以在命令行执行truffle migrate,但是会提示失败,我们需要执行truffle migrate --reset或者,直接在truffle develop的交互式命令下输入migrate即可。
直接在truffle develop交互式命令行下运行migrate:
truffle(develop)> migrate
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'develop'
> Network id: 5777
> Block gas limit: 0x6691b7
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
> transaction hash: 0xdae3f39a310a44d685224dac084b6e2e9d17360cb7a2ac7a9f18449e780dc2da
> Blocks: 0 Seconds: 0
> contract address: 0x21206Eb603Bf8B7e7941bdAf9fcfb076c3Cc6ddf
> block number: 1
> block timestamp: 1572714191
> account: 0xd06755Fb2ff82aB2Df6f51196AE397de76011189
> balance: 99.99477214
> gas used: 261393
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00522786 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00522786 ETH
2_deploy_contracts.js
=====================
Deploying 'SimpleStorage'
-------------------------
> transaction hash: 0x2f1ee9b6b31891926e0a7aee57353f11b211715468b54fc9e8e60b27badddeb6
> Blocks: 0 Seconds: 0
> contract address: 0x64a21797f6d700F6143B37fC19438f7e450b5517
> block number: 3
> block timestamp: 1572714192
> account: 0xd06755Fb2ff82aB2Df6f51196AE397de76011189
> balance: 99.99183138
> gas used: 105015
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.0021003 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.0021003 ETH
1572713506_deploy_helloworld_3.js
=================================
Deploying 'HelloWorld'
----------------------
> transaction hash: 0x76af4c18b9af0a2422e65dd86fd64c295bcc8e29cb19eb0ee103dd16c2115dc7
> Blocks: 0 Seconds: 0
> contract address: 0x91EeB84d6696aBA51Ac078C00Cb3eB311FA7c7FE
> block number: 5
> block timestamp: 1572714192
> account: 0xd06755Fb2ff82aB2Df6f51196AE397de76011189
> balance: 99.98874562
> gas used: 127265
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.0025453 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.0025453 ETH
Summary
=======
> Total deployments: 3
> Final cost: 0.00987346 ETH
truffle(develop)>
输出内容很多,大致意思是helloworld迁移成功,我们可以进行合约部署测试了。
合约部署,需要一句代码,代码是在truffle console下进行,也可以在truffle develop的命令行下。这里还是在truffle develop交互模式下运行,当我们部署完毕,合约就可以被调用了。
HelloWorld.deployed().then(instance => contract = instance)
接下来,执行合约调用:
至此,一个truffle结合以太坊项目的helloworld示例就介绍完了,基本和react没什么关系,主要是在各种踩坑。核心还是在truffle的安装以及truffle各种命令的使用。