被调用的函数突然需要支付
Called function suddenly needs to be payable
我有一个 public uint 变量表示 'which round' 它是一个推进回合并在回合推进的同时进行处理的函数:
uint public round;
function completeRound() public inPaused() inRound() {
if (round == 6) {
// win
} else {
reduceByHalf();
round.add(1);
}
}
如果我运行这个在remix中,它运行s 4次然后第5次一直失败,说明突然需要支付一个功能:
交易到 Playingwithsmartcontracts.completeRound 错误:VM 错误:还原。 revert 交易已经恢复到初始状态。注意:如果您发送价值,并且您发送的价值应小于您的当前余额,则调用的函数应该是可支付的。调试交易以获取更多信息。
如果我在调用 reduceByHalf 的地方注释掉 round.add(1),代码会整天工作。我可以在 Remix 中无限期地点击它而不会出错。
奇怪的是,这开始是一个跟踪回合的枚举,并且有同样的问题。在推进枚举时,我可以在上述失败之前进行 5 次,并将其注释掉使一切正常。
reduceByHalf 代码似乎不是罪魁祸首,但它显示在下面以防它与问题有关:
struct Foo {
address owner;
uint mintedRound;
uint winningRound;
}
struct FooOwner {
uint[] foos;
uint totalWinningFoos;
}
uint[][5] roundFoos;
uint[][5] roundWinners;
mapping(uint => Foo) public winningFoos;
mapping(address => FooOwner) public fooOwners;
uint totalWinningFoos;
function shuffleFoos (uint256[] memory _array) internal view returns(uint[] memory){
uint[] memory clone = cloneArray(_array, _array.length);
for (uint256 i = 0; i < clone.length; i++) {
uint256 n = i + uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp))) % (clone.length - i);
uint256 temp = clone[n];
clone[n] = clone[i];
clone[i] = temp;
}
return clone;
}
function cloneArray(uint256[] memory _array, uint256 _length) internal pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](_length);
for (uint256 i = 0; i < _length; i++) {
array[i] = _array[i];
}
return array;
}
function reduceByHalf() internal {
uint[] memory clone = shuffleFoos(roundFoos[round]);
uint halfLength = 0;
halfLength = roundFoos[round].length.div(2);
for (uint w = 0; w < halfLength; w++) {
uint fooId = clone[w];
roundWinners[round].push(fooId);
winningFoos[round].winningRound = round;
address fooOwner = winningFoos[fooId].owner;
fooOwners[fooOwner].totalWinningFoos = fooOwners[fooOwner].totalWinningFoos.add(1);
}
totalWinningFoos = totalWinningFoos.add(halfLength);
}
据我所知,我没有发送价值,也不确定为什么它只认为我在交易执行时发送价值 5.
谁能帮我理解 Remix/Solidity 的疯狂之处?
我完全不能理解某些东西,但它看起来像是关于数字 5 的东西......我可以将回合推进到 6,但是当我将 uint 值设置为 5 时,我就开始看到这些问题....太奇怪了....
The transaction has been reverted to the initial state.
这是您案例中错误消息的重要部分。
Note: The called function should be payable if you send value
这只是一个注释,可能是因为这种组合经常发生。但是由于您的函数和交易不发送任何值,因此它不适用于您的情况。
round.add(1);
这个(失败的)片段表明,应该有一个库 used for uint
, but it's not defined. I'm gonna go with the SameMath 库,因为 .add()
函数名称和在 uint
上的使用。但理论上,它可以是任何库,SafeMath 只是这种情况下最可能的选择。
注意 round.add(1);
(使用 SafeMath)returns round
的值增加 1,但它不会在任何地方存储(增加的)值.这看起来像是打字错误,实际用法应该是 round = round.add(1);
您的代码没有显示 SafeMath 库的任何用法,也没有显示 Solidity 版本,所以我将把我的回答分为 3 个部分。
您正在使用 Solidity 0.8+。
不需要 SameMath,因为整数溢出在较低级别处理,您可以安全地替换
// even with correctly imported SafeMath, it doesn't update the stored value
round.add(1);
到
// updates the stored value
round++;
您使用的是 Solidity 0.7 或更早版本,以及 uint256
(不是 uint
)
的 SafeMath
更改定义
uint public round;
到
uint256 public round;
这样,SafeMath 将用于 round
并且允许使用函数 .add()
.
请注意,您可能还想存储增量值,请参阅上面示例中的粗体段落。
您使用的是 Solidity 0.7 或更早版本,并且根本没有使用 SafeMath。
您需要import the SafeMath library然后进行第 2 点中描述的更改。
我有一个 public uint 变量表示 'which round' 它是一个推进回合并在回合推进的同时进行处理的函数:
uint public round;
function completeRound() public inPaused() inRound() {
if (round == 6) {
// win
} else {
reduceByHalf();
round.add(1);
}
}
如果我运行这个在remix中,它运行s 4次然后第5次一直失败,说明突然需要支付一个功能:
交易到 Playingwithsmartcontracts.completeRound 错误:VM 错误:还原。 revert 交易已经恢复到初始状态。注意:如果您发送价值,并且您发送的价值应小于您的当前余额,则调用的函数应该是可支付的。调试交易以获取更多信息。
如果我在调用 reduceByHalf 的地方注释掉 round.add(1),代码会整天工作。我可以在 Remix 中无限期地点击它而不会出错。
奇怪的是,这开始是一个跟踪回合的枚举,并且有同样的问题。在推进枚举时,我可以在上述失败之前进行 5 次,并将其注释掉使一切正常。
reduceByHalf 代码似乎不是罪魁祸首,但它显示在下面以防它与问题有关:
struct Foo {
address owner;
uint mintedRound;
uint winningRound;
}
struct FooOwner {
uint[] foos;
uint totalWinningFoos;
}
uint[][5] roundFoos;
uint[][5] roundWinners;
mapping(uint => Foo) public winningFoos;
mapping(address => FooOwner) public fooOwners;
uint totalWinningFoos;
function shuffleFoos (uint256[] memory _array) internal view returns(uint[] memory){
uint[] memory clone = cloneArray(_array, _array.length);
for (uint256 i = 0; i < clone.length; i++) {
uint256 n = i + uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp))) % (clone.length - i);
uint256 temp = clone[n];
clone[n] = clone[i];
clone[i] = temp;
}
return clone;
}
function cloneArray(uint256[] memory _array, uint256 _length) internal pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](_length);
for (uint256 i = 0; i < _length; i++) {
array[i] = _array[i];
}
return array;
}
function reduceByHalf() internal {
uint[] memory clone = shuffleFoos(roundFoos[round]);
uint halfLength = 0;
halfLength = roundFoos[round].length.div(2);
for (uint w = 0; w < halfLength; w++) {
uint fooId = clone[w];
roundWinners[round].push(fooId);
winningFoos[round].winningRound = round;
address fooOwner = winningFoos[fooId].owner;
fooOwners[fooOwner].totalWinningFoos = fooOwners[fooOwner].totalWinningFoos.add(1);
}
totalWinningFoos = totalWinningFoos.add(halfLength);
}
据我所知,我没有发送价值,也不确定为什么它只认为我在交易执行时发送价值 5.
谁能帮我理解 Remix/Solidity 的疯狂之处?
我完全不能理解某些东西,但它看起来像是关于数字 5 的东西......我可以将回合推进到 6,但是当我将 uint 值设置为 5 时,我就开始看到这些问题....太奇怪了....
The transaction has been reverted to the initial state.
这是您案例中错误消息的重要部分。
Note: The called function should be payable if you send value
这只是一个注释,可能是因为这种组合经常发生。但是由于您的函数和交易不发送任何值,因此它不适用于您的情况。
round.add(1);
这个(失败的)片段表明,应该有一个库 used for uint
, but it's not defined. I'm gonna go with the SameMath 库,因为 .add()
函数名称和在 uint
上的使用。但理论上,它可以是任何库,SafeMath 只是这种情况下最可能的选择。
注意 round.add(1);
(使用 SafeMath)returns round
的值增加 1,但它不会在任何地方存储(增加的)值.这看起来像是打字错误,实际用法应该是 round = round.add(1);
您的代码没有显示 SafeMath 库的任何用法,也没有显示 Solidity 版本,所以我将把我的回答分为 3 个部分。
您正在使用 Solidity 0.8+。
不需要 SameMath,因为整数溢出在较低级别处理,您可以安全地替换
// even with correctly imported SafeMath, it doesn't update the stored value round.add(1);
到
// updates the stored value round++;
您使用的是 Solidity 0.7 或更早版本,以及
的 SafeMathuint256
(不是uint
)更改定义
uint public round;
到
uint256 public round;
这样,SafeMath 将用于
round
并且允许使用函数.add()
.请注意,您可能还想存储增量值,请参阅上面示例中的粗体段落。
您使用的是 Solidity 0.7 或更早版本,并且根本没有使用 SafeMath。
您需要import the SafeMath library然后进行第 2 点中描述的更改。