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

合约开发求助:完善ScoreTracker合约的分数查询与排名功能

ScoreTracker合约修复与功能完善

原代码核心问题

  1. Solidity的mapping没有内置length属性,无法直接通过scores.length获取地址数量
  2. Solidity不支持直接遍历mapping,必须额外维护一份地址列表来记录所有有分数的钱包
  3. getAllScores函数定义在合约外部,语法不符合Solidity规范

修复并增强后的完整合约

以下代码不仅修复了getAllScores的问题,还实现了按分数降序的排名功能:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ScoreTracker {
    // 存储地址与分数的映射
    mapping(address => uint) public scores;
    // 维护所有有分数的地址列表,用于遍历
    address[] public scoreHolders;

    // 向钱包添加分数,不存在则创建,存在则累加
    function addScore(address _wallet, uint _score) public {
        // 确保分数为正数
        require(_score > 0, "Score must be positive");
        
        // 如果是首次添加分数,将地址加入列表
        if (scores[_wallet] == 0) {
            scoreHolders.push(_wallet);
        }
        // 累加分数(首次添加时scores[_wallet]是0,直接赋值等价于累加)
        scores[_wallet] += _score;
    }

    // 查询单个钱包的分数
    function getScore(address _wallet) public view returns (uint) {
        return scores[_wallet];
    }

    // 查询所有地址及其分数
    function getAllScores() public view returns (address[] memory, uint[] memory) {
        uint holderCount = scoreHolders.length;
        address[] memory addresses = new address[](holderCount);
        uint[] memory scoreList = new uint[](holderCount);

        for (uint i = 0; i < holderCount; i++) {
            address wallet = scoreHolders[i];
            addresses[i] = wallet;
            scoreList[i] = scores[wallet];
        }

        return (addresses, scoreList);
    }

    // 按分数降序获取排名列表
    function getRankedScores() public view returns (address[] memory, uint[] memory) {
        uint holderCount = scoreHolders.length;
        // 拷贝地址和分数到内存数组,避免修改存储
        address[] memory sortedAddresses = new address[](holderCount);
        uint[] memory sortedScores = new uint[](holderCount);

        // 先复制原始数据
        for (uint i = 0; i < holderCount; i++) {
            sortedAddresses[i] = scoreHolders[i];
            sortedScores[i] = scores[scoreHolders[i]];
        }

        // 冒泡排序(适合小规模数据,大规模建议链下处理)
        for (uint i = 0; i < holderCount; i++) {
            for (uint j = i + 1; j < holderCount; j++) {
                if (sortedScores[i] < sortedScores[j]) {
                    // 交换分数
                    uint tempScore = sortedScores[i];
                    sortedScores[i] = sortedScores[j];
                    sortedScores[j] = tempScore;
                    // 交换对应地址
                    address tempAddr = sortedAddresses[i];
                    sortedAddresses[i] = sortedAddresses[j];
                    sortedAddresses[j] = tempAddr;
                }
            }
        }

        return (sortedAddresses, sortedScores);
    }
}

关键说明

  • 地址列表维护:通过scoreHolders数组记录所有有分数的地址,解决了mapping无法遍历的问题
  • 重复地址处理:在addScore中判断scores[_wallet] == 0,确保同一个地址只会被加入列表一次
  • 排名实现:采用冒泡排序对内存中的分数和地址数组进行降序排序,注意:如果地址数量很大,链上排序会消耗较多Gas,大规模场景建议链下获取数据后排序
  • 分数累加简化:原代码的if-else可以简化为直接scores[_wallet] += _score,因为首次添加时scores[_wallet]初始值为0,累加效果等价于赋值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:20:39