合约开发求助:完善ScoreTracker合约的分数查询与排名功能
ScoreTracker合约修复与功能完善
原代码核心问题
- Solidity的
mapping没有内置length属性,无法直接通过scores.length获取地址数量 - Solidity不支持直接遍历
mapping,必须额外维护一份地址列表来记录所有有分数的钱包 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
相关产品推荐
相关产品推荐

