Solidity
將 array.length 設置為 0 會在solidity 0.5.0 上觸發錯誤
為什麼將 array.length 設置為 0 會觸發錯誤?
我有一個函式可以從映射中的動態結構數組中刪除一個元素,如下所示:
mapping(address => MyStruct[]) public structs;
我的問題是,如果我嘗試將長度設置為 0,則會觸發此錯誤:VM Exception while processing transaction: invalid opcode
structs[_user].length = 0; // will trigger an error !
但是:
structs[_user].length = 1;
會正常工作。它在這樣的函式內部:
function _burn(uint index) internal { require(index < array.length); array[index] = array[array.length-1]; delete array[array.length-1]; // when array.length is set to 0 it doesn't work: array.length = array.length - 1; // doesn't work if array.length = 1 array.length = 0; // doesn't work // when array.length is set to a value > 0 it works: array.length = 1; // works array.length = 2; // works }
我嘗試了至少 45 個小時,卻不知道為什麼會這樣!如果您遇到此問題或知道如何處理它,我們將不勝感激。
PS:我使用的是solidity 0.5.2
這是整個程式碼:
// ---- Redeem a Stake ------ // function stakeclmidx (uint _stakeidx) public { require(_stakeidx >= 0); Stake storage _stake = stakes[msg.sender][_stakeidx]; // See if the stake is over require(block.number > _stake.endBlock); require(_stake.amount > 0); // transfer back token from contract to staker: balances[address(this)] = balances[address(this)].sub(_stake.amount); balances[msg.sender] = balances[msg.sender].add(_stake.amount); emit Transfer(address(this), msg.sender, _stake.amount); emit StakeClaimed(_stakeidx); // deletes the stake _deletestake(msg.sender, _stakeidx); } function _deletestake(address _staker,uint _index) internal { require(_index < stakes[_staker].length); stakes[_staker][_index] = stakes[_staker][stakes[_staker].length-1]; delete stakes[_staker][stakes[_staker].length-1]; stakes[_staker].length = stakes[_staker].length - 1; // this last line is the one triggering the error // it seems it triggers the error only when length value is set to 0 // stakes[_staker].length = 1; works ! // stakes[_staker].length = 2; works ! // stakes[_staker].length = 0; doesn't work ! } // ---- Redeem a Stake ------ //
最好的祝福
您的程式碼中的問題如下行:
array[index] = array[array.length-1];
您不會將值分配給動態數組。你需要推。將其更改為
array.push(array[array.length-1]);
然後這應該工作。只需呼叫 reduce length 兩次。
請記住,減號是非常危險的。長度為零後,再次遞減不會報錯,會導致下溢,新數組會初始化為下溢長度。
pragma solidity ^0.5.0; contract Arraytest{ uint8[] public array ; constructor() public{ for(uint8 counter=0; counter<2; counter++) { array.push(counter); } } event MESSAGE(uint _message); function reduceLength() public returns (uint8[] memory) { array.length--; emit MESSAGE(array.length); return array; // array[index] = array[array.length-1]; // delete array[array.length-1]; // // when array.length is set to 0 it doesn't work: // array.length = array.length - 1; // doesn't work if array.length = 1 // array.length = 0; // doesn't work // // when array.length is set to a value > 0 it works: // array.length = 1; // works // array.length = 2; // works } }