--- eip: 5018 title: Filesystem-like Interface for Contracts description: An interface to provide access to binary objects similar to filesystems. author: Qi Zhou (@qizhou) discussions-to: https://ethereum-magicians.org/t/eip-5018-directory-standard/8958 status: Review type: Standards Track category: ERC created: 2022-04-18 --- ## Abstract The following standardizes an API for directories and files within smart contracts, similar to traditional filesystems. This standard provides basic functionality to read/write binary objects of any size, as well as allow reading/writing chunks of the object if the object is too large to fit in a single transaction. ## Motivation A standard interface allows any binary objects on EVM-based blockchain to be re-used by other dApps. With [EIP-4804](./eip-4804.md), we are able to locate a Web3 resource on blockchain using HTTP-style URIs. One application of Web3 resources are web contents that are referenced within a directory using relative paths such as HTML/SVG. This standard proposes a contract-based directory to simplify the mapping between local web contents and on-chain web contents. Further, with relative paths referenced in the web contents and EIP-4804, the users will have a consistent view of the web contents locally and on-chain. ## Specification ### Directory #### Methods ##### write Writes binary `data` to the file `name` in the directory by an account with write permission. ``` function write(bytes memory name, bytes memory data) external payable ``` ##### read Returns the binary `data` from the file `name` in the directory and existence of the file. ``` function read(bytes memory name) external view returns (bytes memory data, bool exist) ``` ##### fallback read Returns the binary `data` from the file `prefixedName` (prefixed with `/`) in the directory. ``` fallback(bytes calldata prefixedName) external returns (bytes memory data) ``` ##### size Returns the size of the `data` from the file `name` in the directory and the number of chunks of the data. ``` function size(bytes memory name) external view returns (uint256 size, uint256 chunks) ``` ##### remove Removes the file `name` in the directory and returns the number of chunks removed (0 means the file does not exist) by an account with write permission. ``` function remove(bytes memory name) external returns (uint256 numOfChunksRemoved) ``` ##### countChunks Returns the number of chunks of the file `name`. ``` function countChunks(bytes memory name) external view returns (uint256 numOfChunks); ``` ##### writeChunk Writes a chunk of data to the file by an account with write permission. The write will fail if `chunkId > numOfChunks`, i.e., the write must append the file or replace the existing chunk. ``` function writeChunk(bytes memory name, uint256 chunkId, bytes memory chunkData) external payable; ``` ##### readChunk Returns the chunk data of the file `name` and the existence of the chunk. ``` function readChunk(bytes memory name, uint256 chunkId) external view returns (bytes memory chunkData, bool exist); ``` ##### chunkSize Returns the size of a chunk of the file `name` and the existence of the chunk. ``` function chunkSize(bytes memory name, uint256 chunkId) external view returns (uint256 chunkSize, bool exist); ``` ##### removeChunk Removes a chunk of the file `name` and returns `false` if such chunk does not exist. The method should be called by an account with write permission. ``` function removeChunk(bytes memory name, uint256 chunkId) external returns (bool exist); ``` ##### truncate Removes the chunks of the file `name` in the directory from the given `chunkId` and returns the number of chunks removed by an account with write permission. When `chunkId = 0`, the method is essentially the same as `remove()`. ``` function truncate(bytes memory name, uint256 chunkId) external returns (uint256 numOfChunksRemoved); ``` ##### getChunkHash Returns the hash value of the chunk data. ``` function getChunkHash(bytes memory name, uint256 chunkId) external view returns (bytes32); ``` ## Rationale One issue of uploading the web contents to the blockchain is that the web contents may be too large to fit into a single transaction. As a result, the standard provides chunk-based operations so that uploading a content can be split into several transactions. Meanwhile, the read operation can be done in a single transaction, i.e., with a single Web3 URL defined in EIP-4804. ### Interactions Between Unchunked/Chunked Functions `read` method should return the concatenated chunked data written by `writeChunk` method. The following gives some examples of the interactions: - `read("hello.txt")` => "" (file is empty) - `writeChunk("hello.txt", 0, "abc")` will succeed - `read("hello.txt")` => "abc" - `writeChunk("hello.txt", 1, "efg")` will succeed - `read("hello.txt")` => "abcefg" - `writeChunk("hello.txt", 0, "aaa")` will succeed (replace chunk 0's data) - `read("hello.txt")` => "aaaefg" - `writeChunk("hello.txt", 3, "hij")` will fail because the operation is not replacement or append. With `writeChunk` method, we allow writing a file with external data that exceeds the current calldata limit (e.g., 1.8MB now), and it is able to read the whole file in a single `read` method (which is friendly for large web objects such as HTML/SVG/PNG/JPG, etc). For `write` method, calling a `write` method will replace all data chunks of the file with `write` method data, and one implementation can be: 1. `writeChunk(filename, chunkId=0, data_from_write)` to chunk 0 with the same `write` method data; and 2. `truncate(filename, chunkId=1)`, which will remove the rest chunks. ## Backwards Compatibility No backwards compatibility issues were identified. ## Security Considerations No security considerations were found. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).