feat(external-signer): add Visibility arg to file_prepare_upload#39
feat(external-signer): add Visibility arg to file_prepare_upload#39
Conversation
Threads a visibility flag through start_upload -> file_prepare_upload_with_visibility (ant-core PR #39), carries data_map_address out of finalize_upload and finalize_upload_merkle, persists it in upload_history.json, and re-enables the previously disabled "Public" button in the upload dialog. Public uploads now yield a single shareable on-network chunk address that appears in the uploads table with a "Public" badge; clicking copies it. The dialog re-quotes when the user toggles visibility because the payment batch differs (public adds one chunk for the DataMap itself). Requires bumping the ant-core git dep to a commit containing WithAutonomi/ant-client#39. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The quote, chunk PUT, and chunk GET paths now feed a shared helper that upserts peers on success via add_discovered_peer and records latency/success on both outcomes via update_peer_metrics. Cold-start clients can now load real, quality-scored peers from the persisted bootstrap cache instead of always restarting from the 7 bundled peers. Failures never insert, so unreachable peers don't consume cache quota. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Clean PR, well-scoped. The bundling-into-PaymentIntent approach is the right call given What I'd want before merging
P2 — polish
Nits
Core change is right. LGTM after (1), with (2) strongly recommended. |
Blockers: - Plumb explicit `success: bool` from each call site's `Ok` branch instead of inferring from error variants. Previously `Err::Protocol`, `::Payment`, `::Serialization`, `::InvalidData`, and remote PutResponse::Error all fired `add_discovered_peer` + wrote an RTT — the opposite of the stated "failures never insert" invariant. - Drop RTT on the PUT path. `chunk_put_with_proof` wraps a ~4 MB payload upload, so the wall-clock was dominated by the uploader's uplink rather than the peer's responsiveness. Quote-path and GET-path RTTs still feed quality scoring. - Add a cold-start-from-disk test that populates a BootstrapManager (via `add_peer_trusted` to skip the /24 rate limiter), saves, drops, reopens against the same cache_dir, and asserts peers reload. Closes the loop on the cold-start value prop. Polish: - Prefer globally-routable socket addresses when picking a peer's cache key. Previously a peer advertising `[10.0.0.5, 203.0.113.1]` would be keyed under the RFC1918 address and metrics recorded over the public address would land on a stale entry. - Fold the weak "after_download >= before_download" assertion into the main test (now performs PUT + GET + asserts cache grew). The /24 rate limiter saturates during the PUT, so a standalone download assertion carries no information. Nits: - Use `as u64` for elapsed millis (saturates only after ~584M years). - Move `record_peer_outcome` out of `client/mod.rs` into its own `client/peer_cache.rs` module. - Doc now notes that both upstream calls silently discard errors. Test comment on the 3-peer ceiling is rewritten to describe both Sybil mechanisms accurately: `BootstrapIpLimiter` (IP diversity, exempted for loopback) and `JoinRateLimiter` (temporal, NOT exempted) — the latter is what caps /24 inserts at 3/hour. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed in Blockers
P2
Nits
|
`203.0.113.0/24` (TEST-NET-3) and `2001:db8::/32` are documentation prefixes that `is_documentation()` / my v6 approximation correctly reject. The previous test asserted the opposite on those ranges, which passed locally on Windows but failed on Linux/macOS CI. Use `8.8.8.8` and `2606:4700:4700::1111` instead, and add an assertion that the TEST-NET-3 range IS rejected (that's the behaviour we actually want). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds an external-signer path for public uploads. When a PreparedUpload
is prepared with Visibility::Public, the serialized DataMap is bundled
into the payment batch (wave-batch or merkle) as an additional chunk.
FileUploadResult::data_map_address then carries the chunk address of
the stored DataMap, giving the uploader a single network address to
share for retrieval.
Motivation: ant-gui (the Autonomi desktop GUI) currently has to block
its Public upload option in the UI because no external-signer pathway
exists for publishing the data map — `data_map_store` internally calls
`pay_for_storage`, which hard-requires a wallet, and the chunk-storage
plumbing (`store_paid_chunks`, `chunk_put_to_close_group`,
`merkle_upload_chunks`) is pub(crate), so consumers on the
external-signer path cannot hand-roll it. Bundling the data map chunk
into the existing payment batch reuses the one-signature flow that
wave-batch and merkle already use for file chunks, which lets ant-gui
thread a `visibility` flag through its existing code path and re-enable
the Public option with no extra wallet round-trip.
- `Visibility::{Private, Public}` enum (default Private)
- `Client::file_prepare_upload_with_visibility(path, visibility)`;
the existing `file_prepare_upload(path)` now delegates with Private
for backward compatibility
- `PreparedUpload.data_map_address: Option<[u8; 32]>` carries the
address between prepare and finalize
- `FileUploadResult.data_map_address` is Some for public uploads
- Both `finalize_upload` and `finalize_upload_merkle` propagate the
field; no separate network call is needed because the data map chunk
is stored alongside the rest of the batch
- e2e test verifies Private leaves the address unset, Public records
it, and the recorded address matches the serialized data map
The internal-wallet path (`file_upload_with_mode`) is unchanged —
ant-cli continues to use `file_upload` followed by `data_map_store`
for its public upload flow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses review feedback: - **End-to-end round-trip test (wave-batch)**: a small file is prepared as `Visibility::Public`, signed via the testnet wallet, finalized, then retrieved using only `data_map_fetch(&data_map_address)` + `file_download`. Asserts the downloaded bytes match the original. This is the half of the contract the existing test didn't cover: not just that the address is recorded, but that it actually refers to a retrievable DataMap. - **`#[non_exhaustive]` on `FileUploadResult` and `PreparedUpload`**: adding `data_map_address` was already technically a breaking change for any downstream that struct-literal-constructed these; `#[non_exhaustive]` forecloses the same concern for the next field. - **`AlreadyStored` data-map-chunk visibility**: when the serialized `DataMap` hashes to a chunk that's already on the network (same file uploaded twice — plausible under deterministic self-encryption), the prepare step silently drops it from `prepared_chunks` while keeping `data_map_address = Some(addr)`. An `info!` now explicitly logs this, and the `data_map_address` doc comments clarify that `Some` means "retrievable", not "we paid to store it". Merkle-path round-trip was attempted but blocked on an upstream `WrongPoolCount` contract revert between `pay_for_merkle_tree` and the `PaymentVaultV2` contract — reproduces outside this PR's changes and is not caused by anything here. Removing the failing test; calling it out separately for follow-up so the pool-commitment / depth relationship can be investigated without holding up this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
414c38e to
586a129
Compare
Point ant-node at WithAutonomi/ant-node rc-2026.4.2 branch and refresh Cargo.lock. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…' into rc-2026.4.2 # Conflicts: # ant-core/src/data/client/quote.rs
Resolved conflicts in: - ant-core/Cargo.toml (kept both rmp-serde and saorsa-core dev-deps) - ant-core/src/data/client/file.rs (kept both Visibility enum and UploadCostEstimate struct) - ant-core/src/data/mod.rs (merged re-export list to include both Visibility and UploadCostEstimate) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Adds an external-signer pathway for public file uploads. Calling
Client::file_prepare_upload_with_visibility(path, Visibility::Public)bundles the serializedDataMapinto the existing payment batch (wave-batch or merkle) as one additional chunk. Afterfinalize_upload/finalize_upload_merkle,FileUploadResult.data_map_addresscarries the chunk address of the publishedDataMap— a single network address the uploader can share so anyone can retrieve the file.This unblocks public uploads in the Autonomi desktop GUI (ant-gui). The GUI currently has its Public upload option disabled in the UI (WithAutonomi/ant-ui#12, merged) because no external-signer pathway exists for publishing the data map. Once this lands and ant-gui bumps the git dep, a follow-up PR on that repo will thread the
visibilityflag through the Tauri commands and re-enable the Public button.Why bundling, not a separate call
Publishing the data map means storing one extra content-addressed chunk. The two obvious alternatives both hit dead ends on the external-signer path:
client.data_map_store(&data_map)afterfinalize_upload— what ant-cli does. Internally goes throughpay_for_storage, which hard-requiresself.require_wallet()?(ant-core/src/data/client/payment.rs:46). ant-gui's Rust client has no wallet — all payments go via WalletConnect / direct-wallet on the frontend.store_paid_chunks,chunk_put_to_close_group,merkle_upload_chunks) are allpub(crate), so external callers cannot reproduce the flow.Bundling the data map chunk into the existing
PaymentIntent(wave-batch) or merkle batch reuses the one-signature flow that already works for file chunks. The external signer pays for the data chunks and the data map chunk in a single on-chain transaction, andfinalize_upload[_merkle]stores them all in the same wave.Changes
Visibilityenum (Privatedefault,Public) indata::client::file, re-exported fromdata::.Client::file_prepare_upload_with_visibility(path, visibility). The existingfile_prepare_upload(path)delegates withVisibility::Private— signature and behaviour are preserved for existing callers.PreparedUpload.data_map_address: Option<[u8; 32]>carries the address between prepare and finalize.FileUploadResult.data_map_address: Option<[u8; 32]>isSome(addr)for public uploads. Pair it withdata_map_fetch(&addr)+file_download(&data_map, dest)to retrieve the file.finalize_uploadandfinalize_upload_merklepropagatedata_map_address; no extra network call needed, since the data map chunk is stored alongside the rest of the batch.file_upload_with_mode) is unchanged — ant-cli continues to usefile_upload+data_map_storefor its public flow.Test plan
cargo fmt -p ant-corecleancargo check --workspace --all-featurespassescargo clippy --tests -p ant-core --all-features -- -D warningscleantest_file_prepare_upload_visibilityinant-core/tests/e2e_file.rsverifies:data_map_addressunsetcompute_address(rmp_serde::to_vec(&data_map))🤖 Generated with Claude Code