链上存储
链上存储
本页内容正在整理中,欢迎贡献。
概述
以太坊链上存储(EVM Storage)成本极高,不适合存储大量数据。实际开发中,NFT 图片、元数据、用户文件等大型数据通常存储在去中心化存储网络(IPFS、Arweave、Filecoin)上,链上只存储对应的哈希或 CID。
主要内容
存储方案对比
| 方案 | 类型 | 持久性 | 成本 | 适合场景 |
|---|---|---|---|---|
| EVM Storage | 链上 | 永久 | 极高(约 $20K/MB) | 关键状态数据 |
| Calldata | 链上 | 永久(区块) | 高 | 小型不变数据 |
| Blob(EIP-4844) | 链上临时 | ~18 天 | 低 | Rollup 数据 |
| IPFS | 去中心化 | 依赖固定服务 | 低 | NFT 元数据、图片 |
| Arweave | 去中心化 | 永久(一次付费) | 中 | 永久存档 |
| Filecoin | 去中心化 | 合约期内 | 低 | 大文件长期存储 |
EVM 链上存储成本
// 存储成本估算// SSTORE(写入新槽):20,000 gas// 假设 Gas Price = 20 Gwei,ETH = $3,000// 每个 32 字节槽 ≈ 20,000 × 20 Gwei × $3,000 = $1.2
// 1 MB 数据 ≈ 32,768 个槽 ≈ $39,000(!)// 结论:链上不适合存储大文件链上存储最佳实践:
// ✅ 好的做法:只存储必要的状态mapping(address => uint256) public balances;mapping(uint256 => address) public tokenOwner;
// ❌ 坏的做法:在链上存储大型文件string public fullDocument; // 不要这样做!
// ✅ 正确做法:链上存哈希,文件放链下string public documentIPFSHash; // "ipfs://QmXxx..."IPFS(InterPlanetary File System)
特点:
- 内容寻址(CID = 内容的哈希),内容不可篡改
- 去中心化 P2P 网络
- 默认不持久化——需要”固定(Pin)“才能保证可访问
使用 NFT.Storage(免费,针对 NFT):
import { NFTStorage, File } from "nft.storage";
const client = new NFTStorage({ token: process.env.NFT_STORAGE_TOKEN! });
// 上传 NFT 元数据const metadata = await client.store({ name: "My NFT #1", description: "这是第一个 NFT", image: new File([imageBuffer], "image.png", { type: "image/png" }), attributes: [ { trait_type: "Background", value: "Blue" }, { trait_type: "Eyes", value: "Golden" }, ],});
console.log("IPFS URL:", metadata.url);// ipfs://bafy.../metadata.json固定服务(Pinning Services):
| 服务 | 免费额度 | 说明 |
|---|---|---|
| Pinata | 1 GB | 最流行,适合 NFT |
| NFT.Storage | 免费 | 专为 NFT 设计 |
| Web3.Storage | 5 GB | Filecoin 支持 |
| Infura IPFS | 5 GB | 付费 |
Arweave(永久存储)
特点:
- 一次付费,永久存储
- 基于”捐赠”模型(利息支付未来存储成本)
- 适合需要永久不可更改的数据(NFT、文件存档)
import Arweave from "arweave";
const arweave = Arweave.init({ host: "arweave.net", port: 443, protocol: "https",});
// 使用 Bundlr/Turbo 更方便(支持以太坊钱包付费)import { NodeBundlr } from "@bundlr-network/client";
const bundlr = new NodeBundlr( "https://node2.bundlr.network", "ethereum", process.env.PRIVATE_KEY!);
const tags = [{ name: "Content-Type", value: "image/png" }];const receipt = await bundlr.uploadFile("./image.png", { tags });console.log("Arweave ID:", receipt.id);console.log("URL:", `https://arweave.net/${receipt.id}`);NFT 元数据标准
ERC-721 和 ERC-1155 的 tokenURI 通常返回如下 JSON:
{ "name": "My NFT #1", "description": "这是一个示例 NFT", "image": "ipfs://QmXxxx.../image.png", "external_url": "https://myproject.io/nft/1", "attributes": [ { "trait_type": "Background", "value": "Ocean" }, { "trait_type": "Rarity", "value": "Rare", "display_type": "string" }, { "trait_type": "Level", "value": 5, "display_type": "number" } ]}IPFS URL 的注意事项
// IPFS CID 有两种格式,确保使用网关可访问的格式const ipfsUrl = "ipfs://QmXxxx.../metadata.json";
// 转换为 HTTP 网关 URL(供前端访问)function ipfsToHttp(url: string, gateway = "https://ipfs.io"): string { if (url.startsWith("ipfs://")) { return url.replace("ipfs://", `${gateway}/ipfs/`); } return url;}
// 推荐的公共网关const GATEWAYS = [ "https://ipfs.io", "https://cloudflare-ipfs.com", "https://gateway.pinata.cloud",];