|
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