Skip to content

Commit 0f5ff2c

Browse files
authored
refactored cid dag metadata in examples (#151)
1 parent aa69187 commit 0f5ff2c

File tree

7 files changed

+110
-106
lines changed

7 files changed

+110
-106
lines changed

examples/api.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { cidFromBytes } from "./common.js";
1+
import { cidFromBytes } from "./cid_dag_metadata.js";
22
import { Binary } from '@polkadot-api/substrate-bindings';
33

44
export async function authorizeAccount(typedApi, sudoSigner, who, transactions, bytes) {

examples/authorize_and_store.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { ApiPromise, WsProvider } from '@polkadot/api';
22
import { Keyring } from '@polkadot/keyring';
33
import { cryptoWaitReady } from '@polkadot/util-crypto';
44
import { create } from 'ipfs-http-client';
5-
import { waitForNewBlock, cidFromBytes } from './common.js';
5+
import { waitForNewBlock } from './common.js';
6+
import { cidFromBytes } from "./cid_dag_metadata.js";
67

78
async function authorizeAccount(api, pair, who, transactions, bytes) {
89
const tx = api.tx.transactionStorage.authorizeAccount(who, transactions, bytes);

examples/authorize_and_store_papi.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { createClient } from 'polkadot-api';
33
import { getWsProvider } from 'polkadot-api/ws-provider';
44
import { cryptoWaitReady } from '@polkadot/util-crypto';
55
import { authorizeAccount, fetchCid, store} from './api.js';
6-
import { setupKeyringAndSigners, cidFromBytes } from './common.js';
6+
import { setupKeyringAndSigners } from './common.js';
7+
import { cidFromBytes } from "./cid_dag_metadata.js";
78
import { bulletin } from './.papi/descriptors/dist/index.mjs';
89

910
const NODE_WS = 'ws://localhost:10000';

examples/authorize_and_store_papi_smoldot.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { createClient } from 'polkadot-api';
55
import { getSmProvider } from 'polkadot-api/sm-provider';
66
import { cryptoWaitReady } from '@polkadot/util-crypto';
77
import { authorizeAccount, fetchCid, store } from './api.js';
8-
import { setupKeyringAndSigners, cidFromBytes } from './common.js';
8+
import { setupKeyringAndSigners } from './common.js';
9+
import { cidFromBytes } from "./cid_dag_metadata.js";
910
import { bulletin } from './.papi/descriptors/dist/index.mjs';
1011

1112
// Constants

examples/cid_dag_metadata.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { blake2AsU8a } from '@polkadot/util-crypto';
2+
import * as multihash from 'multiformats/hashes/digest';
3+
import { CID } from 'multiformats/cid';
4+
import * as dagPB from '@ipld/dag-pb';
5+
import { UnixFS } from 'ipfs-unixfs';
6+
7+
/**
8+
* Build a UnixFS DAG-PB file node from raw chunks.
9+
*
10+
* (By default with SHA2 multihash)
11+
*/
12+
export async function buildUnixFSDagPB(chunks, mhCode = 0x12) {
13+
if (!chunks?.length) {
14+
throw new Error('❌ buildUnixFSDag: chunks[] is empty')
15+
}
16+
17+
// UnixFS blockSizes = sizes of child blocks
18+
const blockSizes = chunks.map(c => c.len)
19+
20+
console.log(`🧩 Building UnixFS DAG from chunks:
21+
• totalChunks: ${chunks.length}
22+
• blockSizes: ${blockSizes.join(', ')}`)
23+
24+
// Build UnixFS file metadata (no inline data here)
25+
const fileData = new UnixFS({
26+
type: 'file',
27+
blockSizes
28+
})
29+
30+
// DAG-PB node: our file with chunk links
31+
const dagNode = dagPB.prepare({
32+
Data: fileData.marshal(),
33+
Links: chunks.map(c => ({
34+
Name: '',
35+
Tsize: c.len,
36+
Hash: c.cid
37+
}))
38+
})
39+
40+
// Encode DAG-PB
41+
const dagBytes = dagPB.encode(dagNode)
42+
43+
// Hash DAG to produce CIDv1
44+
const rootCid = await cidFromBytes(dagBytes, dagPB.code, mhCode)
45+
46+
console.log(`✅ DAG root CID: ${rootCid.toString()}`)
47+
48+
return { rootCid, dagBytes }
49+
}
50+
51+
/**
52+
* Create CID for data.
53+
* Default to `0x55 (raw)` with blake2b_256 hash.
54+
*
55+
* 0xb220:
56+
* - 0xb2 = the multihash algorithm family for BLAKE2b
57+
* - 0x20 = the digest length in bytes (32 bytes = 256 bits)
58+
*
59+
* See: https://github.com/multiformats/multicodec/blob/master/table.csv
60+
*/
61+
export async function cidFromBytes(bytes, cidCodec = 0x55, mhCode = 0xb220) {
62+
console.log(`[CID]: Using cidCodec: ${cidCodec} and mhCode: ${mhCode}`);
63+
let mh;
64+
switch (mhCode) {
65+
case 0xb220: // blake2b-256
66+
mh = multihash.create(mhCode, blake2AsU8a(bytes));
67+
break;
68+
69+
default:
70+
throw new Error("Unhandled multihash code: " + mhCode)
71+
}
72+
return CID.createV1(cidCodec, mh)
73+
}
74+
75+
export function convertCid(cid, cidCodec) {
76+
const mh = cid.multihash;
77+
return CID.createV1(cidCodec, mh);
78+
}

examples/common.js

Lines changed: 23 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
import { blake2AsU8a } from '@polkadot/util-crypto'
2-
import * as multihash from 'multiformats/hashes/digest'
3-
import { CID } from 'multiformats/cid'
41
import { Keyring } from '@polkadot/keyring';
52
import { getPolkadotSigner } from '@polkadot-api/signer';
6-
import * as dagPB from '@ipld/dag-pb'
7-
import { UnixFS } from 'ipfs-unixfs'
83
import { createCanvas } from "canvas";
94
import fs from "fs";
105
import assert from "assert";
@@ -15,35 +10,6 @@ export async function waitForNewBlock() {
1510
return new Promise(resolve => setTimeout(resolve, 7000))
1611
}
1712

18-
/**
19-
* Create CID for data.
20-
* Default to `0x55 (raw)` with blake2b_256 hash.
21-
*
22-
* 0xb220:
23-
* - 0xb2 = the multihash algorithm family for BLAKE2b
24-
* - 0x20 = the digest length in bytes (32 bytes = 256 bits)
25-
*
26-
* See: https://github.com/multiformats/multicodec/blob/master/table.csv
27-
*/
28-
export async function cidFromBytes(bytes, cidCodec = 0x55, mhCode = 0xb220) {
29-
console.log(`[CID]: Using cidCodec: ${cidCodec} and mhCode: ${mhCode}`);
30-
let mh;
31-
switch (mhCode) {
32-
case 0xb220: // blake2b-256
33-
mh = multihash.create(mhCode, blake2AsU8a(bytes));
34-
break;
35-
36-
default:
37-
throw new Error("Unhandled multihash code: " + mhCode)
38-
}
39-
return CID.createV1(cidCodec, mh)
40-
}
41-
42-
export function convertCid(cid, cidCodec) {
43-
const mh = cid.multihash;
44-
return CID.createV1(cidCodec, mh);
45-
}
46-
4713
/**
4814
* Creates a PAPI-compatible signer from a Keyring account
4915
*/
@@ -70,50 +36,6 @@ export function setupKeyringAndSigners(sudoSeed, accountSeed) {
7036
};
7137
}
7238

73-
/**
74-
* Build a UnixFS DAG-PB file node from raw chunks.
75-
*
76-
* (By default with SHA2 multihash)
77-
*/
78-
export async function buildUnixFSDagPB(chunks, mhCode = 0x12) {
79-
if (!chunks?.length) {
80-
throw new Error('❌ buildUnixFSDag: chunks[] is empty')
81-
}
82-
83-
// UnixFS blockSizes = sizes of child blocks
84-
const blockSizes = chunks.map(c => c.len)
85-
86-
console.log(`🧩 Building UnixFS DAG from chunks:
87-
• totalChunks: ${chunks.length}
88-
• blockSizes: ${blockSizes.join(', ')}`)
89-
90-
// Build UnixFS file metadata (no inline data here)
91-
const fileData = new UnixFS({
92-
type: 'file',
93-
blockSizes
94-
})
95-
96-
// DAG-PB node: our file with chunk links
97-
const dagNode = dagPB.prepare({
98-
Data: fileData.marshal(),
99-
Links: chunks.map(c => ({
100-
Name: '',
101-
Tsize: c.len,
102-
Hash: c.cid
103-
}))
104-
})
105-
106-
// Encode DAG-PB
107-
const dagBytes = dagPB.encode(dagNode)
108-
109-
// Hash DAG to produce CIDv1
110-
const rootCid = await cidFromBytes(dagBytes, dagPB.code, mhCode)
111-
112-
console.log(`✅ DAG root CID: ${rootCid.toString()}`)
113-
114-
return { rootCid, dagBytes }
115-
}
116-
11739
/**
11840
* Generates (dynamic) images based on the input text.
11941
*/
@@ -173,3 +95,26 @@ export function filesAreEqual(path1, path2) {
17395
assert.deepStrictEqual(data1[i], data2[i])
17496
}
17597
}
98+
99+
export async function fileToDisk(outputPath, fullBuffer) {
100+
await new Promise((resolve, reject) => {
101+
const ws = fs.createWriteStream(outputPath);
102+
ws.write(fullBuffer);
103+
ws.end();
104+
ws.on('finish', resolve);
105+
ws.on('error', reject);
106+
});
107+
console.log(`💾 File saved to: ${outputPath}`);
108+
}
109+
110+
export class NonceManager {
111+
constructor(initialNonce) {
112+
this.nonce = initialNonce; // BN instance from api.query.system.account
113+
}
114+
115+
getAndIncrement() {
116+
const current = this.nonce;
117+
this.nonce = this.nonce.addn(1); // increment BN
118+
return current;
119+
}
120+
}

examples/store_chunked_data.js

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { create } from 'ipfs-http-client'
77
import * as dagPB from '@ipld/dag-pb'
88
import { TextDecoder } from 'util'
99
import assert from "assert";
10-
import { waitForNewBlock, cidFromBytes, buildUnixFSDagPB, convertCid, generateTextImage, filesAreEqual } from './common.js'
10+
import { waitForNewBlock, generateTextImage, filesAreEqual, fileToDisk, NonceManager } from './common.js'
1111
import { fetchCid } from "./api.js";
12+
import { buildUnixFSDagPB, cidFromBytes, convertCid } from "./cid_dag_metadata.js";
1213

1314
// ---- CONFIG ----
1415
const WS_ENDPOINT = 'ws://127.0.0.1:10000' // Bulletin node
@@ -72,17 +73,6 @@ async function retrieveMetadata(ipfs, metadataCid) {
7273
return metadataJson;
7374
}
7475

75-
async function fileToDisk(outputPath, fullBuffer) {
76-
await new Promise((resolve, reject) => {
77-
const ws = fs.createWriteStream(outputPath);
78-
ws.write(fullBuffer);
79-
ws.end();
80-
ws.on('finish', resolve);
81-
ws.on('error', reject);
82-
});
83-
console.log(`💾 File saved to: ${outputPath}`);
84-
}
85-
8676
/**
8777
* Fetches all chunks listed in metdataJson, concatenates into a single file,
8878
* and saves to disk (or returns as Buffer).
@@ -210,18 +200,6 @@ async function storeProof(api, sudoPair, pair, rootCID, dagFileBytes, nonceMgr,
210200
return { rawDagCid }
211201
}
212202

213-
class NonceManager {
214-
constructor(initialNonce) {
215-
this.nonce = initialNonce; // BN instance from api.query.system.account
216-
}
217-
218-
getAndIncrement() {
219-
const current = this.nonce;
220-
this.nonce = this.nonce.addn(1); // increment BN
221-
return current;
222-
}
223-
}
224-
225203
async function authorizeStorage(api, sudoPair, pair, nonceMgr) {
226204
// Ensure enough quota.
227205
const auth = await api.query.transactionStorage.authorizations({ "Account": pair.address});

0 commit comments

Comments
 (0)