diff --git a/CHANGELOG.md b/CHANGELOG.md index ee6e437..598522c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) (modification: no type change headlines) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## UNRELEASED + +## New features + +There is a new exported `WalkController` class. Also, `trie.walkTrie()` is now a public method. Using the `WalkController`, one can create own custom ways to traverse the trie. [#135](https://github.com/ethereumjs/merkle-patricia-tree/pull/135) + ## [4.0.0] - 2020-04-17 This release introduces a major API upgrade from callbacks to Promises. diff --git a/benchmarks/checkpointing.ts b/benchmarks/checkpointing.ts index f47bc72..7701c96 100644 --- a/benchmarks/checkpointing.ts +++ b/benchmarks/checkpointing.ts @@ -27,6 +27,7 @@ const iterTest = async (numOfIter: number): Promise> => { } await trie.commit() } + return process.hrtime(hrstart) } const go = async () => { diff --git a/benchmarks/random.ts b/benchmarks/random.ts index 824ead9..d72e107 100644 --- a/benchmarks/random.ts +++ b/benchmarks/random.ts @@ -21,6 +21,7 @@ const run = async (): Promise => { } } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (SYMMETRIC) { await trie.put(key, key) genRoot() @@ -36,6 +37,7 @@ const run = async (): Promise => { const go = async () => { const testName = `benchmarks/random.ts | rounds: ${ROUNDS}, ERA_SIZE: ${ERA_SIZE}, ${ + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition SYMMETRIC ? 'sys' : 'rand' }` console.time(testName) diff --git a/docs/README.md b/docs/README.md index b93a80e..a1536e1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,3 +9,4 @@ * ["baseTrie"](modules/_basetrie_.md) * ["checkpointTrie"](modules/_checkpointtrie_.md) * ["secure"](modules/_secure_.md) +* ["util/walkController"](modules/_util_walkcontroller_.md) diff --git a/docs/classes/_basetrie_.trie.md b/docs/classes/_basetrie_.trie.md index a91c78a..eddffcc 100644 --- a/docs/classes/_basetrie_.trie.md +++ b/docs/classes/_basetrie_.trie.md @@ -25,6 +25,7 @@ The API for the base and the secure interface are about the same. ### Accessors +* [isCheckpoint](_basetrie_.trie.md#ischeckpoint) * [root](_basetrie_.trie.md#root) ### Methods @@ -34,11 +35,9 @@ The API for the base and the secure interface are about the same. * [_findDbNodes](_basetrie_.trie.md#private-_finddbnodes) * [_findValueNodes](_basetrie_.trie.md#private-_findvaluenodes) * [_formatNode](_basetrie_.trie.md#private-_formatnode) -* [_lookupNode](_basetrie_.trie.md#private-_lookupnode) * [_saveStack](_basetrie_.trie.md#private-_savestack) * [_setRoot](_basetrie_.trie.md#_setroot) * [_updateNode](_basetrie_.trie.md#private-_updatenode) -* [_walkTrie](_basetrie_.trie.md#private-_walktrie) * [batch](_basetrie_.trie.md#batch) * [checkRoot](_basetrie_.trie.md#checkroot) * [copy](_basetrie_.trie.md#copy) @@ -46,7 +45,9 @@ The API for the base and the secure interface are about the same. * [del](_basetrie_.trie.md#del) * [findPath](_basetrie_.trie.md#findpath) * [get](_basetrie_.trie.md#get) +* [lookupNode](_basetrie_.trie.md#lookupnode) * [put](_basetrie_.trie.md#put) +* [walkTrie](_basetrie_.trie.md#walktrie) * [createProof](_basetrie_.trie.md#static-createproof) * [fromProof](_basetrie_.trie.md#static-fromproof) * [prove](_basetrie_.trie.md#static-prove) @@ -93,6 +94,18 @@ The backend DB ## Accessors +### isCheckpoint + +• **get isCheckpoint**(): *boolean* + +*Defined in [baseTrie.ts:94](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L94)* + +BaseTrie has no checkpointing so return false + +**Returns:** *boolean* + +___ + ### root • **get root**(): *Buffer* @@ -123,7 +136,7 @@ Name | Type | ▸ **_createInitialNode**(`key`: Buffer, `value`: Buffer): *Promise‹void›* -*Defined in [baseTrie.ts:304](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L304)* +*Defined in [baseTrie.ts:238](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L238)* Creates the initial node from an empty tree. @@ -142,7 +155,7 @@ ___ ▸ **_deleteNode**(`k`: Buffer, `stack`: TrieNode[]): *Promise‹void›* -*Defined in [baseTrie.ts:439](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L439)* +*Defined in [baseTrie.ts:381](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L381)* Deletes a node from the database. @@ -159,9 +172,9 @@ ___ ### `Private` _findDbNodes -▸ **_findDbNodes**(`onFound`: FoundNodeFunction): *Promise‹void›* +▸ **_findDbNodes**(`onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* -*Defined in [baseTrie.ts:740](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L740)* +*Defined in [baseTrie.ts:697](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L697)* Finds all nodes that are stored directly in the db (some nodes are stored raw inside other nodes) @@ -171,7 +184,7 @@ called by {@link ScratchReadStream} Name | Type | ------ | ------ | -`onFound` | FoundNodeFunction | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | **Returns:** *Promise‹void›* @@ -179,9 +192,9 @@ ___ ### `Private` _findValueNodes -▸ **_findValueNodes**(`onFound`: FoundNodeFunction): *Promise‹void›* +▸ **_findValueNodes**(`onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* -*Defined in [baseTrie.ts:756](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L756)* +*Defined in [baseTrie.ts:715](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L715)* Finds all nodes that store k,v values called by {@link TrieReadStream} @@ -190,7 +203,7 @@ called by {@link TrieReadStream} Name | Type | ------ | ------ | -`onFound` | FoundNodeFunction | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | **Returns:** *Promise‹void›* @@ -198,9 +211,9 @@ ___ ### `Private` _formatNode -▸ **_formatNode**(`node`: TrieNode, `topLevel`: boolean, `opStack`: BatchDBOp[], `remove`: boolean): *Buffer | null | Buffer‹› | Buffer‹›[][]* +▸ **_formatNode**(`node`: TrieNode, `topLevel`: boolean, `opStack`: BatchDBOp[], `remove`: boolean): *Buffer | (null | Buffer‹› | Buffer‹›[])[]* -*Defined in [baseTrie.ts:605](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L605)* +*Defined in [baseTrie.ts:549](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L549)* Formats node to be saved by `levelup.batch`. @@ -213,35 +226,17 @@ Name | Type | Default | Description | `opStack` | BatchDBOp[] | - | the opStack to push the node's data. | `remove` | boolean | false | whether to remove the node (only used for CheckpointTrie). | -**Returns:** *Buffer | null | Buffer‹› | Buffer‹›[][]* +**Returns:** *Buffer | (null | Buffer‹› | Buffer‹›[])[]* The node's hash used as the key or the rawNode. ___ -### `Private` _lookupNode - -▸ **_lookupNode**(`node`: Buffer | Buffer[]): *Promise‹TrieNode | null›* - -*Defined in [baseTrie.ts:314](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L314)* - -Retrieves a node from db by hash. - -**Parameters:** - -Name | Type | ------- | ------ | -`node` | Buffer | Buffer[] | - -**Returns:** *Promise‹TrieNode | null›* - -___ - ### `Private` _saveStack ▸ **_saveStack**(`key`: Nibbles, `stack`: TrieNode[], `opStack`: BatchDBOp[]): *Promise‹void›* -*Defined in [baseTrie.ts:567](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L567)* +*Defined in [baseTrie.ts:511](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L511)* Saves a stack of nodes to the database. @@ -277,7 +272,7 @@ ___ ▸ **_updateNode**(`k`: Buffer, `value`: Buffer, `keyRemainder`: Nibbles, `stack`: TrieNode[]): *Promise‹void›* -*Defined in [baseTrie.ts:336](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L336)* +*Defined in [baseTrie.ts:278](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L278)* Updates a node. @@ -294,32 +289,11 @@ Name | Type | Description | ___ -### `Private` _walkTrie - -▸ **_walkTrie**(`root`: Buffer, `onFound`: FoundNodeFunction): *Promise‹void›* - -*Defined in [baseTrie.ts:208](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L208)* - -Walks a trie until finished. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`root` | Buffer | - | -`onFound` | FoundNodeFunction | callback to call when a node is found | - -**Returns:** *Promise‹void›* - -Resolves when finished walking trie. - -___ - ### batch ▸ **batch**(`ops`: BatchDBOp[]): *Promise‹void›* -*Defined in [baseTrie.ts:639](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L639)* +*Defined in [baseTrie.ts:594](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L594)* The given hash of operations (key additions or deletions) are executed on the DB @@ -365,7 +339,7 @@ ___ ▸ **copy**(): *[Trie](_basetrie_.trie.md)* -*Defined in [baseTrie.ts:729](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L729)* +*Defined in [baseTrie.ts:686](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L686)* Creates a new trie backed by the same db. @@ -377,7 +351,7 @@ ___ ▸ **createReadStream**(): *ReadStream* -*Defined in [baseTrie.ts:722](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L722)* +*Defined in [baseTrie.ts:679](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L679)* The `data` event is given an `Object` that has two properties; the `key` and the `value`. Both should be Buffers. @@ -391,7 +365,7 @@ ___ ▸ **del**(`key`: Buffer): *Promise‹void›* -*Defined in [baseTrie.ts:135](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L135)* +*Defined in [baseTrie.ts:143](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L143)* Deletes a value given a `key`. @@ -411,7 +385,7 @@ ___ ▸ **findPath**(`key`: Buffer): *Promise‹Path›* -*Defined in [baseTrie.ts:149](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L149)* +*Defined in [baseTrie.ts:157](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L157)* Tries to find a path to the node for the given key. It returns a `stack` of nodes to the closest node. @@ -430,7 +404,7 @@ ___ ▸ **get**(`key`: Buffer): *Promise‹Buffer | null›* -*Defined in [baseTrie.ts:96](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L96)* +*Defined in [baseTrie.ts:103](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L103)* Gets a value given a `key` @@ -446,11 +420,29 @@ A Promise that resolves to `Buffer` if a value was found or `null` if no value w ___ +### lookupNode + +▸ **lookupNode**(`node`: Buffer | Buffer[]): *Promise‹TrieNode | null›* + +*Defined in [baseTrie.ts:247](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L247)* + +Retrieves a node from db by hash. + +**Parameters:** + +Name | Type | +------ | ------ | +`node` | Buffer | Buffer[] | + +**Returns:** *Promise‹TrieNode | null›* + +___ + ### put ▸ **put**(`key`: Buffer, `value`: Buffer): *Promise‹void›* -*Defined in [baseTrie.ts:111](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L111)* +*Defined in [baseTrie.ts:118](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L118)* Stores a given `value` at the given `key`. @@ -467,11 +459,32 @@ A Promise that resolves once value is stored. ___ +### walkTrie + +▸ **walkTrie**(`root`: Buffer, `onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* + +*Defined in [baseTrie.ts:220](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L220)* + +Walks a trie until finished. + +**Parameters:** + +Name | Type | Description | +------ | ------ | ------ | +`root` | Buffer | - | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | callback to call when a node is found. This schedules new tasks. If no tasks are available, the Promise resolves. | + +**Returns:** *Promise‹void›* + +Resolves when finished walking trie. + +___ + ### `Static` createProof ▸ **createProof**(`trie`: [Trie](_basetrie_.trie.md), `key`: Buffer): *Promise‹[Proof](../modules/_basetrie_.md#proof)›* -*Defined in [baseTrie.ts:692](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L692)* +*Defined in [baseTrie.ts:649](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L649)* Creates a proof from a trie and key that can be verified using [Trie.verifyProof](_basetrie_.trie.md#static-verifyproof). @@ -490,7 +503,7 @@ ___ ▸ **fromProof**(`proof`: [Proof](../modules/_basetrie_.md#proof), `trie?`: [Trie](_basetrie_.trie.md)): *Promise‹[Trie](_basetrie_.trie.md)›* -*Defined in [baseTrie.ts:657](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L657)* +*Defined in [baseTrie.ts:614](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L614)* Saves the nodes from a proof into the trie. If no trie is provided a new one wil be instantiated. @@ -509,7 +522,7 @@ ___ ▸ **prove**(`trie`: [Trie](_basetrie_.trie.md), `key`: Buffer): *Promise‹[Proof](../modules/_basetrie_.md#proof)›* -*Defined in [baseTrie.ts:683](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L683)* +*Defined in [baseTrie.ts:640](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L640)* prove has been renamed to [Trie.createProof](_basetrie_.trie.md#static-createproof). @@ -530,7 +543,7 @@ ___ ▸ **verifyProof**(`rootHash`: Buffer, `key`: Buffer, `proof`: [Proof](../modules/_basetrie_.md#proof)): *Promise‹Buffer | null›* -*Defined in [baseTrie.ts:708](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L708)* +*Defined in [baseTrie.ts:665](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L665)* Verifies a proof. diff --git a/docs/classes/_checkpointtrie_.checkpointtrie.md b/docs/classes/_checkpointtrie_.checkpointtrie.md index 12133d5..0953a42 100644 --- a/docs/classes/_checkpointtrie_.checkpointtrie.md +++ b/docs/classes/_checkpointtrie_.checkpointtrie.md @@ -41,11 +41,9 @@ Adds checkpointing to the {@link BaseTrie} * [_findDbNodes](_checkpointtrie_.checkpointtrie.md#private-_finddbnodes) * [_findValueNodes](_checkpointtrie_.checkpointtrie.md#private-_findvaluenodes) * [_formatNode](_checkpointtrie_.checkpointtrie.md#private-_formatnode) -* [_lookupNode](_checkpointtrie_.checkpointtrie.md#private-_lookupnode) * [_saveStack](_checkpointtrie_.checkpointtrie.md#private-_savestack) * [_setRoot](_checkpointtrie_.checkpointtrie.md#_setroot) * [_updateNode](_checkpointtrie_.checkpointtrie.md#private-_updatenode) -* [_walkTrie](_checkpointtrie_.checkpointtrie.md#private-_walktrie) * [batch](_checkpointtrie_.checkpointtrie.md#batch) * [checkRoot](_checkpointtrie_.checkpointtrie.md#checkroot) * [checkpoint](_checkpointtrie_.checkpointtrie.md#checkpoint) @@ -55,8 +53,10 @@ Adds checkpointing to the {@link BaseTrie} * [del](_checkpointtrie_.checkpointtrie.md#del) * [findPath](_checkpointtrie_.checkpointtrie.md#findpath) * [get](_checkpointtrie_.checkpointtrie.md#get) +* [lookupNode](_checkpointtrie_.checkpointtrie.md#lookupnode) * [put](_checkpointtrie_.checkpointtrie.md#put) * [revert](_checkpointtrie_.checkpointtrie.md#revert) +* [walkTrie](_checkpointtrie_.checkpointtrie.md#walktrie) * [createProof](_checkpointtrie_.checkpointtrie.md#static-createproof) * [fromProof](_checkpointtrie_.checkpointtrie.md#static-fromproof) * [prove](_checkpointtrie_.checkpointtrie.md#static-prove) @@ -70,7 +70,7 @@ Adds checkpointing to the {@link BaseTrie} *Overrides [Trie](_basetrie_.trie.md).[constructor](_basetrie_.trie.md#constructor)* -*Defined in [checkpointTrie.ts:14](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L14)* +*Defined in [checkpointTrie.ts:13](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L13)* **Parameters:** @@ -98,7 +98,7 @@ ___ • **_checkpoints**: *Buffer[]* -*Defined in [checkpointTrie.ts:14](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L14)* +*Defined in [checkpointTrie.ts:13](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L13)* ___ @@ -106,7 +106,7 @@ ___ • **_mainDB**: *DB* -*Defined in [checkpointTrie.ts:12](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L12)* +*Defined in [checkpointTrie.ts:11](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L11)* ___ @@ -114,7 +114,7 @@ ___ • **_scratch**: *ScratchDB | null* -*Defined in [checkpointTrie.ts:13](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L13)* +*Defined in [checkpointTrie.ts:12](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L12)* ___ @@ -134,7 +134,9 @@ The backend DB • **get isCheckpoint**(): *boolean* -*Defined in [checkpointTrie.ts:29](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L29)* +*Overrides [Trie](_basetrie_.trie.md).[isCheckpoint](_basetrie_.trie.md#ischeckpoint)* + +*Defined in [checkpointTrie.ts:28](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L28)* Is the trie during a checkpoint phase? @@ -178,7 +180,7 @@ Name | Type | *Inherited from [Trie](_basetrie_.trie.md).[_createInitialNode](_basetrie_.trie.md#private-_createinitialnode)* -*Defined in [baseTrie.ts:304](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L304)* +*Defined in [baseTrie.ts:238](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L238)* Creates the initial node from an empty tree. @@ -197,7 +199,7 @@ ___ ▸ **_createScratchReadStream**(`scratchDb?`: ScratchDB): *ScratchReadStream‹›* -*Defined in [checkpointTrie.ts:133](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L133)* +*Defined in [checkpointTrie.ts:135](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L135)* Returns a `ScratchReadStream` based on the state updates since checkpoint. @@ -218,7 +220,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[_deleteNode](_basetrie_.trie.md#private-_deletenode)* -*Defined in [baseTrie.ts:439](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L439)* +*Defined in [baseTrie.ts:381](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L381)* Deletes a node from the database. @@ -237,7 +239,7 @@ ___ ▸ **_enterCpMode**(): *void* -*Defined in [checkpointTrie.ts:103](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L103)* +*Defined in [checkpointTrie.ts:105](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L105)* Enter into checkpoint mode. @@ -249,7 +251,7 @@ ___ ▸ **_exitCpMode**(`commitState`: boolean): *Promise‹void›* -*Defined in [checkpointTrie.ts:112](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L112)* +*Defined in [checkpointTrie.ts:114](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L114)* Exit from checkpoint mode. @@ -265,11 +267,11 @@ ___ ### `Private` _findDbNodes -▸ **_findDbNodes**(`onFound`: FoundNodeFunction): *Promise‹void›* +▸ **_findDbNodes**(`onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[_findDbNodes](_basetrie_.trie.md#private-_finddbnodes)* -*Defined in [baseTrie.ts:740](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L740)* +*Defined in [baseTrie.ts:697](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L697)* Finds all nodes that are stored directly in the db (some nodes are stored raw inside other nodes) @@ -279,7 +281,7 @@ called by {@link ScratchReadStream} Name | Type | ------ | ------ | -`onFound` | FoundNodeFunction | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | **Returns:** *Promise‹void›* @@ -287,11 +289,11 @@ ___ ### `Private` _findValueNodes -▸ **_findValueNodes**(`onFound`: FoundNodeFunction): *Promise‹void›* +▸ **_findValueNodes**(`onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[_findValueNodes](_basetrie_.trie.md#private-_findvaluenodes)* -*Defined in [baseTrie.ts:756](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L756)* +*Defined in [baseTrie.ts:715](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L715)* Finds all nodes that store k,v values called by {@link TrieReadStream} @@ -300,7 +302,7 @@ called by {@link TrieReadStream} Name | Type | ------ | ------ | -`onFound` | FoundNodeFunction | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | **Returns:** *Promise‹void›* @@ -308,11 +310,11 @@ ___ ### `Private` _formatNode -▸ **_formatNode**(`node`: TrieNode, `topLevel`: boolean, `opStack`: BatchDBOp[], `remove`: boolean): *Buffer‹› | null | Buffer‹› | Buffer‹›[][]* +▸ **_formatNode**(`node`: TrieNode, `topLevel`: boolean, `opStack`: BatchDBOp[], `remove`: boolean): *Buffer | (null | Buffer‹› | Buffer‹›[])[]* -*Overrides [Trie](_basetrie_.trie.md).[_formatNode](_basetrie_.trie.md#private-_formatnode)* +*Inherited from [Trie](_basetrie_.trie.md).[_formatNode](_basetrie_.trie.md#private-_formatnode)* -*Defined in [checkpointTrie.ts:152](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L152)* +*Defined in [baseTrie.ts:549](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L549)* Formats node to be saved by `levelup.batch`. @@ -325,39 +327,19 @@ Name | Type | Default | Description | `opStack` | BatchDBOp[] | - | the opStack to push the node's data. | `remove` | boolean | false | whether to remove the node (only used for CheckpointTrie). | -**Returns:** *Buffer‹› | null | Buffer‹› | Buffer‹›[][]* +**Returns:** *Buffer | (null | Buffer‹› | Buffer‹›[])[]* The node's hash used as the key or the rawNode. ___ -### `Private` _lookupNode - -▸ **_lookupNode**(`node`: Buffer | Buffer[]): *Promise‹TrieNode | null›* - -*Inherited from [Trie](_basetrie_.trie.md).[_lookupNode](_basetrie_.trie.md#private-_lookupnode)* - -*Defined in [baseTrie.ts:314](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L314)* - -Retrieves a node from db by hash. - -**Parameters:** - -Name | Type | ------- | ------ | -`node` | Buffer | Buffer[] | - -**Returns:** *Promise‹TrieNode | null›* - -___ - ### `Private` _saveStack ▸ **_saveStack**(`key`: Nibbles, `stack`: TrieNode[], `opStack`: BatchDBOp[]): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[_saveStack](_basetrie_.trie.md#private-_savestack)* -*Defined in [baseTrie.ts:567](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L567)* +*Defined in [baseTrie.ts:511](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L511)* Saves a stack of nodes to the database. @@ -397,7 +379,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[_updateNode](_basetrie_.trie.md#private-_updatenode)* -*Defined in [baseTrie.ts:336](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L336)* +*Defined in [baseTrie.ts:278](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L278)* Updates a node. @@ -414,36 +396,13 @@ Name | Type | Description | ___ -### `Private` _walkTrie - -▸ **_walkTrie**(`root`: Buffer, `onFound`: FoundNodeFunction): *Promise‹void›* - -*Inherited from [Trie](_basetrie_.trie.md).[_walkTrie](_basetrie_.trie.md#private-_walktrie)* - -*Defined in [baseTrie.ts:208](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L208)* - -Walks a trie until finished. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`root` | Buffer | - | -`onFound` | FoundNodeFunction | callback to call when a node is found | - -**Returns:** *Promise‹void›* - -Resolves when finished walking trie. - -___ - ### batch ▸ **batch**(`ops`: BatchDBOp[]): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[batch](_basetrie_.trie.md#batch)* -*Defined in [baseTrie.ts:639](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L639)* +*Defined in [baseTrie.ts:594](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L594)* The given hash of operations (key additions or deletions) are executed on the DB @@ -491,7 +450,7 @@ ___ ▸ **checkpoint**(): *void* -*Defined in [checkpointTrie.ts:38](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L38)* +*Defined in [checkpointTrie.ts:37](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L37)* Creates a checkpoint that can later be reverted to or committed. After this is called, no changes to the trie will be permanently saved until `commit` is called. @@ -505,7 +464,7 @@ ___ ▸ **commit**(): *Promise‹void›* -*Defined in [checkpointTrie.ts:53](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L53)* +*Defined in [checkpointTrie.ts:52](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L52)* Commits a checkpoint to disk, if current checkpoint is not nested. If nested, only sets the parent checkpoint as current checkpoint. @@ -522,7 +481,7 @@ ___ *Overrides [Trie](_basetrie_.trie.md).[copy](_basetrie_.trie.md#copy)* -*Defined in [checkpointTrie.ts:88](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L88)* +*Defined in [checkpointTrie.ts:90](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L90)* Returns a copy of the underlying trie with the interface of CheckpointTrie. @@ -542,7 +501,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[createReadStream](_basetrie_.trie.md#createreadstream)* -*Defined in [baseTrie.ts:722](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L722)* +*Defined in [baseTrie.ts:679](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L679)* The `data` event is given an `Object` that has two properties; the `key` and the `value`. Both should be Buffers. @@ -558,7 +517,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[del](_basetrie_.trie.md#del)* -*Defined in [baseTrie.ts:135](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L135)* +*Defined in [baseTrie.ts:143](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L143)* Deletes a value given a `key`. @@ -580,7 +539,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[findPath](_basetrie_.trie.md#findpath)* -*Defined in [baseTrie.ts:149](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L149)* +*Defined in [baseTrie.ts:157](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L157)* Tries to find a path to the node for the given key. It returns a `stack` of nodes to the closest node. @@ -601,7 +560,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[get](_basetrie_.trie.md#get)* -*Defined in [baseTrie.ts:96](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L96)* +*Defined in [baseTrie.ts:103](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L103)* Gets a value given a `key` @@ -617,13 +576,33 @@ A Promise that resolves to `Buffer` if a value was found or `null` if no value w ___ +### lookupNode + +▸ **lookupNode**(`node`: Buffer | Buffer[]): *Promise‹TrieNode | null›* + +*Inherited from [Trie](_basetrie_.trie.md).[lookupNode](_basetrie_.trie.md#lookupnode)* + +*Defined in [baseTrie.ts:247](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L247)* + +Retrieves a node from db by hash. + +**Parameters:** + +Name | Type | +------ | ------ | +`node` | Buffer | Buffer[] | + +**Returns:** *Promise‹TrieNode | null›* + +___ + ### put ▸ **put**(`key`: Buffer, `value`: Buffer): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[put](_basetrie_.trie.md#put)* -*Defined in [baseTrie.ts:111](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L111)* +*Defined in [baseTrie.ts:118](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L118)* Stores a given `value` at the given `key`. @@ -654,13 +633,36 @@ parent checkpoint as current. ___ +### walkTrie + +▸ **walkTrie**(`root`: Buffer, `onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* + +*Inherited from [Trie](_basetrie_.trie.md).[walkTrie](_basetrie_.trie.md#walktrie)* + +*Defined in [baseTrie.ts:220](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L220)* + +Walks a trie until finished. + +**Parameters:** + +Name | Type | Description | +------ | ------ | ------ | +`root` | Buffer | - | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | callback to call when a node is found. This schedules new tasks. If no tasks are available, the Promise resolves. | + +**Returns:** *Promise‹void›* + +Resolves when finished walking trie. + +___ + ### `Static` createProof ▸ **createProof**(`trie`: [Trie](_basetrie_.trie.md), `key`: Buffer): *Promise‹[Proof](../modules/_basetrie_.md#proof)›* *Inherited from [Trie](_basetrie_.trie.md).[createProof](_basetrie_.trie.md#static-createproof)* -*Defined in [baseTrie.ts:692](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L692)* +*Defined in [baseTrie.ts:649](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L649)* Creates a proof from a trie and key that can be verified using [Trie.verifyProof](_basetrie_.trie.md#static-verifyproof). @@ -681,7 +683,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[fromProof](_basetrie_.trie.md#static-fromproof)* -*Defined in [baseTrie.ts:657](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L657)* +*Defined in [baseTrie.ts:614](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L614)* Saves the nodes from a proof into the trie. If no trie is provided a new one wil be instantiated. @@ -702,7 +704,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[prove](_basetrie_.trie.md#static-prove)* -*Defined in [baseTrie.ts:683](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L683)* +*Defined in [baseTrie.ts:640](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L640)* prove has been renamed to [Trie.createProof](_basetrie_.trie.md#static-createproof). @@ -725,7 +727,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[verifyProof](_basetrie_.trie.md#static-verifyproof)* -*Defined in [baseTrie.ts:708](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L708)* +*Defined in [baseTrie.ts:665](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L665)* Verifies a proof. diff --git a/docs/classes/_secure_.securetrie.md b/docs/classes/_secure_.securetrie.md index 38dc2fa..6422a25 100644 --- a/docs/classes/_secure_.securetrie.md +++ b/docs/classes/_secure_.securetrie.md @@ -45,11 +45,9 @@ It has the same methods and constructor as `Trie`. * [_findDbNodes](_secure_.securetrie.md#private-_finddbnodes) * [_findValueNodes](_secure_.securetrie.md#private-_findvaluenodes) * [_formatNode](_secure_.securetrie.md#private-_formatnode) -* [_lookupNode](_secure_.securetrie.md#private-_lookupnode) * [_saveStack](_secure_.securetrie.md#private-_savestack) * [_setRoot](_secure_.securetrie.md#_setroot) * [_updateNode](_secure_.securetrie.md#private-_updatenode) -* [_walkTrie](_secure_.securetrie.md#private-_walktrie) * [batch](_secure_.securetrie.md#batch) * [checkRoot](_secure_.securetrie.md#checkroot) * [checkpoint](_secure_.securetrie.md#checkpoint) @@ -59,8 +57,10 @@ It has the same methods and constructor as `Trie`. * [del](_secure_.securetrie.md#del) * [findPath](_secure_.securetrie.md#findpath) * [get](_secure_.securetrie.md#get) +* [lookupNode](_secure_.securetrie.md#lookupnode) * [put](_secure_.securetrie.md#put) * [revert](_secure_.securetrie.md#revert) +* [walkTrie](_secure_.securetrie.md#walktrie) * [createProof](_secure_.securetrie.md#static-createproof) * [fromProof](_secure_.securetrie.md#static-fromproof) * [prove](_secure_.securetrie.md#static-prove) @@ -104,7 +104,7 @@ ___ *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[_checkpoints](_checkpointtrie_.checkpointtrie.md#_checkpoints)* -*Defined in [checkpointTrie.ts:14](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L14)* +*Defined in [checkpointTrie.ts:13](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L13)* ___ @@ -114,7 +114,7 @@ ___ *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[_mainDB](_checkpointtrie_.checkpointtrie.md#_maindb)* -*Defined in [checkpointTrie.ts:12](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L12)* +*Defined in [checkpointTrie.ts:11](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L11)* ___ @@ -124,7 +124,7 @@ ___ *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[_scratch](_checkpointtrie_.checkpointtrie.md#_scratch)* -*Defined in [checkpointTrie.ts:13](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L13)* +*Defined in [checkpointTrie.ts:12](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L12)* ___ @@ -146,7 +146,9 @@ The backend DB *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[isCheckpoint](_checkpointtrie_.checkpointtrie.md#ischeckpoint)* -*Defined in [checkpointTrie.ts:29](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L29)* +*Overrides [Trie](_basetrie_.trie.md).[isCheckpoint](_basetrie_.trie.md#ischeckpoint)* + +*Defined in [checkpointTrie.ts:28](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L28)* Is the trie during a checkpoint phase? @@ -190,7 +192,7 @@ Name | Type | *Inherited from [Trie](_basetrie_.trie.md).[_createInitialNode](_basetrie_.trie.md#private-_createinitialnode)* -*Defined in [baseTrie.ts:304](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L304)* +*Defined in [baseTrie.ts:238](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L238)* Creates the initial node from an empty tree. @@ -211,7 +213,7 @@ ___ *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[_createScratchReadStream](_checkpointtrie_.checkpointtrie.md#private-_createscratchreadstream)* -*Defined in [checkpointTrie.ts:133](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L133)* +*Defined in [checkpointTrie.ts:135](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L135)* Returns a `ScratchReadStream` based on the state updates since checkpoint. @@ -232,7 +234,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[_deleteNode](_basetrie_.trie.md#private-_deletenode)* -*Defined in [baseTrie.ts:439](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L439)* +*Defined in [baseTrie.ts:381](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L381)* Deletes a node from the database. @@ -253,7 +255,7 @@ ___ *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[_enterCpMode](_checkpointtrie_.checkpointtrie.md#private-_entercpmode)* -*Defined in [checkpointTrie.ts:103](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L103)* +*Defined in [checkpointTrie.ts:105](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L105)* Enter into checkpoint mode. @@ -267,7 +269,7 @@ ___ *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[_exitCpMode](_checkpointtrie_.checkpointtrie.md#private-_exitcpmode)* -*Defined in [checkpointTrie.ts:112](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L112)* +*Defined in [checkpointTrie.ts:114](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L114)* Exit from checkpoint mode. @@ -283,11 +285,11 @@ ___ ### `Private` _findDbNodes -▸ **_findDbNodes**(`onFound`: FoundNodeFunction): *Promise‹void›* +▸ **_findDbNodes**(`onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[_findDbNodes](_basetrie_.trie.md#private-_finddbnodes)* -*Defined in [baseTrie.ts:740](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L740)* +*Defined in [baseTrie.ts:697](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L697)* Finds all nodes that are stored directly in the db (some nodes are stored raw inside other nodes) @@ -297,7 +299,7 @@ called by {@link ScratchReadStream} Name | Type | ------ | ------ | -`onFound` | FoundNodeFunction | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | **Returns:** *Promise‹void›* @@ -305,11 +307,11 @@ ___ ### `Private` _findValueNodes -▸ **_findValueNodes**(`onFound`: FoundNodeFunction): *Promise‹void›* +▸ **_findValueNodes**(`onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[_findValueNodes](_basetrie_.trie.md#private-_findvaluenodes)* -*Defined in [baseTrie.ts:756](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L756)* +*Defined in [baseTrie.ts:715](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L715)* Finds all nodes that store k,v values called by {@link TrieReadStream} @@ -318,7 +320,7 @@ called by {@link TrieReadStream} Name | Type | ------ | ------ | -`onFound` | FoundNodeFunction | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | **Returns:** *Promise‹void›* @@ -326,13 +328,11 @@ ___ ### `Private` _formatNode -▸ **_formatNode**(`node`: TrieNode, `topLevel`: boolean, `opStack`: BatchDBOp[], `remove`: boolean): *Buffer‹› | null | Buffer‹› | Buffer‹›[][]* +▸ **_formatNode**(`node`: TrieNode, `topLevel`: boolean, `opStack`: BatchDBOp[], `remove`: boolean): *Buffer | (null | Buffer‹› | Buffer‹›[])[]* -*Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[_formatNode](_checkpointtrie_.checkpointtrie.md#private-_formatnode)* +*Inherited from [Trie](_basetrie_.trie.md).[_formatNode](_basetrie_.trie.md#private-_formatnode)* -*Overrides [Trie](_basetrie_.trie.md).[_formatNode](_basetrie_.trie.md#private-_formatnode)* - -*Defined in [checkpointTrie.ts:152](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L152)* +*Defined in [baseTrie.ts:549](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L549)* Formats node to be saved by `levelup.batch`. @@ -345,39 +345,19 @@ Name | Type | Default | Description | `opStack` | BatchDBOp[] | - | the opStack to push the node's data. | `remove` | boolean | false | whether to remove the node (only used for CheckpointTrie). | -**Returns:** *Buffer‹› | null | Buffer‹› | Buffer‹›[][]* +**Returns:** *Buffer | (null | Buffer‹› | Buffer‹›[])[]* The node's hash used as the key or the rawNode. ___ -### `Private` _lookupNode - -▸ **_lookupNode**(`node`: Buffer | Buffer[]): *Promise‹TrieNode | null›* - -*Inherited from [Trie](_basetrie_.trie.md).[_lookupNode](_basetrie_.trie.md#private-_lookupnode)* - -*Defined in [baseTrie.ts:314](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L314)* - -Retrieves a node from db by hash. - -**Parameters:** - -Name | Type | ------- | ------ | -`node` | Buffer | Buffer[] | - -**Returns:** *Promise‹TrieNode | null›* - -___ - ### `Private` _saveStack ▸ **_saveStack**(`key`: Nibbles, `stack`: TrieNode[], `opStack`: BatchDBOp[]): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[_saveStack](_basetrie_.trie.md#private-_savestack)* -*Defined in [baseTrie.ts:567](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L567)* +*Defined in [baseTrie.ts:511](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L511)* Saves a stack of nodes to the database. @@ -417,7 +397,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[_updateNode](_basetrie_.trie.md#private-_updatenode)* -*Defined in [baseTrie.ts:336](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L336)* +*Defined in [baseTrie.ts:278](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L278)* Updates a node. @@ -434,36 +414,13 @@ Name | Type | Description | ___ -### `Private` _walkTrie - -▸ **_walkTrie**(`root`: Buffer, `onFound`: FoundNodeFunction): *Promise‹void›* - -*Inherited from [Trie](_basetrie_.trie.md).[_walkTrie](_basetrie_.trie.md#private-_walktrie)* - -*Defined in [baseTrie.ts:208](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L208)* - -Walks a trie until finished. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`root` | Buffer | - | -`onFound` | FoundNodeFunction | callback to call when a node is found | - -**Returns:** *Promise‹void›* - -Resolves when finished walking trie. - -___ - ### batch ▸ **batch**(`ops`: BatchDBOp[]): *Promise‹void›* *Inherited from [Trie](_basetrie_.trie.md).[batch](_basetrie_.trie.md#batch)* -*Defined in [baseTrie.ts:639](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L639)* +*Defined in [baseTrie.ts:594](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L594)* The given hash of operations (key additions or deletions) are executed on the DB @@ -513,7 +470,7 @@ ___ *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[checkpoint](_checkpointtrie_.checkpointtrie.md#checkpoint)* -*Defined in [checkpointTrie.ts:38](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L38)* +*Defined in [checkpointTrie.ts:37](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L37)* Creates a checkpoint that can later be reverted to or committed. After this is called, no changes to the trie will be permanently saved until `commit` is called. @@ -529,7 +486,7 @@ ___ *Inherited from [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[commit](_checkpointtrie_.checkpointtrie.md#commit)* -*Defined in [checkpointTrie.ts:53](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L53)* +*Defined in [checkpointTrie.ts:52](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/checkpointTrie.ts#L52)* Commits a checkpoint to disk, if current checkpoint is not nested. If nested, only sets the parent checkpoint as current checkpoint. @@ -546,7 +503,7 @@ ___ *Overrides [CheckpointTrie](_checkpointtrie_.checkpointtrie.md).[copy](_checkpointtrie_.checkpointtrie.md#copy)* -*Defined in [secure.ts:90](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L90)* +*Defined in [secure.ts:91](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L91)* Returns a copy of the underlying trie with the interface of SecureTrie. @@ -566,7 +523,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[createReadStream](_basetrie_.trie.md#createreadstream)* -*Defined in [baseTrie.ts:722](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L722)* +*Defined in [baseTrie.ts:679](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L679)* The `data` event is given an `Object` that has two properties; the `key` and the `value`. Both should be Buffers. @@ -582,7 +539,7 @@ ___ *Overrides [Trie](_basetrie_.trie.md).[del](_basetrie_.trie.md#del)* -*Defined in [secure.ts:48](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L48)* +*Defined in [secure.ts:49](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L49)* Deletes a value given a `key`. @@ -602,7 +559,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[findPath](_basetrie_.trie.md#findpath)* -*Defined in [baseTrie.ts:149](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L149)* +*Defined in [baseTrie.ts:157](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L157)* Tries to find a path to the node for the given key. It returns a `stack` of nodes to the closest node. @@ -639,6 +596,26 @@ A Promise that resolves to `Buffer` if a value was found or `null` if no value w ___ +### lookupNode + +▸ **lookupNode**(`node`: Buffer | Buffer[]): *Promise‹TrieNode | null›* + +*Inherited from [Trie](_basetrie_.trie.md).[lookupNode](_basetrie_.trie.md#lookupnode)* + +*Defined in [baseTrie.ts:247](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L247)* + +Retrieves a node from db by hash. + +**Parameters:** + +Name | Type | +------ | ------ | +`node` | Buffer | Buffer[] | + +**Returns:** *Promise‹TrieNode | null›* + +___ + ### put ▸ **put**(`key`: Buffer, `val`: Buffer): *Promise‹void›* @@ -677,13 +654,36 @@ parent checkpoint as current. ___ +### walkTrie + +▸ **walkTrie**(`root`: Buffer, `onFound`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)): *Promise‹void›* + +*Inherited from [Trie](_basetrie_.trie.md).[walkTrie](_basetrie_.trie.md#walktrie)* + +*Defined in [baseTrie.ts:220](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L220)* + +Walks a trie until finished. + +**Parameters:** + +Name | Type | Description | +------ | ------ | ------ | +`root` | Buffer | - | +`onFound` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | callback to call when a node is found. This schedules new tasks. If no tasks are available, the Promise resolves. | + +**Returns:** *Promise‹void›* + +Resolves when finished walking trie. + +___ + ### `Static` createProof ▸ **createProof**(`trie`: [SecureTrie](_secure_.securetrie.md), `key`: Buffer): *Promise‹[Proof](../modules/_basetrie_.md#proof)›* *Overrides [Trie](_basetrie_.trie.md).[createProof](_basetrie_.trie.md#static-createproof)* -*Defined in [secure.ts:68](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L68)* +*Defined in [secure.ts:69](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L69)* Creates a proof that can be verified using [SecureTrie.verifyProof](_secure_.securetrie.md#static-verifyproof). @@ -704,7 +704,7 @@ ___ *Inherited from [Trie](_basetrie_.trie.md).[fromProof](_basetrie_.trie.md#static-fromproof)* -*Defined in [baseTrie.ts:657](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L657)* +*Defined in [baseTrie.ts:614](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L614)* Saves the nodes from a proof into the trie. If no trie is provided a new one wil be instantiated. @@ -725,7 +725,7 @@ ___ *Overrides [Trie](_basetrie_.trie.md).[prove](_basetrie_.trie.md#static-prove)* -*Defined in [secure.ts:59](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L59)* +*Defined in [secure.ts:60](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L60)* prove has been renamed to [SecureTrie.createProof](_secure_.securetrie.md#static-createproof). @@ -748,7 +748,7 @@ ___ *Overrides [Trie](_basetrie_.trie.md).[verifyProof](_basetrie_.trie.md#static-verifyproof)* -*Defined in [secure.ts:81](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L81)* +*Defined in [secure.ts:82](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/secure.ts#L82)* Verifies a proof. diff --git a/docs/classes/_util_walkcontroller_.walkcontroller.md b/docs/classes/_util_walkcontroller_.walkcontroller.md new file mode 100644 index 0000000..ee7c8ba --- /dev/null +++ b/docs/classes/_util_walkcontroller_.walkcontroller.md @@ -0,0 +1,129 @@ +[merkle-patricia-tree](../README.md) › ["util/walkController"](../modules/_util_walkcontroller_.md) › [WalkController](_util_walkcontroller_.walkcontroller.md) + +# Class: WalkController + +WalkController is an interface to control how the trie is being traversed. + +## Hierarchy + +* **WalkController** + +## Index + +### Properties + +* [onNode](_util_walkcontroller_.walkcontroller.md#onnode) +* [taskExecutor](_util_walkcontroller_.walkcontroller.md#taskexecutor) +* [trie](_util_walkcontroller_.walkcontroller.md#trie) + +### Methods + +* [allChildren](_util_walkcontroller_.walkcontroller.md#allchildren) +* [onlyBranchIndex](_util_walkcontroller_.walkcontroller.md#onlybranchindex) +* [pushNodeToQueue](_util_walkcontroller_.walkcontroller.md#pushnodetoqueue) +* [newWalk](_util_walkcontroller_.walkcontroller.md#static-newwalk) + +## Properties + +### onNode + +• **onNode**: *[FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction)* + +*Defined in [util/walkController.ts:10](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/util/walkController.ts#L10)* + +___ + +### taskExecutor + +• **taskExecutor**: *PrioritizedTaskExecutor* + +*Defined in [util/walkController.ts:11](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/util/walkController.ts#L11)* + +___ + +### trie + +• **trie**: *BaseTrie* + +*Defined in [util/walkController.ts:12](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/util/walkController.ts#L12)* + +## Methods + +### allChildren + +▸ **allChildren**(`node`: TrieNode, `key`: Nibbles): *void* + +*Defined in [util/walkController.ts:59](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/util/walkController.ts#L59)* + +Run all children of a node. Priority of these nodes are the key length of the children. + +**Parameters:** + +Name | Type | Default | Description | +------ | ------ | ------ | ------ | +`node` | TrieNode | - | Node to get all children of and call onNode on. | +`key` | Nibbles | [] | The current `key` which would yield the `node` when trying to get this node with a `get` operation. | + +**Returns:** *void* + +___ + +### onlyBranchIndex + +▸ **onlyBranchIndex**(`node`: BranchNode, `key`: Nibbles, `childIndex`: number, `priority?`: undefined | number): *void* + +*Defined in [util/walkController.ts:105](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/util/walkController.ts#L105)* + +Push a branch of a certain BranchNode to the event queue. + +**Parameters:** + +Name | Type | Default | Description | +------ | ------ | ------ | ------ | +`node` | BranchNode | - | The node to select a branch on. Should be a BranchNode. | +`key` | Nibbles | [] | The current key which leads to the corresponding node. | +`childIndex` | number | - | The child index to add to the event queue. | +`priority?` | undefined | number | - | Optional priority of the event, defaults to the total key length. | + +**Returns:** *void* + +___ + +### pushNodeToQueue + +▸ **pushNodeToQueue**(`nodeRef`: Buffer, `key`: Nibbles, `priority?`: undefined | number): *void* + +*Defined in [util/walkController.ts:87](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/util/walkController.ts#L87)* + +Push a node to the queue. If the queue has places left for tasks, the node is executed immediately, otherwise it is queued. + +**Parameters:** + +Name | Type | Default | Description | +------ | ------ | ------ | ------ | +`nodeRef` | Buffer | - | Push a node reference to the event queue. This reference is a 32-byte keccak hash of the value corresponding to the `key`. | +`key` | Nibbles | [] | The current key. | +`priority?` | undefined | number | - | Optional priority, defaults to key length | + +**Returns:** *void* + +___ + +### `Static` newWalk + +▸ **newWalk**(`onNode`: [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction), `trie`: BaseTrie, `root`: Buffer, `poolSize?`: undefined | number): *Promise‹void›* + +*Defined in [util/walkController.ts:35](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/util/walkController.ts#L35)* + +Async function to create and start a new walk over a trie. + +**Parameters:** + +Name | Type | Description | +------ | ------ | ------ | +`onNode` | [FoundNodeFunction](../modules/_basetrie_.md#foundnodefunction) | The `FoundNodeFunction to call if a node is found. | +`trie` | BaseTrie | The trie to walk on. | +`root` | Buffer | The root key to walk on. | +`poolSize?` | undefined | number | Task execution pool size to prevent OOM errors. Defaults to 500. | + +**Returns:** *Promise‹void›* diff --git a/docs/modules/_basetrie_.md b/docs/modules/_basetrie_.md index fba7679..b589360 100644 --- a/docs/modules/_basetrie_.md +++ b/docs/modules/_basetrie_.md @@ -10,10 +10,32 @@ ### Type aliases +* [FoundNodeFunction](_basetrie_.md#foundnodefunction) * [Proof](_basetrie_.md#proof) ## Type aliases +### FoundNodeFunction + +Ƭ **FoundNodeFunction**: *function* + +*Defined in [baseTrie.ts:29](https://github.com/ethereumjs/merkle-patricia-tree/blob/master/src/baseTrie.ts#L29)* + +#### Type declaration: + +▸ (`nodeRef`: Buffer, `node`: TrieNode | null, `key`: Nibbles, `walkController`: [WalkController](../classes/_util_walkcontroller_.walkcontroller.md)): *void* + +**Parameters:** + +Name | Type | +------ | ------ | +`nodeRef` | Buffer | +`node` | TrieNode | null | +`key` | Nibbles | +`walkController` | [WalkController](../classes/_util_walkcontroller_.walkcontroller.md) | + +___ + ### Proof Ƭ **Proof**: *Buffer[]* diff --git a/docs/modules/_util_walkcontroller_.md b/docs/modules/_util_walkcontroller_.md new file mode 100644 index 0000000..45d1d76 --- /dev/null +++ b/docs/modules/_util_walkcontroller_.md @@ -0,0 +1,9 @@ +[merkle-patricia-tree](../README.md) › ["util/walkController"](_util_walkcontroller_.md) + +# Module: "util/walkController" + +## Index + +### Classes + +* [WalkController](../classes/_util_walkcontroller_.walkcontroller.md) diff --git a/src/baseTrie.ts b/src/baseTrie.ts index 6523a06..6d6d514 100644 --- a/src/baseTrie.ts +++ b/src/baseTrie.ts @@ -3,8 +3,8 @@ import { LevelUp } from 'levelup' import { keccak, KECCAK256_RLP } from 'ethereumjs-util' import { DB, BatchDBOp, PutBatch } from './db' import { TrieReadStream as ReadStream } from './readStream' -import { PrioritizedTaskExecutor } from './prioritizedTaskExecutor' import { bufferToNibbles, matchingNibbleLength, doKeysMatch } from './util/nibbles' +import { WalkController } from './util/walkController' import { TrieNode, decodeNode, @@ -26,11 +26,11 @@ interface Path { stack: TrieNode[] } -type FoundNodeFunction = ( +export type FoundNodeFunction = ( nodeRef: Buffer, - node: TrieNode, + node: TrieNode | null, key: Nibbles, - walkController: any + walkController: WalkController ) => void /** @@ -117,6 +117,7 @@ export class Trie { */ async put(key: Buffer, value: Buffer): Promise { // If value is empty, delete + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!value || value.toString() === '') { return await this.del(key) } @@ -160,6 +161,9 @@ export class Trie { const targetKey = bufferToNibbles(key) const onFound: FoundNodeFunction = async (nodeRef, node, keyProgress, walkController) => { + if (node === null) { + return + } const keyRemainder = targetKey.slice(matchingNibbleLength(keyProgress, targetKey)) stack.push(node) @@ -175,7 +179,8 @@ export class Trie { resolve({ node: null, remaining: keyRemainder, stack }) } else { // node found, continuing search - await walkController.only(branchIndex) + // this can be optimized as this calls getBranch again. + walkController.onlyBranchIndex(node, keyProgress, branchIndex) } } } else if (node instanceof LeafNode) { @@ -193,13 +198,13 @@ export class Trie { resolve({ node: null, remaining: keyRemainder, stack }) } else { // keys match, continue search - await walkController.next() + walkController.allChildren(node, keyProgress) } } } // walk trie and process nodes - await this._walkTrie(this.root, onFound) + await this.walkTrie(this.root, onFound) // Resolve if _walkTrie finishes without finding any nodes resolve({ node: null, remaining: [], stack }) @@ -208,102 +213,22 @@ export class Trie { /** * Walks a trie until finished. - * @private * @param root - * @param onFound - callback to call when a node is found + * @param onFound - callback to call when a node is found. This schedules new tasks. If no tasks are available, the Promise resolves. * @returns Resolves when finished walking trie. */ - async _walkTrie(root: Buffer, onFound: FoundNodeFunction): Promise { - // eslint-disable-next-line no-async-promise-executor - return new Promise(async (resolve) => { - const self = this - root = root || this.root - - if (root.equals(KECCAK256_RLP)) { - return resolve() - } - - // The maximum pool size should be high enough to utilize - // the parallelizability of reading nodes from disk and - // low enough to utilize the prioritisation of node lookup. - const maxPoolSize = 500 - const taskExecutor = new PrioritizedTaskExecutor(maxPoolSize) - - const processNode = async ( - nodeRef: Buffer, - node: TrieNode, - key: Nibbles = [] - ): Promise => { - const walkController = { - next: async () => { - if (node instanceof LeafNode) { - if (taskExecutor.finished()) { - resolve() - } - return - } - let children - if (node instanceof ExtensionNode) { - children = [[node.key, node.value]] - } else if (node instanceof BranchNode) { - children = node.getChildren().map((b) => [[b[0]], b[1]]) - } - if (!children) { - // Node has no children - return resolve() - } - for (const child of children) { - const keyExtension = child[0] as Nibbles - const childRef = child[1] as Buffer - const childKey = key.concat(keyExtension) - const priority = childKey.length - taskExecutor.execute(priority, async (taskCallback: Function) => { - const childNode = await self._lookupNode(childRef) - taskCallback() - if (childNode) { - await processNode(childRef, childNode as TrieNode, childKey) - } - }) - } - }, - only: async (childIndex: number) => { - if (!(node instanceof BranchNode)) { - throw new Error('Expected branch node') - } - const childRef = node.getBranch(childIndex) - if (!childRef) { - throw new Error('Could not get branch of childIndex') - } - const childKey = key.slice() - childKey.push(childIndex) - const priority = childKey.length - taskExecutor.execute(priority, async (taskCallback: Function) => { - const childNode = await self._lookupNode(childRef) - taskCallback() - if (childNode) { - await processNode(childRef as Buffer, childNode, childKey) - } else { - // could not find child node - resolve() - } - }) - }, - } - - if (node) { - onFound(nodeRef, node, key, walkController) - } else { - resolve() - } - } + async walkTrie(root: Buffer, onFound: FoundNodeFunction): Promise { + await WalkController.newWalk(onFound, this, root) + } - const node = await this._lookupNode(root) - if (node) { - await processNode(root, node as TrieNode, []) - } else { - resolve() - } - }) + /** + * @hidden + * Backwards compatibility + * @param root - + * @param onFound - + */ + async _walkTrie(root: Buffer, onFound: FoundNodeFunction): Promise { + await this.walkTrie(root, onFound) } /** @@ -318,9 +243,8 @@ export class Trie { /** * Retrieves a node from db by hash. - * @private */ - async _lookupNode(node: Buffer | Buffer[]): Promise { + async lookupNode(node: Buffer | Buffer[]): Promise { if (isRawNode(node)) { return decodeRawNode(node as Buffer[]) } @@ -334,6 +258,15 @@ export class Trie { return foundNode } + /** + * @hidden + * Backwards compatibility + * @param node The node hash to lookup from the DB + */ + async _lookupNode(node: Buffer | Buffer[]): Promise { + return this.lookupNode(node) + } + /** * Updates a node. * @private @@ -454,8 +387,10 @@ export class Trie { stack: TrieNode[] ) => { // branchNode is the node ON the branch node not THE branch node + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!parentNode || parentNode instanceof BranchNode) { // branch->? + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (parentNode) { stack.push(parentNode) } @@ -659,10 +594,12 @@ export class Trie { async batch(ops: BatchDBOp[]): Promise { for (const op of ops) { if (op.type === 'put') { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!op.value) { throw new Error('Invalid batch db operation') } await this.put(op.key, op.value) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition } else if (op.type === 'del') { await this.del(op.key) } @@ -760,12 +697,14 @@ export class Trie { async _findDbNodes(onFound: FoundNodeFunction): Promise { const outerOnFound: FoundNodeFunction = async (nodeRef, node, key, walkController) => { if (isRawNode(nodeRef)) { - await walkController.next() + if (node !== null) { + walkController.allChildren(node, key) + } } else { onFound(nodeRef, node, key, walkController) } } - await this._walkTrie(this.root, outerOnFound) + await this.walkTrie(this.root, outerOnFound) } /** @@ -786,9 +725,11 @@ export class Trie { onFound(nodeRef, node, fullKey, walkController) } else { // keep looking for value nodes - await walkController.next() + if (node !== null) { + walkController.allChildren(node, key) + } } } - await this._walkTrie(this.root, outerOnFound) + await this.walkTrie(this.root, outerOnFound) } } diff --git a/src/checkpointTrie.ts b/src/checkpointTrie.ts index 105ee9b..9e43a60 100644 --- a/src/checkpointTrie.ts +++ b/src/checkpointTrie.ts @@ -57,6 +57,7 @@ export class CheckpointTrie extends BaseTrie { await this.lock.wait() this._checkpoints.pop() + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!this.isCheckpoint) { await this._exitCpMode(true) } @@ -71,8 +72,10 @@ export class CheckpointTrie extends BaseTrie { */ async revert(): Promise { await this.lock.wait() + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (this.isCheckpoint) { this.root = this._checkpoints.pop()! + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!this.isCheckpoint) { await this._exitCpMode(false) } diff --git a/src/index.ts b/src/index.ts index 5f76722..a8804e0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ export { CheckpointTrie } from './checkpointTrie' export { SecureTrie } from './secure' export { Trie as BaseTrie } from './baseTrie' +export { WalkController } from './util/walkController' diff --git a/src/prioritizedTaskExecutor.ts b/src/prioritizedTaskExecutor.ts index d7e34f4..26dc56a 100644 --- a/src/prioritizedTaskExecutor.ts +++ b/src/prioritizedTaskExecutor.ts @@ -24,12 +24,15 @@ export class PrioritizedTaskExecutor { } /** - * Executes the task. + * Executes the task or queues it if no spots are available. + * When a task is added, check if there are spots left in the pool. + * If a spot is available, claim that spot and give back the spot once the asynchronous task has been resolved. + * When no spots are available, add the task to the task queue. The task will be executed at some point when another task has been resolved. * @private * @param priority The priority of the task * @param fn The function that accepts the callback, which must be called upon the task completion. */ - execute(priority: number, fn: Function) { + executeOrQueue(priority: number, fn: Function) { if (this.currentPoolSize < this.maxPoolSize) { this.currentPoolSize++ fn(() => { @@ -37,7 +40,7 @@ export class PrioritizedTaskExecutor { if (this.queue.length > 0) { this.queue.sort((a, b) => b.priority - a.priority) const item = this.queue.shift() - this.execute(item!.priority, item!.fn) + this.executeOrQueue(item!.priority, item!.fn) } }) } else { diff --git a/src/readStream.ts b/src/readStream.ts index 8ee3c78..63515cd 100644 --- a/src/readStream.ts +++ b/src/readStream.ts @@ -19,11 +19,13 @@ export class TrieReadStream extends Readable { } this._started = true await this.trie._findValueNodes(async (nodeRef, node, key, walkController) => { - this.push({ - key: nibblesToBuffer(key), - value: node.value, - }) - await walkController.next() + if (node !== null) { + this.push({ + key: nibblesToBuffer(key), + value: node.value, + }) + walkController.allChildren(node, key) + } }) this.push(null) } diff --git a/src/scratch.ts b/src/scratch.ts index 88dbe42..6551798 100644 --- a/src/scratch.ts +++ b/src/scratch.ts @@ -32,6 +32,7 @@ export class ScratchDB extends DB { } // If not found, try searching upstream db + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!value && this._upstream._leveldb) { try { value = await this._upstream._leveldb.get(key, ENCODING_OPTS) diff --git a/src/scratchReadStream.ts b/src/scratchReadStream.ts index 9bc736d..a0447d3 100644 --- a/src/scratchReadStream.ts +++ b/src/scratchReadStream.ts @@ -21,11 +21,13 @@ export class ScratchReadStream extends Readable { } this._started = true await this.trie._findDbNodes(async (nodeRef, node, key, walkController) => { - this.push({ - key: nodeRef, - value: node.serialize(), - }) - await walkController.next() + if (node !== null) { + this.push({ + key: nodeRef, + value: node.serialize(), + }) + walkController.allChildren(node, key) + } }) this.push(null) } diff --git a/src/secure.ts b/src/secure.ts index 6e135f1..0177473 100644 --- a/src/secure.ts +++ b/src/secure.ts @@ -33,6 +33,7 @@ export class SecureTrie extends CheckpointTrie { * @param value */ async put(key: Buffer, val: Buffer): Promise { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!val || val.toString() === '') { await this.del(key) } else { diff --git a/src/util/walkController.ts b/src/util/walkController.ts new file mode 100644 index 0000000..c66946b --- /dev/null +++ b/src/util/walkController.ts @@ -0,0 +1,126 @@ +import { BaseTrie } from '..' +import { FoundNodeFunction } from '../baseTrie' +import { PrioritizedTaskExecutor } from '../prioritizedTaskExecutor' +import { BranchNode, ExtensionNode, LeafNode, Nibbles, TrieNode } from '../trieNode' + +/** + * WalkController is an interface to control how the trie is being traversed. + */ +export class WalkController { + readonly onNode: FoundNodeFunction + readonly taskExecutor: PrioritizedTaskExecutor + readonly trie: BaseTrie + private resolve: Function + + /** + * Creates a new WalkController + * @param onNode - The `FoundNodeFunction` to call if a node is found. + * @param trie - The `Trie` to walk on. + * @param poolSize - The size of the task queue. + */ + private constructor(onNode: FoundNodeFunction, trie: BaseTrie, poolSize: number) { + this.onNode = onNode + this.taskExecutor = new PrioritizedTaskExecutor(poolSize) + this.trie = trie + this.resolve = () => {} + } + + /** + * Async function to create and start a new walk over a trie. + * @param onNode - The `FoundNodeFunction to call if a node is found. + * @param trie - The trie to walk on. + * @param root - The root key to walk on. + * @param poolSize - Task execution pool size to prevent OOM errors. Defaults to 500. + */ + static async newWalk( + onNode: FoundNodeFunction, + trie: BaseTrie, + root: Buffer, + poolSize?: number + ): Promise { + const strategy = new WalkController(onNode, trie, poolSize ?? 500) + await strategy.startWalk(root) + } + + private async startWalk(root: Buffer): Promise { + // eslint-disable-next-line no-async-promise-executor + return await new Promise(async (resolve) => { + this.resolve = resolve + const node = await this.trie._lookupNode(root) + this.processNode(root, node, []) + }) + } + + /** + * Run all children of a node. Priority of these nodes are the key length of the children. + * @param node - Node to get all children of and call onNode on. + * @param key - The current `key` which would yield the `node` when trying to get this node with a `get` operation. + */ + allChildren(node: TrieNode, key: Nibbles = []) { + if (node instanceof LeafNode) { + return + } + let children + if (node instanceof ExtensionNode) { + children = [[node.key, node.value]] + } else if (node instanceof BranchNode) { + children = node.getChildren().map((b) => [[b[0]], b[1]]) + } + if (!children) { + return + } + for (const child of children) { + const keyExtension = child[0] as Nibbles + const childRef = child[1] as Buffer + const childKey = key.concat(keyExtension) + const priority = childKey.length + this.pushNodeToQueue(childRef, childKey, priority) + } + } + + /** + * Push a node to the queue. If the queue has places left for tasks, the node is executed immediately, otherwise it is queued. + * @param nodeRef - Push a node reference to the event queue. This reference is a 32-byte keccak hash of the value corresponding to the `key`. + * @param key - The current key. + * @param priority - Optional priority, defaults to key length + */ + pushNodeToQueue(nodeRef: Buffer, key: Nibbles = [], priority?: number) { + this.taskExecutor.executeOrQueue( + priority ?? key.length, + async (taskFinishedCallback: Function) => { + const childNode = await this.trie._lookupNode(nodeRef) + taskFinishedCallback() // this marks the current task as finished. If there are any tasks left in the queue, this will immediately execute the first task. + this.processNode(nodeRef as Buffer, childNode as TrieNode, key) + } + ) + } + + /** + * Push a branch of a certain BranchNode to the event queue. + * @param node - The node to select a branch on. Should be a BranchNode. + * @param key - The current key which leads to the corresponding node. + * @param childIndex - The child index to add to the event queue. + * @param priority - Optional priority of the event, defaults to the total key length. + */ + onlyBranchIndex(node: BranchNode, key: Nibbles = [], childIndex: number, priority?: number) { + if (!(node instanceof BranchNode)) { + throw new Error('Expected branch node') + } + const childRef = node.getBranch(childIndex) + if (!childRef) { + throw new Error('Could not get branch of childIndex') + } + const childKey = key.slice() // This copies the key to a new array. + childKey.push(childIndex) + const prio = priority ?? childKey.length + this.pushNodeToQueue(childRef as Buffer, childKey, prio) + } + + private processNode(nodeRef: Buffer, node: TrieNode | null, key: Nibbles = []) { + this.onNode(nodeRef, node, key, this) + if (this.taskExecutor.finished()) { + // onNode should schedule new tasks. If no tasks was added and the queue is empty, then we have finished our walk. + this.resolve() + } + } +} diff --git a/test/index.spec.ts b/test/index.spec.ts index d9b8ddc..be7cea8 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -1,7 +1,7 @@ import tape from 'tape' import * as rlp from 'rlp' import { KECCAK256_NULL } from 'ethereumjs-util' -import { CheckpointTrie } from '../src' +import { BaseTrie, CheckpointTrie } from '../src' tape('simple save and retrieve', function (tester) { const it = tester.test @@ -208,6 +208,38 @@ tape('testing deletion cases', function (tester) { }) }) +tape('shall handle the case of node not found correctly', async (t) => { + const trie = new BaseTrie() + await trie.put(Buffer.from('a'), Buffer.from('value1')) + await trie.put(Buffer.from('aa'), Buffer.from('value2')) + await trie.put(Buffer.from('aaa'), Buffer.from('value3')) + + /* Setups a trie which consists of + ExtensionNode -> + BranchNode -> value1 + ExtensionNode -> + BranchNode -> value2 + LeafNode -> value3 + */ + + let path = await trie.findPath(Buffer.from('aaa')) + + t.ok(path.node != null, 'findPath should find a node') + + const { stack } = await trie.findPath(Buffer.from('aaa')) + await trie.db.del(stack[1].hash()) // delete the BranchNode -> value1 from the DB + + path = await trie.findPath(Buffer.from('aaa')) + + t.ok(path.node === null, 'findPath should not return a node now') + t.ok( + path.stack.length == 1, + 'findPath should find the first extension node which is still in the DB' + ) + + t.end() +}) + tape('it should create the genesis state root from ethereum', function (tester) { const it = tester.test const trie4 = new CheckpointTrie() diff --git a/test/prioritizedTaskExecutor.spec.ts b/test/prioritizedTaskExecutor.spec.ts index b78bf96..4e935ce 100644 --- a/test/prioritizedTaskExecutor.spec.ts +++ b/test/prioritizedTaskExecutor.spec.ts @@ -8,7 +8,7 @@ tape('prioritized task executor test', function (t) { const callbacks = [] as any const executionOrder = [] as any tasks.forEach(function (task) { - taskExecutor.execute(task, function (cb: Function) { + taskExecutor.executeOrQueue(task, function (cb: Function) { executionOrder.push(task) callbacks.push(cb) }) diff --git a/typedoc.json b/typedoc.json index d89f0db..4f97325 100644 --- a/typedoc.json +++ b/typedoc.json @@ -5,7 +5,7 @@ "plugin": "typedoc-plugin-markdown", "readme": "none", "gitRevision": "master", - "exclude": ["src/**/!(secure|checkpointTrie|baseTrie).ts", "test/**/*.ts"], + "exclude": ["src/**/!(secure|checkpointTrie|baseTrie|walkController).ts", "test/**/*.ts"], "excludeNotExported": true, "excludeExternals": true, "excludePrivate": true,