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

Solidity中添加含mapping的结构体到数组失败问题求助

问题排查与解决方案

你的核心问题出在包含mapping的结构体添加到数组的实现方式上,两段代码的createRequest函数都存在语法或逻辑错误,导致交易回滚或报错,以下是具体分析和修复方案:

错误分析

1. 第一段代码:push()返回值使用错误

在Solidity 0.6.0及之后的版本中,array.push()的返回值从存储引用改为了新元素的索引(uint类型)。你第一段代码中的写法:

Request storage newRequest = requests.push();

存在类型不匹配的问题,编译器会直接报错,运行时会触发交易回滚,表现为交易pending或调用失败。

2. 第二段代码:数组越界访问

第二段代码中直接通过requests[requestNum]获取存储引用,但初始状态下requests数组长度为0,requestNum初始值为0,此时访问索引0属于数组越界,Solidity的内置边界检查会触发回滚,导致交易失败。

修复后的代码示例

以下是修正后的Campaign合约核心部分,重点修复createRequest函数:

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

contract CampaignFactory{
    address payable [] public deployedCampaigns;

    function createCampaign(uint minimum) public{
        address newCampaign = address(new Campaign(minimum, msg.sender));
        deployedCampaigns.push(payable(newCampaign));
    }

    function getDeployedCampaigns() public view returns (address payable [] memory){
        return deployedCampaigns;
    }
}

contract Campaign{
    struct Request{
        string description;
        uint value;
        address payable recipient;
        bool complete;
        uint approvalCount;
        mapping(address=>bool) approvals;
    }

    Request[] public requests;
    address public manager;
    uint public minimumContribution;
    mapping (address=>bool) public approvers;
    uint public approversCount;

    modifier restricted(){
        require(msg.sender == manager, "Only manager can call this function");
        _;
    }

    constructor(uint minimum, address creator){
        manager = creator;
        minimumContribution = minimum;
    }

    function contribute() public payable {
        require(msg.value > minimumContribution);
        approvers[msg.sender] = true;
        approversCount++;
    } 

    function createRequest(string memory description, uint value, address recipient) public restricted{
        // 先push空结构体,获取新元素索引
        uint newIndex = requests.push();
        // 通过索引获取存储引用
        Request storage newRequest = requests[newIndex];
        
        newRequest.description = description;
        newRequest.value = value;
        newRequest.recipient = payable(recipient);
        newRequest.complete = false;
        newRequest.approvalCount = 0;   
    }

    function approveRequest(uint index) public{
        Request storage request = requests[index];

        require(approvers[msg.sender], "You are not an approver");
        require(!request.approvals[msg.sender], "You already approved this request");

        request.approvals[msg.sender] = true;
        request.approvalCount++; 
    }

    function finalizeRequest(uint index) public restricted {
        Request storage request = requests[index];
    
        require(!request.complete, "Request already finalized");
        require(request.approvalCount > approversCount / 2, "Not enough approvals");
        
        request.recipient.transfer(request.value);
        request.complete = true;
    }
}

额外优化点

  1. 给require语句添加错误提示信息,方便调试时定位问题。
  2. 移除finalizeRequest函数的payable修饰符(该函数不需要接收ETH)。
  3. 统一Solidity版本号,避免跨版本语法差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 16:21:02