|
1 |
| -import { bytesToHex, concatBytes, equalsBytes } from '@ethereumjs/util' |
2 |
| -import { keccak256 } from 'ethereum-cryptography/keccak' |
3 |
| - |
4 |
| -import { createMPTFromProof } from '../constructors.js' |
5 |
| -import { MerklePatriciaTrie } from '../index.js' |
6 |
| -import { bytesToNibbles } from '../util/nibbles.js' |
7 |
| - |
8 |
| -import { verifyRangeProof } from './range.js' |
9 |
| - |
10 |
| -import type { MPTOpts, Proof } from '../index.js' |
11 |
| -import type { PutBatch } from '@ethereumjs/util' |
12 |
| - |
13 |
| -/** |
14 |
| - * An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof contains the encoded trie nodes |
15 |
| - * from the root node to the leaf node storing state data. |
16 |
| - * @param rootHash Root hash of the trie that this proof was created from and is being verified for |
17 |
| - * @param key Key that is being verified and that the proof is created for |
18 |
| - * @param proof An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof contains the encoded trie nodes from the root node to the leaf node storing state data. |
19 |
| - * @param opts optional, the opts may include a custom hashing function to use with the trie for proof verification |
20 |
| - * @throws If proof is found to be invalid. |
21 |
| - * @returns The value from the key, or null if valid proof of non-existence. |
22 |
| - */ |
23 |
| -export async function verifyMPTProof( |
24 |
| - key: Uint8Array, |
25 |
| - proof: Proof, |
26 |
| - opts?: MPTOpts, |
27 |
| -): Promise<Uint8Array | null> { |
28 |
| - try { |
29 |
| - const proofTrie = await createMPTFromProof(proof, opts) |
30 |
| - const value = await proofTrie.get(key, true) |
31 |
| - return value |
32 |
| - } catch (err: any) { |
33 |
| - throw new Error('Invalid proof provided') |
34 |
| - } |
35 |
| -} |
36 |
| - |
37 |
| -// /** |
38 |
| -// * A range proof is a proof that includes the encoded trie nodes from the root node to leaf node for one or more branches of a trie, |
39 |
| -// * allowing an entire range of leaf nodes to be validated. This is useful in applications such as snap sync where contiguous ranges |
40 |
| -// * of state trie data is received and validated for constructing world state, locally. Also see {@link verifyRangeProof}. |
41 |
| -// * @param rootHash - root hash of state trie this proof is being verified against. |
42 |
| -// * @param firstKey - first key of range being proven. |
43 |
| -// * @param lastKey - last key of range being proven. |
44 |
| -// * @param keys - key list of leaf data being proven. |
45 |
| -// * @param values - value list of leaf data being proven, one-to-one correspondence with keys. |
46 |
| -// * @param proof - proof node list, if all-elements-proof where no proof is needed, proof should be null, and both `firstKey` and `lastKey` must be null as well |
47 |
| -// * @param opts - optional, the opts may include a custom hashing function to use with the trie for proof verification |
48 |
| -// * @returns a flag to indicate whether there exists more trie node in the trie |
49 |
| -// */ |
50 |
| -export function verifyMerkleRangeProof( |
51 |
| - rootHash: Uint8Array, |
52 |
| - firstKey: Uint8Array | null, |
53 |
| - lastKey: Uint8Array | null, |
54 |
| - keys: Uint8Array[], |
55 |
| - values: Uint8Array[], |
56 |
| - proof: Uint8Array[] | null, |
57 |
| - opts?: MPTOpts, |
58 |
| -): Promise<boolean> { |
59 |
| - return verifyRangeProof( |
60 |
| - rootHash, |
61 |
| - firstKey && bytesToNibbles(firstKey), |
62 |
| - lastKey && bytesToNibbles(lastKey), |
63 |
| - keys.map((k) => k).map(bytesToNibbles), |
64 |
| - values, |
65 |
| - proof, |
66 |
| - opts?.useKeyHashingFunction ?? keccak256, |
67 |
| - ) |
68 |
| -} |
69 |
| - |
70 |
| -/** |
71 |
| - * Creates a proof from a trie and key that can be verified using {@link verifyMPTWithMerkleProof}. An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof contains |
72 |
| - * the encoded trie nodes from the root node to the leaf node storing state data. The returned proof will be in the format of an array that contains Uint8Arrays of |
73 |
| - * serialized branch, extension, and/or leaf nodes. |
74 |
| - * @param key key to create a proof for |
75 |
| - */ |
76 |
| -export async function createMerkleProof(trie: MerklePatriciaTrie, key: Uint8Array): Promise<Proof> { |
77 |
| - trie['DEBUG'] && trie['debug'](`Creating Proof for Key: ${bytesToHex(key)}`, ['create_proof']) |
78 |
| - const { stack } = await trie.findPath(trie['appliedKey'](key)) |
79 |
| - const p = stack.map((stackElem) => { |
80 |
| - return stackElem.serialize() |
81 |
| - }) |
82 |
| - trie['DEBUG'] && trie['debug'](`Proof created with (${stack.length}) nodes`, ['create_proof']) |
83 |
| - return p |
84 |
| -} |
85 |
| - |
86 |
| -/** |
87 |
| - * Updates a trie from a proof by putting all the nodes in the proof into the trie. Pass {@param shouldVerifyRoot} as true to check |
88 |
| - * that root key of proof matches root of trie and throw if not. |
89 |
| - * An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof contains the encoded trie nodes from the root node to the leaf node storing state data. |
90 |
| - * @param trie The trie to update from the proof. |
91 |
| - * @param proof An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof to update the trie from. |
92 |
| - * @param shouldVerifyRoot - defaults to false. If `true`, verifies that the root key of the proof matches the trie root and throws if not (i.e invalid proof). |
93 |
| - * @returns The root of the proof |
94 |
| - */ |
95 |
| -export async function updateMPTFromMerkleProof( |
96 |
| - trie: MerklePatriciaTrie, |
97 |
| - proof: Proof, |
98 |
| - shouldVerifyRoot: boolean = false, |
99 |
| -) { |
100 |
| - trie['DEBUG'] && trie['debug'](`Saving (${proof.length}) proof nodes in DB`, ['from_proof']) |
101 |
| - const opStack = proof.map((nodeValue) => { |
102 |
| - let key = Uint8Array.from(trie['hash'](nodeValue)) |
103 |
| - key = trie['_opts'].keyPrefix ? concatBytes(trie['_opts'].keyPrefix, key) : key |
104 |
| - return { |
105 |
| - type: 'put', |
106 |
| - key, |
107 |
| - value: nodeValue, |
108 |
| - } as PutBatch |
109 |
| - }) |
110 |
| - |
111 |
| - if (shouldVerifyRoot) { |
112 |
| - if (opStack[0] !== undefined && opStack[0] !== null) { |
113 |
| - if (!equalsBytes(trie.root(), opStack[0].key)) { |
114 |
| - throw new Error('The provided proof does not have the expected trie root') |
115 |
| - } |
116 |
| - } |
117 |
| - } |
118 |
| - |
119 |
| - await trie['_db'].batch(opStack) |
120 |
| - if (opStack[0] !== undefined) { |
121 |
| - return opStack[0].key |
122 |
| - } |
123 |
| -} |
124 |
| - |
125 |
| -/** |
126 |
| - * Verifies a proof by putting all of its nodes into a trie and attempting to get the proven key. An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof |
127 |
| - * contains the encoded trie nodes from the root node to the leaf node storing state data. |
128 |
| - * @param trie The trie to verify the proof against |
129 |
| - * @param rootHash Root hash of the trie that this proof was created from and is being verified for |
130 |
| - * @param key Key that is being verified and that the proof is created for |
131 |
| - * @param proof an EIP-1186 proof to verify the key against |
132 |
| - * @throws If proof is found to be invalid. |
133 |
| - * @returns The value from the key, or null if valid proof of non-existence. |
134 |
| - */ |
135 |
| -export async function verifyMPTWithMerkleProof( |
136 |
| - trie: MerklePatriciaTrie, |
137 |
| - rootHash: Uint8Array, |
138 |
| - key: Uint8Array, |
139 |
| - proof: Proof, |
140 |
| -): Promise<Uint8Array | null> { |
141 |
| - trie['DEBUG'] && |
142 |
| - trie['debug']( |
143 |
| - `Verifying Proof:\n|| Key: ${bytesToHex(key)}\n|| Root: ${bytesToHex( |
144 |
| - rootHash, |
145 |
| - )}\n|| Proof: (${proof.length}) nodes |
146 |
| - `, |
147 |
| - ['VERIFY_PROOF'], |
148 |
| - ) |
149 |
| - const proofTrie = new MerklePatriciaTrie({ |
150 |
| - root: rootHash, |
151 |
| - useKeyHashingFunction: trie['_opts'].useKeyHashingFunction, |
152 |
| - common: trie['_opts'].common, |
153 |
| - }) |
154 |
| - try { |
155 |
| - await updateMPTFromMerkleProof(proofTrie, proof, true) |
156 |
| - } catch (e: any) { |
157 |
| - throw new Error('Invalid proof nodes given') |
158 |
| - } |
159 |
| - try { |
160 |
| - trie['DEBUG'] && |
161 |
| - trie['debug'](`Verifying proof by retrieving key: ${bytesToHex(key)} from proof trie`, [ |
162 |
| - 'VERIFY_PROOF', |
163 |
| - ]) |
164 |
| - const value = await proofTrie.get(trie['appliedKey'](key), true) |
165 |
| - trie['DEBUG'] && trie['debug'](`PROOF VERIFIED`, ['VERIFY_PROOF']) |
166 |
| - return value |
167 |
| - } catch (err: any) { |
168 |
| - if (err.message === 'Missing node in DB') { |
169 |
| - throw new Error('Invalid proof provided') |
170 |
| - } else { |
171 |
| - throw err |
172 |
| - } |
173 |
| - } |
174 |
| -} |
| 1 | +export * from './proof.js' |
0 commit comments