我正在制定一份智能合约,我正在通过将其部署在松露上进行测试。虽然编译很好,但当我调用train()函数时,我收到以下错误:
错误:处理事务时出现VM异常:操作码无效
在阅读了这一点之后,我明白它通常是在一个恢复发生之后引起的,所以我试着评论出2个需要的函数,我只是看它是否会表现不同,而事实并非如此。
检查this问题没有帮助我,或者我没有看到它怎么可能。
这是train()函数,以及我在其中使用的映射和结构类型。我应该注意到,在创建开发人员时,他们的钱包设置为300,所以我看不到所有者对列车功能的第一次调用是如何恢复的。
struct Developer {
address owner;
string name;
bytes32 namehash;
bytes32[] skills;
uint256[] skill_levels;
uint wallet;
}
mapping (bytes32=>Developer) public developers_all;
function train(string _name, bytes32 _skill) public {
bytes32 h = keccak256(abi.encodePacked(_name));
require(developers_all[h].owner == msg.sender, "Only the owner of the developer can train them");
require(developers_all[h].wallet >= 150, "Insufficient funds");
uint256 i = 0;
do {
if (developers_all[h].skills[i] == _skill) {
developers_all[h].skill_levels[i]++;
} else if ((i == (developers_all[h].skills.length - 1)) || (developers_all[h].skills.length == 0)) {
developers_all[h].skills.push(_skill);
developers_all[h].skill_levels.push(1);
}
i++;
} while (i < developers_all[h].skills.length);
developers_all[h].wallet = developers_all[h].wallet - 150;
}
感谢您的任何帮助。
这很可能是因为您尝试访问空数组的第一个条目。您正在使用do while循环,并且在检查developers_all[h].skills[i]
之前尝试访问developers_all[h].skills.length == 0
,因此有可能在do while中的第一个if语句处该数组为空。
您可以将代码重写为以下内容,以确保您永远不会访问未分配的数组插槽。
bool foundSkill = false;
for (uint i = 0; i < developers_all[h].skills.length; i++) {
if (developers_all[h].skills[i] == _skill) {
developers_all[h].skill_levels[i]++;
foundSkill = true;
break;
}
}
if (!foundSkill) {
developers_all[h].skills.push(_skill);
developers_all[h].skill_levels.push(1);
}
请注意,遍历整个数组并进行比较是非常昂贵的,如果数组大小太大,则可能变得不可能。您可能需要考虑将结构更改为:
struct Developer {
address owner;
string name;
bytes32 namehash;
mapping(bytes32 => uint) skill_levels;
uint wallet;
}
这样你就可以用整个东西替换掉
developers_all[h].skill_levels[skill]++;
但是你无法绕过这些技能。