大家好,我是Frank。
在上篇中,我们用JavaScript开发了一个简单的区块链,本篇文章是上一篇的姐妹篇,如果上篇的内容还没有完全消化的话,没关系,多看几遍,自然就对其运行原理有个大概的了解了。 本篇文章主要介绍如何通过Solidity语言来开发智能合约,并在Remix线上平台对我们的程序进行编译、测试和发布。
什么是智能合约?
智能合约可以理解为类似于生活中的合同,不过也有点不同,生活中的合同需要手工去签字,而智能合约则是触发某个前置条件后,便自动执行。这么说比较抽象,可能还是不太好理解,没关系,我们继续往下看。
什么是Solidity?
Solidity是一种专门为开发智能合约而设计的编程语言,它吸收了typescript和OOP中的思想,因此,如果你对二者都熟悉的话,尤其对于后端开发的朋友们来说,学习起来应该没那么吃力。
用Solidity编写的程序和普通程序一样,需要进行编译、测试和部署,不过,我们不需要额外的再搭建平台,本教程会直接使用Remix线上平台走完这些流程。
编写智能合约
打开Remix网页我们可以看到如下界面: 删除红框内的所有文件,然后新建一个新文件Blockchain.sol
我们先看第一行代码:
arduino
// SPDX-License-Identifier: MIT
这行代码是每份合约代码前面必须有的,用于指定代码的许可证类型,这里我们选用MIT协议
ini
pragma solidity ^0.8.20;
第二行代码用于指定Solidity的版本,这里"^"符号指的是版本大于等于0.8.20
markdown
contract Blockchain {
}
创建一份名称为Blockchain的合约,这里的contract就可以理解成JavaScript里的class关键字
在Solidity中,我们可以使用struct关键字创建任何抽象的数据结构,因此我们可以利用它来创建一个表示区块的数据结构:
ini
struct Block {
uint256 index;
uint256 timestamp;
uint256 amount;
address sender;
address recipient;
}
uint ,Solidity语言的一种数据类型,代表无符号整型,后面的数字256限定了数值的最大范围,如果没有数字后缀,如uint,则默认为uint256
address,表示以太坊地址,包含一个20字节的字符串
是不是有点像JavaScript中的对象?
yaml
const Block = {
index: 0,
timestamp: 0,
amount: 0,
sender: '',
recipient: ''
}
接着定义两个变量,分别用于存储区块链和区块的总数量:
ini
Block[] chain;
uint256 chainCount;
有了区块数据结构,我们还需要定义一个与前端环境通信的事件,我们可以在添加完区块后触发它:
csharp
event BlockEvent(uint256 amount, address sender, address recipient);
最后,我们定义三个函数addBlockToChain、getChain、getChainCount,分别用于添加区块、获取区块链和区块总数:
addBlockToChain函数
scss
function addBlockToChain(uint256 amount, address payable recipient) public {
chainCount += 1;
chain.push(Block(
chainCount,
block.timestamp,
amount,
msg.sender,
recipient
));
emit BlockEvent(amount, msg.sender, recipient);
}
address payable 中的payable关键字说明这个钱包地址是可以被以太坊接受的,之所以设计这个关键字,目的就是区分以太坊地址和非以太坊地址,因为智能合约不一定会运行在以太坊上。
函数定义的最后的public,说明这个函数可以被其他合约访问。
接着看看函数内部的代码,我们首先把区块数量+1,接着,把新的区块添加到链上,最后,触发一个事件到前端。
getChain函数:
csharp
function getChain() public view returns (Block[] memory) {
return chain;
}
public 后面的view 关键字表明函数内部不会改变合约的状态,目前合约的状态包含两个变量,分别是chain和chainCount。与之相对应的,还有另外个关键字pure,它对函数内部的约束更加严格,不仅不可修改合约的状态,连读也不可以。
retuns 表示函数有返回值
Block[] 表示函数的返回值类型
memory 说明了函数的返回结果存储在内存上,Solitidy中有两种存储类型,一种Storage 永久存储,另一种Memory表示暂时存储
getChainCount函数:
csharp
function getChainCount() public view returns (uint256) {
return chainCount;
}
完整代码如下:
ini
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Blockchain {
struct Block {
uint256 index;
uint256 timestamp;
uint256 amount;
address sender;
address recipient;
}
Block[] chain;
uint256 chainCount = 0;
event BlockEvent(uint256 amount, address sender, address recipient);
function addBlockToChain(uint256 amount, address payable recipient) public {
chainCount += 1;
chain.push(Block(
chainCount,
block.timestamp,
amount,
msg.sender,
recipient
));
emit BlockEvent(amount, msg.sender, recipient);
}
function getChain() public view returns (Block[] memory) {
return chain;
}
function getChainCount() public view returns (uint256) {
return chainCount;
}
}
编译智能合约
我们从最左边的菜单栏中选中第三个图标将会看到下面的界面,在点击蓝色的编辑按钮:
需要注意的是,最上面红框中的版本号,需跟合约中指定的版本号对应。
部署和测试
接下来我们开始部署智能合约,点击下图中的橘色按钮
看到下图中红框中的内容,说明已经部署成功
接下来,我们测试一次转账,首先,复制一个收款方钱包地址,下拉框选中第三个后,点击复制:
由于每个账户中都预先存入了100以太币,所以,我们可以开始测试转账了:
可以看到,这里有三个可供测试的函数,我们点击第一个addBlock函数后面的下拉按钮:
填入金额,把前面复制好的收款地址粘贴到recipient输入框,最后点击transact按钮,
同样的操作,我们通过测试getChain和getChainCount函数,得到结果:
getChain函数返回了一个元祖数组,大家可以验证下收款地址和金额是否正确,getChainCount返回了数字1,正是我们期望的。
最后
恭喜你!坚持到了最后,现在你已经可以了解了如何开发一个简单的智能合约,并且,还成功完成了一笔转账,这为后面的深入开发奠定了坚实的基础!如果学习过程中你有任何疑问,记得在留言区讨论哦!