From 989ee64faf0ce47d150de3104c81aebfbc26ba08 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 15 Jan 2019 10:28:33 +0100 Subject: [PATCH 1/3] Merge checkpoint & secure interfaces with es6 classes Signed-off-by: Sina Mahmoodi --- src/checkpoint-interface.js | 151 -------------------------------- src/checkpoint-trie.js | 170 ++++++++++++++++++++++++++++++++++++ src/index.js | 19 +--- src/secure-interface.js | 39 --------- src/secure.js | 36 +++++++- 5 files changed, 203 insertions(+), 212 deletions(-) delete mode 100644 src/checkpoint-interface.js create mode 100644 src/checkpoint-trie.js delete mode 100644 src/secure-interface.js diff --git a/src/checkpoint-interface.js b/src/checkpoint-interface.js deleted file mode 100644 index 4968c6b..0000000 --- a/src/checkpoint-interface.js +++ /dev/null @@ -1,151 +0,0 @@ -const level = require('level-mem') -const async = require('async') -const WriteStream = require('level-ws') -const callTogether = require('./util/async').callTogether - -const ScratchReadStream = require('./scratchReadStream') - -module.exports = checkpointInterface - -function checkpointInterface (trie) { - this._scratch = null - trie._checkpoints = [] - - Object.defineProperty(trie, 'isCheckpoint', { - get: function () { - return !!trie._checkpoints.length - } - }) - - // new methods - trie.checkpoint = checkpoint - trie.commit = commit - trie.revert = revert - trie._enterCpMode = _enterCpMode - trie._exitCpMode = _exitCpMode - trie.createScratchReadStream = createScratchReadStream - - // overwrites - trie.copy = copy.bind(trie, trie.copy.bind(trie)) -} - -/** - * 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 - * @method checkpoint - * @private - */ -function checkpoint () { - var self = this - var wasCheckpoint = self.isCheckpoint - self._checkpoints.push(self.root) - if (!wasCheckpoint && self.isCheckpoint) { - self._enterCpMode() - } -} - -/** - * commits a checkpoint to disk - * @method commit - * @private - * @param {Function} cb the callback - */ -function commit (cb) { - var self = this - cb = callTogether(cb, self.sem.leave) - - self.sem.take(function () { - if (self.isCheckpoint) { - self._checkpoints.pop() - if (!self.isCheckpoint) { - self._exitCpMode(true, cb) - } else { - cb() - } - } else { - throw new Error('trying to commit when not checkpointed') - } - }) -} - -/** - * Reverts the trie to the state it was at when `checkpoint` was first called. - * @method revert - * @private - * @param {Function} cb the callback - */ -function revert (cb) { - var self = this - cb = callTogether(cb, self.sem.leave) - - self.sem.take(function () { - if (self.isCheckpoint) { - self.root = self._checkpoints.pop() - if (!self.isCheckpoint) { - self._exitCpMode(false, cb) - return - } - } - - cb() - }) -} - -// enter into checkpoint mode -function _enterCpMode () { - this._scratch = level() - this._getDBs = [this._scratch].concat(this._getDBs) - this.__putDBs = this._putDBs - this._putDBs = [this._scratch] - this._putRaw = this.putRaw - this.putRaw = putRaw -} - -// exit from checkpoint mode -function _exitCpMode (commitState, cb) { - var self = this - var scratch = this._scratch - this._scratch = null - this._getDBs = this._getDBs.slice(1) - this._putDBs = this.__putDBs - this.putRaw = this._putRaw - - function flushScratch (db, cb) { - self.createScratchReadStream(scratch) - .pipe(WriteStream(db)) - .on('close', cb) - } - - if (commitState) { - async.map(this._putDBs, flushScratch, cb) - } else { - cb() - } -} - -// adds the interface when copying the trie -function copy (_super) { - var trie = _super() - checkpointInterface.call(trie, trie) - trie._scratch = this._scratch - // trie._checkpoints = this._checkpoints.slice() - return trie -} - -function putRaw (key, val, cb) { - function dbPut (db, cb2) { - db.put(key, val, { - keyEncoding: 'binary', - valueEncoding: 'binary' - }, cb2) - } - async.each(this.__putDBs, dbPut, cb) -} - -function createScratchReadStream (scratch) { - var trie = this.copy() - scratch = scratch || this._scratch - // only read from the scratch - trie._getDBs = [scratch] - trie._scratch = scratch - return new ScratchReadStream(trie) -} diff --git a/src/checkpoint-trie.js b/src/checkpoint-trie.js new file mode 100644 index 0000000..16fabe6 --- /dev/null +++ b/src/checkpoint-trie.js @@ -0,0 +1,170 @@ +const async = require('async') +const level = require('level-mem') +const WriteStream = require('level-ws') +const BaseTrie = require('./baseTrie') +const proof = require('./proof.js') +const ScratchReadStream = require('./scratchReadStream') +const { asyncFirstSeries, callTogether } = require('./util/async') + +module.exports = class CheckpointTrie extends BaseTrie { + constructor (...args) { + super(...args) + this._scratch = null + this._checkpoints = [] + } + + static prove (...args) { + return proof.prove(...args) + } + + static verifyProof (...args) { + return proof.verifyProof(...args) + } + + /** + * Is the trie during a checkpoint phase? + */ + get isCheckpoint () { + return this._checkpoints.length > 0 + } + + /** + * 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. Calling `putRaw` overrides the checkpointing + * mechanism and would directly write to db. + * @method checkpoint + */ + checkpoint () { + const wasCheckpoint = this.isCheckpoint + this._checkpoints.push(this.root) + + // Entering checkpoint mode is not necessary for nested checkpoints + if (!wasCheckpoint && this.isCheckpoint) { + this._enterCpMode() + } + } + + /** + * Commits a checkpoint to disk, if current checkpoint is not nested. If + * nested, only sets the parent checkpoint as current checkpoint. + * @method commit + * @param {Function} cb the callback + * @throws If not during a checkpoint phase + */ + commit (cb) { + cb = callTogether(cb, this.sem.leave) + + this.sem.take(() => { + if (this.isCheckpoint) { + this._checkpoints.pop() + if (!this.isCheckpoint) { + this._exitCpMode(true, cb) + } else { + cb() + } + } else { + throw new Error('trying to commit when not checkpointed') + } + }) + } + + /** + * Reverts the trie to the state it was at when `checkpoint` was first called. + * If during a nested checkpoint, only sets parent as current checkpoint. + * @method revert + * @param {Function} cb the callback + */ + revert (cb) { + cb = callTogether(cb, this.sem.leave) + + this.sem.take(() => { + if (this.isCheckpoint) { + this.root = this._checkpoints.pop() + if (!this.isCheckpoint) { + this._exitCpMode(false, cb) + return + } + } + + cb() + }) + } + + /** + * Returns a copy of the underlying trie with the interface + * of CheckpointTrie. + * @method copy + */ + copy () { + const trie = new CheckpointTrie(this.db, this.root) + trie._scratch = this._scratch + // trie._checkpoints = this._checkpoints.slice() + return trie + } + + /** + * Returns a `ScratchReadStream` based on the state updates + * since checkpoint. + * @method createScratchReadStream + */ + createScratchReadStream (scratch) { + const trie = this.copy() + scratch = scratch || this._scratch + // Only read from the scratch + trie._getDBs = [scratch] + trie._scratch = scratch + return new ScratchReadStream(trie) + } + + /** + * Puts kv-pair directly to db, ignoring checkpoints. + * @private + */ + _overridePutRaw (key, val, cb) { + const dbPut = (db, cb2) => { + db.put(key, val, { + keyEncoding: 'binary', + valueEncoding: 'binary' + }, cb2) + } + async.each(this.__putDBs, dbPut, cb) + } + + /** + * Enter into checkpoint mode. + * @private + */ + _enterCpMode () { + this._scratch = level() + this._getDBs = [this._scratch].concat(this._getDBs) + this.__putDBs = this._putDBs + this._putDBs = [this._scratch] + this._putRaw = this.putRaw + this.putRaw = this._overridePutRaw + } + + /** + * Exit from checkpoint mode. + * @private + */ + _exitCpMode (commitState, cb) { + var scratch = this._scratch + this._scratch = null + this._getDBs = this._getDBs.slice(1) + this._putDBs = this.__putDBs + this.putRaw = this._putRaw + + const flushScratch = (db, cb) => { + this.createScratchReadStream(scratch) + .pipe(WriteStream(db)) + .on('close', cb) + } + + if (commitState) { + async.map(this._putDBs, flushScratch, cb) + } else { + cb() + } + } +} diff --git a/src/index.js b/src/index.js index 0726d79..bcbc04b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,18 +1 @@ -const BaseTrie = require('./baseTrie') -const checkpointInterface = require('./checkpoint-interface') -const proof = require('./proof.js') - -module.exports = class CheckpointTrie extends BaseTrie { - constructor (...args) { - super(...args) - checkpointInterface.call(this, this) - } - - static prove (...args) { - return proof.prove(...args) - } - - static verifyProof (...args) { - return proof.verifyProof(...args) - } -} +module.exports = require('./checkpoint-trie') diff --git a/src/secure-interface.js b/src/secure-interface.js deleted file mode 100644 index 84dbe99..0000000 --- a/src/secure-interface.js +++ /dev/null @@ -1,39 +0,0 @@ -const ethUtil = require('ethereumjs-util') - -module.exports = secureInterface - -function secureInterface (trie) { - // overwrites - trie.copy = copy.bind(trie, trie.copy.bind(trie)) - trie.get = get.bind(trie, trie.get.bind(trie)) - trie.put = put.bind(trie, trie.put.bind(trie)) - trie.del = del.bind(trie, trie.del.bind(trie)) -} - -// adds the interface when copying the trie -function copy (_super) { - var trie = _super() - secureInterface(trie) - return trie -} - -function get (_super, key, cb) { - var hash = ethUtil.sha3(key) - _super(hash, cb) -} - -// for a falsey value, use the original key -// to avoid double hashing the key -function put (_super, key, val, cb) { - if (!val) { - this.del(key, cb) - } else { - var hash = ethUtil.sha3(key) - _super(hash, val, cb) - } -} - -function del (_super, key, cb) { - var hash = ethUtil.sha3(key) - _super(hash, cb) -} diff --git a/src/secure.js b/src/secure.js index 0084362..78f60aa 100644 --- a/src/secure.js +++ b/src/secure.js @@ -1,8 +1,10 @@ -const CheckpointTrie = require('./index') -const secureInterface = require('./secure-interface') +const ethUtil = require('ethereumjs-util') +const CheckpointTrie = require('./checkpoint-trie') /** - * You can create a secure Trie where the keys are automatically hashed using **SHA3** by using `require('merkle-patricia-tree/secure')`. It has the same methods and constructor as `Trie`. + * You can create a secure Trie where the keys are automatically hashed + * using **keccak256** by using `require('merkle-patricia-tree/secure')`. + * It has the same methods and constructor as `Trie`. * @class SecureTrie * @extends Trie * @public @@ -10,6 +12,32 @@ const secureInterface = require('./secure-interface') module.exports = class SecureTrie extends CheckpointTrie { constructor (...args) { super(...args) - secureInterface(this) + } + + copy () { + return new SecureTrie(this.db, this.root) + } + + get (key, cb) { + const hash = ethUtil.keccak256(key) + super.get(hash, cb) + } + + /** + * For a falsey value, use the original key + * to avoid double hashing the key. + */ + put (key, val, cb) { + if (!val) { + this.del(key, cb) + } else { + const hash = ethUtil.keccak256(key) + super.put(hash, val, cb) + } + } + + del (key, cb) { + const hash = ethUtil.keccak256(key) + super.del(hash, cb) } } From 4194fd7855a3b9bd85742ea3c20ebfc405182742 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 15 Jan 2019 10:29:30 +0100 Subject: [PATCH 2/3] Remove unnecessary require Signed-off-by: Sina Mahmoodi --- src/checkpoint-trie.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/checkpoint-trie.js b/src/checkpoint-trie.js index 16fabe6..5beb3b1 100644 --- a/src/checkpoint-trie.js +++ b/src/checkpoint-trie.js @@ -4,7 +4,7 @@ const WriteStream = require('level-ws') const BaseTrie = require('./baseTrie') const proof = require('./proof.js') const ScratchReadStream = require('./scratchReadStream') -const { asyncFirstSeries, callTogether } = require('./util/async') +const { callTogether } = require('./util/async') module.exports = class CheckpointTrie extends BaseTrie { constructor (...args) { From 7fa1ca3db5488e48ce1968457922d3ac6c231d4a Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 15 Jan 2019 10:47:43 +0100 Subject: [PATCH 3/3] Re-generate docs Signed-off-by: Sina Mahmoodi --- docs/index.md | 123 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 103 insertions(+), 20 deletions(-) diff --git a/docs/index.md b/docs/index.md index 26a3fc3..1ef081a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,11 +2,13 @@ ## SecureTrie -[src/secure.js:10-15][1] +[src/secure.js:12-43][1] **Extends Trie** -You can create a secure Trie where the keys are automatically hashed using **SHA3** by using `require('merkle-patricia-tree/secure')`. It has the same methods and constructor as `Trie`. +You can create a secure Trie where the keys are automatically hashed +using **keccak256** by using `require('merkle-patricia-tree/secure')`. +It has the same methods and constructor as `Trie`. ## Trie @@ -231,9 +233,76 @@ Compare two nibble array keys. Take two or more functions and returns a function that will execute all of the given functions -[1]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/secure.js#L10-L15 "Source code on GitHub" +## isCheckpoint -[2]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L23-L779 "Source code on GitHub" +[src/checkpoint-trie.js:27-29][30] + +Is the trie during a checkpoint phase? + +## put + +[src/secure.js:30-37][31] + +For a falsey value, use the original key +to avoid double hashing the key. + +### Parameters + +- `key` +- `val` +- `cb` + +## checkpoint + +[src/checkpoint-trie.js:38-46][32] + +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. Calling `putRaw` overrides the checkpointing +mechanism and would directly write to db. + +## commit + +[src/checkpoint-trie.js:55-70][33] + +Commits a checkpoint to disk, if current checkpoint is not nested. If +nested, only sets the parent checkpoint as current checkpoint. + +### Parameters + +- `cb` **[Function][10]** the callback + + +- Throws **any** If not during a checkpoint phase + +## revert + +[src/checkpoint-trie.js:78-92][34] + +Reverts the trie to the state it was at when `checkpoint` was first called. +If during a nested checkpoint, only sets parent as current checkpoint. + +### Parameters + +- `cb` **[Function][10]** the callback + +## copy + +[src/checkpoint-trie.js:99-104][35] + +Returns a copy of the underlying trie with the interface +of CheckpointTrie. + +## createScratchReadStream + +[src/checkpoint-trie.js:111-118][36] + +Returns a `ScratchReadStream` based on the state updates +since checkpoint. + +[1]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/secure.js#L12-L43 "Source code on GitHub" + +[2]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L23-L779 "Source code on GitHub" [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object @@ -247,44 +316,58 @@ the given functions [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean -[9]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L63-L75 "Source code on GitHub" +[9]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L63-L75 "Source code on GitHub" [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function -[11]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L85-L109 "Source code on GitHub" +[11]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L85-L109 "Source code on GitHub" -[12]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L118-L134 "Source code on GitHub" +[12]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L118-L134 "Source code on GitHub" -[13]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L143-L160 "Source code on GitHub" +[13]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L143-L160 "Source code on GitHub" -[14]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L190-L199 "Source code on GitHub" +[14]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L190-L199 "Source code on GitHub" -[15]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L208-L216 "Source code on GitHub" +[15]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L208-L216 "Source code on GitHub" -[16]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L250-L296 "Source code on GitHub" +[16]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L250-L296 "Source code on GitHub" -[17]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L728-L730 "Source code on GitHub" +[17]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L728-L730 "Source code on GitHub" [18]: https://nodejs.org/api/stream.html#stream_class_stream_readable [19]: https://nodejs.org/dist/latest-v5.x/docs/api/stream.html#stream_class_stream_readable -[20]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L754-L764 "Source code on GitHub" +[20]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L754-L764 "Source code on GitHub" [21]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array -[22]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/baseTrie.js#L773-L778 "Source code on GitHub" +[22]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/baseTrie.js#L773-L778 "Source code on GitHub" -[23]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/proof.js#L12-L29 "Source code on GitHub" +[23]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/proof.js#L12-L29 "Source code on GitHub" [24]: #trie -[25]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/proof.js#L39-L100 "Source code on GitHub" +[25]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/proof.js#L39-L100 "Source code on GitHub" + +[26]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/util/hex.js#L7-L22 "Source code on GitHub" + +[27]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/util/async.js#L38-L54 "Source code on GitHub" + +[28]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/util/nibbles.js#L56-L59 "Source code on GitHub" + +[29]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/util/async.js#L3-L6 "Source code on GitHub" + +[30]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/checkpoint-trie.js#L27-L29 "Source code on GitHub" + +[31]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/secure.js#L30-L37 "Source code on GitHub" + +[32]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/checkpoint-trie.js#L38-L46 "Source code on GitHub" -[26]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/util/hex.js#L7-L22 "Source code on GitHub" +[33]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/checkpoint-trie.js#L55-L70 "Source code on GitHub" -[27]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/util/async.js#L38-L54 "Source code on GitHub" +[34]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/checkpoint-trie.js#L78-L92 "Source code on GitHub" -[28]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/util/nibbles.js#L56-L59 "Source code on GitHub" +[35]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/checkpoint-trie.js#L99-L104 "Source code on GitHub" -[29]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/f6dbe761448c6a886a2e8fdb920c396c29d8c99b/src/util/async.js#L3-L6 "Source code on GitHub" +[36]: https://git@github.com/:ethereumjs/merkle-patricia-tree/blob/4194fd7855a3b9bd85742ea3c20ebfc405182742/src/checkpoint-trie.js#L111-L118 "Source code on GitHub"