Skip to content

Commit

Permalink
feat: add identity blockstore (#298)
Browse files Browse the repository at this point in the history
Add a blockstore implementation that supports identity CIDs.
  • Loading branch information
achingbrain committed Feb 12, 2024
1 parent bf0b007 commit b8dce49
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 2 deletions.
15 changes: 15 additions & 0 deletions packages/blockstore-core/README.md
Expand Up @@ -74,6 +74,21 @@ const store = new TieredBlockstore([
])
```

## Example - IdentityBlockstore

An identity blockstore is one that deals exclusively in Identity CIDs - this is a special CID with the codec [0x00](https://github.com/multiformats/multicodec/blob/d06fc6194710e8909bac64273c43f16b56ca4c34/table.csv#L2) where the multihash digest is the data that makes up the block.

```TypeScript
import { IdentityBlockstore } from 'blockstore-core/identity'
import { CID } from 'multiformats/cid'

const blockstore = new IdentityBlockstore()

blockstore.has(CID.parse('QmFoo')) // false

blockstore.has(CID.parse('bafkqac3imvwgy3zao5xxe3de')) // true
```

# Install

```console
Expand Down
4 changes: 4 additions & 0 deletions packages/blockstore-core/package.json
Expand Up @@ -63,6 +63,10 @@
"types": "./dist/src/errors.d.ts",
"import": "./dist/src/errors.js"
},
"./identity": {
"types": "./dist/src/identity.d.ts",
"import": "./dist/src/identity.js"
},
"./memory": {
"types": "./dist/src/memory.d.ts",
"import": "./dist/src/memory.js"
Expand Down
4 changes: 2 additions & 2 deletions packages/blockstore-core/src/base.ts
Expand Up @@ -31,8 +31,8 @@ export class BaseBlockstore implements Blockstore {
}
}

async delete (key: CID, options?: AbortOptions): Promise<void> {
await Promise.reject(new Error('.delete is not implemented'))
delete (key: CID, options?: AbortOptions): Await<void> {
return Promise.reject(new Error('.delete is not implemented'))
}

async * deleteMany (source: AwaitIterable<CID>, options?: AbortOptions): AwaitIterable<CID> {
Expand Down
34 changes: 34 additions & 0 deletions packages/blockstore-core/src/identity.ts
@@ -0,0 +1,34 @@
import { BaseBlockstore } from './base.js'
import * as Errors from './errors.js'
import type { Pair } from 'interface-blockstore'
import type { Await, AwaitIterable } from 'interface-store'
import type { CID } from 'multiformats/cid'

// https://github.com/multiformats/multicodec/blob/d06fc6194710e8909bac64273c43f16b56ca4c34/table.csv#L2
const IDENTITY_CODEC = 0x00

export class IdentityBlockstore extends BaseBlockstore {
put (key: CID): CID {
return key
}

get (key: CID): Await<Uint8Array> {
if (key.code === IDENTITY_CODEC) {
return key.multihash.digest
}

throw Errors.notFoundError()
}

has (key: CID): boolean {
return key.code === IDENTITY_CODEC
}

delete (): void {

}

* getAll (): AwaitIterable<Pair> {

}
}
15 changes: 15 additions & 0 deletions packages/blockstore-core/src/index.ts
Expand Up @@ -65,6 +65,21 @@
* // ...etc
* ])
* ```
*
* @example IdentityBlockstore
*
* An identity blockstore is one that deals exclusively in Identity CIDs - this is a special CID with the codec [0x00](https://github.com/multiformats/multicodec/blob/d06fc6194710e8909bac64273c43f16b56ca4c34/table.csv#L2) where the multihash digest is the data that makes up the block.
*
* ```TypeScript
* import { IdentityBlockstore } from 'blockstore-core/identity'
* import { CID } from 'multiformats/cid'
*
* const blockstore = new IdentityBlockstore()
*
* blockstore.has(CID.parse('QmFoo')) // false
*
* blockstore.has(CID.parse('bafkqac3imvwgy3zao5xxe3de')) // true
* ```
*/

import * as ErrorsImport from './errors.js'
Expand Down
59 changes: 59 additions & 0 deletions packages/blockstore-core/test/identity.spec.ts
@@ -0,0 +1,59 @@
/* eslint-env mocha */

import { expect } from 'aegir/chai'
import drain from 'it-drain'
import { CID } from 'multiformats/cid'
import * as raw from 'multiformats/codecs/raw'
import { identity } from 'multiformats/hashes/identity'
import { sha256 } from 'multiformats/hashes/sha2'
import { IdentityBlockstore } from '../src/identity.js'
import type { Blockstore } from 'interface-blockstore'

describe('identity', () => {
let blockstore: Blockstore

beforeEach(() => {
blockstore = new IdentityBlockstore()
})

it('has an identity CID', () => {
const block = Uint8Array.from([0, 1, 2, 3, 4])
const multihash = identity.digest(block)
const cid = CID.createV1(identity.code, multihash)

expect(blockstore.has(cid)).to.be.true()
expect(blockstore.get(cid)).to.equalBytes(block)
})

it('does not have a non-identity CID', async () => {
const block = Uint8Array.from([0, 1, 2, 3, 4])
const multihash = await sha256.digest(block)
const cid = CID.createV1(raw.code, multihash)

expect(blockstore.has(cid)).to.be.false()

await blockstore.put(cid, block)

expect(blockstore.has(cid)).to.be.false()
})

it('cannot delete an identity CID', async () => {
const block = Uint8Array.from([0, 1, 2, 3, 4])
const multihash = identity.digest(block)
const cid = CID.createV1(identity.code, multihash)

await blockstore.delete(cid)

expect(blockstore.has(cid)).to.be.true()
})

it('cannot delete many identity CIDs', async () => {
const block = Uint8Array.from([0, 1, 2, 3, 4])
const multihash = identity.digest(block)
const cid = CID.createV1(identity.code, multihash)

await drain(blockstore.deleteMany([cid]))

expect(blockstore.has(cid)).to.be.true()
})
})
1 change: 1 addition & 0 deletions packages/blockstore-core/typedoc.json
Expand Up @@ -4,6 +4,7 @@
"./src/base.ts",
"./src/black-hole.ts",
"./src/errors.ts",
"./src/identity.ts",
"./src/memory.ts",
"./src/tiered.ts"
]
Expand Down

0 comments on commit b8dce49

Please sign in to comment.