教程区块链区块链技术ch1414.5 去中心化存储:IPFS 与 Arweave 前端集成

本页目录

区块链存储 1GB 数据需要数百 ETH。元数据、图片、前端静态文件必须放在链下存储。IPFS(内容寻址,可能丢失)和 Arweave(一次付费,永久保存)是两大标准。


14.5.1 内容寻址 vs 位置寻址

传统 URL(HTTPS):通过位置访问。

  • https://somesite.com/image.jpg —— 文件在这个服务器的这个路径上,服务器关闭 = 文件消失。

IPFS:通过内容访问。

  • ipfs://Qmabc.../image.jpg —— 这个 CID(Content Identifier)永远指向这个内容,存储在哪台机器上无关紧要。

CID 的生成

CID=Multiformat(multihash(content))\text{CID} = \text{Multiformat}(\text{multihash}(\text{content}))
typescript
/**
 * IPFS 的内容寻址(简化模拟)
 */
function sha256(data: string): string {
  // 简化哈希演示
  let h = 0;
  for (let i = 0; i < data.length; i++) {
    h = ((h << 5) - h + data.charCodeAt(i)) | 0;
  }
  return h.toString(16).padStart(64, '0');
}

function computeCID(data: string): string {
  const hash = sha256(data);
  // IPFS 使用 CIDv1 多格式编码:
  // 0x12 = sha2-256, 0x20 = 32 字节, 0x01 = CIDv1, 0x55 = raw
  return "bafybei" + hash.slice(0, 44); // 简化 base32 前缀
}

// 关键特性:相同数据 => 相同 CID
const cid1 = computeCID("Hello World");
const cid2 = computeCID("Hello World");
console.log("CID 匹配:", cid1 === cid2, cid1);

// 即使文件名不同,内容一样,CID 也一样
const cid3 = computeCID("Hello World");
console.log("内容相同 CID 相同:", cid1 === cid3);

14.5.2 IPFS 的工作机制

graph LR
    subgraph IPFS["IPFS 网络"]
        A[上传文件] --> B[分片: 256KB 块]
        B --> C[计算每个块 CID]
        C --> D[Merkle DAG 链接]
        D --> E[根 CID]
        E --> F[广播到 DHT 节点]
    end
    
    User[用户] --> |"GET /ipfs/<cid>"| Gateway[Gateway 节点]
    Gateway --> |DHT 查找| P1[节点 P1] & P2[节点 P2]
    P1 --> |返回分片| Gateway
    Gateway --> |重组文件| User
    
    style IPFS fill:#e3f2fd

前端集成路径

服务类型持久化免费额度用途
Pinata托管 pinning付费长期1GB 免费NFT 元数据
Web3.storageIPFS + Filecoin协商5GB 免费DApp 存储
NFT.storageIPFS + Filecoin永久(*)免费NFT 专属
Infura IPFS节点托管付费5GB 免费企业级
公共 Gateway只读不保证免费最简访问

(*) NFT.storage 将文件同时 pin 到 IPFS 和 Filecoin 存储交易,理论上永久免费(受项目资金限制)。

前端上传示例

typescript
/**
 * IPFS 上传(前端概念模拟)
 */
interface IPFSPinataResponse {
  IpfsHash: string;     // CID
  PinSize: number;      // 字节数
  Timestamp: string;
}

