Skip to main content

Overview

The @filoz/synapse-core/piece module provides utilities for working with Filecoin PieceCIDs - content-addressable identifiers for data pieces.
import * as Piece from '@filoz/synapse-core/piece'

PieceCID Format

A PieceCID is a CID (Content Identifier) with a specific structure:
  • Padding: Variable-length uvarint
  • Height: uint8 (merkle tree height)
  • Root Hash: 32-byte piece data merkle root
Contract DigestContracts expect only the last 32 bytes (the root hash), not the full CID.

Core Functions

calculate()

Calculate PieceCID from data.
import * as Piece from '@filoz/synapse-core/piece'

const data = new Uint8Array([1, 2, 3, 4])
const pieceCid = Piece.calculate(data)

console.log('PieceCID:', pieceCid.toString())
// baga6ea4seaq...

asPieceCID()

Validate and convert string to PieceCID.
import * as Piece from '@filoz/synapse-core/piece'

const cid = 'baga6ea4seaq...'
const pieceCid = Piece.asPieceCID(cid)

if (pieceCid) {
  console.log('Valid PieceCID')
} else {
  console.error('Invalid format')
}

createPieceCIDStream()

Calculate PieceCID from a stream.
import * as Piece from '@filoz/synapse-core/piece'

const fileStream = readableStream // ReadableStream<Uint8Array>

const { pieceCid, size } = await Piece.createPieceCIDStream(fileStream)

console.log('Stream PieceCID:', pieceCid.toString())
console.log('Stream size:', size)

URL Construction

createPieceUrlPDP()

Create a retrieval URL for a piece.
import * as Piece from '@filoz/synapse-core/piece'

const url = Piece.createPieceUrlPDP({
  cid: pieceCid.toString(),
  serviceURL: 'https://pdp.provider.com'
})

console.log('Retrieval URL:', url)
// https://pdp.provider.com/piece/baga6ea4seaq...

Download and Validation

downloadAndValidate()

Download a piece and validate its CID.
import * as Piece from '@filoz/synapse-core/piece'

const data = await Piece.downloadAndValidate({
  url: 'https://pdp.provider.com/piece/baga6ea4seaq...',
  expectedPieceCid: pieceCid
})

console.log('Downloaded and validated:', data.length, 'bytes')

URL Resolution

resolvePieceUrl()

Resolve a piece URL using multiple strategies.
import * as Piece from '@filoz/synapse-core/piece'

const url = await Piece.resolvePieceUrl({
  client,
  address: clientAddress,
  pieceCid,
  resolvers: [
    Piece.filbeamResolver,     // Try FilBeam CDN first
    Piece.chainResolver,       // Then check chain records
    Piece.providersResolver([  // Finally try known providers
      { id: 1n, pdp: { serviceURL: 'https://...' } }
    ])
  ]
})

console.log('Resolved URL:', url)

Digest Extraction

Extract the 32-byte root hash for contracts:
import * as Piece from '@filoz/synapse-core/piece'

const pieceCid = Piece.calculate(data)
const digest = pieceCid.bytes.slice(-32) // Last 32 bytes

// Use digest in contract calls

Complete Example

import * as Piece from '@filoz/synapse-core/piece'
import { createPublicClient, http } from 'viem'
import { calibration } from '@filoz/synapse-core/chains'

const client = createPublicClient({
  chain: calibration,
  transport: http()
})

// Calculate PieceCID
const data = new Uint8Array([1, 2, 3, 4])
const pieceCid = Piece.calculate(data)
console.log('PieceCID:', pieceCid.toString())

// Create retrieval URL
const url = Piece.createPieceUrlPDP({
  cid: pieceCid.toString(),
  serviceURL: 'https://pdp.provider.com'
})

// Download and validate
try {
  const retrieved = await Piece.downloadAndValidate({
    url,
    expectedPieceCid: pieceCid
  })
  console.log('Retrieved:', retrieved.length, 'bytes')
  
  // Verify data matches
  const match = retrieved.every((byte, i) => byte === data[i])
  console.log('Data matches:', match)
} catch (error) {
  console.error('Download failed:', error)
}

// Resolve URL from multiple sources
const resolvedUrl = await Piece.resolvePieceUrl({
  client,
  address: '0x...',
  pieceCid,
  resolvers: [
    Piece.filbeamResolver,
    Piece.chainResolver
  ]
})

console.log('Resolved from:', resolvedUrl)

Streaming Example

import * as Piece from '@filoz/synapse-core/piece'
import { createReadStream } from 'fs'

// Read file as stream
const fileStream = createReadStream('large-file.bin')
const webStream = Readable.toWeb(fileStream) // Convert to web stream

// Calculate CID from stream
const { pieceCid, size } = await Piece.createPieceCIDStream(webStream)

console.log('File PieceCID:', pieceCid.toString())
console.log('File size:', size, 'bytes')

Validation

import * as Piece from '@filoz/synapse-core/piece'

// Validate string format
const input = 'baga6ea4seaq...'
const pieceCid = Piece.asPieceCID(input)

if (!pieceCid) {
  throw new Error('Invalid PieceCID format')
}

// Validate downloaded data
const data = await fetch(url).then(r => r.arrayBuffer())
const calculated = Piece.calculate(new Uint8Array(data))

if (calculated.toString() !== expected.toString()) {
  throw new Error('PieceCID mismatch - data corrupted')
}

See Also

Build docs developers (and LLMs) love