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

By [0xdoux.eth](https://paragraph.com/@0xdoux) · 2022-03-29

---

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

需求
--

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

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

代码示例
----

接下来，我们使用 Solidity 来编写智能合约，环境为 [Ethereum Remix](https://remix.ethereum.org/) ，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 会提供好一些测试的账号，同时合约也是部署在测试网络上，这可以大幅降低我们开发合约的成本。部署完成后，打卡刚部署的合约，就可以看到上述代码中的添加数据和获取数据的接口了，我们可以在此处直接进行交互测试

![](https://storage.googleapis.com/papyrus_images/23639a41c6c91ce8750c1a316bd3a54517839973334fcc7b4a0899a25aef6599.png)

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

![](https://storage.googleapis.com/papyrus_images/62ee33752147a5639f261cb82743b3b504e087b5cfca0026ada055908f7021db.png)

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

![](https://storage.googleapis.com/papyrus_images/7fdfa626e8d915ab40c4a96bb2ba73a80158bdc6b681750a99610dd400102330.png)

总结
--

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

---

*Originally published on [0xdoux.eth](https://paragraph.com/@0xdoux/SRaxkXyc28o7uVIGOzzN)*
