Solidity带数组存储合约调用saveStandard触发VM revert错误原因求助
合约错误排查与修复方案
核心错误原因
1. 动态数组越界访问
Solidity 中存储位置的动态数组默认初始长度为 0,你代码中直接通过下标id给time、emission数组赋值时,数组还没有分配对应下标的存储空间,下标访问越界直接触发VM异常回滚。
你删除数组相关逻辑之后,结构体的成员都是单个值,直接赋值不需要处理数组扩容逻辑,因此不会触发越界问题,合约可以正常运行。
2. 逻辑冗余与错误
- 结构体中定义的
string[] source数组全程未使用,属于冗余字段 search函数的while循环逻辑完全无效,第一次循环就会直接return,同样存在数组越界风险,且只能返回第一条数据,不符合多组数据存储的需求
修复后的完整合约代码
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; contract Storage{ struct UserInfo { string[] time; uint[] emission; } mapping (string => UserInfo) public users; function saveStandard(uint input_material, uint weight, string memory input_time, string memory input_source) public returns (string memory, uint, uint, string memory){ uint Combustion = weight * input_material / 10; uint Process = weight * input_material / 10; // 使用push方法追加数组元素,自动完成扩容 users[input_source].time.push(input_time); users[input_source].emission.push(Combustion + Process); return (input_source, Combustion, Process, input_time); } // 支持按序号查询指定数据 function search(string memory input_source, uint index) public view returns (uint, string memory) { require(index < users[input_source].emission.length, "查询序号超出范围"); return (users[input_source].emission[index], users[input_source].time[index]); } // 新增获取企业数据总条数的方法 function getRecordCount(string memory input_source) public view returns(uint) { return users[input_source].emission.length; } }
修复说明
- 替换直接给数组下标赋值的逻辑为
push()方法,动态数组会自动扩容,彻底解决越界回滚问题 - 删除冗余的index字段和未使用的source数组,降低gas消耗
- 优化search函数,新增下标合法性校验,避免异常回滚,支持查询任意序号的历史数据
- 新增getRecordCount方法,方便查询企业存储的总数据条数,可配合完成全量数据遍历
内容的提问来源于stack exchange,提问作者ginwei
相关产品推荐
相关产品推荐

