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

Solidity合约struct内嵌mapping时数据未持久化问题咨询

问题背景

查阅mapping使用方法、struct嵌套mapping相关技术资料,参考社区讨论编写了如下Solidity测试合约,已知Solidity 0.7.0版本后调整了struct内嵌套mapping的语法规则,代码如下:

contract Test {
    constructor() {
    }   

    struct Bid {
        uint auction_id;
        address addr;
        uint amount;
    }   

    struct Auction {
        uint id; 
        string dtype;
        uint start_date;
        uint end_date;
        string label;
        uint price;
        uint amount;
        bool closed;
        mapping(uint => Bid) bids;
        uint bidCount;
    }   

    uint public auctionCount = 0;
    mapping(uint => Auction) public auctions;

    function createAuction( string memory plabel, string memory ptype, uint nbhours, uint pprice) external {
        Auction storage nd = auctions[auctionCount];
        nd.id = auctionCount;
        nd.dtype = ptype;
        nd.start_date = block.timestamp;
        nd.end_date = block.timestamp+nbhours*60*60;
        nd.label = plabel;
        nd.price = pprice;
        nd.amount = 0;
        nd.closed = false;
        nd.bidCount = 0;
        auctionCount++;
    }
}

代码可正常编译,createAuction交易执行返回成功。在Ganache中查看合约状态时,auctionCount变量可正常递增,但auctions mapping中没有新增对应条目;通过Truffle调试交易,确认函数执行过程中完成了各字段赋值,但状态变更看起来没有被持久化存储。曾尝试移除一个string类型属性(曾看到资料称struct内存在3个string属性可能引发问题,当前代码中最多只有2个string字段),问题仍未解决。

根本原因

该问题不是Solidity语法错误,也不是状态没有持久化,是本地开发工具的展示能力限制:

  • 合约逻辑本身完全符合Solidity存储规则:当通过Auction storage nd = auctions[auctionCount];访问mapping中不存在的键时,Solidity会自动在存储中为该键初始化空的struct实例,后续对nd的所有字段赋值都会直接写入链上存储,auctionCount成功递增已经证明交易被正常打包执行,状态写入实际已经生效。
  • Ganache状态面板、旧版本Truffle调试器没有实现对含嵌套mapping的动态大小struct的解析能力:包含mapping类型成员的struct属于复杂动态存储结构,工具无法自动遍历解析这类结构的链上数据,因此不会在状态面板中展示对应条目,本质是工具“看不到”已经存好的数据,不是数据没存上。
  • 网传“struct内3个string会引发问题”是Solidity 0.6之前版本的编译器bug,0.7及之后版本已经完全修复,和当前现象无关。
验证与修复方案

可以通过自定义视图函数自行验证存储状态,操作如下:

  • 在合约中新增专门的查询函数,手动返回struct中除嵌套mapping外的所有字段(含mapping的struct无法直接在memory中承载,因此不能整体作为返回值):
function getAuction(uint _auctionId) external view returns(
    uint id,
    string memory dtype,
    uint start_date,
    uint end_date,
    string memory label,
    uint price,
    uint amount,
    bool closed,
    uint bidCount
) {
    Auction storage targetAuction = auctions[_auctionId];
    return (
        targetAuction.id,
        targetAuction.dtype,
        targetAuction.start_date,
        targetAuction.end_date,
        targetAuction.label,
        targetAuction.price,
        targetAuction.amount,
        targetAuction.closed,
        targetAuction.bidCount
    );
}
  • 重新部署合约,调用createAuction发起交易,待交易确认后,调用getAuction传入对应拍卖ID,即可读取到之前写入的所有字段值,直接证明状态已经完成持久化。
  • 后续如果需要读取Auction struct内嵌套的bids mapping数据,单独编写对应入参为拍卖ID、出价ID的查询函数即可,不要尝试直接返回整个struct。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:48:33