Solidity - Truffle: Error: VM Exception while processing transaction: invalid opcode NOT because of revert
Solidity - Truffle: Error: VM Exception while processing transaction: invalid opcode NOT because of revert
我正在研究一个智能合约,我正在通过将它部署在 truffle 上来测试它。虽然编译正常,但当我调用 train() 函数时,出现以下错误:
Error: VM Exception while processing transaction: invalid opcode
阅读了一些相关内容后,我了解到这通常是在发生还原后引起的,因此我尝试注释掉我刚刚使用的 2 个 require 函数,看看它的行为是否会有所不同,但事实并非如此。
检查 this 问题对我没有帮助,或者我没有看到它怎么可能。
这是 train() 函数,以及我在其中使用的映射和结构类型。我应该注意到,在创建开发人员时,他们的钱包设置为 300,所以我看不到所有者第一次调用 train 函数如何恢复。
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.length == 0
之前尝试访问 developers_all[h].skills[i]
,因此在 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]++;
但是你不能循环技能。
我正在研究一个智能合约,我正在通过将它部署在 truffle 上来测试它。虽然编译正常,但当我调用 train() 函数时,出现以下错误:
Error: VM Exception while processing transaction: invalid opcode
阅读了一些相关内容后,我了解到这通常是在发生还原后引起的,因此我尝试注释掉我刚刚使用的 2 个 require 函数,看看它的行为是否会有所不同,但事实并非如此。
检查 this 问题对我没有帮助,或者我没有看到它怎么可能。
这是 train() 函数,以及我在其中使用的映射和结构类型。我应该注意到,在创建开发人员时,他们的钱包设置为 300,所以我看不到所有者第一次调用 train 函数如何恢复。
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.length == 0
之前尝试访问 developers_all[h].skills[i]
,因此在 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]++;
但是你不能循环技能。