Skip to content

Commit 08507bd

Browse files
committed
feat: store blocks under multihash key
BREAKING CHANGE: repo.blocks.query() now returns multihashes as a key instead of CID. If you want to have CID returned call it as query({}, true), which will constructs CIDv1 using IPLD's RAW codec. This means that this constructed CID might not equal to the one that the block was originally saved. Related to ipfs/js-ipfs#2415
1 parent 9b85b16 commit 08507bd

6 files changed

+65
-44
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,13 @@ Get block.
197197

198198
* `cid` is the content id of [type CID](https://github.com/ipld/js-cid#readme).
199199

200+
#### `Promise<Array<Object>> repo.blocks.query (query, reconstructsCids)`
201+
202+
Query what blocks are available in blockstore.
203+
204+
* `query` is a object as specified in [interface-datastore](https://github.com/ipfs/interface-datastore#query).
205+
* `reconstructsCids` a flag defining if the block's key is a reconstructed CID (eq. CIDv1 with RAW IPLD codec) or multihash
206+
200207
Datastore:
201208

202209
#### `repo.datastore`

src/blockstore-utils.js

+38-3
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,53 @@ const CID = require('cids')
1212
*/
1313
exports.cidToKey = cid => {
1414
const enc = new base32.Encoder()
15-
return new Key('/' + enc.write(cid.buffer).finalize(), false)
15+
return new Key('/' + enc.write(cid.multihash).finalize(), false)
1616
}
1717

1818
/**
1919
* Transform a datastore Key instance to a CID
20+
* As Key is a multihash of the CID, it is reconstructed using IPLD's RAW codec.
21+
* Hence it is highly probable that stored CID will differ from a CID retrieved from blockstore.
2022
*
2123
* @param {Key} key
2224
* @returns {CID}
2325
*/
24-
exports.keyToCid = key => {
26+
27+
function keyToCid (key) {
28+
// Block key is of the form /<base32 encoded string>
29+
const decoder = new base32.Decoder()
30+
const buff = decoder.write(key.toString().slice(1)).finalize()
31+
return new CID(1, 'raw', Buffer.from(buff))
32+
}
33+
34+
exports.keyToCid = keyToCid
35+
36+
/**
37+
* Transform a datastore Key instance to a multihash instance.
38+
*
39+
* @param {Key} key
40+
* @returns {Buffer}
41+
*/
42+
43+
function keyToMultihash (key) {
2544
// Block key is of the form /<base32 encoded string>
2645
const decoder = new base32.Decoder()
2746
const buff = decoder.write(key.toString().slice(1)).finalize()
28-
return new CID(Buffer.from(buff))
47+
return Buffer.from(buff)
48+
}
49+
50+
exports.keyToMultihash = keyToMultihash
51+
52+
/**
53+
* Transforms a datastore Key containing multihash to a Key that contains reconstructed CID
54+
*
55+
* @param {Key} key
56+
* @returns {CID}
57+
*/
58+
function keyToCidKey (key) {
59+
const cid = keyToCid(key)
60+
const enc = new base32.Encoder()
61+
return new Key('/' + enc.write(cid.buffer).finalize(), false)
2962
}
63+
64+
exports.keyToCidKey = keyToCidKey

src/blockstore.js

+12-37
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const ShardingStore = core.ShardingDatastore
55
const Block = require('ipfs-block')
66
const CID = require('cids')
77
const errcode = require('err-code')
8-
const { cidToKey } = require('./blockstore-utils')
8+
const { cidToKey, keyToCidKey } = require('./blockstore-utils')
99

1010
module.exports = async (filestore, options) => {
1111
const store = await maybeWithSharding(filestore, options)
@@ -26,10 +26,15 @@ function createBaseStore (store) {
2626
* Query the store.
2727
*
2828
* @param {object} query
29+
* @param {boolean} reconstructsCids - Defines if Keys are converted to a reconstructed CID using IPLD_RAW codec
2930
* @return {Iterable}
3031
*/
31-
async * query (query) {
32+
async * query (query, reconstructsCids = false) {
3233
for await (const block of store.query(query)) {
34+
if (reconstructsCids) {
35+
block.key = keyToCidKey(block.key)
36+
}
37+
3338
yield block
3439
}
3540
},
@@ -44,26 +49,8 @@ function createBaseStore (store) {
4449
throw errcode(new Error('Not a valid cid'), 'ERR_INVALID_CID')
4550
}
4651
const key = cidToKey(cid)
47-
let blockData
48-
try {
49-
blockData = await store.get(key)
50-
return new Block(blockData, cid)
51-
} catch (err) {
52-
if (err.code === 'ERR_NOT_FOUND') {
53-
const otherCid = cidToOtherVersion(cid)
54-
55-
if (!otherCid) {
56-
throw err
57-
}
58-
59-
const otherKey = cidToKey(otherCid)
60-
const blockData = await store.get(otherKey)
61-
await store.put(key, blockData)
62-
return new Block(blockData, cid)
63-
}
64-
65-
throw err
66-
}
52+
const blockData = await store.get(key)
53+
return new Block(blockData, cid)
6754
},
6855
/**
6956
* Write a single block to the store.
@@ -112,18 +99,14 @@ function createBaseStore (store) {
11299
* Does the store contain block with this cid?
113100
*
114101
* @param {CID} cid
115-
* @returns {Promise<bool>}
102+
* @returns {Promise<boolean>}
116103
*/
117-
async has (cid) {
104+
has (cid) {
118105
if (!CID.isCID(cid)) {
119106
throw errcode(new Error('Not a valid cid'), 'ERR_INVALID_CID')
120107
}
121108

122-
const exists = await store.has(cidToKey(cid))
123-
if (exists) return exists
124-
const otherCid = cidToOtherVersion(cid)
125-
if (!otherCid) return false
126-
return store.has(cidToKey(otherCid))
109+
return store.has(cidToKey(cid))
127110
},
128111
/**
129112
* Delete a block from the store
@@ -147,11 +130,3 @@ function createBaseStore (store) {
147130
}
148131
}
149132
}
150-
151-
function cidToOtherVersion (cid) {
152-
try {
153-
return cid.version === 0 ? cid.toV1() : cid.toV0()
154-
} catch (err) {
155-
return null
156-
}
157-
}

src/index.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,11 @@ class IpfsRepo {
277277
let count = new Big(0)
278278
let size = new Big(0)
279279

280-
for await (const block of this.blocks.query({})) {
280+
for await (const block of this.blocks.query({}, false)) {
281281
count = count.plus(1)
282282
size = size
283283
.plus(block.value.byteLength)
284-
.plus(block.key._buf.byteLength)
284+
.plus(block.key.toBuffer().byteLength)
285285
}
286286

287287
return { count, size }
@@ -292,7 +292,7 @@ async function getSize (queryFn) {
292292
let sum = new Big(0)
293293
for await (const block of queryFn.query({})) {
294294
sum.plus(block.value.byteLength)
295-
.plus(block.key._buf.byteLength)
295+
.plus(block.key.toBuffer().byteLength)
296296
}
297297
return sum
298298
}

test/blockstore-test.js

+3
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,11 @@ module.exports = (repo) => {
8585
close () {
8686

8787
}
88+
8889
has () {
8990
return true
9091
}
92+
9193
batch () {
9294
return {
9395
put () {
@@ -217,6 +219,7 @@ module.exports = (repo) => {
217219
close () {
218220

219221
}
222+
220223
get (c) {
221224
if (c.toString() === key.toString()) {
222225
throw err

test/blockstore-utils-test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ const Repo = require('../src')
1111
module.exports = () => {
1212
describe('blockstore utils', () => {
1313
it('converts a CID to a datastore Key and back', () => {
14-
const originalCid = new CID('Qme6KJdKcp85TYbLxuLV7oQzMiLremD7HMoXLZEmgo6Rnh')
14+
// CIDv1 in base32 with IPLD raw codec
15+
const originalCid = new CID('bafkreihkb3vrxxex5zvzkr3s3a6noe223r7jka4ofjy2nkzu27kueg76ii')
1516
const key = Repo.utils.blockstore.cidToKey(originalCid)
1617
expect(key instanceof Key).to.be.true()
1718
const cid = Repo.utils.blockstore.keyToCid(key)

0 commit comments

Comments
 (0)