11月30日,【传统安全X区块链】群直播课程中,由看雪讲师、看雪区块链研究员roysue为区块链、安全领域爱好者分享了知识大宴《第一个智能合约 在树莓派上部署》,下面我们一起来回顾一下~
roysue:今天我们将学习第一个智能合约,就是说通过智能合约来实现前端和后端的交互。现在我们先来实现一个最基本的操作,从hello world入手。(2018/11/30)
我们的第一个智能合约
首先,我们将在以太坊建立 the Greeter, a Hello World 智能合约。它被描述为“存活在以太坊上的智能数字资产,可以和任何与他交互的人进行对话”,也就是你说啥、它也说啥。
在第一部分中,我们描述了如何用 solidity 编写智能合约,和Java类似,它会被编译为字节码,以太坊的虚拟机来执行这个字节码。现在我们来安装这个编译器。编译器也是在笔记本上来安装,命令行如下:
$ sudo add-apt-repository ppa:ethereum/ethereum
$ sudo apt-get update
$ sudo apt-get install solc
编译会占用大量系统资源,在桌面平台会比树莓派这样的平台快很多倍。这里安装的solc就是solidity语言的编译器。solc不只有一个版本,还有很多分支,我们这里装的是最原始的版本。从solidity官方网站看到,很多编译器都可以用,官方推荐的是Remix,安装步骤都有文档说明。
https://solidity.readthedocs.io/en/v0.4.25/installing-solidity.html
其他版本的安装我们就不演示了,我们只演示官方版本的安装。
solc编译器的安装
首先,新建一个文件夹,
```js
mkdir solc
cd sol/
```
然后,新建一个文件
```js
touch Greeter.sol
```
用你喜欢的编译器打开Greeter.sol文件,并将如下内容写进去。
```js
contract Mortal {
/* Define variable owner of the type address */
address owner;
/* This function is executed at initialization and sets the owner of the contract */
functionMortal(){ owner = msg.sender; }
/* Function to recover the funds on the contract */
functionkill(){if(msg.sender == owner) selfdestruct(owner); }
}
contract Greeter is Mortal {
/* Define variable greeting of the type string */
string greeting;
/* This runs when the contract is executed */
functionGreeter(string _greeting)public{
greeting = _greeting;
}
/* Main function */
functiongreet()constantreturns(string){
returngreeting;
}
}
编译:
```js
>$ solc -o target --bin --abi Greeter.sol
ABI可以理解为符号,在windows的PE里,符号是集成在windows的可执行文件中的。在编译器里面,符号是不会集成在可执行文件里的。
这张图片是它演示编译的一个结果。虽然有一些警告,但是会有一个target的文件夹会产生,包含四个文件:Greeter 和 Mortal 的ABI与bin文件。我们只需要有Greeter的这两个文件就可以了,因为它已经集成了Mortal的contract。
接下来就是把Greeter的ABI和bin打包进智能合约中去。可以一句话一句话的把所有命令都敲一遍进去,这样就可以打包进去;也可以把所有命令保存为一个脚本,命名为 greeter.js,直接加载脚本就已经把这个ABI和binary打包进智能合约。我们来操作一遍。
大家可以看到最后的编译结果是16进制,符号也标的很明显。
vargreeterFactory = eth.contract([{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"greet","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_greeting","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}])
vargreeterCompiled ="0x"+"608060405234801561001057600080fd5b5060405161039b38038061039b83398101806040528101908080518201929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019080519060200190610089929190610090565b5050610135565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100d157805160ff19168380011785556100ff565b828001600101855582156100ff579182015b828111156100fe5782518255916020019190600101906100e3565b5b50905061010c9190610110565b5090565b61013291905b8082111561012e576000816000905550600101610116565b5090565b90565b610257806101446000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063cfae321714610068575b600080fd5b34801561005d57600080fd5b506100666100f8565b005b34801561007457600080fd5b5061007d610189565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100bd5780820151818401526020810190506100a2565b50505050905090810190601f1680156100ea5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610187576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b565b606060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102215780601f106101f657610100808354040283529160200191610221565b820191906000526020600020905b81548152906001019060200180831161020457829003601f168201915b50505050509050905600a165627a7a72305820467ac32dfa208b06ba97f3a7f72d039f2f912938b54b9881c603d80f6b004df40029"
var_greeting ="Hello DesignSpark!"
vargreeter = greeterFactory.new(_greeting,{from:eth.accounts[0],data:greeterCompiled,gas:1000000},function(e, contract){
if(e) {
console.error(e);// If something goes wrong, at least we'll know.
return;
}
if(!contract.address) {
console.log("Contract transaction send: TransactionHash: "+ contract.transactionHash +" waiting to be mined...");
}else{
console.log("Contract mined! Address: "+ contract.address);
console.log(contract);
}
})
var _greeting可以定义你任何想说的话,greeterFactory可以定义你新建的实例,gas是消耗的单位,我们默认的账户实例要加载到区块链上。
console.error(e)是打印的错误。如果合约成功执行,我们就会打印一个log , 就是说合约已经执行了,hash加载成功。把Hash放出来,这个hash就会等在挖矿的人附近。如果合约部署失败了,或者说合约被挖到了,合约的地址就会暴露出来。
vargreeterFactory = eth.contract(<contents of the file Greeter.abi>)
vargreeterCompiled ="0x"+"<contents of the file Greeter.bin>"
`ABI`是接口,可以理解为符号,`bin`就纯粹的是二进制。所以接下来的编译,一部分是符号,一部分纯粹的是二进制。
查看版本信息
solc --version
0.4.24这个版本的信息还是蛮重要的,现在我们先来把这个实验操作完成。
安装一个可以读目录的一个工具:
sudo apt install tree
接下来,如果我们确保在合适的节点上运行矿工,然后解锁我们希望部署的联系人的计算机帐户。 在我们的例子中,我们再次在笔记本电脑的geth控制台上执行了 miner.start(),并决定通过 Raspberry Pi 部署合同。
所以我们在树莓派上输入:
>personal.unlockAccount(eth.coinbase,"")
>loadScript("greeter.js")
成功!在同步消息中,我们可以看到正在发送的合约消息,等待挖掘的通知,然后通知完成。
我们可以用以下方法进行验证:
>eth.getCode(greeter.address)
我们检查树莓派上帐户的余额,发现略有减少。
资金将转到相应的矿工,在我们这个案例中,是笔记本电脑上的帐户。
最后,我们可以执行合约:
> greeter.greet();
如以太坊网站所述,这会立即返回,因为该调用不会改变区块链上的任何内容并且没有 Gas 成本。
在这种情况下,如果笔记本正在挖矿,把这个合约加载进去,把数据先传到树莓派上,内容在树莓派上进行部署,然后在树莓派上敲命令。运行节点信息,先把账户解锁,把greeter.js加载一次,加载上去后就能马上看到。
> personal.unlockAccount(eth.coinbase, "")
> loadScript("greeter.js")
挖矿的同时,会在节点显示同步信息。
我们先来进行挖矿,
miner.start()
查看挖矿速度,
htop
可以看到在合约地址上的内容。
因为我们部署智能合约是需要gas的。我们可以执行合约:
> greeter.greet();
合约查询是不会消耗wei的。如果涉及到合约存储、缓存,会消耗wei。所以我们可以在网上查询区块的信息,都是不会涉及到wei的消耗的。
在结束的时候会总结,其实这个合约是官方的教程。因为它没有在区块链上做任何改变,所以不会消耗gas。最后我们可以研究下文档和debug。
文档和debugging
它的建议是以太坊正在飞速的发展,任何合约可能在诞生不久后就会过时,各种官网和wiki也会过时,哪怕比较权威的人写的文章也会过时。一个典型的例子是,官网上的一个2017年的例子,已经不在维护中了,已经认为是过时了。
https://github.com/ethereum/go-ethereum/wiki/Contract-Tutorial
以太坊正在飞速运行,各种改进都会提高它的稳定性及效率。如果哪里做的不对,看看是不是自己的文档过期了,以太坊的版本是不是和文档相匹配的。在测试的链上,用旧的版本也没关系,但是在主网上旧版不一定适用。
如果想把刚刚做的实验全部删掉的话,执行下面的命令,就可以把文件夹全部删掉。
```js
$ geth removedb --datadir .designspark
```
重新建一个文件夹,重新建一个流程,就可以开始做你自己的私链,重新做一个创世区块。
最后我们总结一下,做了哪些事。
1.从理论上讲,树莓派运行智能合约,树莓派参加一个私链,哪怕树莓派参加私链用轻同步模式,参加主网,都是没问题的。
2.一个私链是如何建起来的。
3.私链在两个账户之间转账,编译智能合约,在树莓派上把智能合约应用起来,调用了一个函数。
我们现在开始,就可以加入更多的节点,运行更多复杂的智能合约,做一些更加复杂的事情。我们这节课的任务就完成了。
我们后面将介绍智能合约的编写到部署,按要求来进行智能合约的开发,最后再讲智能合约安全开发的事情。
问答
接下来,我们一起来看一下,上次课程中又有哪些精彩问答吧~!
学员:桌面到底使用solc还是remix编译合约程序?
r0ysue:remix是在云端的,在桌面是没有的。只是一个网页,其实我觉得这个随意哈。写完是这样:
然后编译,$ solc -o target --bin --abi Greeter.sol:
学员:用solc编译后的应该是一个中间代码吧?感觉你部署交叉编译环境......
r0ysue:这张图片是它演示编译的一个结果。你了解什么叫“交叉编译环境”吗?交叉编译环境是指在x86机器上,编译arm指令的代码。或者说我们在x86的机器上,编译跑在EVM虚拟机里的字节码。编译完之后的,就是EVM虚拟机的字节码。在这一点之上remix和solc功能是一样的。虽然有一些警告,但是会有一个target的文件架会产生。包含四个文件夹:Greeter和Mortal的ABI与bin文件。
学员:你后不是要拿去树莓派上用吗?你本机是x86的系统,树莓派是arm的系统,需要交叉编译的环境才能移植过去吧。
r0ysue:编译完成之后,是EVM的字节码。这个字节码可以跑在EVM的虚拟机里面的,不是直接跑在arm上面的,不需要arm的机器码。
......
本期教程视频已经上传到看雪学院,[传统安全X区块链]栏目
(https://www.kanxue.com/book-13-418.htm)
下期活动,邀你参与~
【传统安全X区块链】下期活动来啦~!
将于 2018年12月8日,19:00~20:00开讲~
讲师:看雪讲师、看雪区块链小组成员、上海交通大学密码学实验室成员xrosherat。
扫描下图海报二维码,即可添加看雪工作人员,入群免费学习~!
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!