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  }