@@ -43,15 +43,25 @@ library TreeCbor {
4343 function getCid (Tree memory tree , CidCbor.CidBytes32 indexCid , uint startIdx )
4444 internal
4545 pure
46- returns (TreeNodeCbor.TreeNode memory , uint index )
46+ returns (TreeNodeCbor.TreeNode memory , uint )
4747 {
4848 bytes32 indexBytes = CidCbor.CidBytes32.unwrap (indexCid);
4949 for (uint i = startIdx; i < tree.cids.length ; i++ ) {
5050 if (CidCbor.CidBytes32.unwrap (tree.cids[i]) == indexBytes) {
5151 return (tree.nodes[i], i);
5252 }
5353 }
54- revert ("node not found " );
54+ revert ("couldn't get cid, not found " );
55+ }
56+
57+ function hasCid (Tree memory tree , CidCbor.CidBytes32 indexCid , uint startIdx ) internal pure returns (bool , uint ) {
58+ bytes32 indexBytes = CidCbor.CidBytes32.unwrap (indexCid);
59+ for (uint i = startIdx; i < tree.cids.length ; i++ ) {
60+ if (CidCbor.CidBytes32.unwrap (tree.cids[i]) == indexBytes) {
61+ return (true , i);
62+ }
63+ }
64+ return (false , 0 );
5565 }
5666
5767 function validTree (Tree memory tree ) internal pure returns (Tree memory ) {
@@ -64,4 +74,68 @@ library TreeCbor {
6474 }
6575 return tree;
6676 }
77+
78+ function verifyInclusion (
79+ TreeCbor.Tree memory tree ,
80+ bytes [] memory treeCbor ,
81+ CidCbor.CidBytes32 entryCid ,
82+ bytes memory targetRecord ,
83+ string memory targetKey
84+ ) internal pure returns (bool ) {
85+ CidCbor.CidBytes32 targetCid = CidCbor.CidBytes32.wrap (sha256 (targetRecord));
86+ CidCbor.CidBytes32[] memory queue = new CidCbor.CidBytes32 [](1 );
87+ queue[0 ] = entryCid;
88+
89+ CidCbor.CidBytes32 leftWalk;
90+ CidCbor.CidBytes32[] memory rightWalk;
91+ CidCbor.CidBytes32 currentCid;
92+ TreeNodeCbor.TreeNode memory currentNode;
93+ uint currentIndex;
94+
95+ bool found = false ;
96+ bool hasCurrent = false ;
97+
98+ CidCbor.CidBytes32[] memory newQueue;
99+
100+ while (queue.length > 0 ) {
101+ currentCid = queue[0 ];
102+ (hasCurrent, currentIndex) = TreeCbor.hasCid (tree, currentCid, currentIndex);
103+ if (! hasCurrent) {
104+ newQueue = new CidCbor.CidBytes32 [](queue.length - 1 );
105+ for (uint i = 0 ; i < newQueue.length ; i++ ) {
106+ newQueue[i] = queue[i + 1 ];
107+ }
108+ queue = newQueue;
109+ continue ;
110+ }
111+ (currentNode, currentIndex) = TreeCbor.getCid (tree, currentCid, currentIndex);
112+
113+ leftWalk = CidCbor.readCidBytes32 (treeCbor[currentIndex], currentNode.left);
114+ rightWalk = new CidCbor.CidBytes32 [](currentNode.entries.length );
115+
116+ for (uint i = 0 ; i < currentNode.entries.length ; i++ ) {
117+ rightWalk[i] = CidCbor.readCidBytes32 (treeCbor[currentIndex], currentNode.entries[i].tree);
118+ if (keccak256 (abi.encode (targetKey)) == keccak256 (abi.encode (currentNode.entries[i].key))) {
119+ CidCbor.CidBytes32 valueCid =
120+ CidCbor.readCidBytes32 (treeCbor[currentIndex], currentNode.entries[i].value);
121+ if (CidCbor.CidBytes32.unwrap (valueCid) == CidCbor.CidBytes32.unwrap (targetCid)) {
122+ require (! found, "duplicate entry " );
123+ found = true ;
124+ }
125+ }
126+ }
127+
128+ newQueue = new CidCbor.CidBytes32 [](queue.length + rightWalk.length );
129+ newQueue[0 ] = leftWalk;
130+ for (uint i = 1 ; i < queue.length ; i++ ) {
131+ newQueue[i] = queue[i];
132+ }
133+ for (uint i = 0 ; i < rightWalk.length ; i++ ) {
134+ newQueue[queue.length + i] = rightWalk[i];
135+ }
136+ queue = newQueue;
137+ }
138+
139+ return found;
140+ }
67141}
0 commit comments