async function uploadToIPFS(
  apiKey: string,
  secret: string,
  file: File,
): Promise<string> {
  const formData = new FormData();
  formData.append("file", file);
  
  // Pinata 的 pinning 服务
  const res = await fetch("https://api.pinata.cloud/pinning/pinFileToIPFS", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${await signJWT(apiKey, secret)}`,
    },
    body: formData,
  });
  
  const data: IPFSPinataResponse = await res.json();
  // 返回的 CID 就是 URI: ipfs://{IpfsHash}
  return `ipfs://${data.IpfsHash}`;
}

// 选择 Gateway
function resolveIPFSUri(uri: string): string {
  if (uri.startsWith("ipfs://")) {
    const cid = uri.replace("ipfs://", "");
    // 选择可靠的 Gateway
    return `https://cloudflare-ipfs.com/ipfs/${cid}`;
    // 备选: https://ipfs.io/ipfs/${cid}
    // 备选: https://gateway.pinata.cloud/ipfs/${cid}
  }
  return uri;
}

function signJWT(_apiKey: string, _secret: string): Promise<string> {
  return Promise.resolve("mock-jwt-token");
}

console.log("IPFS URI 示例:", resolveIPFSUri("ipfs://Qmdemo.../metadata.json"));

14.5.3 Arweave:一次付费,永久存储

经济模型

对比传统云 (AWS S3)IPFSArweave
支付订阅/月付免费/按 pin一次性
持久化只要付费就存在只要有人 pin 就存在永久
成本0.023/GB/免费0.023/GB/月 | 免费-10/GB$1-5/GB 一次性
访问HTTPipfs:// 或 gateway专用网关
元数据标准ANS-110 等

Permaweb:网页都存在 Arweave 上

Arweave 不仅存文件,还可以托管完整的前端应用(HTML/JS/CSS)。

typescript
/**
 * Arweave 上传(概念模拟)
 */
interface ArweaveTransaction {
  id: string;            // 交易 ID 同时作为访问地址
  data: string;          // 文件内容(base64)
  tags: { name: string; value: string }[]; // 元数据标签
  reward: bigint;        // 存储费用
  signature?: string;
}

async function uploadToArweave(
  fileContent: string,
  fileType: string,
): Promise<string> {
  const arweave = {
    // ANS-110 标准标签
    tags: [
      { name: "Content-Type", value: fileType },
      { name: "App-Name", value: "MyDApp" },
      { name: "App-Version", value: "1.0.0" },
    ],
    // 费用 = 数据大小 × 当前 AR 价格 × 永久存储成本模型
    async getPrice(dataSize: number): Promise<bigint> {
      return BigInt(dataSize) * 10000n; // 简化
    },
  };
  
  const price = await arweave.getPrice(fileContent.length);
  console.log(`Storage cost: pricewinston({price} winston ({Number(price) / 1e12} AR)`);
  
  // 签名并提交到 Arweave 网络
  const txId = "abc123...";
  return `https://arweave.net/${txId}`; // 永久可访问
}

// NFT 元数据标准:指向 Arweave 永久 URI
const artMetadata = {
  name: "Digital Art #1",
  description: "...",
  image: "https://arweave.net/txId_of_image",  // 永久图片
  animation_url: "https://arweave.net/txId_of_glb", // 永久 3D 模型
};

console.log("Arweave: 存一次,永远可用");

14.5.4 前端去中心化存储的实战建议

场景推荐方案URI 格式
NFT 小图片 (< 10MB)IPFS (Pinata / Web3.storage)ipfs://
NFT 大图/视频Arweave (Irys 代付)https://arweave.net/
DApp 前端托管Arweave Permawebhttps://arweave.net/
链上元数据 (base64)data URIdata:application/json;base64,...
临时测试Pinata 免费层ipfs://
graph LR
    subgraph Storage["存储方案决策树"]
        Q1{"数据大小?"}
        Q2{"持久性要求?"}
        Q3{"预算?"}
    end
    
    Q1 --> |< 1MB| Small[IPFS free]
    Q1 --> |> 10MB| Large[Arweave 或 Filecoin]
    Q2 --> |临时| Temp[IPFS, 自行 pin]
    Q2 --> |永久| Perm[Arweave / NFT.storage]
    Q3 --> |零预算| Free[NFT.storage / Web3.storage]
    Q3 --> |可付费| Paid[Pinata / Infura]
    
    style Storage fill:#e3f2fd

> ← 14.4 事件同步 | 前往 → 14.6 多链与跨链桥 |*

评论

0

评论加载中…

发表评论

0/2000