github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/cannon/PreimageOracle.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity 0.8.15;
     3  
     4  import { IPreimageOracle } from "./interfaces/IPreimageOracle.sol";
     5  import { ISemver } from "src/universal/ISemver.sol";
     6  import { PreimageKeyLib } from "./PreimageKeyLib.sol";
     7  import { LibKeccak } from "@lib-keccak/LibKeccak.sol";
     8  import "src/cannon/libraries/CannonErrors.sol";
     9  import "src/cannon/libraries/CannonTypes.sol";
    10  
    11  /// @title PreimageOracle
    12  /// @notice A contract for storing permissioned pre-images.
    13  /// @custom:attribution Solady <https://github.com/Vectorized/solady/blob/main/src/utils/MerkleProofLib.sol#L13-L43>
    14  /// @custom:attribution Beacon Deposit Contract <0x00000000219ab540356cbb839cbe05303d7705fa>
    15  contract PreimageOracle is IPreimageOracle, ISemver {
    16      ////////////////////////////////////////////////////////////////
    17      //                   Constants & Immutables                   //
    18      ////////////////////////////////////////////////////////////////
    19  
    20      /// @notice The duration of the large preimage proposal challenge period.
    21      uint256 internal immutable CHALLENGE_PERIOD;
    22      /// @notice The minimum size of a preimage that can be proposed in the large preimage path.
    23      uint256 internal immutable MIN_LPP_SIZE_BYTES;
    24      /// @notice The minimum bond size for large preimage proposals.
    25      uint256 public constant MIN_BOND_SIZE = 0.25 ether;
    26      /// @notice The depth of the keccak256 merkle tree. Supports up to 65,536 keccak blocks, or ~8.91MB preimages.
    27      uint256 public constant KECCAK_TREE_DEPTH = 16;
    28      /// @notice The maximum number of keccak blocks that can fit into the merkle tree.
    29      uint256 public constant MAX_LEAF_COUNT = 2 ** KECCAK_TREE_DEPTH - 1;
    30  
    31      /// @notice The semantic version of the Preimage Oracle contract.
    32      /// @custom:semver 0.1.0
    33      string public constant version = "0.1.0";
    34  
    35      ////////////////////////////////////////////////////////////////
    36      //                 Authorized Preimage Parts                  //
    37      ////////////////////////////////////////////////////////////////
    38  
    39      /// @notice Mapping of pre-image keys to pre-image lengths.
    40      mapping(bytes32 => uint256) public preimageLengths;
    41      /// @notice Mapping of pre-image keys to pre-image offsets to pre-image parts.
    42      mapping(bytes32 => mapping(uint256 => bytes32)) public preimageParts;
    43      /// @notice Mapping of pre-image keys to pre-image part offsets to preimage preparedness.
    44      mapping(bytes32 => mapping(uint256 => bool)) public preimagePartOk;
    45  
    46      ////////////////////////////////////////////////////////////////
    47      //                  Large Preimage Proposals                  //
    48      ////////////////////////////////////////////////////////////////
    49  
    50      /// @notice A raw leaf of the large preimage proposal merkle tree.
    51      struct Leaf {
    52          /// @notice The input absorbed for the block, exactly 136 bytes.
    53          bytes input;
    54          /// @notice The index of the block in the absorption process.
    55          uint256 index;
    56          /// @notice The hash of the internal state after absorbing the input.
    57          bytes32 stateCommitment;
    58      }
    59  
    60      /// @notice Unpacked keys for large preimage proposals.
    61      struct LargePreimageProposalKeys {
    62          /// @notice The claimant of the large preimage proposal.
    63          address claimant;
    64          /// @notice The UUID of the large preimage proposal.
    65          uint256 uuid;
    66      }
    67  
    68      /// @notice Static padding hashes. These values are persisted in storage, but are entirely immutable
    69      ///         after the constructor's execution.
    70      bytes32[KECCAK_TREE_DEPTH] public zeroHashes;
    71      /// @notice Append-only array of large preimage proposals for off-chain reference.
    72      LargePreimageProposalKeys[] public proposals;
    73      /// @notice Mapping of claimants to proposal UUIDs to the current branch path of the merkleization process.
    74      mapping(address => mapping(uint256 => bytes32[KECCAK_TREE_DEPTH])) public proposalBranches;
    75      /// @notice Mapping of claimants to proposal UUIDs to the timestamp of creation of the proposal as well as the
    76      /// challenged status.
    77      mapping(address => mapping(uint256 => LPPMetaData)) public proposalMetadata;
    78      /// @notice Mapping of claimants to proposal UUIDs to bond amounts.
    79      mapping(address => mapping(uint256 => uint256)) public proposalBonds;
    80      /// @notice Mapping of claimants to proposal UUIDs to the preimage part picked up during the absorbtion process.
    81      mapping(address => mapping(uint256 => bytes32)) public proposalParts;
    82      /// @notice Mapping of claimants to proposal UUIDs to blocks which leaves were added to the merkle tree.
    83      mapping(address => mapping(uint256 => uint64[])) public proposalBlocks;
    84  
    85      ////////////////////////////////////////////////////////////////
    86      //                        Constructor                         //
    87      ////////////////////////////////////////////////////////////////
    88  
    89      constructor(uint256 _minProposalSize, uint256 _challengePeriod) {
    90          MIN_LPP_SIZE_BYTES = _minProposalSize;
    91          CHALLENGE_PERIOD = _challengePeriod;
    92  
    93          // Compute hashes in empty sparse Merkle tree. The first hash is not set, and kept as zero as the identity.
    94          for (uint256 height = 0; height < KECCAK_TREE_DEPTH - 1; height++) {
    95              zeroHashes[height + 1] = keccak256(abi.encodePacked(zeroHashes[height], zeroHashes[height]));
    96          }
    97      }
    98  
    99      ////////////////////////////////////////////////////////////////
   100      //             Standard Preimage Route (External)             //
   101      ////////////////////////////////////////////////////////////////
   102  
   103      /// @inheritdoc IPreimageOracle
   104      function readPreimage(bytes32 _key, uint256 _offset) external view returns (bytes32 dat_, uint256 datLen_) {
   105          require(preimagePartOk[_key][_offset], "pre-image must exist");
   106  
   107          // Calculate the length of the pre-image data
   108          // Add 8 for the length-prefix part
   109          datLen_ = 32;
   110          uint256 length = preimageLengths[_key];
   111          if (_offset + 32 >= length + 8) {
   112              datLen_ = length + 8 - _offset;
   113          }
   114  
   115          // Retrieve the pre-image data
   116          dat_ = preimageParts[_key][_offset];
   117      }
   118  
   119      /// @inheritdoc IPreimageOracle
   120      function loadLocalData(
   121          uint256 _ident,
   122          bytes32 _localContext,
   123          bytes32 _word,
   124          uint256 _size,
   125          uint256 _partOffset
   126      )
   127          external
   128          returns (bytes32 key_)
   129      {
   130          // Compute the localized key from the given local identifier.
   131          key_ = PreimageKeyLib.localizeIdent(_ident, _localContext);
   132  
   133          // Revert if the given part offset is not within bounds.
   134          if (_partOffset > _size + 8 || _size > 32) {
   135              revert PartOffsetOOB();
   136          }
   137  
   138          // Prepare the local data part at the given offset
   139          bytes32 part;
   140          assembly {
   141              // Clean the memory in [0x20, 0x40)
   142              mstore(0x20, 0x00)
   143  
   144              // Store the full local data in scratch space.
   145              mstore(0x00, shl(192, _size))
   146              mstore(0x08, _word)
   147  
   148              // Prepare the local data part at the requested offset.
   149              part := mload(_partOffset)
   150          }
   151  
   152          // Store the first part with `_partOffset`.
   153          preimagePartOk[key_][_partOffset] = true;
   154          preimageParts[key_][_partOffset] = part;
   155          // Assign the length of the preimage at the localized key.
   156          preimageLengths[key_] = _size;
   157      }
   158  
   159      /// @inheritdoc IPreimageOracle
   160      function loadKeccak256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external {
   161          uint256 size;
   162          bytes32 key;
   163          bytes32 part;
   164          assembly {
   165              // len(sig) + len(partOffset) + len(preimage offset) = 4 + 32 + 32 = 0x44
   166              size := calldataload(0x44)
   167  
   168              // revert if part offset >= size+8 (i.e. parts must be within bounds)
   169              if iszero(lt(_partOffset, add(size, 8))) {
   170                  // Store "PartOffsetOOB()"
   171                  mstore(0x00, 0xfe254987)
   172                  // Revert with "PartOffsetOOB()"
   173                  revert(0x1c, 0x04)
   174              }
   175              // we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory.
   176              let ptr := 0x80
   177              // put size as big-endian uint64 at start of pre-image
   178              mstore(ptr, shl(192, size))
   179              ptr := add(ptr, 0x08)
   180              // copy preimage payload into memory so we can hash and read it.
   181              calldatacopy(ptr, _preimage.offset, size)
   182              // Note that it includes the 8-byte big-endian uint64 length prefix.
   183              // this will be zero-padded at the end, since memory at end is clean.
   184              part := mload(add(sub(ptr, 0x08), _partOffset))
   185              let h := keccak256(ptr, size) // compute preimage keccak256 hash
   186              // mask out prefix byte, replace with type 2 byte
   187              key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x02))
   188          }
   189          preimagePartOk[key][_partOffset] = true;
   190          preimageParts[key][_partOffset] = part;
   191          preimageLengths[key] = size;
   192      }
   193  
   194      /// @inheritdoc IPreimageOracle
   195      function loadSha256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external {
   196          uint256 size;
   197          bytes32 key;
   198          bytes32 part;
   199          assembly {
   200              // len(sig) + len(partOffset) + len(preimage offset) = 4 + 32 + 32 = 0x44
   201              size := calldataload(0x44)
   202  
   203              // revert if part offset >= size+8 (i.e. parts must be within bounds)
   204              if iszero(lt(_partOffset, add(size, 8))) {
   205                  // Store "PartOffsetOOB()"
   206                  mstore(0, 0xfe254987)
   207                  // Revert with "PartOffsetOOB()"
   208                  revert(0x1c, 4)
   209              }
   210              // we leave solidity slots 0x40 and 0x60 untouched,
   211              // and everything after as scratch-memory.
   212              let ptr := 0x80
   213              // put size as big-endian uint64 at start of pre-image
   214              mstore(ptr, shl(192, size))
   215              ptr := add(ptr, 8)
   216              // copy preimage payload into memory so we can hash and read it.
   217              calldatacopy(ptr, _preimage.offset, size)
   218              // Note that it includes the 8-byte big-endian uint64 length prefix.
   219              // this will be zero-padded at the end, since memory at end is clean.
   220              part := mload(add(sub(ptr, 8), _partOffset))
   221  
   222              // compute SHA2-256 hash with pre-compile
   223              let success :=
   224                  staticcall(
   225                      gas(), // Forward all available gas
   226                      0x02, // Address of SHA-256 precompile
   227                      ptr, // Start of input data in memory
   228                      size, // Size of input data
   229                      0, // Store output in scratch memory
   230                      0x20 // Output is always 32 bytes
   231                  )
   232              // Check if the staticcall succeeded
   233              if iszero(success) { revert(0, 0) }
   234              let h := mload(0) // get return data
   235              // mask out prefix byte, replace with type 4 byte
   236              key := or(and(h, not(shl(248, 0xFF))), shl(248, 4))
   237          }
   238          preimagePartOk[key][_partOffset] = true;
   239          preimageParts[key][_partOffset] = part;
   240          preimageLengths[key] = size;
   241      }
   242  
   243      /// @inheritdoc IPreimageOracle
   244      function loadBlobPreimagePart(
   245          uint256 _z,
   246          uint256 _y,
   247          bytes calldata _commitment,
   248          bytes calldata _proof,
   249          uint256 _partOffset
   250      )
   251          external
   252      {
   253          bytes32 key;
   254          bytes32 part;
   255          assembly {
   256              // Compute the versioned hash. The SHA2 hash of the 48 byte commitment is masked with the version byte,
   257              // which is currently 1. https://eips.ethereum.org/EIPS/eip-4844#parameters
   258              // SAFETY: We're only reading 48 bytes from `_commitment` into scratch space, so we're not reading into the
   259              //         free memory ptr region. Since the exact number of btyes that is copied into scratch space is
   260              //         the same size as the hash input, there's no concern of dirty memory being read into the hash
   261              //         input.
   262              calldatacopy(0x00, _commitment.offset, 0x30)
   263              let success := staticcall(gas(), 0x02, 0x00, 0x30, 0x00, 0x20)
   264              if iszero(success) {
   265                  // Store the "ShaFailed()" error selector.
   266                  mstore(0x00, 0xf9112969)
   267                  // revert with "ShaFailed()"
   268                  revert(0x1C, 0x04)
   269              }
   270              // Set the `VERSIONED_HASH_VERSION_KZG` byte = 1 in the high-order byte of the hash.
   271              let versionedHash := or(and(mload(0x00), not(shl(248, 0xFF))), shl(248, 0x01))
   272  
   273              // we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory.
   274              let ptr := 0x80
   275  
   276              // Load the inputs for the point evaluation precompile into memory. The inputs to the point evaluation
   277              // precompile are packed, and not supposed to be ABI-encoded.
   278              mstore(ptr, versionedHash)
   279              mstore(add(ptr, 0x20), _z)
   280              mstore(add(ptr, 0x40), _y)
   281              calldatacopy(add(ptr, 0x60), _commitment.offset, 0x30)
   282              calldatacopy(add(ptr, 0x90), _proof.offset, 0x30)
   283  
   284              // Verify the KZG proof by calling the point evaluation precompile. If the proof is invalid, the precompile
   285              // will revert.
   286              success :=
   287                  staticcall(
   288                      gas(), // forward all gas
   289                      0x0A, // point evaluation precompile address
   290                      ptr, // input ptr
   291                      0xC0, // input size = 192 bytes
   292                      0x00, // output ptr
   293                      0x00 // output size
   294                  )
   295              if iszero(success) {
   296                  // Store the "InvalidProof()" error selector.
   297                  mstore(0x00, 0x09bde339)
   298                  // revert with "InvalidProof()"
   299                  revert(0x1C, 0x04)
   300              }
   301  
   302              // revert if part offset >= 32+8 (i.e. parts must be within bounds)
   303              if iszero(lt(_partOffset, 0x28)) {
   304                  // Store "PartOffsetOOB()"
   305                  mstore(0x00, 0xfe254987)
   306                  // Revert with "PartOffsetOOB()"
   307                  revert(0x1C, 0x04)
   308              }
   309              // Clean the word at `ptr + 0x28` to ensure that data out of bounds of the preimage is zero, if the part
   310              // offset requires a partial read.
   311              mstore(add(ptr, 0x28), 0x00)
   312              // put size (32) as a big-endian uint64 at start of pre-image
   313              mstore(ptr, shl(192, 0x20))
   314              // copy preimage payload into memory so we can hash and read it.
   315              mstore(add(ptr, 0x08), _y)
   316              // Note that it includes the 8-byte big-endian uint64 length prefix. This will be zero-padded at the end,
   317              // since memory at end is guaranteed to be clean.
   318              part := mload(add(ptr, _partOffset))
   319  
   320              // Compute the key: `keccak256(commitment ++ z)`. Since the exact number of btyes that is copied into
   321              // scratch space is the same size as the hash input, there's no concern of dirty memory being read into
   322              // the hash input.
   323              calldatacopy(ptr, _commitment.offset, 0x30)
   324              mstore(add(ptr, 0x30), _z)
   325              let h := keccak256(ptr, 0x50)
   326              // mask out prefix byte, replace with type 5 byte
   327              key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x05))
   328          }
   329          preimagePartOk[key][_partOffset] = true;
   330          preimageParts[key][_partOffset] = part;
   331          preimageLengths[key] = 32;
   332      }
   333  
   334      /// @inheritdoc IPreimageOracle
   335      function loadPrecompilePreimagePart(uint256 _partOffset, address _precompile, bytes calldata _input) external {
   336          bytes32 res;
   337          bytes32 key;
   338          bytes32 part;
   339          uint256 size;
   340          assembly {
   341              // we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory.
   342              let ptr := 0x80
   343  
   344              // copy precompile address and input into memory
   345              // len(sig) + len(_partOffset) + address-offset-in-slot
   346              calldatacopy(ptr, 48, 20)
   347              calldatacopy(add(20, ptr), _input.offset, _input.length)
   348              // compute the hash
   349              let h := keccak256(ptr, add(20, _input.length))
   350              // mask out prefix byte, replace with type 6 byte
   351              key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x06))
   352  
   353              // Call the precompile to get the result.
   354              res :=
   355                  staticcall(
   356                      gas(), // forward all gas
   357                      _precompile,
   358                      add(20, ptr), // input ptr
   359                      _input.length,
   360                      0x0, // Unused as we don't copy anything
   361                      0x00 // don't copy anything
   362                  )
   363  
   364              size := add(1, returndatasize())
   365              // revert if part offset >= size+8 (i.e. parts must be within bounds)
   366              if iszero(lt(_partOffset, add(size, 8))) {
   367                  // Store "PartOffsetOOB()"
   368                  mstore(0, 0xfe254987)
   369                  // Revert with "PartOffsetOOB()"
   370                  revert(0x1c, 4)
   371              }
   372  
   373              // Reuse the `ptr` to store the preimage part: <sizePrefix ++ precompileStatus ++ returrnData>
   374              // put size as big-endian uint64 at start of pre-image
   375              mstore(ptr, shl(192, size))
   376              ptr := add(ptr, 0x08)
   377  
   378              // write precompile result status to the first byte of `ptr`
   379              mstore8(ptr, res)
   380              // write precompile return data to the rest of `ptr`
   381              returndatacopy(add(ptr, 0x01), 0x0, returndatasize())
   382  
   383              // compute part given ofset
   384              part := mload(add(sub(ptr, 0x08), _partOffset))
   385          }
   386          preimagePartOk[key][_partOffset] = true;
   387          preimageParts[key][_partOffset] = part;
   388          preimageLengths[key] = size;
   389      }
   390  
   391      ////////////////////////////////////////////////////////////////
   392      //            Large Preimage Proposals (External)             //
   393      ////////////////////////////////////////////////////////////////
   394  
   395      /// @notice Returns the length of the `proposals` array
   396      function proposalCount() external view returns (uint256 count_) {
   397          count_ = proposals.length;
   398      }
   399  
   400      /// @notice Returns the length of the array with the block numbers of `addLeavesLPP` calls for a given large
   401      ///         preimage proposal.
   402      function proposalBlocksLen(address _claimant, uint256 _uuid) external view returns (uint256 len_) {
   403          len_ = proposalBlocks[_claimant][_uuid].length;
   404      }
   405  
   406      /// @notice Returns the length of the large preimage proposal challenge period.
   407      function challengePeriod() external view returns (uint256 challengePeriod_) {
   408          challengePeriod_ = CHALLENGE_PERIOD;
   409      }
   410  
   411      /// @notice Returns the minimum size (in bytes) of a large preimage proposal.
   412      function minProposalSize() external view returns (uint256 minProposalSize_) {
   413          minProposalSize_ = MIN_LPP_SIZE_BYTES;
   414      }
   415  
   416      /// @notice Initialize a large preimage proposal. Must be called before adding any leaves.
   417      function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) external payable {
   418          // The bond provided must be at least `MIN_BOND_SIZE`.
   419          if (msg.value < MIN_BOND_SIZE) revert InsufficientBond();
   420  
   421          // The caller of `addLeavesLPP` must be an EOA, so that the call inputs are always available in block bodies.
   422          if (msg.sender != tx.origin) revert NotEOA();
   423  
   424          // The part offset must be within the bounds of the claimed size + 8.
   425          if (_partOffset >= _claimedSize + 8) revert PartOffsetOOB();
   426  
   427          // The claimed size must be at least `MIN_LPP_SIZE_BYTES`.
   428          if (_claimedSize < MIN_LPP_SIZE_BYTES) revert InvalidInputSize();
   429  
   430          // Initialize the proposal metadata.
   431          LPPMetaData metaData = proposalMetadata[msg.sender][_uuid];
   432          proposalMetadata[msg.sender][_uuid] = metaData.setPartOffset(_partOffset).setClaimedSize(_claimedSize);
   433          proposals.push(LargePreimageProposalKeys(msg.sender, _uuid));
   434  
   435          // Assign the bond to the proposal.
   436          proposalBonds[msg.sender][_uuid] = msg.value;
   437      }
   438  
   439      /// @notice Adds a contiguous list of keccak state matrices to the merkle tree.
   440      function addLeavesLPP(
   441          uint256 _uuid,
   442          uint256 _inputStartBlock,
   443          bytes calldata _input,
   444          bytes32[] calldata _stateCommitments,
   445          bool _finalize
   446      )
   447          external
   448      {
   449          // If we're finalizing, pad the input for the submitter. If not, copy the input into memory verbatim.
   450          bytes memory input;
   451          if (_finalize) {
   452              input = LibKeccak.pad(_input);
   453          } else {
   454              input = _input;
   455          }
   456  
   457          // Pull storage variables onto the stack / into memory for operations.
   458          bytes32[KECCAK_TREE_DEPTH] memory branch = proposalBranches[msg.sender][_uuid];
   459          LPPMetaData metaData = proposalMetadata[msg.sender][_uuid];
   460          uint256 blocksProcessed = metaData.blocksProcessed();
   461  
   462          // The caller of `addLeavesLPP` must be an EOA.
   463          if (msg.sender != tx.origin) revert NotEOA();
   464  
   465          // Revert if the proposal has not been initialized. 0-size preimages are *not* allowed.
   466          if (metaData.claimedSize() == 0) revert NotInitialized();
   467  
   468          // Revert if the proposal has already been finalized. No leaves can be added after this point.
   469          if (metaData.timestamp() != 0) revert AlreadyFinalized();
   470  
   471          // Revert if the starting block is not the next block to be added. This is to aid submitters in ensuring that
   472          // they don't corrupt an in-progress proposal by submitting input out of order.
   473          if (blocksProcessed != _inputStartBlock) revert WrongStartingBlock();
   474  
   475          // Attempt to extract the preimage part from the input data, if the part offset is present in the current
   476          // chunk of input. This function has side effects, and will persist the preimage part to the caller's large
   477          // preimage proposal storage if the part offset is present in the input data.
   478          _extractPreimagePart(_input, _uuid, _finalize, metaData);
   479  
   480          assembly {
   481              let inputLen := mload(input)
   482              let inputPtr := add(input, 0x20)
   483  
   484              // The input length must be a multiple of 136 bytes
   485              // The input lenth / 136 must be equal to the number of state commitments.
   486              if or(mod(inputLen, 136), iszero(eq(_stateCommitments.length, div(inputLen, 136)))) {
   487                  // Store "InvalidInputSize()" error selector
   488                  mstore(0x00, 0x7b1daf1)
   489                  revert(0x1C, 0x04)
   490              }
   491  
   492              // Allocate a hashing buffer the size of the leaf preimage.
   493              let hashBuf := mload(0x40)
   494              mstore(0x40, add(hashBuf, 0xC8))
   495  
   496              for { let i := 0 } lt(i, inputLen) { i := add(i, 136) } {
   497                  // Copy the leaf preimage into the hashing buffer.
   498                  let inputStartPtr := add(inputPtr, i)
   499                  mstore(hashBuf, mload(inputStartPtr))
   500                  mstore(add(hashBuf, 0x20), mload(add(inputStartPtr, 0x20)))
   501                  mstore(add(hashBuf, 0x40), mload(add(inputStartPtr, 0x40)))
   502                  mstore(add(hashBuf, 0x60), mload(add(inputStartPtr, 0x60)))
   503                  mstore(add(hashBuf, 0x80), mload(add(inputStartPtr, 0x80)))
   504                  mstore(add(hashBuf, 136), blocksProcessed)
   505                  mstore(add(hashBuf, 168), calldataload(add(_stateCommitments.offset, shl(0x05, div(i, 136)))))
   506  
   507                  // Hash the leaf preimage to get the node to add.
   508                  let node := keccak256(hashBuf, 0xC8)
   509  
   510                  // Increment the number of blocks processed.
   511                  blocksProcessed := add(blocksProcessed, 0x01)
   512  
   513                  // Add the node to the tree.
   514                  let size := blocksProcessed
   515                  for { let height := 0x00 } lt(height, shl(0x05, KECCAK_TREE_DEPTH)) { height := add(height, 0x20) } {
   516                      if and(size, 0x01) {
   517                          mstore(add(branch, height), node)
   518                          break
   519                      }
   520  
   521                      // Hash the node at `height` in the branch and the node together.
   522                      mstore(0x00, mload(add(branch, height)))
   523                      mstore(0x20, node)
   524                      node := keccak256(0x00, 0x40)
   525                      size := shr(0x01, size)
   526                  }
   527              }
   528          }
   529  
   530          // Do not allow for posting preimages larger than the merkle tree can support. The incremental merkle tree
   531          // algorithm only supports 2**height - 1 leaves, the right most leaf must always be kept empty.
   532          // Reference: https://daejunpark.github.io/papers/deposit.pdf - Page 10, Section 5.1.
   533          if (blocksProcessed > MAX_LEAF_COUNT) revert TreeSizeOverflow();
   534  
   535          // Update the proposal metadata to include the number of blocks processed and total bytes processed.
   536          metaData = metaData.setBlocksProcessed(uint32(blocksProcessed)).setBytesProcessed(
   537              uint32(_input.length + metaData.bytesProcessed())
   538          );
   539          // If the proposal is being finalized, set the timestamp to the current block timestamp. This begins the
   540          // challenge period, which must be waited out before the proposal can be finalized.
   541          if (_finalize) {
   542              metaData = metaData.setTimestamp(uint64(block.timestamp));
   543  
   544              // If the number of bytes processed is not equal to the claimed size, the proposal cannot be finalized.
   545              if (metaData.bytesProcessed() != metaData.claimedSize()) revert InvalidInputSize();
   546          }
   547  
   548          // Perist the latest branch to storage.
   549          proposalBranches[msg.sender][_uuid] = branch;
   550          // Persist the block number that these leaves were added in. This assists off-chain observers in reconstructing
   551          // the proposal merkle tree by querying block bodies.
   552          proposalBlocks[msg.sender][_uuid].push(uint64(block.number));
   553          // Persist the updated metadata to storage.
   554          proposalMetadata[msg.sender][_uuid] = metaData;
   555      }
   556  
   557      /// @notice Challenge a keccak256 block that was committed to in the merkle tree.
   558      function challengeLPP(
   559          address _claimant,
   560          uint256 _uuid,
   561          LibKeccak.StateMatrix memory _stateMatrix,
   562          Leaf calldata _preState,
   563          bytes32[] calldata _preStateProof,
   564          Leaf calldata _postState,
   565          bytes32[] calldata _postStateProof
   566      )
   567          external
   568      {
   569          // Verify that both leaves are present in the merkle tree.
   570          bytes32 root = getTreeRootLPP(_claimant, _uuid);
   571          if (
   572              !(
   573                  _verify(_preStateProof, root, _preState.index, _hashLeaf(_preState))
   574                      && _verify(_postStateProof, root, _postState.index, _hashLeaf(_postState))
   575              )
   576          ) revert InvalidProof();
   577  
   578          // Verify that the prestate passed matches the intermediate state claimed in the leaf.
   579          if (keccak256(abi.encode(_stateMatrix)) != _preState.stateCommitment) revert InvalidPreimage();
   580  
   581          // Verify that the pre/post state are contiguous.
   582          if (_preState.index + 1 != _postState.index) revert StatesNotContiguous();
   583  
   584          // Absorb and permute the input bytes.
   585          LibKeccak.absorb(_stateMatrix, _postState.input);
   586          LibKeccak.permutation(_stateMatrix);
   587  
   588          // Verify that the post state hash doesn't match the expected hash.
   589          if (keccak256(abi.encode(_stateMatrix)) == _postState.stateCommitment) revert PostStateMatches();
   590  
   591          // Mark the keccak claim as countered.
   592          proposalMetadata[_claimant][_uuid] = proposalMetadata[_claimant][_uuid].setCountered(true);
   593  
   594          // Pay out the bond to the challenger.
   595          _payoutBond(_claimant, _uuid, msg.sender);
   596      }
   597  
   598      /// @notice Challenge the first keccak256 block that was absorbed.
   599      function challengeFirstLPP(
   600          address _claimant,
   601          uint256 _uuid,
   602          Leaf calldata _postState,
   603          bytes32[] calldata _postStateProof
   604      )
   605          external
   606      {
   607          // Verify that the leaf is present in the merkle tree.
   608          bytes32 root = getTreeRootLPP(_claimant, _uuid);
   609          if (!_verify(_postStateProof, root, _postState.index, _hashLeaf(_postState))) revert InvalidProof();
   610  
   611          // The poststate index must be 0 in order to challenge it with this function.
   612          if (_postState.index != 0) revert StatesNotContiguous();
   613  
   614          // Absorb and permute the input bytes into a fresh state matrix.
   615          LibKeccak.StateMatrix memory stateMatrix;
   616          LibKeccak.absorb(stateMatrix, _postState.input);
   617          LibKeccak.permutation(stateMatrix);
   618  
   619          // Verify that the post state hash doesn't match the expected hash.
   620          if (keccak256(abi.encode(stateMatrix)) == _postState.stateCommitment) revert PostStateMatches();
   621  
   622          // Mark the keccak claim as countered.
   623          proposalMetadata[_claimant][_uuid] = proposalMetadata[_claimant][_uuid].setCountered(true);
   624  
   625          // Pay out the bond to the challenger.
   626          _payoutBond(_claimant, _uuid, msg.sender);
   627      }
   628  
   629      /// @notice Finalize a large preimage proposal after the challenge period has passed.
   630      function squeezeLPP(
   631          address _claimant,
   632          uint256 _uuid,
   633          LibKeccak.StateMatrix memory _stateMatrix,
   634          Leaf calldata _preState,
   635          bytes32[] calldata _preStateProof,
   636          Leaf calldata _postState,
   637          bytes32[] calldata _postStateProof
   638      )
   639          external
   640      {
   641          LPPMetaData metaData = proposalMetadata[_claimant][_uuid];
   642  
   643          // Check if the proposal was countered.
   644          if (metaData.countered()) revert BadProposal();
   645  
   646          // Check if the challenge period has passed since the proposal was finalized.
   647          if (block.timestamp - metaData.timestamp() <= CHALLENGE_PERIOD) revert ActiveProposal();
   648  
   649          // Verify that both leaves are present in the merkle tree.
   650          bytes32 root = getTreeRootLPP(_claimant, _uuid);
   651          if (
   652              !(
   653                  _verify(_preStateProof, root, _preState.index, _hashLeaf(_preState))
   654                      && _verify(_postStateProof, root, _postState.index, _hashLeaf(_postState))
   655              )
   656          ) revert InvalidProof();
   657  
   658          // Verify that the prestate passed matches the intermediate state claimed in the leaf.
   659          if (keccak256(abi.encode(_stateMatrix)) != _preState.stateCommitment) revert InvalidPreimage();
   660  
   661          // Verify that the pre/post state are contiguous.
   662          if (_preState.index + 1 != _postState.index || _postState.index != metaData.blocksProcessed() - 1) {
   663              revert StatesNotContiguous();
   664          }
   665  
   666          // Absorb and permute the input bytes. We perform no final verification on the state matrix here, since the
   667          // proposal has passed the challenge period and is considered valid.
   668          LibKeccak.absorb(_stateMatrix, _postState.input);
   669          LibKeccak.permutation(_stateMatrix);
   670          bytes32 finalDigest = LibKeccak.squeeze(_stateMatrix);
   671          assembly {
   672              finalDigest := or(and(finalDigest, not(shl(248, 0xFF))), shl(248, 0x02))
   673          }
   674  
   675          // Write the preimage part to the authorized preimage parts mapping.
   676          uint256 partOffset = metaData.partOffset();
   677          preimagePartOk[finalDigest][partOffset] = true;
   678          preimageParts[finalDigest][partOffset] = proposalParts[_claimant][_uuid];
   679          preimageLengths[finalDigest] = metaData.claimedSize();
   680  
   681          // Pay out the bond to the claimant.
   682          _payoutBond(_claimant, _uuid, _claimant);
   683      }
   684  
   685      /// @notice Gets the current merkle root of the large preimage proposal tree.
   686      function getTreeRootLPP(address _owner, uint256 _uuid) public view returns (bytes32 treeRoot_) {
   687          uint256 size = proposalMetadata[_owner][_uuid].blocksProcessed();
   688          for (uint256 height = 0; height < KECCAK_TREE_DEPTH; height++) {
   689              if ((size & 1) == 1) {
   690                  treeRoot_ = keccak256(abi.encode(proposalBranches[_owner][_uuid][height], treeRoot_));
   691              } else {
   692                  treeRoot_ = keccak256(abi.encode(treeRoot_, zeroHashes[height]));
   693              }
   694              size >>= 1;
   695          }
   696      }
   697  
   698      /// @notice Attempts to persist the preimage part to the caller's large preimage proposal storage, if the preimage
   699      ///         part is present in the input data being posted.
   700      /// @param _input The portion of the preimage being posted.
   701      /// @param _uuid The UUID of the large preimage proposal.
   702      /// @param _finalize Whether or not the proposal is being finalized in the current call.
   703      /// @param _metaData The metadata of the large preimage proposal.
   704      function _extractPreimagePart(
   705          bytes calldata _input,
   706          uint256 _uuid,
   707          bool _finalize,
   708          LPPMetaData _metaData
   709      )
   710          internal
   711      {
   712          uint256 offset = _metaData.partOffset();
   713          uint256 claimedSize = _metaData.claimedSize();
   714          uint256 currentSize = _metaData.bytesProcessed();
   715  
   716          // Check if the part offset is present in the input data being posted. If it is, assign the part to the mapping.
   717          if (offset < 8 && currentSize == 0) {
   718              bytes32 preimagePart;
   719              assembly {
   720                  mstore(0x00, shl(192, claimedSize))
   721                  mstore(0x08, calldataload(_input.offset))
   722                  preimagePart := mload(offset)
   723              }
   724              proposalParts[msg.sender][_uuid] = preimagePart;
   725          } else if (offset >= 8 && (offset = offset - 8) >= currentSize && offset < currentSize + _input.length) {
   726              uint256 relativeOffset = offset - currentSize;
   727  
   728              // Revert if the full preimage part is not available in the data we're absorbing. The submitter must
   729              // supply data that contains the full preimage part so that no partial preimage parts are stored in the
   730              // oracle. Partial parts are *only* allowed at the tail end of the preimage, where no more data is available
   731              // to be absorbed.
   732              if (relativeOffset + 32 >= _input.length && !_finalize) revert PartOffsetOOB();
   733  
   734              // If the preimage part is in the data we're about to absorb, persist the part to the caller's large
   735              // preimaage metadata.
   736              bytes32 preimagePart;
   737              assembly {
   738                  preimagePart := calldataload(add(_input.offset, relativeOffset))
   739              }
   740              proposalParts[msg.sender][_uuid] = preimagePart;
   741          }
   742      }
   743  
   744      /// @notice Check if leaf` at `index` verifies against the Merkle `root` and `branch`.
   745      /// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_valid_merkle_branch
   746      function _verify(
   747          bytes32[] calldata _proof,
   748          bytes32 _root,
   749          uint256 _index,
   750          bytes32 _leaf
   751      )
   752          internal
   753          pure
   754          returns (bool isValid_)
   755      {
   756          /// @solidity memory-safe-assembly
   757          assembly {
   758              function hashTwo(a, b) -> hash {
   759                  mstore(0x00, a)
   760                  mstore(0x20, b)
   761                  hash := keccak256(0x00, 0x40)
   762              }
   763  
   764              let value := _leaf
   765              for { let i := 0x00 } lt(i, KECCAK_TREE_DEPTH) { i := add(i, 0x01) } {
   766                  let branchValue := calldataload(add(_proof.offset, shl(0x05, i)))
   767  
   768                  switch and(shr(i, _index), 0x01)
   769                  case 1 { value := hashTwo(branchValue, value) }
   770                  default { value := hashTwo(value, branchValue) }
   771              }
   772  
   773              isValid_ := eq(value, _root)
   774          }
   775      }
   776  
   777      /// @notice Pay out a proposal's bond. Reverts if the transfer fails.
   778      function _payoutBond(address _claimant, uint256 _uuid, address _to) internal {
   779          // Pay out the bond to the claimant.
   780          uint256 bond = proposalBonds[_claimant][_uuid];
   781          proposalBonds[_claimant][_uuid] = 0;
   782          (bool success,) = _to.call{ value: bond }("");
   783          if (!success) revert BondTransferFailed();
   784      }
   785  
   786      /// @notice Hashes leaf data for the preimage proposals tree
   787      function _hashLeaf(Leaf memory _leaf) internal pure returns (bytes32 leaf_) {
   788          leaf_ = keccak256(abi.encodePacked(_leaf.input, _leaf.index, _leaf.stateCommitment));
   789      }
   790  }