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]++;

但是你不能循环技能。