-
Notifications
You must be signed in to change notification settings - Fork 23
Description
Bug Description
IdentityBlockstore.get() is defined as a synchronous generator (* get) but uses yield* to delegate to child blockstores that return async generators (async * get). This causes a TypeError: yield* (intermediate value) is not iterable error.
Affected Version
- Package:
blockstore-core - Version:
6.1.1(and likely6.1.0) - File:
packages/blockstore-core/src/identity.ts:48
Error Message
TypeError: yield* (intermediate value) is not iterable
at IdentityBlockstore.get (blockstore-core/dist/src/identity.js:44:27)
Root Cause
In packages/blockstore-core/src/identity.ts, line 48:
* get (key: CID, options?: AbortOptions): AwaitGenerator<Uint8Array> {
// ...
yield * this.child.get(key, options); // Line 62 - ERROR HERE
}The method is a synchronous generator (* get), but this.child.get() (e.g., from LevelBlockstore) returns an async generator (async * get). You cannot use yield* to delegate from a sync generator to an async generator.
Steps to Reproduce
import { IdentityBlockstore } from 'blockstore-core/identity'
import { LevelBlockstore } from 'blockstore-level'
import { CID } from 'multiformats/cid'
import * as raw from 'multiformats/codecs/raw'
import { sha256 } from 'multiformats/hashes/sha2'
import toBuffer from 'it-to-buffer'
const levelBlockstore = new LevelBlockstore('./test-blocks')
await levelBlockstore.open()
const identityBlockstore = new IdentityBlockstore(levelBlockstore)
const input = Uint8Array.from([0, 1, 2, 3, 4])
const digest = await sha256.digest(input)
const cid = CID.createV1(raw.code, digest)
await identityBlockstore.put(cid, input)
// This will throw: TypeError: yield* (intermediate value) is not iterable
const result = await toBuffer(identityBlockstore.get(cid))Expected Behavior
IdentityBlockstore.get() should successfully retrieve blocks from child blockstores.
Actual Behavior
Throws TypeError: yield* (intermediate value) is not iterable when trying to get a block.
Proposed Fix
Change line 48 from:
* get (key: CID, options?: AbortOptions): AwaitGenerator<Uint8Array> {To:
async * get (key: CID, options?: AbortOptions): AwaitGenerator<Uint8Array> {This makes it an async generator, which can properly delegate to async generators using yield*.
Impact
This bug affects any code using IdentityBlockstore with blockstores that return async generators (like LevelBlockstore, FSBlockstore, etc.). This includes:
- Helia's
NetworkedStoragewhich wraps blockstores withIdentityBlockstore - Any OrbitDB usage with Helia/IPFS
- Any code using
IdentityBlockstorewith persistent blockstores
Related
- Introduced in commit
4dbb136("feat!: streaming blockstores feat!: streaming blockstores #358") - Affects
blockstore-core@6.1.0and6.1.1 blockstore-core@6.0.0works correctly (doesn't have this bug)
Test Case
A minimal reproduction test:
import { IdentityBlockstore } from 'blockstore-core/identity'
import { LevelBlockstore } from 'blockstore-level'
import { CID } from 'multiformats/cid'
import * as raw from 'multiformats/codecs/raw'
import { sha256 } from 'multiformats/hashes/sha2'
import toBuffer from 'it-to-buffer'
import { join } from 'path'
import { tmpdir } from 'os'
import { rmSync } from 'fs'
async function testIdentityBlockstoreBug() {
const testDir = join(tmpdir(), `blockstore-test-${Date.now()}`)
const levelBlockstore = new LevelBlockstore(testDir)
await levelBlockstore.open()
const identityBlockstore = new IdentityBlockstore(levelBlockstore)
const input = Uint8Array.from([0, 1, 2, 3, 4])
const digest = await sha256.digest(input)
const cid = CID.createV1(raw.code, digest)
await identityBlockstore.put(cid, input)
// This throws: TypeError: yield* (intermediate value) is not iterable
const result = await toBuffer(identityBlockstore.get(cid))
await levelBlockstore.close()
rmSync(testDir, { recursive: true, force: true })
}
testIdentityBlockstoreBug().catch(console.error)The test confirms the bug and shows it's fixed when IdentityBlockstore.get is changed to async * get.