Commit 9d435aec authored by smartcontracts's avatar smartcontracts Committed by GitHub

style(ctb): clean MerkleTrie and SecureMerkleTrie (#3006)

Cleans up natspec in the MerkleTrie and SecureMerkleTrie contracts.
parent ae4440b3
---
'@eth-optimism/contracts-bedrock': patch
---
Cleans up natspec in MerkleTrie and SecureMerkleTrie contracts
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.9; pragma solidity ^0.8.9;
/* Library Imports */
import { BytesUtils } from "../BytesUtils.sol"; import { BytesUtils } from "../BytesUtils.sol";
import { RLPReader } from "../rlp/RLPReader.sol"; import { RLPReader } from "../rlp/RLPReader.sol";
import { RLPWriter } from "../rlp/RLPWriter.sol"; import { RLPWriter } from "../rlp/RLPWriter.sol";
/** /**
* @title MerkleTrie * @title MerkleTrie
* @notice MerkleTrie is a small library for verifying standard Ethereum Merkle-Patricia trie
* inclusion proofs. By default, this library assumes a hexary trie. One can change the
* trie radix constant to support other trie radixes.
*/ */
library MerkleTrie { library MerkleTrie {
/******************* /**
* Data Structures * * @notice Struct representing a node in the trie.
*******************/ */
struct TrieNode { struct TrieNode {
bytes encoded; bytes encoded;
RLPReader.RLPItem[] decoded; RLPReader.RLPItem[] decoded;
} }
/********************** /**
* Contract Constants * * @notice Determines the number of elements per branch node.
**********************/ */
// TREE_RADIX determines the number of elements per branch node.
uint256 constant TREE_RADIX = 16; uint256 constant TREE_RADIX = 16;
// Branch nodes have TREE_RADIX elements plus an additional `value` slot.
/**
* @notice Branch nodes have TREE_RADIX elements and one value element.
*/
uint256 constant BRANCH_NODE_LENGTH = TREE_RADIX + 1; uint256 constant BRANCH_NODE_LENGTH = TREE_RADIX + 1;
// Leaf nodes and extension nodes always have two elements, a `path` and a `value`.
/**
* @notice Leaf nodes and extension nodes have two elements, a `path` and a `value`.
*/
uint256 constant LEAF_OR_EXTENSION_NODE_LENGTH = 2; uint256 constant LEAF_OR_EXTENSION_NODE_LENGTH = 2;
// Prefixes are prepended to the `path` within a leaf or extension node and /**
// allow us to differentiate between the two node types. `ODD` or `EVEN` is * @notice Prefix for even-nibbled extension node paths.
// determined by the number of nibbles within the unprefixed `path`. If the */
// number of nibbles if even, we need to insert an extra padding nibble so
// the resulting prefixed `path` has an even number of nibbles.
uint8 constant PREFIX_EXTENSION_EVEN = 0; uint8 constant PREFIX_EXTENSION_EVEN = 0;
/**
* @notice Prefix for odd-nibbled extension node paths.
*/
uint8 constant PREFIX_EXTENSION_ODD = 1; uint8 constant PREFIX_EXTENSION_ODD = 1;
/**
* @notice Prefix for even-nibbled leaf node paths.
*/
uint8 constant PREFIX_LEAF_EVEN = 2; uint8 constant PREFIX_LEAF_EVEN = 2;
/**
* @notice Prefix for odd-nibbled leaf node paths.
*/
uint8 constant PREFIX_LEAF_ODD = 3; uint8 constant PREFIX_LEAF_ODD = 3;
// Just a utility constant. RLP represents `NULL` as 0x80. /**
* @notice RLP representation of `NULL`.
*/
bytes1 constant RLP_NULL = bytes1(0x80); bytes1 constant RLP_NULL = bytes1(0x80);
/**********************
* Internal Functions *
**********************/
/** /**
* @notice Verifies a proof that a given key/value pair is present in the * @notice Verifies a proof that a given key/value pair is present in the trie.
* Merkle trie. *
* @param _key Key of the node to search for, as a hex string. * @param _key Key of the node to search for, as a hex string.
* @param _value Value of the node to search for, as a hex string. * @param _value Value of the node to search for, as a hex string.
* @param _proof Merkle trie inclusion proof for the desired node. Unlike * @param _proof Merkle trie inclusion proof for the desired node. Unlike traditional Merkle
* traditional Merkle trees, this proof is executed top-down and consists * trees, this proof is executed top-down and consists of a list of RLP-encoded
* of a list of RLP-encoded nodes that make a path down to the target node. * nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the * @param _root Known root of the Merkle trie. Used to verify that the included proof is
* included proof is correctly constructed. * correctly constructed.
* @return _verified `true` if the k/v pair exists in the trie, `false` otherwise. *
* @return Whether or not the proof is valid.
*/ */
function verifyInclusionProof( function verifyInclusionProof(
bytes memory _key, bytes memory _key,
bytes memory _value, bytes memory _value,
bytes memory _proof, bytes memory _proof,
bytes32 _root bytes32 _root
) internal pure returns (bool _verified) { ) internal pure returns (bool) {
(bool exists, bytes memory value) = get(_key, _proof, _root); (bool exists, bytes memory value) = get(_key, _proof, _root);
return (exists && BytesUtils.equal(_value, value)); return (exists && BytesUtils.equal(_value, value));
} }
/** /**
* @notice Retrieves the value associated with a given key. * @notice Retrieves the value associated with a given key.
* @param _key Key to search for, as hex bytes. *
* @param _key Key to search for, as hex bytes.
* @param _proof Merkle trie inclusion proof for the key. * @param _proof Merkle trie inclusion proof for the key.
* @param _root Known root of the Merkle trie. * @param _root Known root of the Merkle trie.
* @return _exists Whether or not the key exists. *
* @return _value Value of the key if it exists. * @return Whether or not the key exists.
* @return Value of the key if it exists.
*/ */
function get( function get(
bytes memory _key, bytes memory _key,
bytes memory _proof, bytes memory _proof,
bytes32 _root bytes32 _root
) internal pure returns (bool _exists, bytes memory _value) { ) internal pure returns (bool, bytes memory) {
TrieNode[] memory proof = _parseProof(_proof); TrieNode[] memory proof = _parseProof(_proof);
(uint256 pathLength, bytes memory keyRemainder, bool isFinalNode) = _walkNodePath( (uint256 pathLength, bytes memory keyRemainder, bool isFinalNode) = _walkNodePath(
proof, proof,
...@@ -99,18 +114,16 @@ library MerkleTrie { ...@@ -99,18 +114,16 @@ library MerkleTrie {
return (exists, value); return (exists, value);
} }
/*********************
* Private Functions *
*********************/
/** /**
* @notice Walks through a proof using a provided key. * @notice Walks through a proof using a provided key.
*
* @param _proof Inclusion proof to walk through. * @param _proof Inclusion proof to walk through.
* @param _key Key to use for the walk. * @param _key Key to use for the walk.
* @param _root Known root of the trie. * @param _root Known root of the trie.
* @return _pathLength Length of the final path *
* @return _keyRemainder Portion of the key remaining after the walk. * @return Length of the final path
* @return _isFinalNode Whether or not we've hit a dead end. * @return Portion of the key remaining after the walk.
* @return Whether or not we've hit a dead end.
*/ */
function _walkNodePath( function _walkNodePath(
TrieNode[] memory _proof, TrieNode[] memory _proof,
...@@ -120,9 +133,9 @@ library MerkleTrie { ...@@ -120,9 +133,9 @@ library MerkleTrie {
private private
pure pure
returns ( returns (
uint256 _pathLength, uint256,
bytes memory _keyRemainder, bytes memory,
bool _isFinalNode bool
) )
{ {
uint256 pathLength = 0; uint256 pathLength = 0;
...@@ -223,10 +236,12 @@ library MerkleTrie { ...@@ -223,10 +236,12 @@ library MerkleTrie {
/** /**
* @notice Parses an RLP-encoded proof into something more useful. * @notice Parses an RLP-encoded proof into something more useful.
*
* @param _proof RLP-encoded proof to parse. * @param _proof RLP-encoded proof to parse.
* @return _parsed Proof parsed into easily accessible structs. *
* @return Proof parsed into easily accessible structs.
*/ */
function _parseProof(bytes memory _proof) private pure returns (TrieNode[] memory _parsed) { function _parseProof(bytes memory _proof) private pure returns (TrieNode[] memory) {
RLPReader.RLPItem[] memory nodes = RLPReader.readList(_proof); RLPReader.RLPItem[] memory nodes = RLPReader.readList(_proof);
TrieNode[] memory proof = new TrieNode[](nodes.length); TrieNode[] memory proof = new TrieNode[](nodes.length);
...@@ -239,13 +254,14 @@ library MerkleTrie { ...@@ -239,13 +254,14 @@ library MerkleTrie {
} }
/** /**
* @notice Picks out the ID for a node. Node ID is referred to as the * @notice Picks out the ID for a node. Node ID is referred to as the "hash" within the
* "hash" within the specification, but nodes < 32 bytes are not actually * specification, but nodes < 32 bytes are not actually hashed.
* hashed. *
* @param _node Node to pull an ID for. * @param _node Node to pull an ID for.
* @return _nodeID ID for the node, depending on the size of its contents. *
* @return ID for the node, depending on the size of its contents.
*/ */
function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes32 _nodeID) { function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes32) {
bytes memory nodeID; bytes memory nodeID;
if (_node.length < 32) { if (_node.length < 32) {
...@@ -261,33 +277,38 @@ library MerkleTrie { ...@@ -261,33 +277,38 @@ library MerkleTrie {
/** /**
* @notice Gets the path for a leaf or extension node. * @notice Gets the path for a leaf or extension node.
*
* @param _node Node to get a path for. * @param _node Node to get a path for.
* @return _path Node path, converted to an array of nibbles. *
* @return Node path, converted to an array of nibbles.
*/ */
function _getNodePath(TrieNode memory _node) private pure returns (bytes memory _path) { function _getNodePath(TrieNode memory _node) private pure returns (bytes memory) {
return BytesUtils.toNibbles(RLPReader.readBytes(_node.decoded[0])); return BytesUtils.toNibbles(RLPReader.readBytes(_node.decoded[0]));
} }
/** /**
* @notice Gets the path for a node. * @notice Gets the path for a node.
*
* @param _node Node to get a value for. * @param _node Node to get a value for.
* @return _value Node value, as hex bytes. *
* @return Node value, as hex bytes.
*/ */
function _getNodeValue(TrieNode memory _node) private pure returns (bytes memory _value) { function _getNodeValue(TrieNode memory _node) private pure returns (bytes memory) {
return RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]); return RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]);
} }
/** /**
* @notice Utility; determines the number of nibbles shared between two * @notice Utility; determines the number of nibbles shared between two nibble arrays.
* nibble arrays. *
* @param _a First nibble array. * @param _a First nibble array.
* @param _b Second nibble array. * @param _b Second nibble array.
* @return _shared Number of shared nibbles. *
* @return Number of shared nibbles.
*/ */
function _getSharedNibbleLength(bytes memory _a, bytes memory _b) function _getSharedNibbleLength(bytes memory _a, bytes memory _b)
private private
pure pure
returns (uint256 _shared) returns (uint256)
{ {
uint256 i = 0; uint256 i = 0;
while (_a.length > i && _b.length > i && _a[i] == _b[i]) { while (_a.length > i && _b.length > i && _a[i] == _b[i]) {
......
...@@ -6,61 +6,60 @@ import { MerkleTrie } from "./MerkleTrie.sol"; ...@@ -6,61 +6,60 @@ import { MerkleTrie } from "./MerkleTrie.sol";
/** /**
* @title SecureMerkleTrie * @title SecureMerkleTrie
* @notice SecureMerkleTrie is a thin wrapper around the MerkleTrie library that hashes the input
* keys. Ethereum's state trie hashes input keys before storing them.
*/ */
library SecureMerkleTrie { library SecureMerkleTrie {
/**********************
* Internal Functions *
**********************/
/** /**
* @notice Verifies a proof that a given key/value pair is present in the * @notice Verifies a proof that a given key/value pair is present in the Merkle trie.
* Merkle trie. *
* @param _key Key of the node to search for, as a hex string. * @param _key Key of the node to search for, as a hex string.
* @param _value Value of the node to search for, as a hex string. * @param _value Value of the node to search for, as a hex string.
* @param _proof Merkle trie inclusion proof for the desired node. Unlike * @param _proof Merkle trie inclusion proof for the desired node. Unlike traditional Merkle
* traditional Merkle trees, this proof is executed top-down and consists * trees, this proof is executed top-down and consists of a list of RLP-encoded
* of a list of RLP-encoded nodes that make a path down to the target node. * nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the * @param _root Known root of the Merkle trie. Used to verify that the included proof is
* included proof is correctly constructed. * correctly constructed.
* @return _verified `true` if the k/v pair exists in the trie, `false` otherwise. *
* @return Whether or not the proof is valid.
*/ */
function verifyInclusionProof( function verifyInclusionProof(
bytes memory _key, bytes memory _key,
bytes memory _value, bytes memory _value,
bytes memory _proof, bytes memory _proof,
bytes32 _root bytes32 _root
) internal pure returns (bool _verified) { ) internal pure returns (bool) {
bytes memory key = _getSecureKey(_key); bytes memory key = _getSecureKey(_key);
return MerkleTrie.verifyInclusionProof(key, _value, _proof, _root); return MerkleTrie.verifyInclusionProof(key, _value, _proof, _root);
} }
/** /**
* @notice Retrieves the value associated with a given key. * @notice Retrieves the value associated with a given key.
* @param _key Key to search for, as hex bytes. *
* @param _key Key to search for, as hex bytes.
* @param _proof Merkle trie inclusion proof for the key. * @param _proof Merkle trie inclusion proof for the key.
* @param _root Known root of the Merkle trie. * @param _root Known root of the Merkle trie.
* @return _exists Whether or not the key exists. *
* @return _value Value of the key if it exists. * @return Whether or not the key exists.
* @return Value of the key if it exists.
*/ */
function get( function get(
bytes memory _key, bytes memory _key,
bytes memory _proof, bytes memory _proof,
bytes32 _root bytes32 _root
) internal pure returns (bool _exists, bytes memory _value) { ) internal pure returns (bool, bytes memory) {
bytes memory key = _getSecureKey(_key); bytes memory key = _getSecureKey(_key);
return MerkleTrie.get(key, _proof, _root); return MerkleTrie.get(key, _proof, _root);
} }
/*********************
* Private Functions *
*********************/
/** /**
* Computes the secure counterpart to a key. * @notice Computes the hashed version of the input key.
* @param _key Key to get a secure key from. *
* @return _secureKey Secure version of the key. * @param _key Key to hash.
*
* @return Hashed version of the key.
*/ */
function _getSecureKey(bytes memory _key) private pure returns (bytes memory _secureKey) { function _getSecureKey(bytes memory _key) private pure returns (bytes memory) {
return abi.encodePacked(keccak256(_key)); return abi.encodePacked(keccak256(_key));
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment