diff --git a/packages/statemanager/src/stateManager.ts b/packages/statemanager/src/stateManager.ts index 79c75a34f7..3f82d46d90 100644 --- a/packages/statemanager/src/stateManager.ts +++ b/packages/statemanager/src/stateManager.ts @@ -1,6 +1,12 @@ import { Chain, Common } from '@ethereumjs/common' import { RLP } from '@ethereumjs/rlp' -import { Trie, createTrieFromProof, verifyTrieProof } from '@ethereumjs/trie' +import { + Trie, + createProof, + createTrieFromProof, + updateFromProof, + verifyTrieProof, +} from '@ethereumjs/trie' import { Account, KECCAK256_NULL, @@ -629,19 +635,19 @@ export class DefaultStateManager implements StateManagerInterface { codeHash: KECCAK256_NULL_S, nonce: '0x0', storageHash: KECCAK256_RLP_S, - accountProof: (await this._trie.createProof(address.bytes)).map((p) => bytesToHex(p)), + accountProof: (await createProof(this._trie, address.bytes)).map((p) => bytesToHex(p)), storageProof: [], } return returnValue } - const accountProof: PrefixedHexString[] = (await this._trie.createProof(address.bytes)).map( + const accountProof: PrefixedHexString[] = (await createProof(this._trie, address.bytes)).map( (p) => bytesToHex(p), ) const storageProof: StorageProof[] = [] const storageTrie = this._getStorageTrie(address, account) for (const storageKey of storageSlots) { - const proof = (await storageTrie.createProof(storageKey)).map((p) => bytesToHex(p)) + const proof = (await createProof(storageTrie, storageKey)).map((p) => bytesToHex(p)) const value = bytesToHex(await this.getStorage(address, storageKey)) const proofItem: StorageProof = { key: bytesToHex(storageKey), @@ -717,7 +723,8 @@ export class DefaultStateManager implements StateManagerInterface { const trie = this._getStorageTrie(address) trie.root(hexToBytes(storageHash)) for (let i = 0; i < storageProof.length; i++) { - await trie.updateFromProof( + await updateFromProof( + trie, storageProof[i].proof.map((e) => hexToBytes(e)), safe, ) @@ -733,7 +740,8 @@ export class DefaultStateManager implements StateManagerInterface { async addProofData(proof: Proof | Proof[], safe: boolean = false) { if (Array.isArray(proof)) { for (let i = 0; i < proof.length; i++) { - await this._trie.updateFromProof( + await updateFromProof( + this._trie, proof[i].accountProof.map((e) => hexToBytes(e)), safe, ) diff --git a/packages/trie/examples/createFromProof.ts b/packages/trie/examples/createFromProof.ts index f3db4f5867..e1f08dbfa4 100644 --- a/packages/trie/examples/createFromProof.ts +++ b/packages/trie/examples/createFromProof.ts @@ -1,4 +1,4 @@ -import { Trie, createTrieFromProof } from '@ethereumjs/trie' +import { Trie, createProof, createTrieFromProof, updateFromProof } from '@ethereumjs/trie' import { bytesToUtf8, utf8ToBytes } from '@ethereumjs/util' async function main() { @@ -9,12 +9,12 @@ async function main() { await someOtherTrie.put(k1, utf8ToBytes('valueOne')) await someOtherTrie.put(k2, utf8ToBytes('valueTwo')) - const proof = await someOtherTrie.createProof(k1) + const proof = await createProof(someOtherTrie, k1) const trie = await createTrieFromProof(proof, { useKeyHashing: true }) - const otherProof = await someOtherTrie.createProof(k2) + const otherProof = await createProof(someOtherTrie, k2) // To add more proofs to the trie, use `updateFromProof` - await trie.updateFromProof(otherProof) + await updateFromProof(trie, otherProof) const value = await trie.get(k1) console.log(bytesToUtf8(value!)) // valueOne diff --git a/packages/trie/examples/logDemo.ts b/packages/trie/examples/logDemo.ts index 536ec7e2a0..0875a22c3a 100644 --- a/packages/trie/examples/logDemo.ts +++ b/packages/trie/examples/logDemo.ts @@ -1,7 +1,7 @@ /** * Run with DEBUG=ethjs,trie:* to see debug log ouput */ -import { Trie } from '@ethereumjs/trie' +import { Trie, createProof, verifyProof } from '@ethereumjs/trie' import { utf8ToBytes } from '@ethereumjs/util' const trie_entries: [string, string | null][] = [ @@ -22,8 +22,8 @@ const main = async () => { for (const [key, value] of trie_entries) { await trie.put(utf8ToBytes(key), value === null ? Uint8Array.from([]) : utf8ToBytes(value)) } - const proof = await trie.createProof(utf8ToBytes('doge')) - const valid = await trie.verifyProof(trie.root(), utf8ToBytes('doge'), proof) + const proof = await createProof(trie, utf8ToBytes('doge')) + const valid = await verifyProof(trie, trie.root(), utf8ToBytes('doge'), proof) console.log('valid', valid) } diff --git a/packages/trie/examples/proofs.ts b/packages/trie/examples/proofs.ts index 4f618a688b..c2a14f38b1 100644 --- a/packages/trie/examples/proofs.ts +++ b/packages/trie/examples/proofs.ts @@ -1,4 +1,4 @@ -import { Trie } from '@ethereumjs/trie' +import { Trie, createProof, verifyProof } from '@ethereumjs/trie' import { bytesToUtf8, utf8ToBytes } from '@ethereumjs/util' const trie = new Trie() @@ -11,24 +11,24 @@ async function main() { // proof-of-inclusion await trie.put(k1, v1) - let proof = await trie.createProof(k1) - let value = await trie.verifyProof(trie.root(), k1, proof) + let proof = await createProof(trie, k1) + let value = await verifyProof(trie, trie.root(), k1, proof) console.log(value ? bytesToUtf8(value) : 'not found') // 'one' // proof-of-exclusion await trie.put(k1, v1) await trie.put(k2, v2) - proof = await trie.createProof(utf8ToBytes('key3')) - value = await trie.verifyProof(trie.root(), utf8ToBytes('key3'), proof) + proof = await createProof(trie, utf8ToBytes('key3')) + value = await verifyProof(trie, trie.root(), utf8ToBytes('key3'), proof) console.log(value ? bytesToUtf8(value) : 'null') // null // invalid proof await trie.put(k1, v1) await trie.put(k2, v2) - proof = await trie.createProof(k2) + proof = await createProof(trie, k2) proof[0].reverse() try { - const _value = await trie.verifyProof(trie.root(), k2, proof) // results in error + const _value = await verifyProof(trie, trie.root(), k2, proof) // results in error } catch (err) { console.log(err) } diff --git a/packages/trie/src/constructors.ts b/packages/trie/src/constructors.ts index 42676729ad..0d5844bbd1 100644 --- a/packages/trie/src/constructors.ts +++ b/packages/trie/src/constructors.ts @@ -7,7 +7,7 @@ import { import { keccak256 } from 'ethereum-cryptography/keccak' import { concatBytes } from 'ethereum-cryptography/utils' -import { ROOT_DB_KEY, Trie } from './index.js' +import { ROOT_DB_KEY, Trie, updateFromProof } from './index.js' import type { Proof, TrieOpts } from './index.js' @@ -63,7 +63,7 @@ export async function createTrie(opts?: TrieOpts) { export async function createTrieFromProof(proof: Proof, trieOpts?: TrieOpts) { const shouldVerifyRoot = trieOpts?.root !== undefined const trie = new Trie(trieOpts) - const root = await trie.updateFromProof(proof, shouldVerifyRoot) + const root = await updateFromProof(trie, proof, shouldVerifyRoot) trie.root(root) await trie.persistRoot() return trie diff --git a/packages/trie/src/proof/index.ts b/packages/trie/src/proof/index.ts index 022acdaf27..c7ec4ac5cc 100644 --- a/packages/trie/src/proof/index.ts +++ b/packages/trie/src/proof/index.ts @@ -1,13 +1,15 @@ +import { bytesToHex, concatBytes, equalsBytes } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak' import { createTrieFromProof } from '../constructors.js' -import { verifyRangeProof } from '../index.js' +import { Trie, verifyRangeProof } from '../index.js' import { bytesToNibbles } from '../util/nibbles.js' import type { Proof, TrieOpts } from '../index.js' +import type { PutBatch } from '@ethereumjs/util' /** - * Static version of verifyProof function with the same behavior. An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof contains the encoded trie nodes + * 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. * @param rootHash Root hash of the trie that this proof was created from and is being verified for * @param key Key that is being verified and that the proof is created for @@ -33,8 +35,7 @@ export async function verifyTrieProof( // /** // * 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, // * allowing an entire range of leaf nodes to be validated. This is useful in applications such as snap sync where contiguous ranges -// * of state trie data is received and validated for constructing world state, locally. Also see {@link verifyRangeProof}. A static -// * version of this function also exists. +// * of state trie data is received and validated for constructing world state, locally. Also see {@link verifyRangeProof}. // * @param rootHash - root hash of state trie this proof is being verified against. // * @param firstKey - first key of range being proven. // * @param lastKey - last key of range being proven. @@ -64,4 +65,104 @@ export function verifyTrieRangeProof( ) } +/** + * Creates a proof from a trie and key that can be verified using {@link verifyTrieProof}. 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. The returned proof will be in the format of an array that contains Uint8Arrays of + * serialized branch, extension, and/or leaf nodes. + * @param key key to create a proof for + */ +export async function createProof(trie: Trie, key: Uint8Array): Promise { + trie['DEBUG'] && trie['debug'](`Creating Proof for Key: ${bytesToHex(key)}`, ['CREATE_PROOF']) + const { stack } = await trie.findPath(trie['appliedKey'](key)) + const p = stack.map((stackElem) => { + return stackElem.serialize() + }) + trie['DEBUG'] && trie['debug'](`Proof created with (${stack.length}) nodes`, ['CREATE_PROOF']) + return p +} + +/** + * Updates a trie from a proof by putting all the nodes in the proof into the trie. Pass {@param shouldVerifyRoot} as true to check + * that root key of proof matches root of trie and throw if not. + * 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. + * @param proof An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof to update the trie from. + * @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). + * @returns The root of the proof + */ +export async function updateFromProof(trie: Trie, proof: Proof, shouldVerifyRoot: boolean = false) { + trie['DEBUG'] && trie['debug'](`Saving (${proof.length}) proof nodes in DB`, ['FROM_PROOF']) + const opStack = proof.map((nodeValue) => { + let key = Uint8Array.from(trie['hash'](nodeValue)) + key = trie['_opts'].keyPrefix ? concatBytes(trie['_opts'].keyPrefix, key) : key + return { + type: 'put', + key, + value: nodeValue, + } as PutBatch + }) + + if (shouldVerifyRoot) { + if (opStack[0] !== undefined && opStack[0] !== null) { + if (!equalsBytes(trie.root(), opStack[0].key)) { + throw new Error('The provided proof does not have the expected trie root') + } + } + } + + await trie['_db'].batch(opStack) + if (opStack[0] !== undefined) { + return opStack[0].key + } +} + +/** + * 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 + * contains the encoded trie nodes from the root node to the leaf node storing state data. + * @param rootHash Root hash of the trie that this proof was created from and is being verified for + * @param key Key that is being verified and that the proof is created for + * @param proof an EIP-1186 proof to verify the key against + * @throws If proof is found to be invalid. + * @returns The value from the key, or null if valid proof of non-existence. + */ +export async function verifyProof( + trie: Trie, + rootHash: Uint8Array, + key: Uint8Array, + proof: Proof, +): Promise { + trie['DEBUG'] && + trie['debug']( + `Verifying Proof:\n|| Key: ${bytesToHex(key)}\n|| Root: ${bytesToHex( + rootHash, + )}\n|| Proof: (${proof.length}) nodes + `, + ['VERIFY_PROOF'], + ) + const proofTrie = new Trie({ + root: rootHash, + useKeyHashingFunction: trie['_opts'].useKeyHashingFunction, + common: trie['_opts'].common, + }) + try { + await updateFromProof(proofTrie, proof, true) + } catch (e: any) { + throw new Error('Invalid proof nodes given') + } + try { + trie['DEBUG'] && + trie['debug'](`Verifying proof by retrieving key: ${bytesToHex(key)} from proof trie`, [ + 'VERIFY_PROOF', + ]) + const value = await proofTrie.get(trie['appliedKey'](key), true) + trie['DEBUG'] && trie['debug'](`PROOF VERIFIED`, ['VERIFY_PROOF']) + return value + } catch (err: any) { + if (err.message === 'Missing node in DB') { + throw new Error('Invalid proof provided') + } else { + throw err + } + } +} + export * from './range.js' diff --git a/packages/trie/src/trie.ts b/packages/trie/src/trie.ts index 53f8cea120..6f32b8ec62 100644 --- a/packages/trie/src/trie.ts +++ b/packages/trie/src/trie.ts @@ -28,7 +28,6 @@ import { decodeRawNode, isRawNode, } from './node/index.js' -import { verifyRangeProof } from './proof/range.js' import { ROOT_DB_KEY } from './types.js' import { _walkTrie } from './util/asyncWalk.js' import { bytesToNibbles, matchingNibbleLength, nibblesTypeToPackedBytes } from './util/nibbles.js' @@ -39,14 +38,13 @@ import type { FoundNodeFunction, Nibbles, Path, - Proof, TrieNode, TrieOpts, TrieOptsWithDefaults, TrieShallowCopyOpts, } from './types.js' import type { OnFound } from './util/asyncWalk.js' -import type { BatchDBOp, DB, PutBatch } from '@ethereumjs/util' +import type { BatchDBOp, DB } from '@ethereumjs/util' import type { Debugger } from 'debug' /** @@ -134,157 +132,6 @@ export class Trie { || ----------------`) } - /** - * 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, - * allowing an entire range of leaf nodes to be validated. This is useful in applications such as snap sync where contiguous ranges - * of state trie data is received and validated for constructing world state, locally. Also see {@link verifyRangeProof}. A static - * version of this function also exists. - * @param rootHash - root hash of state trie this proof is being verified against. - * @param firstKey - first key of range being proven. - * @param lastKey - last key of range being proven. - * @param keys - key list of leaf data being proven. - * @param values - value list of leaf data being proven, one-to-one correspondence with keys. - * @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 - * @returns a flag to indicate whether there exists more trie node in the trie - */ - verifyRangeProof( - rootHash: Uint8Array, - firstKey: Uint8Array | null, - lastKey: Uint8Array | null, - keys: Uint8Array[], - values: Uint8Array[], - proof: Uint8Array[] | null, - ): Promise { - return verifyRangeProof( - rootHash, - firstKey && bytesToNibbles(this.appliedKey(firstKey)), - lastKey && bytesToNibbles(this.appliedKey(lastKey)), - keys.map((k) => this.appliedKey(k)).map(bytesToNibbles), - values, - proof, - this._opts.useKeyHashingFunction, - ) - } - - /** - * Creates a proof from a trie and key that can be verified using {@link verifyTrieProof}. 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. The returned proof will be in the format of an array that contains Uint8Arrays of - * serialized branch, extension, and/or leaf nodes. - * @param key key to create a proof for - */ - async createProof(key: Uint8Array): Promise { - this.DEBUG && this.debug(`Creating Proof for Key: ${bytesToHex(key)}`, ['CREATE_PROOF']) - const { stack } = await this.findPath(this.appliedKey(key)) - const p = stack.map((stackElem) => { - return stackElem.serialize() - }) - this.DEBUG && this.debug(`Proof created with (${stack.length}) nodes`, ['CREATE_PROOF']) - return p - } - - /** - * Updates a trie from a proof by putting all the nodes in the proof into the trie. If a trie is being updated with multiple proofs, {@param shouldVerifyRoot} can - * be passed as false in order to not immediately throw on an unexpected root, so that root verification can happen after all proofs and their nodes have been added. - * 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. - * @param proof An (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof to update the trie from. - * @param shouldVerifyRoot If `true`, verifies that the root key of the proof matches the trie root. Throws if this is not the case. - * @returns The root of the proof - */ - async updateFromProof(proof: Proof, shouldVerifyRoot: boolean = false) { - this.DEBUG && this.debug(`Saving (${proof.length}) proof nodes in DB`, ['FROM_PROOF']) - const opStack = proof.map((nodeValue) => { - let key = Uint8Array.from(this.hash(nodeValue)) - key = this._opts.keyPrefix ? concatBytes(this._opts.keyPrefix, key) : key - return { - type: 'put', - key, - value: nodeValue, - } as PutBatch - }) - - if (shouldVerifyRoot) { - if (opStack[0] !== undefined && opStack[0] !== null) { - if (!equalsBytes(this.root(), opStack[0].key)) { - throw new Error('The provided proof does not have the expected trie root') - } - } - } - - await this._db.batch(opStack) - if (opStack[0] !== undefined) { - return opStack[0].key - } - } - - /** - * 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 - * contains the encoded trie nodes from the root node to the leaf node storing state data. A static version of this function exists with the same name. - * @param rootHash Root hash of the trie that this proof was created from and is being verified for - * @param key Key that is being verified and that the proof is created for - * @param proof an EIP-1186 proof to verify the key against - * @throws If proof is found to be invalid. - * @returns The value from the key, or null if valid proof of non-existence. - */ - async verifyProof( - rootHash: Uint8Array, - key: Uint8Array, - proof: Proof, - ): Promise { - this.DEBUG && - this.debug( - `Verifying Proof:\n|| Key: ${bytesToHex(key)}\n|| Root: ${bytesToHex( - rootHash, - )}\n|| Proof: (${proof.length}) nodes - `, - ['VERIFY_PROOF'], - ) - const proofTrie = new Trie({ - root: rootHash, - useKeyHashingFunction: this._opts.useKeyHashingFunction, - common: this._opts.common, - }) - try { - await proofTrie.updateFromProof(proof, true) - } catch (e: any) { - throw new Error('Invalid proof nodes given') - } - try { - this.DEBUG && - this.debug(`Verifying proof by retrieving key: ${bytesToHex(key)} from proof trie`, [ - 'VERIFY_PROOF', - ]) - const value = await proofTrie.get(this.appliedKey(key), true) - this.DEBUG && this.debug(`PROOF VERIFIED`, ['VERIFY_PROOF']) - return value - } catch (err: any) { - if (err.message === 'Missing node in DB') { - throw new Error('Invalid proof provided') - } else { - throw err - } - } - } - - /** - * Create a trie from a given (EIP-1186)[https://eips.ethereum.org/EIPS/eip-1186] proof. An EIP-1186 proof contains the encoded trie nodes from the root - * node to the leaf node storing state data. This function does not check if the proof has the same expected root. A static version of this function exists - * with the same name. - * @param proof an EIP-1186 proof to update the trie from - * @deprecated Use `updateFromProof` - */ - async fromProof(proof: Proof): Promise { - await this.updateFromProof(proof, false) - - if (equalsBytes(this.root(), this.EMPTY_TRIE_ROOT) && proof[0] !== undefined) { - let rootKey = Uint8Array.from(this.hash(proof[0])) - // TODO: what if we have keyPrefix and we set root? This should not work, right? (all trie nodes are non-reachable) - rootKey = this._opts.keyPrefix ? concatBytes(this._opts.keyPrefix, rootKey) : rootKey - this.root(rootKey) - await this.persistRoot() - } - return - } - database(db?: DB, valueEncoding?: ValueEncoding) { if (db !== undefined) { if (db instanceof CheckpointDB) { diff --git a/packages/trie/test/proof.spec.ts b/packages/trie/test/proof.spec.ts index 2a5b751830..56d22c195e 100644 --- a/packages/trie/test/proof.spec.ts +++ b/packages/trie/test/proof.spec.ts @@ -2,7 +2,13 @@ import { RLP } from '@ethereumjs/rlp' import { bytesToUtf8, equalsBytes, setLengthLeft, utf8ToBytes } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' -import { Trie, createTrieFromProof, verifyTrieProof } from '../src/index.js' +import { + Trie, + createProof, + createTrieFromProof, + updateFromProof, + verifyTrieProof, +} from '../src/index.js' describe('simple merkle proofs generation and verification', () => { it('create a merkle proof and verify it', async () => { @@ -12,27 +18,27 @@ describe('simple merkle proofs generation and verification', () => { await trie.put(utf8ToBytes('key2bb'), utf8ToBytes('aval2')) await trie.put(utf8ToBytes('key3cc'), utf8ToBytes('aval3')) - let proof = await trie.createProof(utf8ToBytes('key2bb')) + let proof = await createProof(trie, utf8ToBytes('key2bb')) let val = await verifyTrieProof(utf8ToBytes('key2bb'), proof) assert.equal(bytesToUtf8(val!), 'aval2') - proof = await trie.createProof(utf8ToBytes('key1aa')) + proof = await createProof(trie, utf8ToBytes('key1aa')) val = await verifyTrieProof(utf8ToBytes('key1aa'), proof) assert.equal(bytesToUtf8(val!), '0123456789012345678901234567890123456789xx') - proof = await trie.createProof(utf8ToBytes('key2bb')) + proof = await createProof(trie, utf8ToBytes('key2bb')) val = await verifyTrieProof(utf8ToBytes('key2'), proof) // In this case, the proof _happens_ to contain enough nodes to prove `key2` because // traversing into `key22` would touch all the same nodes as traversing into `key2` assert.equal(val, null, 'Expected value at a random key to be null') let myKey = utf8ToBytes('anyrandomkey') - proof = await trie.createProof(myKey) + proof = await createProof(trie, myKey) val = await verifyTrieProof(myKey, proof) assert.equal(val, null, 'Expected value to be null') myKey = utf8ToBytes('anothergarbagekey') // should generate a valid proof of null - proof = await trie.createProof(myKey) + proof = await createProof(trie, myKey) proof.push(utf8ToBytes('123456')) // extra nodes are just ignored val = await verifyTrieProof(myKey, proof) assert.equal(val, null, 'Expected value to be null') @@ -40,7 +46,7 @@ describe('simple merkle proofs generation and verification', () => { await trie.put(utf8ToBytes('another'), utf8ToBytes('3498h4riuhgwe')) // to fail our proof we can request a proof for one key - proof = await trie.createProof(utf8ToBytes('another')) + proof = await createProof(trie, utf8ToBytes('another')) // and try to use that proof on another key try { await verifyTrieProof(utf8ToBytes('key1aa'), proof) @@ -50,7 +56,7 @@ describe('simple merkle proofs generation and verification', () => { } // we can also corrupt a valid proof - proof = await trie.createProof(utf8ToBytes('key2bb')) + proof = await createProof(trie, utf8ToBytes('key2bb')) proof[0].reverse() try { await verifyTrieProof(utf8ToBytes('key2bb'), proof) @@ -62,7 +68,7 @@ describe('simple merkle proofs generation and verification', () => { // test an invalid exclusion proof by creating // a valid exclusion proof then making it non-null myKey = utf8ToBytes('anyrandomkey') - proof = await trie.createProof(myKey) + proof = await createProof(trie, myKey) val = await verifyTrieProof(myKey, proof) assert.equal(val, null, 'Expected value to be null') // now make the key non-null so the exclusion proof becomes invalid @@ -80,7 +86,7 @@ describe('simple merkle proofs generation and verification', () => { await trie.put(utf8ToBytes('key1aa'), utf8ToBytes('0123456789012345678901234567890123456789xx')) - const proof = await trie.createProof(utf8ToBytes('key1aa')) + const proof = await createProof(trie, utf8ToBytes('key1aa')) const val = await verifyTrieProof(utf8ToBytes('key1aa'), proof) assert.equal(bytesToUtf8(val!), '0123456789012345678901234567890123456789xx') }) @@ -90,7 +96,7 @@ describe('simple merkle proofs generation and verification', () => { await trie.put(utf8ToBytes('key1aa'), utf8ToBytes('01234')) - const proof = await trie.createProof(utf8ToBytes('key1aa')) + const proof = await createProof(trie, utf8ToBytes('key1aa')) const val = await verifyTrieProof(utf8ToBytes('key1aa'), proof) assert.equal(bytesToUtf8(val!), '01234') }) @@ -111,15 +117,15 @@ describe('simple merkle proofs generation and verification', () => { await trie.put(utf8ToBytes('key3cc'), utf8ToBytes('aval3')) await trie.put(utf8ToBytes('key3'), utf8ToBytes('1234567890123456789012345678901')) - let proof = await trie.createProof(utf8ToBytes('key1')) + let proof = await createProof(trie, utf8ToBytes('key1')) let val = await verifyTrieProof(utf8ToBytes('key1'), proof) assert.equal(bytesToUtf8(val!), '0123456789012345678901234567890123456789Very_Long') - proof = await trie.createProof(utf8ToBytes('key2')) + proof = await createProof(trie, utf8ToBytes('key2')) val = await verifyTrieProof(utf8ToBytes('key2'), proof) assert.equal(bytesToUtf8(val!), 'short') - proof = await trie.createProof(utf8ToBytes('key3')) + proof = await createProof(trie, utf8ToBytes('key3')) val = await verifyTrieProof(utf8ToBytes('key3'), proof) assert.equal(bytesToUtf8(val!), '1234567890123456789012345678901') }) @@ -131,15 +137,15 @@ describe('simple merkle proofs generation and verification', () => { await trie.put(utf8ToBytes('b'), utf8ToBytes('b')) await trie.put(utf8ToBytes('c'), utf8ToBytes('c')) - let proof = await trie.createProof(utf8ToBytes('a')) + let proof = await createProof(trie, utf8ToBytes('a')) let val = await verifyTrieProof(utf8ToBytes('a'), proof) assert.equal(bytesToUtf8(val!), 'a') - proof = await trie.createProof(utf8ToBytes('b')) + proof = await createProof(trie, utf8ToBytes('b')) val = await verifyTrieProof(utf8ToBytes('b'), proof) assert.equal(bytesToUtf8(val!), 'b') - proof = await trie.createProof(utf8ToBytes('c')) + proof = await createProof(trie, utf8ToBytes('c')) val = await verifyTrieProof(utf8ToBytes('c'), proof) assert.equal(bytesToUtf8(val!), 'c') }) @@ -159,7 +165,7 @@ describe('simple merkle proofs generation and verification', () => { await trie.put(key, encodedValue) await trie.put(key2, encodedValue2) await trie.put(key3, encodedValue3) - const proof = await trie.createProof(key) + const proof = await createProof(trie, key) const newTrie = await createTrieFromProof(proof, { useKeyHashing: true }) const trieValue = await newTrie.get(key) @@ -167,8 +173,8 @@ describe('simple merkle proofs generation and verification', () => { assert.ok(equalsBytes(trieValue!, encodedValue), 'trie value sucessfully copied') assert.ok(equalsBytes(trie.root(), newTrie.root()), 'root set correctly') - const proof2 = await trie.createProof(key2) - await newTrie.updateFromProof(proof2) + const proof2 = await createProof(trie, key2) + await updateFromProof(newTrie, proof2) const trieValue2 = await newTrie.get(key2) assert.ok(equalsBytes(trieValue2!, encodedValue2), 'trie value succesfully updated') @@ -182,16 +188,16 @@ describe('simple merkle proofs generation and verification', () => { const safeValue = RLP.encode(new Uint8Array([1337])) await safeTrie.put(safeKey, safeValue) - const safeProof = await safeTrie.createProof(safeKey) + const safeProof = await createProof(safeTrie, safeKey) try { - await newTrie.updateFromProof(safeProof, true) + await updateFromProof(newTrie, safeProof, true) assert.fail('cannot reach this') } catch (e) { assert.ok(true, 'throws on unmatching proof') } - await newTrie.updateFromProof(safeProof) + await updateFromProof(newTrie, safeProof) assert.ok(equalsBytes(trie.root(), newTrie.root()), 'root set correctly') const newSafeValue = await newTrie.get(safeKey) diff --git a/packages/trie/test/proof/range.spec.ts b/packages/trie/test/proof/range.spec.ts index 3fb45cf464..2ca66baefa 100644 --- a/packages/trie/test/proof/range.spec.ts +++ b/packages/trie/test/proof/range.spec.ts @@ -9,7 +9,7 @@ import { } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' -import { Trie } from '../../src/index.js' +import { Trie, createProof, verifyTrieRangeProof } from '../../src/index.js' import type { DB } from '@ethereumjs/util' @@ -88,13 +88,13 @@ async function verify( startKey = startKey ?? entries[start][0] endKey = endKey ?? entries[end][0] const targetRange = entries.slice(start, end + 1) - return trie.verifyRangeProof( + return verifyTrieRangeProof( trie.root(), startKey, endKey, keys ?? targetRange.map(([key]) => key), vals ?? targetRange.map(([, val]) => val), - [...(await trie.createProof(startKey)), ...(await trie.createProof(endKey))], + [...(await createProof(trie, startKey)), ...(await createProof(trie, endKey))], ) } @@ -211,7 +211,7 @@ describe('simple merkle range proofs generation and verification', () => { const { trie, entries } = await randomTrie(new MapDB()) assert.equal( - await trie.verifyRangeProof( + await verifyTrieRangeProof( trie.root(), null, null, @@ -474,7 +474,7 @@ describe('simple merkle range proofs generation and verification', () => { let bloatedProof: Uint8Array[] = [] for (let i = 0; i < TRIE_SIZE; i++) { - bloatedProof = bloatedProof.concat(await trie.createProof(entries[i][0])) + bloatedProof = bloatedProof.concat(await createProof(trie, entries[i][0])) } assert.equal(await verify(trie, entries, 0, entries.length - 1), false) diff --git a/packages/trie/test/trie/secure.spec.ts b/packages/trie/test/trie/secure.spec.ts index 2a866250af..a13171adb4 100644 --- a/packages/trie/test/trie/secure.spec.ts +++ b/packages/trie/test/trie/secure.spec.ts @@ -10,7 +10,7 @@ import { keccak256 } from 'ethereum-cryptography/keccak.js' import { sha256 } from 'ethereum-cryptography/sha256.js' import { assert, describe, it } from 'vitest' -import { ROOT_DB_KEY, Trie, verifyTrieProof } from '../../src/index.js' +import { ROOT_DB_KEY, Trie, createProof, verifyTrieProof } from '../../src/index.js' import secureTrieTests from '../fixtures/trietest_secureTrie.json' describe('SecureTrie', () => { @@ -52,7 +52,7 @@ describe('SecureTrie proof', () => { const trie = new Trie({ useKeyHashing: true, db: new MapDB() }) await trie.put(utf8ToBytes('key1aa'), utf8ToBytes('01234')) - const proof = await trie.createProof(utf8ToBytes('key1aa')) + const proof = await createProof(trie, utf8ToBytes('key1aa')) const val = await verifyTrieProof(utf8ToBytes('key1aa'), proof, { useKeyHashing: true, }) diff --git a/packages/trie/test/util/asyncWalk.spec.ts b/packages/trie/test/util/asyncWalk.spec.ts index 51fefddc9f..0adf4e2d09 100644 --- a/packages/trie/test/util/asyncWalk.spec.ts +++ b/packages/trie/test/util/asyncWalk.spec.ts @@ -1,7 +1,13 @@ import { bytesToHex, equalsBytes, hexToBytes, utf8ToBytes } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' -import { LeafNode, Trie, createTrieFromProof, verifyTrieProof } from '../../src/index.js' +import { + LeafNode, + Trie, + createProof, + createTrieFromProof, + verifyTrieProof, +} from '../../src/index.js' import { _walkTrie } from '../../src/util/asyncWalk.js' import { bytesToNibbles } from '../../src/util/nibbles.js' import trieTests from '../fixtures/trietest.json' @@ -78,7 +84,7 @@ describe('walk a sparse trie', async () => { }) // Generate a proof for inputs[0] const proofKey = inputs[0][0] - const proof = await trie.createProof(proofKey) + const proof = await createProof(trie, proofKey) assert.ok(await verifyTrieProof(proofKey, proof)) // Build a sparse trie from the proof diff --git a/packages/trie/test/util/log.spec.ts b/packages/trie/test/util/log.spec.ts index bb58340d2b..b4f79826d1 100644 --- a/packages/trie/test/util/log.spec.ts +++ b/packages/trie/test/util/log.spec.ts @@ -1,6 +1,7 @@ import { utf8ToBytes } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' +import { createProof, createTrieFromProof, verifyProof } from '../../src/index.js' import { Trie } from '../../src/trie.js' describe('Run Trie script with DEBUG enabled', async () => { @@ -19,8 +20,8 @@ describe('Run Trie script with DEBUG enabled', async () => { await trie.put(utf8ToBytes(key), value === null ? Uint8Array.from([]) : utf8ToBytes(value)) } - const proof = await trie.createProof(utf8ToBytes('doge')) - const valid = await trie.verifyProof(trie.root(), utf8ToBytes('doge'), proof) + const proof = await createProof(trie, utf8ToBytes('doge')) + const valid = await verifyProof(trie, trie.root(), utf8ToBytes('doge'), proof) it('should be valid', async () => { assert.deepEqual(valid, utf8ToBytes('coin')) @@ -32,9 +33,8 @@ describe('Run Trie script with DEBUG enabled', async () => { trie.checkpoint() await trie.revert() process.env.DEBUG = '' - const trie2 = new Trie({}) + const trie2 = await createTrieFromProof(proof) trie2['DEBUG'] = true - await trie2.fromProof(proof) it('tries should share root', async () => { assert.deepEqual(trie.root(), trie2.root()) })