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; } }
额外优化点
- 给
require语句添加错误提示信息,方便调试时定位问题。 - 移除
finalizeRequest函数的payable修饰符(该函数不需要接收ETH)。 - 统一Solidity版本号,避免跨版本语法差异。
内容的提问来源于stack exchange,提问作者Shubham Tiwary
相关产品推荐
相关产品推荐

