eip: 5018
title: Directory Standard
description: A standard interface for filesystem directories.
author: Qi Zhou (@qizhou)
discussions-to: TBD
status: Draft
type: Standards Track
category: ERC
created: 2022-04-18
Abstract
The following standard allows for the implementation of a standard API for filesystem directories within smart contracts.
This standard provides basic functionality to read/write binary objects for any size, as well as allow reading/writing chunks of the object if the object is too large to fit in a single transaction.
Thanks for the comment. I agree that the current interface is quite similar to a key-value store. The reason is that we want a filesystem-like smart contract with minimal necessary interfaces that can host a decentralized website:
chunked-based functions are needed because we want to support reading a large BLOB, which cannot be fit in a single tx;
ls (list directory contents) may not be needed in the minimal version as most websites do not offer it to users;
sub-directory can be achieved by allowing β/β's in the filename, e.g., β/a/b/c/dβ, so we may not need an explicit interface of sub-directory.
Note that, a key-value store may not have 1. Moreover, if the applications do need 2 or 3, we can create the extension EIPs to include the features (similar to the extensions to ERC-20/ERC-721).
Thanks for the comment. Current EVM supports two types of storage.
local contract storage via SLOAD/SSTORE; and
contract-code-based via CREATE/CREATE2/EXTCODECOPY.
The first storage is efficient for 32-bytes operations, but if the data is large with dynamic size, using contract-code-based storage can be more efficient in both gas and IO. The following is a table of the gas for different storage (note that the gas for put only accounts for the the-first-time put):
For local contract storage, we use keccak256(filename || chunkId) as the key, and the value is an optimized version of solidity bytes storage
For contract-code-based storage, we use keccak256(filename || chunkId) as the key, and the value is a contract, whose code contains the corresponding chunk data.
Furthermore, the code is deployed to Rinkeby to store ENS and Uniswap homepages, and works very well:
A good design question! To support large BLOB, we can definitely do bytes ranges as UNIX read/write do. However, this seems to be complicated in some cases such as read-modify-write - if a write overrides multiple physical storages (e.g., storage slots or contract code), the contract needs to read existing data/override the data/rewrite the data. Using chunk ids, we can simplify the logic and let the off-chain application determine how to use them (and do read-modify-write off-chain). What do you think?