Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion py_hamt/store_httpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,19 @@ def __init__(
self.gateway_base_urls = [_normalize_gateway_base_url(gateway_base_url)]

pin_string: str = "true" if pin_on_add else "false"
self.rpc_url: str = f"{rpc_base_url}/api/v0/add?hash={self.hasher}&chunker={self.chunker}&pin={pin_string}"
# cid-version=1 is required, not cosmetic. Kubo returns a CIDv0 for any
# add that does not ask for v1, and a CIDv0 is dag-pb by definition --
# so with sha2-256 (a CIDv0-representable hasher) the daemon would wrap
# the payload in a UnixFS dag-pb node and hand back Qm... regardless of
# the codec this store asked for. That breaks two things:
# * save() cannot relabel the CID's codec, because the stored block is
# the protobuf wrapper rather than the bytes passed in, so the digest
# would no longer match the block.
# * _cid_is_verifiable() declines to check dag-pb responses, so
# verify_content would silently pass every block through unverified.
# Requesting v1 makes Kubo store the raw bytes under the codec asked
# for, which is what blake3 (not CIDv0-representable) already got.
self.rpc_url: str = f"{rpc_base_url}/api/v0/add?hash={self.hasher}&chunker={self.chunker}&pin={pin_string}&cid-version=1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM
cid-version=1 only makes leaf chunks raw. Once data exceeds the configured chunk size (1 MiB by default), Kubo returns a UnixFS dag-pb root (layout documentation); save() then declines to apply the requested codec and verify_content still skips verification. Handle/reject multi-chunk inputs or use an endpoint that stores the payload as one block, and add a payload-larger-than-chunker regression test.

"""@private"""
self.gateway_base_url: str = self.gateway_base_urls[0]
"""@private"""
Expand Down Expand Up @@ -1085,6 +1097,23 @@ async def save(self, data: bytes, codec: ContentAddressedStore.CodecInput) -> CI
cid: CID = CID.decode(cid_str)
if cid.codec.code != self.DAG_PB_MARKER:
cid = cid.set(codec=codec)
elif self.verify_content:
# Kubo splits payloads larger than ``chunker`` into a UnixFS
# dag-pb tree, so the root block is the protobuf node rather
# than the bytes handed in. The requested codec cannot be
# applied (the digest would stop matching the block), and
# _cid_is_verifiable() skips dag-pb, so verify_content
# silently does nothing for this object. Warn rather than
# fail: the data still round-trips correctly, and the
# threshold depends on the caller's chunker setting.
warnings.warn(
f"Saved {len(data)} bytes exceeded the '{self.chunker}' "
f"chunker, so Kubo returned a dag-pb CID ({cid}). "
"Content verification is not possible for this object; "
"raise the chunker size to keep payloads in one block.",
RuntimeWarning,
stacklevel=2,
)
return cid

except httpx.RequestError:
Expand Down
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ def pytest_addoption(parser):
default=False,
help="run tests that require a Kubo daemon",
)
parser.addoption(
"--benchmark-report",
action="store_true",
default=False,
help="print timing and request-count tables from the benchmark suite "
"(combine with -s); benchmarks assert on request counts either way",
)


def pytest_configure(config):
Expand Down
Loading
Loading