在 BTFS 上托管 NFT 元数据
将 NFT 图片和元数据 JSON 上传到 BTFS,并将生成的 URI 用作 tokenURI。
前置阅读
BitTorrent File System(BTFS)是基于 TRON 网络与 BitTorrent 生态构建的去中心化文件存储协议。在 NFT 场景中,定义每个 Token 名称、图像及属性的元数据 JSON 文件通常托管在链下,并通过智能合约中的 tokenURI 函数引用。BTFS 可用于托管这类元数据,降低对单一 Web 服务器的依赖。
本指南将引导你将图片和元数据 JSON 上传到 BTFS,生成可用于 TRC-721 合约的 URI。
元数据托管选择:BTFS 与其他方案
| 选项 | 费用 | 持久性 | 去中心化程度 |
|---|---|---|---|
| BTFS | 以当前客户端和存储服务报价为准 | 取决于存储合约、续费和副本可用性 | 在 BTFS 网络上去中心化 |
| IPFS + 固定服务(如 Pinata) | 订阅或按固定付费 | 只要固定即可持续 | 在 IPFS 网络上去中心化 |
| Arweave | 一次性付费永久存储 | 永久 | 去中心化 |
| 自托管 CDN | 托管费用 | 只要你维护主机即可持续 | 中心化 |
BTFS 是 TRON 生态中常用的 NFT 元数据托管方案之一。
步骤 1——安装并初始化 BTFS
从官方 go-btfs 仓库安装,并从 Releases 下载适合当前系统和架构的最新稳定版本,核对页面提供的 SHA-256 摘要。
执行 btfs init 初始化本地节点时,系统会生成节点密钥,并可从同一密钥派生 TRON 格式地址和 BTTC 格式地址。初始化后应用 storage renter 配置,以启用从 BTFS 网络购买存储的功能:
btfs config profile apply storage-client节点启动后,可运行 btfs id 查看地址。本指南的 Gas 和存储付费流程使用输出中的 BTTC 格式 BttcAddress(0x...),不要将它与 TRON Base58 格式地址(T...)混用。
步骤 2——启动节点并准备存储费用
运行 btfs daemon。首次启动时,节点会显示本次生成的 BTTC 地址;如果提示 Gas 余额不足,保持 daemon 运行,核对终端中由本地节点输出的地址和所需余额,再从你控制的钱包通过 BTTC 网络向该地址转入足量 BTT,使其余额达到本次客户端提示的要求。BTT 用于 BTTC 链上 Gas,不用于支付存储费用。节点检测到余额后会继续部署 vault;部署完成后运行 btfs id,确认输出中的 BttcAddress 与充值地址一致,并且同时显示 VaultAddress。
上传者属于 BTFS storage renter,需要用 WBTT 支付存储提供者。通过当前版本 BTFS Dashboard 的 Swap 功能或你控制的 BTTC 钱包准备 WBTT,并转入本节点的 BttcAddress;然后使用本地节点把 WBTT 存入它自己的 vault:
# 查看 vault 的 WBTT 余额;输出以 10^18 基础单位计
btfs vault balance
# 示例:将 1 WBTT(10^18 基础单位)从本节点的 BttcAddress 存入 VaultAddress
WBTT_AMOUNT_WEI=1000000000000000000
btfs vault deposit "$WBTT_AMOUNT_WEI"等待存入交易确认后,再运行 btfs vault balance。余额应增加;随后可先上传一个小文件验证完整流程。不同版本的 Dashboard 布局可能变化,操作前应以已安装版本的 Release Notes、btfs vault --help 和界面提示为准。
旧版教程中的btfs wallet deposit流程不适用于当前 BTFS 版本。不要把资金发送到截图、示例输出或第三方教程中的地址;只使用你本地节点本次启动生成并经btfs id核对的地址。
步骤 3——上传图片
步骤 3.1——将图片添加到本地节点
准备一个图片文件(本指南使用 coral.jpeg)。要把内容上传到 BTFS 存储提供者,应在添加时启用 Reed-Solomon 纠删码(Reed-Solomon erasure coding):
btfs add --chunker=reed-solomon coral.jpeg
printf '粘贴上一条命令返回的图片 CID:'
read -r FILE_CID
第一条命令输出一个 CID;将该值粘贴到紧随其后的提示中,后续命令通过 FILE_CID 复用它。不同分片方式会为同一文件生成不同 CID,不能用旧教程或截图中的 CID 代替本次输出。
不带--chunker=reed-solomon的普通btfs add只按默认分块方式加入本地节点。BTFS 4.1 的storage upload对这类 CID 会进入copy=0兼容路径,只创建一个待存储副本;自动续期只延长该存储合约,不会增加副本或纠删码冗余。普通模式适合本地或临时验证,不应作为长期 NFT 元数据的默认方案。
步骤 3.2——上传到 BTFS 网络
通过步骤 3.1 返回的 Reed-Solomon CID 上传文件;BTFS 会把数据分片和校验分片分配给存储提供者。对于需要长期托管的 NFT 元数据,可在 BTFS 4.1 或更高版本中启用自动续期。如果只需要固定期限,可将 --autorenew 改为 --storage-length=30 等明确天数。自动续期仍需 Vault 中有充足余额;应持续监控余额和续期状态,不能把内容寻址 URI 本身视为永久存储保证。
以下完整示例使用 jq 从本次上传响应中提取 Session ID、查询上传状态并确认自动续期。如果未安装 jq,脚本会给出提示且不会执行上传:
if [ -z "${FILE_CID:-}" ]; then
printf '%s\n' "请先完成步骤 3.1,并在当前终端设置 FILE_CID" >&2
elif command -v jq >/dev/null 2>&1; then
UPLOAD_RESULT=$(btfs storage upload "$FILE_CID" --autorenew) &&
printf '%s\n' "$UPLOAD_RESULT" &&
SESSION_ID=$(printf '%s\n' "$UPLOAD_RESULT" | jq -er '.ID') &&
btfs storage upload status "$SESSION_ID" &&
btfs storage upload renew info "$FILE_CID"
else
printf '%s\n' "需要先安装 jq,然后重新运行此代码块" >&2
fi其中 status 命令只查询一次当前状态;请使用同一个 SESSION_ID 重复执行该命令,直到所有数据分片和校验分片均显示完成。还可以运行 btfs storage upload renew list 查看本节点启用自动续期的全部文件。自动续期只延长已建立的分片存储关系;它不能替代分片完成检查,也不会自行增加冗余。
步骤 3.3——验证文件可读取
在另一个从未导入该 CID 的 BTFS 节点上读取文件。先粘贴步骤 3.1 得到的 CID,再确认该节点能通过网络发现并获取内容:
printf '粘贴步骤 3.1 返回的图片 CID:'
read -r FILE_CID
btfs cat "/btfs/$FILE_CID" > downloaded-coral.jpeg分别计算原文件和下载文件的 SHA-256 摘要,两者应一致:
Linux:
sha256sum coral.jpeg downloaded-coral.jpegmacOS:
shasum -a 256 coral.jpeg downloaded-coral.jpeg如果没有第二个节点,也可以通过你选择的独立 BTFS 网关按 https://<GATEWAY_HOST>/btfs/<CID> 获取并比较内容,但不要使用上传节点自身的本地网关完成这项检查。第二节点或网关取回只能证明检查当时可用,不能单独证明各分片由相互独立的提供者保存或保证长期可用;还应结合上传会话中全部分片的完成状态、续期状态和 Vault 余额判断。公共网关也可能限流、迁移或下线。
步骤 4——构建元数据 JSON
创建一个 JSON 文件(本指南使用 coral.json),遵循 TRC-721 元数据结构。将 REPLACE_WITH_IMAGE_CID 替换为步骤 3.1 实际返回的图片 CID,使 image 字段采用内容寻址的 btfs://<CID> URI,避免把元数据绑定到单一 HTTP 网关:
{
"name": "Coral #1",
"description": "A unique TRC-721 collectible.",
"image": "btfs://REPLACE_WITH_IMAGE_CID",
"attributes": [
{ "trait_type": "Color", "value": "Pink" },
{ "trait_type": "Rarity", "value": "Rare" }
]
}步骤 5——上传元数据 JSON
以与图片相同的方式上传 JSON:先运行 btfs add --chunker=reed-solomon coral.json,保存返回的元数据 CID,并将其赋给步骤 3.2 使用的 FILE_CID。图片和元数据是两个独立 CID;应分别确认两次上传的全部分片均已完成。如果使用自动续期,还应分别运行 renew info 确认两者都已启用:
btfs add --chunker=reed-solomon coral.json
printf '粘贴上一条命令返回的元数据 CID:'
read -r METADATA_CID
FILE_CID=$METADATA_CID然后在当前终端中重新运行步骤 3.2 的命令块,把元数据文件上传到 BTFS Storage。上面的赋值会让该命令块使用元数据 CID。
上传完成后,在步骤 3.3 使用的独立节点或网关读取元数据。先粘贴步骤 5 得到的 CID,再验证返回的是预期 JSON:
printf '粘贴步骤 5 返回的元数据 CID:'
read -r METADATA_CID
btfs cat "/btfs/$METADATA_CID"步骤 6——铸造时将 URI 用作 tokenURI
tokenURI在已部署的 TRC-721 合约上调用 safeMint 时,将步骤 5 返回的元数据 CID 组成 btfs://<METADATA_CID>,并作为 uri 参数。铸造前确认目标钱包、市场或索引器能解析 btfs://;如果只能接受 HTTPS,应选用你能够长期维护或替换的网关转换层,而不是依赖某个示例网关域名。完整的铸造流程请参见发行 TRC-721 Token。
相关资源
- TRC-721 —— 标准概览
- TRC-721 协议接口 —— TRC-721 函数与事件参考
- 发行 TRC-721 Token —— 部署和铸造演练
Updated about 9 hours ago
