You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Solidity智能合约中存储用户成绩记录历史的技术问询

实现Solidity用户成绩历史记录查询功能

问题背景

需要编写Solidity智能合约,实现用户成绩的历史记录存储与查询:调用setUserDetails多次为同一用户添加不同成绩后,getUserGrades能返回该用户所有成绩及对应的添加时间。

当前遇到的问题:

  • 通过事件获取历史数据需指定区块号,操作不便
  • 原有合约中结构体每次会覆盖旧数据,仅能返回最新成绩

输入示例:

setUserDetails('XYZ', 5)
setUserDetails('XYZ', 3)

期望输出:

getUserGrades('XYZ')

Grade 5 added for XYZ on 01/01/22 12:00
Grade 3 added for XYZ on 01/01/22 12:01

原有合约代码:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Users {

    struct User {
        string username;
        uint grade;
    }

    mapping(string => User) userMap;

    event userDetailsChanged(
        string username,
        uint grade
    );

    function setUserDetails(string memory _username, uint _grade) external {

        userMap[_username].username = _username;
        userMap[_username].grade = _grade;

        emit userDetailsChanged(_username, _grade);
    }

    function getUserGrades(string memory _username) external view returns(uint _grade) {
        return (
            userMap[_username].grade
        );
    }
}

解决方案

要实现需求,需利用Solidity的结构体数组、映射关联数组和区块时间戳特性,修改后的合约如下:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Users {
    // 定义单条成绩记录,包含成绩和添加时间戳
    struct GradeRecord {
        uint grade;
        uint timestamp;
    }

    // 映射:用户名对应其所有成绩记录的数组
    mapping(string => GradeRecord[]) private userGradeHistory;

    event GradeAdded(string username, uint grade, uint timestamp);

    function setUserDetails(string memory _username, uint _grade) external {
        // 向用户的成绩数组中追加新记录,不会覆盖旧数据
        userGradeHistory[_username].push(GradeRecord({
            grade: _grade,
            timestamp: block.timestamp
        }));

        emit GradeAdded(_username, _grade, block.timestamp);
    }

    function getUserGrades(string memory _username) external view returns(GradeRecord[] memory) {
        // 返回该用户的全部成绩历史记录
        return userGradeHistory[_username];
    }
}

关键修改说明

  1. 结构体重构:将原User结构体改为GradeRecord,专注存储单条成绩的核心数据(成绩值+时间戳)
  2. 映射类型调整:把mapping(string => User)替换为mapping(string => GradeRecord[]),让每个用户对应一个成绩记录数组,每次添加成绩时通过push追加新元素,彻底避免覆盖旧数据
  3. 时间戳记录:使用block.timestamp获取区块打包时间(单位为秒),前端可将其转换为可读的日期时间格式
  4. 查询功能升级:getUserGrades返回整个成绩数组,前端遍历数组即可格式化输出所有历史记录
  5. 事件优化:事件中加入时间戳,方便链下服务监听同步数据

注意事项

  • block.timestamp存在一定误差(取决于区块打包速度,通常几秒到几十秒),无法实现毫秒级精度的时间记录
  • 数组存储会增加链上存储空间占用,每次添加成绩的gas成本会随记录数量缓慢上升,但对于成绩记录这类低频操作完全可接受

内容的提问来源于stack exchange,提问作者Wojtek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 15:40:28