diff --git a/.changeset/lemon-pianos-study.md b/.changeset/lemon-pianos-study.md new file mode 100644 index 0000000000000..69aa8f0315114 --- /dev/null +++ b/.changeset/lemon-pianos-study.md @@ -0,0 +1,5 @@ +--- +'@eth-optimism/contracts': patch +--- + +Deleted update and helper functions/tests from Lib_MerkleTrie.sol and Lib_SecureMerkleTrie.sol diff --git a/packages/contracts/contracts/libraries/trie/Lib_MerkleTrie.sol b/packages/contracts/contracts/libraries/trie/Lib_MerkleTrie.sol index 14dab070a52bb..d25154de78bfc 100644 --- a/packages/contracts/contracts/libraries/trie/Lib_MerkleTrie.sol +++ b/packages/contracts/contracts/libraries/trie/Lib_MerkleTrie.sol @@ -48,8 +48,6 @@ library Lib_MerkleTrie { // Just a utility constant. RLP represents `NULL` as 0x80. bytes1 constant RLP_NULL = bytes1(0x80); - bytes constant RLP_NULL_BYTES = hex"80"; - bytes32 internal constant KECCAK256_RLP_NULL_BYTES = keccak256(RLP_NULL_BYTES); /********************** * Internal Functions * @@ -78,35 +76,6 @@ library Lib_MerkleTrie { return (exists && Lib_BytesUtils.equal(_value, value)); } - /** - * @notice Updates a Merkle trie and returns a new root hash. - * @param _key Key of the node to update, as a hex string. - * @param _value Value of the node to update, as a hex string. - * @param _proof Merkle trie inclusion proof for the node *nearest* the - * target node. If the key exists, we can simply update the value. - * Otherwise, we need to modify the trie to handle the new k/v pair. - * @param _root Known root of the Merkle trie. Used to verify that the - * included proof is correctly constructed. - * @return _updatedRoot Root hash of the newly constructed trie. - */ - function update( - bytes memory _key, - bytes memory _value, - bytes memory _proof, - bytes32 _root - ) internal pure returns (bytes32 _updatedRoot) { - // Special case when inserting the very first node. - if (_root == KECCAK256_RLP_NULL_BYTES) { - return getSingleNodeRootHash(_key, _value); - } - - TrieNode[] memory proof = _parseProof(_proof); - (uint256 pathLength, bytes memory keyRemainder, ) = _walkNodePath(proof, _key, _root); - TrieNode[] memory newPath = _getNewPath(proof, pathLength, _key, keyRemainder, _value); - - return _getUpdatedTrieRoot(newPath, _key); - } - /** * @notice Retrieves the value associated with a given key. * @param _key Key to search for, as hex bytes. @@ -136,20 +105,6 @@ library Lib_MerkleTrie { return (exists, value); } - /** - * Computes the root hash for a trie with a single node. - * @param _key Key for the single node. - * @param _value Value for the single node. - * @return _updatedRoot Hash of the trie. - */ - function getSingleNodeRootHash(bytes memory _key, bytes memory _value) - internal - pure - returns (bytes32 _updatedRoot) - { - return keccak256(_makeLeafNode(Lib_BytesUtils.toNibbles(_key), _value).encoded); - } - /********************* * Private Functions * *********************/ @@ -272,241 +227,6 @@ library Lib_MerkleTrie { return (pathLength, Lib_BytesUtils.slice(key, currentKeyIndex), isFinalNode); } - /** - * @notice Creates new nodes to support a k/v pair insertion into a given Merkle trie path. - * @param _path Path to the node nearest the k/v pair. - * @param _pathLength Length of the path. Necessary because the provided path may include - * additional nodes (e.g., it comes directly from a proof) and we can't resize in-memory - * arrays without costly duplication. - * @param _key Full original key. - * @param _keyRemainder Portion of the initial key that must be inserted into the trie. - * @param _value Value to insert at the given key. - * @return _newPath A new path with the inserted k/v pair and extra supporting nodes. - */ - function _getNewPath( - TrieNode[] memory _path, - // slither-disable-next-line variable-scope - uint256 _pathLength, - bytes memory _key, - bytes memory _keyRemainder, - bytes memory _value - ) private pure returns (TrieNode[] memory _newPath) { - bytes memory keyRemainder = _keyRemainder; - - // Most of our logic depends on the status of the last node in the path. - TrieNode memory lastNode = _path[_pathLength - 1]; - NodeType lastNodeType = _getNodeType(lastNode); - - // Create an array for newly created nodes. - // We need up to three new nodes, depending on the contents of the last node. - // Since array resizing is expensive, we'll keep track of the size manually. - // We're using an explicit `totalNewNodes += 1` after insertions for clarity. - TrieNode[] memory newNodes = new TrieNode[](3); - uint256 totalNewNodes = 0; - - // solhint-disable-next-line max-line-length - // Reference: https://github.com/ethereumjs/merkle-patricia-tree/blob/c0a10395aab37d42c175a47114ebfcbd7efcf059/src/baseTrie.ts#L294-L313 - bool matchLeaf = false; - if (lastNodeType == NodeType.LeafNode) { - uint256 l = 0; - if (_path.length > 0) { - for (uint256 i = 0; i < _path.length - 1; i++) { - if (_getNodeType(_path[i]) == NodeType.BranchNode) { - l++; - } else { - l += _getNodeKey(_path[i]).length; - } - } - } - - if ( - _getSharedNibbleLength( - _getNodeKey(lastNode), - Lib_BytesUtils.slice(Lib_BytesUtils.toNibbles(_key), l) - ) == - _getNodeKey(lastNode).length && - keyRemainder.length == 0 - ) { - matchLeaf = true; - } - } - - if (matchLeaf) { - // We've found a leaf node with the given key. - // Simply need to update the value of the node to match. - newNodes[totalNewNodes] = _makeLeafNode(_getNodeKey(lastNode), _value); - totalNewNodes += 1; - } else if (lastNodeType == NodeType.BranchNode) { - if (keyRemainder.length == 0) { - // We've found a branch node with the given key. - // Simply need to update the value of the node to match. - newNodes[totalNewNodes] = _editBranchValue(lastNode, _value); - totalNewNodes += 1; - } else { - // We've found a branch node, but it doesn't contain our key. - // Reinsert the old branch for now. - newNodes[totalNewNodes] = lastNode; - totalNewNodes += 1; - // Create a new leaf node, slicing our remainder since the first byte points - // to our branch node. - newNodes[totalNewNodes] = _makeLeafNode( - Lib_BytesUtils.slice(keyRemainder, 1), - _value - ); - totalNewNodes += 1; - } - } else { - // Our last node is either an extension node or a leaf node with a different key. - bytes memory lastNodeKey = _getNodeKey(lastNode); - uint256 sharedNibbleLength = _getSharedNibbleLength(lastNodeKey, keyRemainder); - - if (sharedNibbleLength != 0) { - // We've got some shared nibbles between the last node and our key remainder. - // We'll need to insert an extension node that covers these shared nibbles. - bytes memory nextNodeKey = Lib_BytesUtils.slice(lastNodeKey, 0, sharedNibbleLength); - newNodes[totalNewNodes] = _makeExtensionNode(nextNodeKey, _getNodeHash(_value)); - totalNewNodes += 1; - - // Cut down the keys since we've just covered these shared nibbles. - lastNodeKey = Lib_BytesUtils.slice(lastNodeKey, sharedNibbleLength); - keyRemainder = Lib_BytesUtils.slice(keyRemainder, sharedNibbleLength); - } - - // Create an empty branch to fill in. - TrieNode memory newBranch = _makeEmptyBranchNode(); - - if (lastNodeKey.length == 0) { - // Key remainder was larger than the key for our last node. - // The value within our last node is therefore going to be shifted into - // a branch value slot. - newBranch = _editBranchValue(newBranch, _getNodeValue(lastNode)); - } else { - // Last node key was larger than the key remainder. - // We're going to modify some index of our branch. - uint8 branchKey = uint8(lastNodeKey[0]); - // Move on to the next nibble. - lastNodeKey = Lib_BytesUtils.slice(lastNodeKey, 1); - - if (lastNodeType == NodeType.LeafNode) { - // We're dealing with a leaf node. - // We'll modify the key and insert the old leaf node into the branch index. - TrieNode memory modifiedLastNode = _makeLeafNode( - lastNodeKey, - _getNodeValue(lastNode) - ); - newBranch = _editBranchIndex( - newBranch, - branchKey, - _getNodeHash(modifiedLastNode.encoded) - ); - } else if (lastNodeKey.length != 0) { - // We're dealing with a shrinking extension node. - // We need to modify the node to decrease the size of the key. - TrieNode memory modifiedLastNode = _makeExtensionNode( - lastNodeKey, - _getNodeValue(lastNode) - ); - newBranch = _editBranchIndex( - newBranch, - branchKey, - _getNodeHash(modifiedLastNode.encoded) - ); - } else { - // We're dealing with an unnecessary extension node. - // We're going to delete the node entirely. - // Simply insert its current value into the branch index. - newBranch = _editBranchIndex(newBranch, branchKey, _getNodeValue(lastNode)); - } - } - - if (keyRemainder.length == 0) { - // We've got nothing left in the key remainder. - // Simply insert the value into the branch value slot. - newBranch = _editBranchValue(newBranch, _value); - // Push the branch into the list of new nodes. - newNodes[totalNewNodes] = newBranch; - totalNewNodes += 1; - } else { - // We've got some key remainder to work with. - // We'll be inserting a leaf node into the trie. - // First, move on to the next nibble. - keyRemainder = Lib_BytesUtils.slice(keyRemainder, 1); - // Push the branch into the list of new nodes. - newNodes[totalNewNodes] = newBranch; - totalNewNodes += 1; - // Push a new leaf node for our k/v pair. - newNodes[totalNewNodes] = _makeLeafNode(keyRemainder, _value); - totalNewNodes += 1; - } - } - - // Finally, join the old path with our newly created nodes. - // Since we're overwriting the last node in the path, we use `_pathLength - 1`. - return _joinNodeArrays(_path, _pathLength - 1, newNodes, totalNewNodes); - } - - /** - * @notice Computes the trie root from a given path. - * @param _nodes Path to some k/v pair. - * @param _key Key for the k/v pair. - * @return _updatedRoot Root hash for the updated trie. - */ - function _getUpdatedTrieRoot(TrieNode[] memory _nodes, bytes memory _key) - private - pure - returns (bytes32 _updatedRoot) - { - bytes memory key = Lib_BytesUtils.toNibbles(_key); - - // Some variables to keep track of during iteration. - // slither-disable-next-line uninitialized-local - TrieNode memory currentNode; - NodeType currentNodeType; - // slither-disable-next-line uninitialized-local - bytes memory previousNodeHash; - - // Run through the path backwards to rebuild our root hash. - for (uint256 i = _nodes.length; i > 0; i--) { - // Pick out the current node. - currentNode = _nodes[i - 1]; - currentNodeType = _getNodeType(currentNode); - - if (currentNodeType == NodeType.LeafNode) { - // Leaf nodes are already correctly encoded. - // Shift the key over to account for the nodes key. - bytes memory nodeKey = _getNodeKey(currentNode); - key = Lib_BytesUtils.slice(key, 0, key.length - nodeKey.length); - } else if (currentNodeType == NodeType.ExtensionNode) { - // Shift the key over to account for the nodes key. - bytes memory nodeKey = _getNodeKey(currentNode); - key = Lib_BytesUtils.slice(key, 0, key.length - nodeKey.length); - - // If this node is the last element in the path, it'll be correctly encoded - // and we can skip this part. - if (previousNodeHash.length > 0) { - // Re-encode the node based on the previous node. - currentNode = _editExtensionNodeValue(currentNode, previousNodeHash); - } - } else if (currentNodeType == NodeType.BranchNode) { - // If this node is the last element in the path, it'll be correctly encoded - // and we can skip this part. - if (previousNodeHash.length > 0) { - // Re-encode the node based on the previous node. - uint8 branchKey = uint8(key[key.length - 1]); - key = Lib_BytesUtils.slice(key, 0, key.length - 1); - currentNode = _editBranchIndex(currentNode, branchKey, previousNodeHash); - } - } - - // Compute the node hash for the next iteration. - previousNodeHash = _getNodeHash(currentNode.encoded); - } - - // Current node should be the root at this point. - // Simply return the hash of its encoding. - return keccak256(currentNode.encoded); - } - /** * @notice Parses an RLP-encoded proof into something more useful. * @param _proof RLP-encoded proof to parse. @@ -554,16 +274,6 @@ library Lib_MerkleTrie { return Lib_BytesUtils.toNibbles(Lib_RLPReader.readBytes(_node.decoded[0])); } - /** - * @notice Gets the key for a leaf or extension node. Keys are essentially - * just paths without any prefix. - * @param _node Node to get a key for. - * @return _key Node key, converted to an array of nibbles. - */ - function _getNodeKey(TrieNode memory _node) private pure returns (bytes memory _key) { - return _removeHexPrefix(_getNodePath(_node)); - } - /** * @notice Gets the path for a node. * @param _node Node to get a value for. @@ -573,42 +283,6 @@ library Lib_MerkleTrie { return Lib_RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]); } - /** - * @notice Computes the node hash for an encoded node. Nodes < 32 bytes - * are not hashed, all others are keccak256 hashed. - * @param _encoded Encoded node to hash. - * @return _hash Hash of the encoded node. Simply the input if < 32 bytes. - */ - function _getNodeHash(bytes memory _encoded) private pure returns (bytes memory _hash) { - if (_encoded.length < 32) { - return _encoded; - } else { - return abi.encodePacked(keccak256(_encoded)); - } - } - - /** - * @notice Determines the type for a given node. - * @param _node Node to determine a type for. - * @return _type Type of the node; BranchNode/ExtensionNode/LeafNode. - */ - function _getNodeType(TrieNode memory _node) private pure returns (NodeType _type) { - if (_node.decoded.length == BRANCH_NODE_LENGTH) { - return NodeType.BranchNode; - } else if (_node.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) { - bytes memory path = _getNodePath(_node); - uint8 prefix = uint8(path[0]); - - if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) { - return NodeType.LeafNode; - } else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) { - return NodeType.ExtensionNode; - } - } - - revert("Invalid node type"); - } - /** * @notice Utility; determines the number of nibbles shared between two * nibble arrays. @@ -627,204 +301,4 @@ library Lib_MerkleTrie { } return i; } - - /** - * @notice Utility; converts an RLP-encoded node into our nice struct. - * @param _raw RLP-encoded node to convert. - * @return _node Node as a TrieNode struct. - */ - function _makeNode(bytes[] memory _raw) private pure returns (TrieNode memory _node) { - bytes memory encoded = Lib_RLPWriter.writeList(_raw); - - return TrieNode({ encoded: encoded, decoded: Lib_RLPReader.readList(encoded) }); - } - - /** - * @notice Utility; converts an RLP-decoded node into our nice struct. - * @param _items RLP-decoded node to convert. - * @return _node Node as a TrieNode struct. - */ - function _makeNode(Lib_RLPReader.RLPItem[] memory _items) - private - pure - returns (TrieNode memory _node) - { - bytes[] memory raw = new bytes[](_items.length); - for (uint256 i = 0; i < _items.length; i++) { - raw[i] = Lib_RLPReader.readRawBytes(_items[i]); - } - return _makeNode(raw); - } - - /** - * @notice Creates a new extension node. - * @param _key Key for the extension node, unprefixed. - * @param _value Value for the extension node. - * @return _node New extension node with the given k/v pair. - */ - function _makeExtensionNode(bytes memory _key, bytes memory _value) - private - pure - returns (TrieNode memory _node) - { - bytes[] memory raw = new bytes[](2); - bytes memory key = _addHexPrefix(_key, false); - raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key)); - raw[1] = Lib_RLPWriter.writeBytes(_value); - return _makeNode(raw); - } - - /** - * Creates a new extension node with the same key but a different value. - * @param _node Extension node to copy and modify. - * @param _value New value for the extension node. - * @return New node with the same key and different value. - */ - function _editExtensionNodeValue(TrieNode memory _node, bytes memory _value) - private - pure - returns (TrieNode memory) - { - bytes[] memory raw = new bytes[](2); - bytes memory key = _addHexPrefix(_getNodeKey(_node), false); - raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key)); - if (_value.length < 32) { - raw[1] = _value; - } else { - raw[1] = Lib_RLPWriter.writeBytes(_value); - } - return _makeNode(raw); - } - - /** - * @notice Creates a new leaf node. - * @dev This function is essentially identical to `_makeExtensionNode`. - * Although we could route both to a single method with a flag, it's - * more gas efficient to keep them separate and duplicate the logic. - * @param _key Key for the leaf node, unprefixed. - * @param _value Value for the leaf node. - * @return _node New leaf node with the given k/v pair. - */ - function _makeLeafNode(bytes memory _key, bytes memory _value) - private - pure - returns (TrieNode memory _node) - { - bytes[] memory raw = new bytes[](2); - bytes memory key = _addHexPrefix(_key, true); - raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key)); - raw[1] = Lib_RLPWriter.writeBytes(_value); - return _makeNode(raw); - } - - /** - * @notice Creates an empty branch node. - * @return _node Empty branch node as a TrieNode struct. - */ - function _makeEmptyBranchNode() private pure returns (TrieNode memory _node) { - bytes[] memory raw = new bytes[](BRANCH_NODE_LENGTH); - for (uint256 i = 0; i < raw.length; i++) { - raw[i] = RLP_NULL_BYTES; - } - return _makeNode(raw); - } - - /** - * @notice Modifies the value slot for a given branch. - * @param _branch Branch node to modify. - * @param _value Value to insert into the branch. - * @return _updatedNode Modified branch node. - */ - function _editBranchValue(TrieNode memory _branch, bytes memory _value) - private - pure - returns (TrieNode memory _updatedNode) - { - bytes memory encoded = Lib_RLPWriter.writeBytes(_value); - _branch.decoded[_branch.decoded.length - 1] = Lib_RLPReader.toRLPItem(encoded); - return _makeNode(_branch.decoded); - } - - /** - * @notice Modifies a slot at an index for a given branch. - * @param _branch Branch node to modify. - * @param _index Slot index to modify. - * @param _value Value to insert into the slot. - * @return _updatedNode Modified branch node. - */ - function _editBranchIndex( - TrieNode memory _branch, - uint8 _index, - bytes memory _value - ) private pure returns (TrieNode memory _updatedNode) { - bytes memory encoded = _value.length < 32 ? _value : Lib_RLPWriter.writeBytes(_value); - _branch.decoded[_index] = Lib_RLPReader.toRLPItem(encoded); - return _makeNode(_branch.decoded); - } - - /** - * @notice Utility; adds a prefix to a key. - * @param _key Key to prefix. - * @param _isLeaf Whether or not the key belongs to a leaf. - * @return _prefixedKey Prefixed key. - */ - function _addHexPrefix(bytes memory _key, bool _isLeaf) - private - pure - returns (bytes memory _prefixedKey) - { - uint8 prefix = _isLeaf ? uint8(0x02) : uint8(0x00); - uint8 offset = uint8(_key.length % 2); - bytes memory prefixed = new bytes(2 - offset); - prefixed[0] = bytes1(prefix + offset); - return abi.encodePacked(prefixed, _key); - } - - /** - * @notice Utility; removes a prefix from a path. - * @param _path Path to remove the prefix from. - * @return _unprefixedKey Unprefixed key. - */ - function _removeHexPrefix(bytes memory _path) - private - pure - returns (bytes memory _unprefixedKey) - { - if (uint8(_path[0]) % 2 == 0) { - return Lib_BytesUtils.slice(_path, 2); - } else { - return Lib_BytesUtils.slice(_path, 1); - } - } - - /** - * @notice Utility; combines two node arrays. Array lengths are required - * because the actual lengths may be longer than the filled lengths. - * Array resizing is extremely costly and should be avoided. - * @param _a First array to join. - * @param _aLength Length of the first array. - * @param _b Second array to join. - * @param _bLength Length of the second array. - * @return _joined Combined node array. - */ - function _joinNodeArrays( - TrieNode[] memory _a, - uint256 _aLength, - TrieNode[] memory _b, - uint256 _bLength - ) private pure returns (TrieNode[] memory _joined) { - TrieNode[] memory ret = new TrieNode[](_aLength + _bLength); - - // Copy elements from the first array. - for (uint256 i = 0; i < _aLength; i++) { - ret[i] = _a[i]; - } - - // Copy elements from the second array. - for (uint256 i = 0; i < _bLength; i++) { - ret[i + _aLength] = _b[i]; - } - - return ret; - } } diff --git a/packages/contracts/contracts/libraries/trie/Lib_SecureMerkleTrie.sol b/packages/contracts/contracts/libraries/trie/Lib_SecureMerkleTrie.sol index 60b75dd91b4de..3ef14fc29188c 100644 --- a/packages/contracts/contracts/libraries/trie/Lib_SecureMerkleTrie.sol +++ b/packages/contracts/contracts/libraries/trie/Lib_SecureMerkleTrie.sol @@ -34,27 +34,6 @@ library Lib_SecureMerkleTrie { return Lib_MerkleTrie.verifyInclusionProof(key, _value, _proof, _root); } - /** - * @notice Updates a Merkle trie and returns a new root hash. - * @param _key Key of the node to update, as a hex string. - * @param _value Value of the node to update, as a hex string. - * @param _proof Merkle trie inclusion proof for the node *nearest* the - * target node. If the key exists, we can simply update the value. - * Otherwise, we need to modify the trie to handle the new k/v pair. - * @param _root Known root of the Merkle trie. Used to verify that the - * included proof is correctly constructed. - * @return _updatedRoot Root hash of the newly constructed trie. - */ - function update( - bytes memory _key, - bytes memory _value, - bytes memory _proof, - bytes32 _root - ) internal pure returns (bytes32 _updatedRoot) { - bytes memory key = _getSecureKey(_key); - return Lib_MerkleTrie.update(key, _value, _proof, _root); - } - /** * @notice Retrieves the value associated with a given key. * @param _key Key to search for, as hex bytes. @@ -72,21 +51,6 @@ library Lib_SecureMerkleTrie { return Lib_MerkleTrie.get(key, _proof, _root); } - /** - * Computes the root hash for a trie with a single node. - * @param _key Key for the single node. - * @param _value Value for the single node. - * @return _updatedRoot Hash of the trie. - */ - function getSingleNodeRootHash(bytes memory _key, bytes memory _value) - internal - pure - returns (bytes32 _updatedRoot) - { - bytes memory key = _getSecureKey(_key); - return Lib_MerkleTrie.getSingleNodeRootHash(key, _value); - } - /********************* * Private Functions * *********************/ diff --git a/packages/contracts/contracts/test-libraries/trie/TestLib_MerkleTrie.sol b/packages/contracts/contracts/test-libraries/trie/TestLib_MerkleTrie.sol index 481d2d76a3da1..025f78e6ca644 100644 --- a/packages/contracts/contracts/test-libraries/trie/TestLib_MerkleTrie.sol +++ b/packages/contracts/contracts/test-libraries/trie/TestLib_MerkleTrie.sol @@ -17,15 +17,6 @@ contract TestLib_MerkleTrie { return Lib_MerkleTrie.verifyInclusionProof(_key, _value, _proof, _root); } - function update( - bytes memory _key, - bytes memory _value, - bytes memory _proof, - bytes32 _root - ) public pure returns (bytes32) { - return Lib_MerkleTrie.update(_key, _value, _proof, _root); - } - function get( bytes memory _key, bytes memory _proof, @@ -33,12 +24,4 @@ contract TestLib_MerkleTrie { ) public pure returns (bool, bytes memory) { return Lib_MerkleTrie.get(_key, _proof, _root); } - - function getSingleNodeRootHash(bytes memory _key, bytes memory _value) - public - pure - returns (bytes32) - { - return Lib_MerkleTrie.getSingleNodeRootHash(_key, _value); - } } diff --git a/packages/contracts/contracts/test-libraries/trie/TestLib_SecureMerkleTrie.sol b/packages/contracts/contracts/test-libraries/trie/TestLib_SecureMerkleTrie.sol index 48d2a604ea0a7..5aa1b1dc7db61 100644 --- a/packages/contracts/contracts/test-libraries/trie/TestLib_SecureMerkleTrie.sol +++ b/packages/contracts/contracts/test-libraries/trie/TestLib_SecureMerkleTrie.sol @@ -17,15 +17,6 @@ contract TestLib_SecureMerkleTrie { return Lib_SecureMerkleTrie.verifyInclusionProof(_key, _value, _proof, _root); } - function update( - bytes memory _key, - bytes memory _value, - bytes memory _proof, - bytes32 _root - ) public pure returns (bytes32) { - return Lib_SecureMerkleTrie.update(_key, _value, _proof, _root); - } - function get( bytes memory _key, bytes memory _proof, @@ -33,12 +24,4 @@ contract TestLib_SecureMerkleTrie { ) public pure returns (bool, bytes memory) { return Lib_SecureMerkleTrie.get(_key, _proof, _root); } - - function getSingleNodeRootHash(bytes memory _key, bytes memory _value) - public - pure - returns (bytes32) - { - return Lib_SecureMerkleTrie.getSingleNodeRootHash(_key, _value); - } } diff --git a/packages/contracts/test/contracts/libraries/trie/Lib_MerkleTrie.spec.ts b/packages/contracts/test/contracts/libraries/trie/Lib_MerkleTrie.spec.ts index bbd1a752ae7e1..18d61b93708f7 100644 --- a/packages/contracts/test/contracts/libraries/trie/Lib_MerkleTrie.spec.ts +++ b/packages/contracts/test/contracts/libraries/trie/Lib_MerkleTrie.spec.ts @@ -2,14 +2,11 @@ import * as rlp from 'rlp' import { ethers } from 'hardhat' import { Contract } from 'ethers' -import { fromHexString, toHexString } from '@eth-optimism/core-utils' -import { Trie } from 'merkle-patricia-tree/dist/baseTrie' +import { toHexString } from '@eth-optimism/core-utils' /* Internal Imports */ import { expect } from '../../../setup' import { TrieTestGenerator } from '../../../helpers' -import * as officialTestJson from '../../../data/json/libraries/trie/trietest.json' -import * as officialTestAnyOrderJson from '../../../data/json/libraries/trie/trieanyorder.json' const NODE_COUNTS = [1, 2, 32, 128] @@ -22,100 +19,6 @@ describe('Lib_MerkleTrie', () => { }) // Eth-foundation tests: https://github.com/ethereum/tests/tree/develop/TrieTests - describe('official tests', () => { - for (const testName of Object.keys(officialTestJson.tests)) { - it(`should perform official test: ${testName}`, async () => { - const trie = new Trie() - const inputs = officialTestJson.tests[testName].in - const expected = officialTestJson.tests[testName].root - - for (const input of inputs) { - let key: Buffer - if (input[0].startsWith('0x')) { - key = fromHexString(input[0]) - } else { - key = fromHexString( - ethers.utils.hexlify(ethers.utils.toUtf8Bytes(input[0])) - ) - } - - let val: Buffer - if (input[1] === null) { - throw new Error('deletions not supported, check your tests') - } else if (input[1].startsWith('0x')) { - val = fromHexString(input[1]) - } else { - val = fromHexString( - ethers.utils.hexlify(ethers.utils.toUtf8Bytes(input[1])) - ) - } - - const proof = await Trie.createProof(trie, key) - const root = trie.root - await trie.put(key, val) - - const out = await Lib_MerkleTrie.update( - toHexString(key), - toHexString(val), - toHexString(rlp.encode(proof)), - root - ) - - expect(out).to.equal(toHexString(trie.root)) - } - - expect(toHexString(trie.root)).to.equal(expected) - }) - } - }) - - describe('official tests - trie any order', () => { - for (const testName of Object.keys(officialTestAnyOrderJson.tests)) { - it(`should perform official test: ${testName}`, async () => { - const trie = new Trie() - const inputs = officialTestAnyOrderJson.tests[testName].in - const expected = officialTestAnyOrderJson.tests[testName].root - - for (const input of Object.keys(inputs)) { - let key: Buffer - if (input.startsWith('0x')) { - key = fromHexString(input) - } else { - key = fromHexString( - ethers.utils.hexlify(ethers.utils.toUtf8Bytes(input)) - ) - } - - let val: Buffer - if (inputs[input] === null) { - throw new Error('deletions not supported, check your tests') - } else if (inputs[input].startsWith('0x')) { - val = fromHexString(inputs[input]) - } else { - val = fromHexString( - ethers.utils.hexlify(ethers.utils.toUtf8Bytes(inputs[input])) - ) - } - - const proof = await Trie.createProof(trie, key) - const root = trie.root - await trie.put(key, val) - - const out = await Lib_MerkleTrie.update( - toHexString(key), - toHexString(val), - toHexString(rlp.encode(proof)), - root - ) - - expect(out).to.equal(toHexString(trie.root)) - } - - expect(toHexString(trie.root)).to.equal(expected) - }) - } - }) - describe('verifyInclusionProof', () => { for (const nodeCount of NODE_COUNTS) { describe(`inside a trie with ${nodeCount} nodes and keys/vals of size ${nodeCount} bytes`, () => { @@ -152,62 +55,6 @@ describe('Lib_MerkleTrie', () => { } }) - describe('update', () => { - for (const nodeCount of NODE_COUNTS) { - describe(`inside a trie with ${nodeCount} nodes and keys/vals of size ${nodeCount} bytes`, () => { - let generator: TrieTestGenerator - before(async () => { - generator = await TrieTestGenerator.fromRandom({ - seed: `seed.update.${nodeCount}`, - nodeCount, - secure: false, - keySize: nodeCount, - valSize: nodeCount, - }) - }) - - for ( - let i = 0; - i < nodeCount; - i += nodeCount / (nodeCount > 8 ? 8 : 1) - ) { - it(`should correctly update node #${i}`, async () => { - const test = await generator.makeNodeUpdateTest( - i, - '0x1234123412341234' - ) - - expect( - await Lib_MerkleTrie.update( - test.key, - test.val, - test.proof, - test.root - ) - ).to.equal(test.newRoot) - }) - } - }) - } - - it('should return the single-node root hash if the trie was previously empty', async () => { - const key = '0x1234' - const val = '0x5678' - - const trie = new Trie() - await trie.put(fromHexString(key), fromHexString(val)) - - expect( - await Lib_MerkleTrie.update( - key, - val, - '0x', // Doesn't require a proof - ethers.utils.keccak256('0x80') // Empty Merkle trie root hash - ) - ).to.equal(toHexString(trie.root)) - }) - }) - describe('get', () => { for (const nodeCount of NODE_COUNTS) { describe(`inside a trie with ${nodeCount} nodes and keys/vals of size ${nodeCount} bytes`, () => { diff --git a/packages/contracts/test/contracts/libraries/trie/Lib_SecureMerkleTrie.spec.ts b/packages/contracts/test/contracts/libraries/trie/Lib_SecureMerkleTrie.spec.ts index f8b238c7d3d3f..674e8ddc3fde3 100644 --- a/packages/contracts/test/contracts/libraries/trie/Lib_SecureMerkleTrie.spec.ts +++ b/packages/contracts/test/contracts/libraries/trie/Lib_SecureMerkleTrie.spec.ts @@ -50,43 +50,6 @@ describe('Lib_SecureMerkleTrie', () => { } }) - describe('update', () => { - for (const nodeCount of NODE_COUNTS) { - describe(`inside a trie with ${nodeCount} nodes`, () => { - let generator: TrieTestGenerator - before(async () => { - generator = await TrieTestGenerator.fromRandom({ - seed: `seed.update.${nodeCount}`, - nodeCount, - secure: true, - }) - }) - - for ( - let i = 0; - i < nodeCount; - i += nodeCount / (nodeCount > 8 ? 8 : 1) - ) { - it(`should correctly update node #${i}`, async () => { - const test = await generator.makeNodeUpdateTest( - i, - '0x1234123412341234' - ) - - expect( - await Lib_SecureMerkleTrie.update( - test.key, - test.val, - test.proof, - test.root - ) - ).to.equal(test.newRoot) - }) - } - }) - } - }) - describe('get', () => { for (const nodeCount of NODE_COUNTS) { describe(`inside a trie with ${nodeCount} nodes`, () => { @@ -115,22 +78,4 @@ describe('Lib_SecureMerkleTrie', () => { }) } }) - - describe('getSingleNodeRootHash', () => { - let generator: TrieTestGenerator - before(async () => { - generator = await TrieTestGenerator.fromRandom({ - seed: `seed.get.${1}`, - nodeCount: 1, - secure: true, - }) - }) - - it(`should get the root hash of a trie with a single node`, async () => { - const test = await generator.makeInclusionProofTest(0) - expect( - await Lib_SecureMerkleTrie.getSingleNodeRootHash(test.key, test.val) - ).to.equal(test.root) - }) - }) })