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

Solidity地址簿智能合约创建映射条目时返回错误求助

问题分析与修复

你的合约首次调用createBook就报错,核心问题有三个:

1. 数组越界错误

循环条件使用i <= Alias.length,当Alias数组为空时(首次调用),Alias.length为0,i=0满足0 <= 0,此时访问Alias[0]会触发数组越界,直接报错。正确的循环条件应该是i < Alias.length,只遍历数组中已存在的元素。

2. 逻辑执行顺序错误

你把账户赋值和别名入数组的操作放在了循环内部,这会导致每次循环都执行一次赋值和push,完全不符合“检查所有别名无重复后再创建”的逻辑,应该把这两个操作移到循环结束之后。

3. 重复检查逻辑漏洞

当前代码的require是检查当前遍历的别名不等于输入值,但正确逻辑应该是:只要发现有任何一个已存在的别名和输入值重复,就立即终止并报错,遍历完所有别名都无重复时,才执行创建操作。


修正后的合约代码

contract AddressBook {
    struct ownerInfo {
        string ownerAlias;
    }

    string[] Alias;
    mapping(address => ownerInfo) public ownerToAlias;

    function createBook(string memory _ownerAlias) public {
        // 遍历所有已存在的别名,检查是否重复
        for(uint i = 0; i < Alias.length; i++) {
            require(keccak256(abi.encodePacked(_ownerAlias)) != keccak256(abi.encodePacked(Alias[i])), "Alias already exists");
        }
        // 所有检查通过后,执行创建操作
        ownerToAlias[msg.sender] = ownerInfo(_ownerAlias);
        Alias.push(_ownerAlias);
    }
}

额外优化建议

用mapping(bytes32 => bool)存储已使用的别名哈希,这样不需要遍历整个数组,检查重复的时间复杂度从O(n)降到O(1),更高效:

contract AddressBook {
    struct ownerInfo {
        string ownerAlias;
    }

    string[] Alias;
    mapping(address => ownerInfo) public ownerToAlias;
    mapping(bytes32 => bool) public aliasExists; // 新增映射存储已使用的别名哈希

    function createBook(string memory _ownerAlias) public {
        bytes32 aliasHash = keccak256(abi.encodePacked(_ownerAlias));
        require(!aliasExists[aliasHash], "Alias already exists");
        
        ownerToAlias[msg.sender] = ownerInfo(_ownerAlias);
        Alias.push(_ownerAlias);
        aliasExists[aliasHash] = true; // 标记该别名已使用
    }
}

这个优化在别名数量较多时能显著降低gas消耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 17:10:29