Skip to content

Commit 29799e4

Browse files
authored
mpt: adjust verifyMPTProof naming and restructure index file (#3730)
1 parent 036f63c commit 29799e4

File tree

7 files changed

+201
-200
lines changed

7 files changed

+201
-200
lines changed

packages/mpt/src/proof/index.ts

Lines changed: 1 addition & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,174 +1 @@
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'

packages/mpt/src/proof/proof.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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 verifyMerkleProof(
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+
}

0 commit comments

Comments
 (0)