Skip to content
Open
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
1 change: 1 addition & 0 deletions packages/utils/src/components.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod blocklist;
pub mod deposit;
pub mod filestorage;
pub mod nonce;
pub mod pausable;
pub mod replaceability;
Expand Down
6 changes: 6 additions & 0 deletions packages/utils/src/components/filestorage.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pub(crate) mod filestorage;
// pub(crate) mod errors;
// pub mod events;
pub mod interface;

pub use filestorage::FileStorage;
71 changes: 71 additions & 0 deletions packages/utils/src/components/filestorage/filestorage.cairo
Original file line number Diff line number Diff line change
@@ -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<felt252, FileMetadata>,
pub storage: Map<(felt252, u64), felt252>,
}

#[event]
#[derive(Drop, PartialEq, starknet::Event)]
pub enum Event {}


#[embeddable_as(DepositImpl)]
Copy link

Choose a reason for hiding this comment

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

Bug: Incorrect Embeddable Attribute for FileStorage

The #[embeddable_as] attribute for the FileStorage component is incorrectly set to DepositImpl instead of FileStorageImpl (or similar), likely due to a copy-paste error from another component.

Locations (1)

Fix in Cursor Fix in Web

impl FileStorage<
TContractState, +HasComponent<TContractState>, +Drop<TContractState>,
> of IFileStorage<ComponentState<TContractState>> {
/// Create a new file with given metadata. Only callable once per file_id.
fn create_file(
ref self: ComponentState<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: ComponentState<TContractState>,
file_id: felt252,
offset_kb: u32,
chunk: OneKilobyte,
) {}

/// Appends a 1KB chunk to the end of the file.
fn append_1kb(
ref self: ComponentState<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: @ComponentState<TContractState>, 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<TContractState>, file_id: felt252) -> FileMetadata {
self.get_metadata(file_id)
}
Copy link

Choose a reason for hiding this comment

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

Bug: Infinite Recursion in Metadata Retrieval

The get_metadata function recursively calls itself (self.get_metadata(file_id)) instead of reading from the storage map. This leads to infinite recursion and a stack overflow. It should instead read from the metadata storage map using self.metadata.read(file_id).

Locations (1)

Fix in Cursor Fix in Web


/// Delete a file. Only callable by the owner. Does not erase chunks, only marks metadata.
fn delete_file(ref self: ComponentState<TContractState>, file_id: felt252) {}
}
}
74 changes: 74 additions & 0 deletions packages/utils/src/components/filestorage/interface.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use starknet::ContractAddress;
#[starknet::interface]
pub trait IFileStorage<TContractState> {
/// 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<OneKilobyte> {
fn default() -> OneKilobyte {
OneKilobyte { data: [0; 33] }
}
}

impl SerdeOneKilobyte of Serde<[felt252; 33]> {
fn serialize(self: @[felt252; 33], ref output: Array<felt252>) {
for element in self.span() {
output.append(*element);
}
}

fn deserialize(ref serialized: Span<felt252>) -> 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,
}