以太坊平台实验手记

最近带我师弟做项目,顺手衍生了一份实验手记。我自觉不错。就放上来了。


以太坊 Go 客户端的安装与区块链的导入导出


以下实验在 Ubuntu 16.04 LTS 中进行,验证对 Ethereum Go 客户端(geth)的 1.6.6- stable-10a45cb5 版本有效。其他版本的特性参见 Git Hub 项目主页 [1]。 在 Ubuntu 上使用 PPA 安装的命令如下:


sudo apt-get install software-properties-common


sudo add-apt-repository -y ppa:ethereum/ethereum


sudo add-apt-repository -y ppa:ethereum/ethereum-dev


sudo apt-get update


sudo apt-get install ethereum


在使用上述命令安装后,在控制台使用 geth --help 命令应当有所回应,如图1所示。 需要注意的是,安装之后若直接运行 geth,则程序将会把所有需要持久化的数据(除 了工作量证明的 Ethash 算法需要生成的有向无环图)写入默认的数据文件夹中,在 Linux 下 这个默认的数据文件夹为~/.ethereum。 即区块链的数据就会被默认存储在该文件夹下,但在运行 geth 时也可以通过--datadir <data dir> 选项来指定区块链数据的位置。 这些区块链的数据可以进行导入和导出操作,相关的命令如下:


• 升级数据库: geth upgradedb


• 清除数据库: geth removedb


• 导入区块链: geth import <filename>


• 导出区块链: geth export <filename> 多说一句,之前提到的用于工作量证明(PoW,Proof of Work)的 Ethash 算法需要生 成的有向无环图(DAG)将被保存在~/.ethash 目录下,因而可以被所有的客户端节点复用, 即只在第一次生成客户端节点时下载并缓存 DAG,这个过程通常非常漫长,我们后续会提到。


1 图 1: 安装后验证安装成功

2


节点创建和初始化


首先使用如下命令创建两个数据文件夹,对应将来我们创建的两个节点:


mkdir -p ~/BlockChain/miner1


mkdir -p ~/BlockChain/miner2


然后我们编写一个创世区块的配置文件genesis.json,内容如下:


{


" nonce" : " 0x0000000000000042" ,


" mixhash" : " 0


x0000000000000000000000000000000000000000000000000000000000000000" ,


" difficulty" : " 0x400" ,


" alloc" : {},


" coinbase" : " 0x0000000000000000000000000000000000000000" ,


" timestamp" : " 0x00" ,


" parentHash" : " 0


x0000000000000000000000000000000000000000000000000000000000000000" ,


" extraData" : " " ,


" gasLimit" : " 0xffffffff" ,


2 " config" : {


" chainId" : 42,


" homesteadBlock" : 0,


" eip155Block" : 0,


" eip158Block" : 0


}


}


其中各项的含义如下:


• nonce:一个 64 位随机数,用于挖矿,其设置需要满足以太坊的黄皮书([2])的要求


• mixhash:与 nonce 配合用于挖矿,由上一个区块的一部分生成的 hash,其设置同样需 要满足以太坊的黄皮书的要求


• difficulty:设置当前区块的难度,如果难度过大,CPU 挖矿就很难,这里设置较小难度


• coinbase:矿工的账号,此处可随便填


• timestamp:设置创世块的时间戳


• parentHash:上一个区块的 hash 值,因为是创世块,所以这个值是 0


• extraData:额外信息,这里留空。


• gasLimit:该值设置对 GAS 的消耗总量限制,用来限制区块能包含的交易信息总和,因 为我们是私有链,所以填最大。


• config:从 geth 1.6 版本开始,所有的创世区块的配置文件必须包含此项,用于指定链 的 id(chainId,也被称为 network id),此处我们指定为 42。


设置好的创世区块配置文件我们放在~/BlockChain/genesis.json 处,如图2 所示。 接着使用以下命令初始化节点:


cd ~/BlockChain # 工 作 目 录 切 换 到BlockChain


geth --datadir miner1 init genesis.json


geth --datadir miner2 init genesis.json


这条命令的作用是以 genesis.json 中的配置初始化两个节点 miner1 和 miner2,将节点 的数据分别存储在对应的文件夹下。在使用这创建命令后,控制台会输出相应的提示,如图3, 几行 INFO 表示我们成功将节点数据写其中唯一一行 WARN 表示我们还没有为这个节点创 建默认用户,这将在之后完成。


BlockChain 的目录结构应当如下,其中 geth 文件夹下保存了你建好的私有区块链的数 据库,而 keystore 则存储了当前节点中账户的数据。


3 图 2: 创建数据文件夹并编写创世区块配置文件


4 图 3: 初始化并写进创始区块


5 图 4: 初始化并写进创始区块后的目录结构


然后在 contracts 目录下创建并编写 SmartToken.sol 文件如下,其中定义了三个合约函 数和一个事件记录。三个合约函数中,depositToken 是向指定的对象发放一定数量的令牌,并 触发事件记录;withdrawToken 是从指定的对象处收回一定数量的令牌,并触发事件记录;最 后的 getTokens 是一个常量函数,所以在调用的时候不会有 gas 值的开销。


