|
| 1 | +diff -ruN DoubleLinkedList.sol DoubleLinkedList.sol |
| 2 | +--- DoubleLinkedList.sol 2022-10-25 18:11:24.798784245 +0200 |
| 3 | ++++ DoubleLinkedList.sol 2022-11-11 11:24:29.066289033 +0100 |
| 4 | +@@ -18,6 +18,8 @@ |
| 5 | + mapping(address => Account) accounts; |
| 6 | + address head; |
| 7 | + address tail; |
| 8 | ++ address insertedBefore; // HARNESS: address of the account before which the account was inserted at last insertion. |
| 9 | ++ address insertedAfter; // HARNESS: address of the account after which the account was inserted at last insertion. |
| 10 | + } |
| 11 | + |
| 12 | + /// ERRORS /// |
| 13 | +@@ -93,33 +95,27 @@ |
| 14 | + /// @param _list The list to search in. |
| 15 | + /// @param _id The address of the account. |
| 16 | + /// @param _value The value of the account. |
| 17 | +- /// @param _maxIterations The max number of iterations. |
| 18 | + function insertSorted( |
| 19 | + List storage _list, |
| 20 | + address _id, |
| 21 | +- uint256 _value, |
| 22 | +- uint256 _maxIterations |
| 23 | ++ uint256 _value |
| 24 | + ) internal { |
| 25 | + if (_value == 0) revert ValueIsZero(); |
| 26 | + if (_id == address(0)) revert AddressIsZero(); |
| 27 | + if (_list.accounts[_id].value != 0) revert AccountAlreadyInserted(); |
| 28 | + |
| 29 | +- uint256 numberOfIterations; |
| 30 | +- address next = _list.head; // If not added at the end of the list `_id` will be inserted before `next`. |
| 31 | ++ _list.insertedAfter = address(0); |
| 32 | ++ address next = _list.head; // `_id` will be inserted before `next`. |
| 33 | + |
| 34 | +- while ( |
| 35 | +- numberOfIterations < _maxIterations && |
| 36 | +- next != address(0) && |
| 37 | +- _list.accounts[next].value >= _value |
| 38 | +- ) { |
| 39 | ++ while (next != address(0) && _list.accounts[next].value >= _value) { |
| 40 | ++ _list.insertedAfter = next; |
| 41 | + next = _list.accounts[next].next; |
| 42 | +- unchecked { |
| 43 | +- ++numberOfIterations; |
| 44 | +- } |
| 45 | + } |
| 46 | + |
| 47 | ++ _list.insertedBefore = next; |
| 48 | ++ |
| 49 | + // Account is not the new tail. |
| 50 | +- if (numberOfIterations < _maxIterations && next != address(0)) { |
| 51 | ++ if (next != address(0)) { |
| 52 | + // Account is the new head. |
| 53 | + if (next == _list.head) { |
| 54 | + _list.accounts[_id] = Account({prev: address(0), next: next, value: _value}); |
| 55 | +diff -ruN MockDLL.sol MockDLL.sol |
| 56 | +--- MockDLL.sol 1970-01-01 01:00:00.000000000 +0100 |
| 57 | ++++ MockDLL.sol 2022-11-11 11:27:17.368989154 +0100 |
| 58 | +@@ -0,0 +1,91 @@ |
| 59 | ++// SPDX-License-Identifier: GNU AGPLv3 |
| 60 | ++pragma solidity ^0.8.0; |
| 61 | ++ |
| 62 | ++import "./DoubleLinkedList.sol"; |
| 63 | ++ |
| 64 | ++contract MockDLL { |
| 65 | ++ using DoubleLinkedList for DoubleLinkedList.List; |
| 66 | ++ |
| 67 | ++ // VERIFICATION INTERFACE |
| 68 | ++ |
| 69 | ++ DoubleLinkedList.List public dll; |
| 70 | ++ |
| 71 | ++ uint256 internal dummy_state_variable; |
| 72 | ++ |
| 73 | ++ function dummy_state_modifying_function() public { |
| 74 | ++ // to fix a CVL error when only one function is accessible |
| 75 | ++ dummy_state_variable = 1; |
| 76 | ++ } |
| 77 | ++ |
| 78 | ++ function getValueOf(address _id) public view returns (uint256) { |
| 79 | ++ return dll.getValueOf(_id); |
| 80 | ++ } |
| 81 | ++ |
| 82 | ++ function getHead() public view returns (address) { |
| 83 | ++ return dll.getHead(); |
| 84 | ++ } |
| 85 | ++ |
| 86 | ++ function getTail() public view returns (address) { |
| 87 | ++ return dll.getTail(); |
| 88 | ++ } |
| 89 | ++ |
| 90 | ++ function getNext(address _id) public view returns (address) { |
| 91 | ++ return dll.getNext(_id); |
| 92 | ++ } |
| 93 | ++ |
| 94 | ++ function getPrev(address _id) public view returns (address) { |
| 95 | ++ return dll.getPrev(_id); |
| 96 | ++ } |
| 97 | ++ |
| 98 | ++ function remove(address _id) public { |
| 99 | ++ dll.remove(_id); |
| 100 | ++ } |
| 101 | ++ |
| 102 | ++ function insertSorted(address _id, uint256 _value) public { |
| 103 | ++ dll.insertSorted(_id, _value); |
| 104 | ++ } |
| 105 | ++ |
| 106 | ++ // SPECIFICATION HELPERS |
| 107 | ++ |
| 108 | ++ function getInsertedAfter() public view returns (address) { |
| 109 | ++ return dll.insertedAfter; |
| 110 | ++ } |
| 111 | ++ |
| 112 | ++ function getInsertedBefore() public view returns (address) { |
| 113 | ++ return dll.insertedBefore; |
| 114 | ++ } |
| 115 | ++ |
| 116 | ++ function getLength() internal view returns (uint256) { |
| 117 | ++ uint256 len; |
| 118 | ++ for (address current = getHead(); current != address(0); current = getNext(current)) len++; |
| 119 | ++ return len; |
| 120 | ++ } |
| 121 | ++ |
| 122 | ++ function linkBetween(address _start, address _end) internal view returns (bool, address) { |
| 123 | ++ if (_start == _end) return (true, address(0)); |
| 124 | ++ for (uint256 maxIter = getLength(); maxIter > 0; maxIter--) { |
| 125 | ++ address next = getNext(_start); |
| 126 | ++ if (next == _end) return (true, _start); |
| 127 | ++ _start = next; |
| 128 | ++ } |
| 129 | ++ return (false, address(0)); |
| 130 | ++ } |
| 131 | ++ |
| 132 | ++ function isForwardLinkedBetween(address _start, address _end) public view returns (bool ret) { |
| 133 | ++ (ret, ) = linkBetween(_start, _end); |
| 134 | ++ } |
| 135 | ++ |
| 136 | ++ function getPreceding(address _end) public view returns (address last) { |
| 137 | ++ (, last) = linkBetween(getHead(), _end); |
| 138 | ++ } |
| 139 | ++ |
| 140 | ++ function isDecrSortedFrom(address _start) public view returns (bool) { |
| 141 | ++ for (uint256 maxIter = getLength(); maxIter > 0; maxIter--) { |
| 142 | ++ address next = getNext(_start); |
| 143 | ++ if (next == address(0)) return true; |
| 144 | ++ if (getValueOf(_start) < getValueOf(next)) return false; |
| 145 | ++ _start = getNext(_start); |
| 146 | ++ } |
| 147 | ++ return true; |
| 148 | ++ } |
| 149 | ++} |
0 commit comments