智能合约使用示例:跑步群打卡

在本文里,我们通过一个非常简单的示例来了解下智能合约。这个例子是跑步群打卡。本文的例子旨在对智能合约做简单介绍,所以它并不是一个设计良好的区块链项目,在后续的文章里,我么会不断的来完善这个设计。

需求

首先来看下跑步群的需求,最简单的就是跑步打卡,上传自己的跑步记录。再复杂一些的,就是每个月设置跑步次数,然后交钱,没有完成目标的扣钱。完整的需求还是比较符合区块链上的玩法的,在本文里我们先来解决简单的需求,在后续的文章里我们再来实现复杂的需求。

所以需求很清晰,用户需要能够上传打卡记录,可以查询打卡记录即可。为了增加一些限制,我们可以要求上传的打卡数据,至少是 2 公里。

代码示例

接下来,我们使用 Solidity 来编写智能合约,环境为 Ethereum Remix ,Remix 的介绍可以参考我之前的文章。

首先要定义打卡记录的数据存储

mapping(address => uint[]) records;

其中,mapping 是字典,所有的打卡数据都存储在其中。address 代表具体的人,uint[] 里是这个人的打卡数据记录

然后,我们来编写上传打卡数据的接口

uint constant MIN_MILE = 2000;
function newRecord(uint _miles) public {
    require(_miles > MIN_MILE, "distance is too short");
    records[msg.sender].push(_miles);
}

其中,require 是对参数的判断,在需求里我们要求上传的打卡数据至少是 2 公里,即 2000 米,所以在上传记录的时候做一下验证。而 msg.sender 代表每个调用者的账号,public 代表这这个接口是访问等级,此处表示它可以被外部,也就是前端页面来调用

然后编写获取个人打卡记录的接口

function myRecord() public view returns (uint[] memory) {
    return records[msg.sender];
}

view 的含义是这个方法是只读的,在 Solidity 中,如果一个方法只会读取数据,那么就需要加上 view。相应的还有 pure,是不读也不写

将上述的代码包装在 contract 下就可以了,完整的示例代码如下

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.0 <0.9.0;

contract Running {
    uint constant MIN_MILE = 2000;
    
    mapping(address => uint[]) records;

    function newRecord(uint _miles) public {
        require(_miles > MIN_MILE, "distance is too short");
        records[msg.sender].push(_miles);
    }

    function myRecord() public view returns (uint[] memory) {
        return records[msg.sender];
    }
}

运行合约

在 Remix 中使用 command + s 即可保存并编译合约,这是 mac 上的快捷键,windows 电脑上可以将 command 键换成 windows 键或者是 ctrl 试下。这就是我们常用的保存快捷键

打开 Remix 的 DEPLOY & RUN TRANSACTIONS 菜单,选择好对应的合约,点击 Deploy 就可以完成部署了。Remix 会提供好一些测试的账号,同时合约也是部署在测试网络上,这可以大幅降低我们开发合约的成本。部署完成后,打卡刚部署的合约,就可以看到上述代码中的添加数据和获取数据的接口了,我们可以在此处直接进行交互测试

post image

如果我们在 newRecord 这边输入 1000,因为没达到 2000 这个要求,它是上传不成功的

post image

正常上传后,可以通过 myRecord 获取到当前用户的数据

post image

总结

本文是一个非常简单的智能合约的示例,在后续的文章里,我们会完善项目的设计,实现上述复杂部分的需求。同时在实际的项目中,还需要一个前端页面,用来负责与用户的交互。