pragma solidity ^0.4.0;


contract SmartToken {


mapping(address => uint) tokens;


event OnValueChanged(address indexed _from, uint _value);


function depositToken(address recipient, uint value) returns (bool


success) {


tokens[recipient] += value;


OnValueChanged(recipient, tokens[recipient]);


return true;


}


function withdrawToken(address recipient, uint value) returns (bool


success) {


if ((tokens[recipient] - value) < 0) {


tokens[recipient] = 0;


} else {


tokens[recipient] -= value;


}


OnValueChanged(recipient, tokens[recipient]);


return true;


}


function getTokens(address recipient) constant returns (uint value) {


return tokens[recipient];


}


}


接着通过修改migrations/2_deploy_contracts.js 修改部署配置相关的代码,修改 后的代码如下:


23 图 23: 使用 truffle 编译部署的结果


部署成功后我们可以在 truffle 控制台中查看合约地址与 ABI 接口信息(这里的 ABI 用 JSON 表示,如图24):


truffle console


# 进 入truffle控 制 台


SmartToken.address


# 查看地址


JSON.stringify(SmartToken.abi) # 查 看abi, JSON格 式


.exit


# 退 出truffle控 制 台


25 图 24: 查看合约被部署的地址与 JSON 格式的 ABI 接口信息


8


通过 Mist 客户端查看和测试合约


最后我们通过 Mist 这个客户端来查看和测试合约,直接从图形界面点击之前安装好的 Mist 客户端,他会自己找到默认路径下的 geth.ipc 文件,然后以该文件对应的节点的身份登 录并获取账户信息,即会以 miner1 的第一个账户的身份登录 Mist 浏览器。


打开 Mist 浏览器最初的界面会如图25所示,由于 miner1 节点正在挖矿,你会看到默认 账户的以太币不断增加。


26 图 25: Mist 自动登录后的钱包界面,可以看到当前登录的 miner1 节点上的两个账户,下面的 ADD ACCOUNT 提供了增加账户的选项,这实际只是对我们之前控制台创建账户命令做的 上层封装


点击上面的 SEND 标签,可以从 WALLET 切换到交易的界面,如图26,从这里可以看 到,以太坊的客户端 Mist 实际也就是对我们 JS 控制台中的命令进行了封装。Mist 这个客户 端本来也就是被设计成给普通用户参与以太币交易的。


27 图 26: Mist 的交易界面,其实就是对我们之前在 JS 控制台中交易的封装 我们也可以点击初始界面的 CONTRACTS 标签,切换到合约界面,大致的状况如图27所 示,我们可以看到他提供了部署合约和查看合约的选项。


28 图 27: 合约相关界面


而从合约界面上 Mist 也提供了部署合约的选项,如果我们点击 DEPLOY NEW CON- TRACT 则会进入图28 所示的界面,可以看到他在这个客户端中提供了一个 Solidity 的编辑 器,能够供普通用户编写合约代码部署到当前节点。


29 图 28: 点击 DEPLOY NEW CONTRACT 进入的部署合约的界面


而如果我们在之前的合约界面点击 WATCH CONTRACT,则会弹出图29 所示界面,我 们输入之前从 truffle 控制台得来的合约地址、合约名、以及 JSON 格式的接口,就可以查看 和运行之前编写的智能合约了。


30 图 29: Mist 中输入之前部署好的智能合约信息


我们点击我们输入的智能合约的图标,会进入图30所示界面,其中因为 getTokens 是一个 const 函数,所以执行时不会花费 gas,我们在左侧输入地址即可查询,我们这里输入 miner2 的第二个账户的地址,查看其初始令牌数为 0。接着我们在右侧选择 Deposit Token 这个函 数,然后输入 miner2 的第二个账户的地址,Value 填入 1234,并看到右下方合约的执行者是 miner1 的主账户(默认第一个账户),我们点击图中的 EXECUTE 按钮。


31 图 30: 查看 miner2 的第二个账户最开始的令牌数量,然后准备用 miner1 的第一个账户执行 合约函数,发放 1234 个令牌给 miner2 的第二个账户


按下 EXECUTE 按钮后,我们能看到一个确认执行合约的弹窗(图31),需要输入当前合 约执行人的密码,我们输入后点击 SEND TRANSACTION。


32 图 31: 输入密码确认合约 之后可以看到, 确认执行的弹窗消失后回到执行合约的界面32,我们可以看到左侧的 miner2 的第二个账户的令牌数量变为 1234。 33 图 32: 合约执行结束后,再查看 miner2 的第二个账户的令牌数量,发现已经从 0 变成了 1234


我们再下拉,勾选上图33中的 Watch contract events 之后就可以看到之前的 deposit 操 作触发的事件也被永久记录下来了。


34 图 33: 下面关于合约函数执行后触发的函数会自动增加

参考文献



[1] https://github.com/ethereum/go-ethereum.


[2] http://gavwood.com/Paper.pdf.


[3] https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.


图暂时没放上去了,pdf版如果需要,可以在下面评论区留言。

猜你喜欢

转载自blog.csdn.net/w497629433/article/details/75087753