github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/dispute/lib/LibPosition.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity ^0.8.15; 3 4 import "src/libraries/DisputeTypes.sol"; 5 import "src/libraries/DisputeErrors.sol"; 6 7 /// @title LibPosition 8 /// @notice This library contains helper functions for working with the `Position` type. 9 library LibPosition { 10 /// @notice Computes a generalized index (2^{depth} + indexAtDepth). 11 /// @param _depth The depth of the position. 12 /// @param _indexAtDepth The index at the depth of the position. 13 /// @return position_ The computed generalized index. 14 function wrap(uint64 _depth, uint64 _indexAtDepth) internal pure returns (Position position_) { 15 assembly { 16 // gindex = 2^{_depth} + _indexAtDepth 17 position_ := add(shl(_depth, 1), _indexAtDepth) 18 } 19 } 20 21 /// @notice Pulls the `depth` out of a `Position` type. 22 /// @param _position The generalized index to get the `depth` of. 23 /// @return depth_ The `depth` of the `position` gindex. 24 /// @custom:attribution Solady <https://github.com/Vectorized/Solady> 25 function depth(Position _position) internal pure returns (uint64 depth_) { 26 // Return the most significant bit offset, which signifies the depth of the gindex. 27 assembly { 28 depth_ := or(depth_, shl(6, lt(0xffffffffffffffff, shr(depth_, _position)))) 29 depth_ := or(depth_, shl(5, lt(0xffffffff, shr(depth_, _position)))) 30 31 // For the remaining 32 bits, use a De Bruijn lookup. 32 _position := shr(depth_, _position) 33 _position := or(_position, shr(1, _position)) 34 _position := or(_position, shr(2, _position)) 35 _position := or(_position, shr(4, _position)) 36 _position := or(_position, shr(8, _position)) 37 _position := or(_position, shr(16, _position)) 38 39 depth_ := 40 or( 41 depth_, 42 byte( 43 shr(251, mul(_position, shl(224, 0x07c4acdd))), 44 0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f 45 ) 46 ) 47 } 48 } 49 50 /// @notice Pulls the `indexAtDepth` out of a `Position` type. 51 /// The `indexAtDepth` is the left/right index of a position at a specific depth within 52 /// the binary tree, starting from index 0. For example, at gindex 2, the `depth` = 1 53 /// and the `indexAtDepth` = 0. 54 /// @param _position The generalized index to get the `indexAtDepth` of. 55 /// @return indexAtDepth_ The `indexAtDepth` of the `position` gindex. 56 function indexAtDepth(Position _position) internal pure returns (uint64 indexAtDepth_) { 57 // Return bits p_{msb-1}...p_{0}. This effectively pulls the 2^{depth} out of the gindex, 58 // leaving only the `indexAtDepth`. 59 uint256 msb = depth(_position); 60 assembly { 61 indexAtDepth_ := sub(_position, shl(msb, 1)) 62 } 63 } 64 65 /// @notice Get the left child of `_position`. 66 /// @param _position The position to get the left position of. 67 /// @return left_ The position to the left of `position`. 68 function left(Position _position) internal pure returns (Position left_) { 69 assembly { 70 left_ := shl(1, _position) 71 } 72 } 73 74 /// @notice Get the right child of `_position` 75 /// @param _position The position to get the right position of. 76 /// @return right_ The position to the right of `position`. 77 function right(Position _position) internal pure returns (Position right_) { 78 assembly { 79 right_ := or(1, shl(1, _position)) 80 } 81 } 82 83 /// @notice Get the parent position of `_position`. 84 /// @param _position The position to get the parent position of. 85 /// @return parent_ The parent position of `position`. 86 function parent(Position _position) internal pure returns (Position parent_) { 87 assembly { 88 parent_ := shr(1, _position) 89 } 90 } 91 92 /// @notice Get the deepest, right most gindex relative to the `position`. This is equivalent to 93 /// calling `right` on a position until the maximum depth is reached. 94 /// @param _position The position to get the relative deepest, right most gindex of. 95 /// @param _maxDepth The maximum depth of the game. 96 /// @return rightIndex_ The deepest, right most gindex relative to the `position`. 97 function rightIndex(Position _position, uint256 _maxDepth) internal pure returns (Position rightIndex_) { 98 uint256 msb = depth(_position); 99 assembly { 100 let remaining := sub(_maxDepth, msb) 101 rightIndex_ := or(shl(remaining, _position), sub(shl(remaining, 1), 1)) 102 } 103 } 104 105 /// @notice Get the deepest, right most trace index relative to the `position`. This is 106 /// equivalent to calling `right` on a position until the maximum depth is reached and 107 /// then finding its index at depth. 108 /// @param _position The position to get the relative trace index of. 109 /// @param _maxDepth The maximum depth of the game. 110 /// @return traceIndex_ The trace index relative to the `position`. 111 function traceIndex(Position _position, uint256 _maxDepth) internal pure returns (uint256 traceIndex_) { 112 uint256 msb = depth(_position); 113 assembly { 114 let remaining := sub(_maxDepth, msb) 115 traceIndex_ := sub(or(shl(remaining, _position), sub(shl(remaining, 1), 1)), shl(_maxDepth, 1)) 116 } 117 } 118 119 /// @notice Gets the position of the highest ancestor of `_position` that commits to the same 120 /// trace index. 121 /// @param _position The position to get the highest ancestor of. 122 /// @return ancestor_ The highest ancestor of `position` that commits to the same trace index. 123 function traceAncestor(Position _position) internal pure returns (Position ancestor_) { 124 // Create a field with only the lowest unset bit of `_position` set. 125 Position lsb; 126 assembly { 127 lsb := and(not(_position), add(_position, 1)) 128 } 129 // Find the index of the lowest unset bit within the field. 130 uint256 msb = depth(lsb); 131 // The highest ancestor that commits to the same trace index is the original position 132 // shifted right by the index of the lowest unset bit. 133 assembly { 134 let a := shr(msb, _position) 135 // Bound the ancestor to the minimum gindex, 1. 136 ancestor_ := or(a, iszero(a)) 137 } 138 } 139 140 /// @notice Gets the position of the highest ancestor of `_position` that commits to the same 141 /// trace index, while still being below `_upperBoundExclusive`. 142 /// @param _position The position to get the highest ancestor of. 143 /// @param _upperBoundExclusive The exclusive upper depth bound, used to inform where to stop in order 144 /// to not escape a sub-tree. 145 /// @return ancestor_ The highest ancestor of `position` that commits to the same trace index. 146 function traceAncestorBounded( 147 Position _position, 148 uint256 _upperBoundExclusive 149 ) 150 internal 151 pure 152 returns (Position ancestor_) 153 { 154 // This function only works for positions that are below the upper bound. 155 if (_position.depth() <= _upperBoundExclusive) revert ClaimAboveSplit(); 156 157 // Grab the global trace ancestor. 158 ancestor_ = traceAncestor(_position); 159 160 // If the ancestor is above or at the upper bound, shift it to be below the upper bound. 161 // This should be a special case that only covers positions that commit to the final leaf 162 // in a sub-tree. 163 if (ancestor_.depth() <= _upperBoundExclusive) { 164 ancestor_ = ancestor_.rightIndex(_upperBoundExclusive + 1); 165 } 166 } 167 168 /// @notice Get the move position of `_position`, which is the left child of: 169 /// 1. `_position` if `_isAttack` is true. 170 /// 2. `_position | 1` if `_isAttack` is false. 171 /// @param _position The position to get the relative attack/defense position of. 172 /// @param _isAttack Whether or not the move is an attack move. 173 /// @return move_ The move position relative to `position`. 174 function move(Position _position, bool _isAttack) internal pure returns (Position move_) { 175 assembly { 176 move_ := shl(1, or(iszero(_isAttack), _position)) 177 } 178 } 179 180 /// @notice Get the value of a `Position` type in the form of the underlying uint128. 181 /// @param _position The position to get the value of. 182 /// @return raw_ The value of the `position` as a uint128 type. 183 function raw(Position _position) internal pure returns (uint128 raw_) { 184 assembly { 185 raw_ := _position 186 } 187 } 188 }