diff --git a/ffi/rust/ant-ffi/src/client.rs b/ffi/rust/ant-ffi/src/client.rs index df4eb84..6a8de39 100644 --- a/ffi/rust/ant-ffi/src/client.rs +++ b/ffi/rust/ant-ffi/src/client.rs @@ -596,7 +596,10 @@ impl Client { // ===== File Operations ===== - /// Upload a file from disk (public). Returns the address. + /// Upload a file from disk (public). The serialized data map is stored as + /// part of the same upload payment batch — one payment covers the file's + /// chunks and the data-map chunk. Returns the shareable address plus + /// chunk/cost details. pub async fn file_upload_public( &self, path: String, @@ -606,13 +609,12 @@ impl Client { .map_err(|e| ClientError::InvalidInput { reason: e })?; let file_path = PathBuf::from(&path); - let result = self.inner.file_upload_with_mode(&file_path, mode).await?; - - let address = self.inner.data_map_store(&result.data_map).await?; + let result = self + .inner + .file_upload_public_with_mode(&file_path, mode) + .await?; - Ok(FilePutPublicResult { - address: hex::encode(address), - }) + Self::to_file_put_public_result(result) } /// Same as [`Self::file_upload_public`] but reports live progress to @@ -634,20 +636,14 @@ impl Client { let (sender, handle) = upload_progress_bridge(listener); let result = self .inner - .file_upload_with_progress(&file_path, mode, Some(sender)) + .file_upload_public_with_progress(&file_path, mode, Some(sender)) .await; // Drop of `sender` inside the call ends the bridge; await it to flush // any queued progress events before returning either way. let _ = handle.await; let result = result?; - // The data-map chunk is small and stored separately (no progress), - // matching `file_upload_public`. - let address = self.inner.data_map_store(&result.data_map).await?; - - Ok(FilePutPublicResult { - address: hex::encode(address), - }) + Self::to_file_put_public_result(result) } /// Upload a file from disk privately. Returns the serialized data map (hex) @@ -665,14 +661,7 @@ impl Client { let result = self.inner.file_upload_with_mode(&file_path, mode).await?; - let data_map_bytes = - rmp_serde::to_vec(&result.data_map).map_err(|e| ClientError::InternalError { - reason: format!("failed to serialize data map: {e}"), - })?; - - Ok(FilePutPrivateResult { - data_map: hex::encode(data_map_bytes), - }) + Self::to_file_put_private_result(result) } /// Same as [`Self::file_upload_private`] but reports live progress to @@ -696,14 +685,7 @@ impl Client { let _ = handle.await; let result = result?; - let data_map_bytes = - rmp_serde::to_vec(&result.data_map).map_err(|e| ClientError::InternalError { - reason: format!("failed to serialize data map: {e}"), - })?; - - Ok(FilePutPrivateResult { - data_map: hex::encode(data_map_bytes), - }) + Self::to_file_put_private_result(result) } /// Publish an existing private data map as a public network chunk, returning @@ -1215,6 +1197,43 @@ impl Client { .expect("session entry present while holding the lock")) } + /// Convert ant-core's [`FileUploadResult`] into the FFI + /// [`FilePutPublicResult`]. Public uploads always carry a data-map address. + fn to_file_put_public_result( + result: FileUploadResult, + ) -> Result { + let address = result + .data_map_address + .ok_or_else(|| ClientError::InternalError { + reason: "public upload returned no data-map address".into(), + })?; + Ok(FilePutPublicResult { + address: hex::encode(address), + chunks_stored: result.chunks_stored as u64, + storage_cost_atto: result.storage_cost_atto, + gas_cost_wei: result.gas_cost_wei.to_string(), + payment_mode_used: format_payment_mode(result.payment_mode_used), + }) + } + + /// Convert ant-core's [`FileUploadResult`] into the FFI + /// [`FilePutPrivateResult`] (serializes the data map for the caller). + fn to_file_put_private_result( + result: FileUploadResult, + ) -> Result { + let data_map_bytes = + rmp_serde::to_vec(&result.data_map).map_err(|e| ClientError::InternalError { + reason: format!("failed to serialize data map: {e}"), + })?; + Ok(FilePutPrivateResult { + data_map: hex::encode(data_map_bytes), + chunks_stored: result.chunks_stored as u64, + storage_cost_atto: result.storage_cost_atto, + gas_cost_wei: result.gas_cost_wei.to_string(), + payment_mode_used: format_payment_mode(result.payment_mode_used), + }) + } + /// Convert ant-core's [`FileUploadResult`] into the FFI [`ExternalUploadResult`]. fn to_external_result(result: FileUploadResult) -> Result { let data_map_bytes = diff --git a/ffi/rust/ant-ffi/src/lib.rs b/ffi/rust/ant-ffi/src/lib.rs index 8e3a0fd..d8116bf 100644 --- a/ffi/rust/ant-ffi/src/lib.rs +++ b/ffi/rust/ant-ffi/src/lib.rs @@ -45,6 +45,14 @@ pub struct DataPutPrivateResult { pub struct FilePutPublicResult { /// Hex-encoded address of the stored data map. pub address: String, + /// Number of chunks stored on the network. + pub chunks_stored: u64, + /// Total storage cost paid, in atto-tokens (base-10). "0" if all pre-existed. + pub storage_cost_atto: String, + /// Total gas cost in wei (base-10). + pub gas_cost_wei: String, + /// Payment mode that was used: "auto", "merkle", or "single". + pub payment_mode_used: String, } /// Result of uploading a file (private). The data map is returned to the @@ -54,6 +62,14 @@ pub struct FilePutPublicResult { pub struct FilePutPrivateResult { /// Hex-encoded serialized data map (caller keeps this secret). pub data_map: String, + /// Number of chunks stored on the network. + pub chunks_stored: u64, + /// Total storage cost paid, in atto-tokens (base-10). "0" if all pre-existed. + pub storage_cost_atto: String, + /// Total gas cost in wei (base-10). + pub gas_cost_wei: String, + /// Payment mode that was used: "auto", "merkle", or "single". + pub payment_mode_used: String, } /// Estimated cost of uploading a file, produced *before* any payment by