github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/libraries/trie/MerkleTrie.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity ^0.8.0;
     3  
     4  import { Bytes } from "../Bytes.sol";
     5  import { RLPReader } from "../rlp/RLPReader.sol";
     6  
     7  /// @title MerkleTrie
     8  /// @notice MerkleTrie is a small library for verifying standard Ethereum Merkle-Patricia trie
     9  ///         inclusion proofs. By default, this library assumes a hexary trie. One can change the
    10  ///         trie radix constant to support other trie radixes.
    11  library MerkleTrie {
    12      /// @notice Struct representing a node in the trie.
    13      /// @custom:field encoded The RLP-encoded node.
    14      /// @custom:field decoded The RLP-decoded node.
    15      struct TrieNode {
    16          bytes encoded;
    17          RLPReader.RLPItem[] decoded;
    18      }
    19  
    20      /// @notice Determines the number of elements per branch node.
    21      uint256 internal constant TREE_RADIX = 16;
    22  
    23      /// @notice Branch nodes have TREE_RADIX elements and one value element.
    24      uint256 internal constant BRANCH_NODE_LENGTH = TREE_RADIX + 1;
    25  
    26      /// @notice Leaf nodes and extension nodes have two elements, a `path` and a `value`.
    27      uint256 internal constant LEAF_OR_EXTENSION_NODE_LENGTH = 2;
    28  
    29      /// @notice Prefix for even-nibbled extension node paths.
    30      uint8 internal constant PREFIX_EXTENSION_EVEN = 0;
    31  
    32      /// @notice Prefix for odd-nibbled extension node paths.
    33      uint8 internal constant PREFIX_EXTENSION_ODD = 1;
    34  
    35      /// @notice Prefix for even-nibbled leaf node paths.
    36      uint8 internal constant PREFIX_LEAF_EVEN = 2;
    37  
    38      /// @notice Prefix for odd-nibbled leaf node paths.
    39      uint8 internal constant PREFIX_LEAF_ODD = 3;
    40  
    41      /// @notice Verifies a proof that a given key/value pair is present in the trie.
    42      /// @param _key   Key of the node to search for, as a hex string.
    43      /// @param _value Value of the node to search for, as a hex string.
    44      /// @param _proof Merkle trie inclusion proof for the desired node. Unlike traditional Merkle
    45      ///               trees, this proof is executed top-down and consists of a list of RLP-encoded
    46      ///               nodes that make a path down to the target node.
    47      /// @param _root  Known root of the Merkle trie. Used to verify that the included proof is
    48      ///               correctly constructed.
    49      /// @return valid_ Whether or not the proof is valid.
    50      function verifyInclusionProof(
    51          bytes memory _key,
    52          bytes memory _value,
    53          bytes[] memory _proof,
    54          bytes32 _root
    55      )
    56          internal
    57          pure
    58          returns (bool valid_)
    59      {
    60          valid_ = Bytes.equal(_value, get(_key, _proof, _root));
    61      }
    62  
    63      /// @notice Retrieves the value associated with a given key.
    64      /// @param _key   Key to search for, as hex bytes.
    65      /// @param _proof Merkle trie inclusion proof for the key.
    66      /// @param _root  Known root of the Merkle trie.
    67      /// @return value_ Value of the key if it exists.
    68      function get(bytes memory _key, bytes[] memory _proof, bytes32 _root) internal pure returns (bytes memory value_) {
    69          require(_key.length > 0, "MerkleTrie: empty key");
    70  
    71          TrieNode[] memory proof = _parseProof(_proof);
    72          bytes memory key = Bytes.toNibbles(_key);
    73          bytes memory currentNodeID = abi.encodePacked(_root);
    74          uint256 currentKeyIndex = 0;
    75  
    76          // Proof is top-down, so we start at the first element (root).
    77          for (uint256 i = 0; i < proof.length; i++) {
    78              TrieNode memory currentNode = proof[i];
    79  
    80              // Key index should never exceed total key length or we'll be out of bounds.
    81              require(currentKeyIndex <= key.length, "MerkleTrie: key index exceeds total key length");
    82  
    83              if (currentKeyIndex == 0) {
    84                  // First proof element is always the root node.
    85                  require(
    86                      Bytes.equal(abi.encodePacked(keccak256(currentNode.encoded)), currentNodeID),
    87                      "MerkleTrie: invalid root hash"
    88                  );
    89              } else if (currentNode.encoded.length >= 32) {
    90                  // Nodes 32 bytes or larger are hashed inside branch nodes.
    91                  require(
    92                      Bytes.equal(abi.encodePacked(keccak256(currentNode.encoded)), currentNodeID),
    93                      "MerkleTrie: invalid large internal hash"
    94                  );
    95              } else {
    96                  // Nodes smaller than 32 bytes aren't hashed.
    97                  require(Bytes.equal(currentNode.encoded, currentNodeID), "MerkleTrie: invalid internal node hash");
    98              }
    99  
   100              if (currentNode.decoded.length == BRANCH_NODE_LENGTH) {
   101                  if (currentKeyIndex == key.length) {
   102                      // Value is the last element of the decoded list (for branch nodes). There's
   103                      // some ambiguity in the Merkle trie specification because bytes(0) is a
   104                      // valid value to place into the trie, but for branch nodes bytes(0) can exist
   105                      // even when the value wasn't explicitly placed there. Geth treats a value of
   106                      // bytes(0) as "key does not exist" and so we do the same.
   107                      value_ = RLPReader.readBytes(currentNode.decoded[TREE_RADIX]);
   108                      require(value_.length > 0, "MerkleTrie: value length must be greater than zero (branch)");
   109  
   110                      // Extra proof elements are not allowed.
   111                      require(i == proof.length - 1, "MerkleTrie: value node must be last node in proof (branch)");
   112  
   113                      return value_;
   114                  } else {
   115                      // We're not at the end of the key yet.
   116                      // Figure out what the next node ID should be and continue.
   117                      uint8 branchKey = uint8(key[currentKeyIndex]);
   118                      RLPReader.RLPItem memory nextNode = currentNode.decoded[branchKey];
   119                      currentNodeID = _getNodeID(nextNode);
   120                      currentKeyIndex += 1;
   121                  }
   122              } else if (currentNode.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) {
   123                  bytes memory path = _getNodePath(currentNode);
   124                  uint8 prefix = uint8(path[0]);
   125                  uint8 offset = 2 - (prefix % 2);
   126                  bytes memory pathRemainder = Bytes.slice(path, offset);
   127                  bytes memory keyRemainder = Bytes.slice(key, currentKeyIndex);
   128                  uint256 sharedNibbleLength = _getSharedNibbleLength(pathRemainder, keyRemainder);
   129  
   130                  // Whether this is a leaf node or an extension node, the path remainder MUST be a
   131                  // prefix of the key remainder (or be equal to the key remainder) or the proof is
   132                  // considered invalid.
   133                  require(
   134                      pathRemainder.length == sharedNibbleLength,
   135                      "MerkleTrie: path remainder must share all nibbles with key"
   136                  );
   137  
   138                  if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) {
   139                      // Prefix of 2 or 3 means this is a leaf node. For the leaf node to be valid,
   140                      // the key remainder must be exactly equal to the path remainder. We already
   141                      // did the necessary byte comparison, so it's more efficient here to check that
   142                      // the key remainder length equals the shared nibble length, which implies
   143                      // equality with the path remainder (since we already did the same check with
   144                      // the path remainder and the shared nibble length).
   145                      require(
   146                          keyRemainder.length == sharedNibbleLength,
   147                          "MerkleTrie: key remainder must be identical to path remainder"
   148                      );
   149  
   150                      // Our Merkle Trie is designed specifically for the purposes of the Ethereum
   151                      // state trie. Empty values are not allowed in the state trie, so we can safely
   152                      // say that if the value is empty, the key should not exist and the proof is
   153                      // invalid.
   154                      value_ = RLPReader.readBytes(currentNode.decoded[1]);
   155                      require(value_.length > 0, "MerkleTrie: value length must be greater than zero (leaf)");
   156  
   157                      // Extra proof elements are not allowed.
   158                      require(i == proof.length - 1, "MerkleTrie: value node must be last node in proof (leaf)");
   159  
   160                      return value_;
   161                  } else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) {
   162                      // Prefix of 0 or 1 means this is an extension node. We move onto the next node
   163                      // in the proof and increment the key index by the length of the path remainder
   164                      // which is equal to the shared nibble length.
   165                      currentNodeID = _getNodeID(currentNode.decoded[1]);
   166                      currentKeyIndex += sharedNibbleLength;
   167                  } else {
   168                      revert("MerkleTrie: received a node with an unknown prefix");
   169                  }
   170              } else {
   171                  revert("MerkleTrie: received an unparseable node");
   172              }
   173          }
   174  
   175          revert("MerkleTrie: ran out of proof elements");
   176      }
   177  
   178      /// @notice Parses an array of proof elements into a new array that contains both the original
   179      ///         encoded element and the RLP-decoded element.
   180      /// @param _proof Array of proof elements to parse.
   181      /// @return proof_ Proof parsed into easily accessible structs.
   182      function _parseProof(bytes[] memory _proof) private pure returns (TrieNode[] memory proof_) {
   183          uint256 length = _proof.length;
   184          proof_ = new TrieNode[](length);
   185          for (uint256 i = 0; i < length;) {
   186              proof_[i] = TrieNode({ encoded: _proof[i], decoded: RLPReader.readList(_proof[i]) });
   187              unchecked {
   188                  ++i;
   189              }
   190          }
   191      }
   192  
   193      /// @notice Picks out the ID for a node. Node ID is referred to as the "hash" within the
   194      ///         specification, but nodes < 32 bytes are not actually hashed.
   195      /// @param _node Node to pull an ID for.
   196      /// @return id_ ID for the node, depending on the size of its contents.
   197      function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes memory id_) {
   198          id_ = _node.length < 32 ? RLPReader.readRawBytes(_node) : RLPReader.readBytes(_node);
   199      }
   200  
   201      /// @notice Gets the path for a leaf or extension node.
   202      /// @param _node Node to get a path for.
   203      /// @return nibbles_ Node path, converted to an array of nibbles.
   204      function _getNodePath(TrieNode memory _node) private pure returns (bytes memory nibbles_) {
   205          nibbles_ = Bytes.toNibbles(RLPReader.readBytes(_node.decoded[0]));
   206      }
   207  
   208      /// @notice Utility; determines the number of nibbles shared between two nibble arrays.
   209      /// @param _a First nibble array.
   210      /// @param _b Second nibble array.
   211      /// @return shared_ Number of shared nibbles.
   212      function _getSharedNibbleLength(bytes memory _a, bytes memory _b) private pure returns (uint256 shared_) {
   213          uint256 max = (_a.length < _b.length) ? _a.length : _b.length;
   214          for (; shared_ < max && _a[shared_] == _b[shared_];) {
   215              unchecked {
   216                  ++shared_;
   217              }
   218          }
   219      }
   220  }