From 12153743a4f3fd8e616e60e7f20682ee00b628ce Mon Sep 17 00:00:00 2001 From: roee Date: Mon, 28 Jul 2025 10:29:41 +0300 Subject: [PATCH] feat: FileStorage --- packages/utils/src/components.cairo | 1 + .../utils/src/components/filestorage.cairo | 6 ++ .../components/filestorage/filestorage.cairo | 71 ++++++++++++++++++ .../components/filestorage/interface.cairo | 74 +++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 packages/utils/src/components/filestorage.cairo create mode 100644 packages/utils/src/components/filestorage/filestorage.cairo create mode 100644 packages/utils/src/components/filestorage/interface.cairo diff --git a/packages/utils/src/components.cairo b/packages/utils/src/components.cairo index 6581ec9..272ed5a 100644 --- a/packages/utils/src/components.cairo +++ b/packages/utils/src/components.cairo @@ -1,5 +1,6 @@ pub mod blocklist; pub mod deposit; +pub mod filestorage; pub mod nonce; pub mod pausable; pub mod replaceability; diff --git a/packages/utils/src/components/filestorage.cairo b/packages/utils/src/components/filestorage.cairo new file mode 100644 index 0000000..626b614 --- /dev/null +++ b/packages/utils/src/components/filestorage.cairo @@ -0,0 +1,6 @@ +pub(crate) mod filestorage; +// pub(crate) mod errors; +// pub mod events; +pub mod interface; + +pub use filestorage::FileStorage; diff --git a/packages/utils/src/components/filestorage/filestorage.cairo b/packages/utils/src/components/filestorage/filestorage.cairo new file mode 100644 index 0000000..a1ffc87 --- /dev/null +++ b/packages/utils/src/components/filestorage/filestorage.cairo @@ -0,0 +1,71 @@ +#[starknet::component] +pub(crate) mod FileStorage { + use starknet::storage::{ + Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, + StoragePointerWriteAccess, + }; + use starkware_utils::components::filestorage::interface::{ + FileMetadata, IFileStorage, OneKilobyte, + }; + + #[storage] + pub struct Storage { + pub metadata: Map, + pub storage: Map<(felt252, u64), felt252>, + } + + #[event] + #[derive(Drop, PartialEq, starknet::Event)] + pub enum Event {} + + + #[embeddable_as(DepositImpl)] + impl FileStorage< + TContractState, +HasComponent, +Drop, + > of IFileStorage> { + /// Create a new file with given metadata. Only callable once per file_id. + fn create_file( + ref self: ComponentState, file_id: felt252, metadata: FileMetadata, + ) {} + + /// Write a 1KB chunk at the given offset (in KB) to the specified file. + /// + /// This function overwrites existing data at the given offset. + /// If the offset is greater than or equal to the current file size, + /// the function will revert with an error. + /// + /// To add data beyond the end of the file, use append functions instead. + fn write_chunk( + ref self: ComponentState, + file_id: felt252, + offset_kb: u32, + chunk: OneKilobyte, + ) {} + + /// Appends a 1KB chunk to the end of the file. + fn append_1kb( + ref self: ComponentState, file_id: felt252, chunk: OneKilobyte, + ) {} + + // /// Appends 4 consecutive 1KB chunks to the end of the file. + // fn append_4kb(ref self: TContractState, file_id: felt252, chunks: [OneKilobyte; 4]); + + // /// Appends 16 consecutive 1KB chunks to the end of the file. + // fn append_16kb(ref self: TContractState, file_id: felt252, chunks: [OneKilobyte; 16]); + + /// Read a 1KB chunk from a specific offset(in KB). + fn read_chunk( + self: @ComponentState, file_id: felt252, offset_kb: u32, + ) -> OneKilobyte { + OneKilobyte { data: [0; 33] } // Placeholder implementation + } + + /// Get metadata about the file (owner, size, timestamps, etc.) + fn get_metadata(self: @ComponentState, file_id: felt252) -> FileMetadata { + self.get_metadata(file_id) + } + + /// Delete a file. Only callable by the owner. Does not erase chunks, only marks metadata. + fn delete_file(ref self: ComponentState, file_id: felt252) {} + } +} diff --git a/packages/utils/src/components/filestorage/interface.cairo b/packages/utils/src/components/filestorage/interface.cairo new file mode 100644 index 0000000..ab9f724 --- /dev/null +++ b/packages/utils/src/components/filestorage/interface.cairo @@ -0,0 +1,74 @@ +use starknet::ContractAddress; +#[starknet::interface] +pub trait IFileStorage { + /// Create a new file with given metadata. Only callable once per file_id. + fn create_file(ref self: TContractState, file_id: felt252, metadata: FileMetadata); + + /// Write a 1KB chunk at the given offset (in KB) to the specified file. + /// + /// This function overwrites existing data at the given offset. + /// If the offset is greater than or equal to the current file size, + /// the function will revert with an error. + /// + /// To add data beyond the end of the file, use append functions instead. + fn write_chunk(ref self: TContractState, file_id: felt252, offset_kb: u32, chunk: OneKilobyte); + + /// Appends a 1KB chunk to the end of the file. + fn append_1kb(ref self: TContractState, file_id: felt252, chunk: OneKilobyte); + + // /// Appends 4 consecutive 1KB chunks to the end of the file. + // fn append_4kb(ref self: TContractState, file_id: felt252, chunks: [OneKilobyte; 4]); + + // /// Appends 16 consecutive 1KB chunks to the end of the file. + // fn append_16kb(ref self: TContractState, file_id: felt252, chunks: [OneKilobyte; 16]); + + /// Read a 1KB chunk from a specific offset(in KB). + fn read_chunk(self: @TContractState, file_id: felt252, offset_kb: u32) -> OneKilobyte; + + /// Get metadata about the file (owner, size, timestamps, etc.) + fn get_metadata(self: @TContractState, file_id: felt252) -> FileMetadata; + + /// Delete a file. Only callable by the owner. Does not erase chunks, only marks metadata. + fn delete_file(ref self: TContractState, file_id: felt252); +} + +#[derive(Drop, Copy, Serde)] +pub struct OneKilobyte { + pub data: [felt252; 33] // 1KB chunk represented as an array of felt252 +} + +impl DefaultOneKilobyte of Default { + fn default() -> OneKilobyte { + OneKilobyte { data: [0; 33] } + } +} + +impl SerdeOneKilobyte of Serde<[felt252; 33]> { + fn serialize(self: @[felt252; 33], ref output: Array) { + for element in self.span() { + output.append(*element); + } + } + + fn deserialize(ref serialized: Span) -> Option<[felt252; 33]> { + /// todo : impl. + if serialized.len() != 33 { + return Option::None; + } + let data = serialized.multi_pop_front::<33>().unwrap().unbox(); + Option::Some(data) + } +} + + +#[derive(Debug, PartialEq, Drop, Serde, Copy, starknet::Store)] +pub struct FileMetadata { + /// File size in kilobytes (number of 1KB chunks) + pub size_in_kb: u32, + /// Block number when the file was created + pub created_at_block: u64, + /// Block number of the last modification + pub modified_at_block: u64, + /// Address that last modified the file + pub last_modifier: ContractAddress, +}