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 }