Skip to content

Commit 837fe76

Browse files
authored
feat(pdp): add find_piece_ids_by_cid for efficient CID→ID lookup (#26)
Mirrors FilOzone/synapse-sdk#718. Adds a direct on-chain findPieceIdsByCid call on SyncPDPVerifier and AsyncPDPVerifier so callers can resolve a PieceCID to piece IDs in O(1) rather than scanning getActivePieces (which pages and fails on large datasets).
1 parent b8ae276 commit 837fe76

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

src/pynapse/pdp/verifier.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
from __future__ import annotations
22

3+
from typing import List
4+
35
from web3 import AsyncWeb3, Web3
46

57
from pynapse.contracts import PDP_VERIFIER_ABI
68
from pynapse.core.chains import Chain
9+
from pynapse.core.typed_data import _piece_cid_bytes
710

811

912
class SyncPDPVerifier:
@@ -21,6 +24,24 @@ def get_active_piece_count(self, data_set_id: int) -> int:
2124
def get_active_pieces(self, data_set_id: int, offset: int, limit: int):
2225
return self._contract.functions.getActivePieces(data_set_id, offset, limit).call()
2326

27+
def find_piece_ids_by_cid(
28+
self,
29+
data_set_id: int,
30+
piece_cid: str,
31+
start_piece_id: int = 0,
32+
limit: int = 1,
33+
) -> List[int]:
34+
"""Direct on-chain CID→piece-id lookup.
35+
36+
Mirrors the upstream ``findPieceIdsByCid`` helper — replaces an
37+
O(n) scan through ``getActivePieces``.
38+
"""
39+
cid_tuple = (_piece_cid_bytes(piece_cid),)
40+
ids = self._contract.functions.findPieceIdsByCid(
41+
data_set_id, cid_tuple, start_piece_id, limit
42+
).call()
43+
return [int(pid) for pid in ids]
44+
2445
def get_data_set_leaf_count(self, data_set_id: int) -> int:
2546
return int(self._contract.functions.getDataSetLeafCount(data_set_id).call())
2647

@@ -59,6 +80,24 @@ async def get_active_piece_count(self, data_set_id: int) -> int:
5980
async def get_active_pieces(self, data_set_id: int, offset: int, limit: int):
6081
return await self._contract.functions.getActivePieces(data_set_id, offset, limit).call()
6182

83+
async def find_piece_ids_by_cid(
84+
self,
85+
data_set_id: int,
86+
piece_cid: str,
87+
start_piece_id: int = 0,
88+
limit: int = 1,
89+
) -> List[int]:
90+
"""Direct on-chain CID→piece-id lookup.
91+
92+
Mirrors the upstream ``findPieceIdsByCid`` helper — replaces an
93+
O(n) scan through ``getActivePieces``.
94+
"""
95+
cid_tuple = (_piece_cid_bytes(piece_cid),)
96+
ids = await self._contract.functions.findPieceIdsByCid(
97+
data_set_id, cid_tuple, start_piece_id, limit
98+
).call()
99+
return [int(pid) for pid in ids]
100+
62101
async def get_data_set_leaf_count(self, data_set_id: int) -> int:
63102
return int(await self._contract.functions.getDataSetLeafCount(data_set_id).call())
64103

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""Tests for PDPVerifier.find_piece_ids_by_cid (#718)."""
2+
3+
from __future__ import annotations
4+
5+
from pynapse.core.typed_data import _piece_cid_bytes
6+
from pynapse.pdp.verifier import AsyncPDPVerifier, SyncPDPVerifier
7+
8+
9+
def test_find_piece_ids_by_cid_method_exists():
10+
assert hasattr(SyncPDPVerifier, "find_piece_ids_by_cid")
11+
assert hasattr(AsyncPDPVerifier, "find_piece_ids_by_cid")
12+
13+
14+
def test_piece_cid_bytes_roundtrip_known_v1():
15+
# Sample CommP PieceCIDv1 from upstream fixtures. The important property
16+
# is that the helper can decode it into the bytes payload expected by
17+
# the on-chain Cids.Cid tuple without throwing.
18+
piece_cid_v1 = "baga6ea4seaqlwzed5tgjxpcnlxz2ilhpgitfhuodvgfhc6e6kroivbxmsjpesbi"
19+
data = _piece_cid_bytes(piece_cid_v1)
20+
# CIDv1 with fil-commitment-unsealed codec and 32-byte SHA256: always
21+
# starts with 0x01 version, 0x81 0xe2 0x03 codec varint.
22+
assert data[0] == 0x01
23+
assert data[1:4] == b"\x81\xe2\x03"
24+
# 32-byte digest at the tail
25+
assert len(data) >= 32

0 commit comments

Comments
 (0)