Day 20【ERC-721】They don't know I own this song's non-fungible token

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f821ec11-341b-4b56-9a3a-2e259b1b5b07/Elon-Musk-NFT-meme.jpg

【前言】
就我们所知,所谓的链上数据通常都是一串的数字或者是文字,但艺术品通常都有其相当的外观,那这些「图像」甚至「影片」到底是怎麽储存,并且出现在我们眼前的呢?

【把图片存在以太坊上到底要多少钱?】

首先要知道,如果我们把 NFT 的 MetaData 以及相关数据全部储存在链上,那将耗费极大的成本。

在以太坊之中是以 256 bits 为主,假设我们要储存一张大小为 1 MB 的图片:

在 Ethereum 中每"单位"是 256 bits = 32 bytes = 2^5 bytes
1 MB =  1,024 KB = 1024 * 1024 bytes = 2^20 bytes

也就是说我们需要 2^20 / 2^5 = 2^15 = 32,768 "单位"

从以下这个网站我们可以发现当前的 STANDARD Gas Prices 是 68 Gwei( in 2021/8/30)。

ETH Gas Station

从 yellow paper 以及 EIP-2200 之中我们可以得知,如果要储存 32,768 单位的资料,需要 call SSTORE 32,768 次,这个函数是表示把一个值从零设置为非零,而每次需要耗费 20000 的 Gas。

GitHub - ethereum/yellowpaper: The "Yellow Paper": Ethereum's formal specification
EIPs/eip-2200.md at master · ethereum/EIPs

每笔交易的 gas limit 是 21,000 gas,从以下这个网站我们可以发现得到 1 ETH 的价值为 3,163.08 USD ( in 2021/8/30)。

CoinDesk: Bitcoin, Ethereum, Crypto News and Price Data

每一次 call SSTORE 都需要耗费 20000 Gas:


储存并且交易 1 MB 的资料需耗费 20,000 * 32,768 + 21000 = 655381000 GAS

其价值 655381000 * 68 = 44565908000 Gwei;已知 10^9 Gwei = 1 ETH

= 44.565908 ETH
 
= 140,965.532 USD

= 3,913,696.555. NTD 

没错,如果你需要储存 1 MB 的资料,就需要 3,913,696.555 NTD。所以我们不可能把资料存在链上面对吧!

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/45ad6f6d-cabc-47b8-8e39-16f80ad24329/39bcf1b4b69c391c998fd0a41808e5de.jpg

【tokenURI 元数据方法】
当然如果这张图片的价值超过所需要付出的 Gas,也许有人会决定把所有资讯放上链。不过如果不要把 JPEG 放在链上的话,那 NFT 的 JPEG 会出现在哪,以何种方式「安全地」呈现呢?

我们接续昨天介绍的 ERC-721 API 与内置函数,

interface ERC721 {
    event Transfer(...);
    event Approval(...);
    event ApprovalForAll(...);

    function balanceOf(...);
    function ownerOf(...);
    function safeTransferFrom(...);
    function safeTransferFrom(...);
    function transferFrom(...);
    function approve(...);
    function setApprovalForAll(...);
    function getApproved(...);
    function isApprovedForAll(...);
}
interface ERC721Metadata {
    function name(...);
    function symbol(...);
    function tokenURI(...);
}

我们要聚焦在 tokenURI 之上。

function tokenURI(uint256 _tokenId) external view returns (string);
// A distinct Uniform Resource Identifier (URI) for a given asset.

观察之後会发现 NFT 在链上其实是储存成一个 256-bit 的整数。

如果我们去到任何 Etherscan 上的 NFT 合约查看 Contract Source Code,像是我们查看有名的 BAYC 可以发现以下程序码。

图片 22.png

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
    ...
    // Optional mapping for token URIs
    mapping (uint256 => string) private _tokenURIs;
		...

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory _tokenURI = _tokenURIs[tokenId];
        string memory base = baseURI();

        // If there is no base URI, return the token URI.
        if (bytes(base).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(base, _tokenURI));
        }
        // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
        return string(abi.encodePacked(base, tokenId.toString()));
    }

也就是说当我们查看 tokenURI 的时候他执行一个内部的 map 函数,有点像 python 的 dict 杂凑,并不是一个从合约外部来 hash 的函数。

图片 23.png

此时我们去 Read Contract 的部分查看 tokenURI ,并输入任意的 tokenId (uint256) 即可查看回传的 string 是长什麽样子。我在 Bored Ape Yacht Club 的合约底下查询 9946 的猴子後,回传的是:

string :  ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/9946

那图片到底是储存在哪并且显示的呢?我们接下来查看 IPFS 这个东西。

【IPFS】
所谓的 IPFS 译为 星际文件系统 (Inter Planetary File System),是一个分散式的网站点到点网路传输协议。提供一个可用於存取档案、网站、应用程序与资料的分散式系统。IPFS 协议的目标是取代传统的互联网协议 HTTP,因为 HTTP 是中心化且低效的,成本也更高。此外 HTTP 的生存周期也大概只有三个月,Web 文件有可能在储存成本太高的情况下被删除。

这边我们不多加叙述 IPFS 的块储存模型、加密方法和与众不同的服务,回来聚焦在我们的主题上!

如果我们把字串中的 ipfs:// 改成 https://ipfs.io/ipfs/ 就可以来到一个神秘的地方!

https://ipfs.io/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/9946

我们可以发现这是一个 JSON 的档案格式,里面储存的就是这个 NFT 该要有的资料,也就是 NFT 的 MetaData!

{"image":"ipfs://QmQn9BnEMHrbqApJ59wDnFqEjtoZE6pKy4LoxFhWA7MKPw",
 "attributes":[{"trait_type":"Hat","value":"Sea Captain's Hat"},
						 	 {"trait_type":"Mouth","value":"Phoneme Vuh"},
							 {"trait_type":"Eyes","value":"Sad"},
							 {"trait_type":"Background","value":"New Punk Blue"},
							 {"trait_type":"Fur","value":"Golden Brown"}]}

最重要的是我们会看到心心念念的 "image",如果我们使用一样的方法把字串中的 ipfs:// 改成 https://ipfs.io/ipfs/ 後,就可以看见图片啦!

https://ipfs.io/ipfs/QmQn9BnEMHrbqApJ59wDnFqEjtoZE6pKy4LoxFhWA7MKPw

现在我们知道了 ERC-721 上的 Token 不管是图片还是元数据,其实都是藉由合约访问,并且储存在 IPFS 上的!

【小结】
相信各位在看完这两天的文章之後对 ERC-721 Token 以及 NFT 加密艺术品都更有了解!明天就会开始进入查询 Token Owner 的环节,回到我们的 Project 之中罗!

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9373891c-36c1-4f20-8dda-3a08e1c45399/52hdm4.jpg

【参考资料】
EIPs/eip-721.md at master · ethereum/EIPs
LEVELUPUP
ERC-721 Token with on chain metadata
EIPs/eip-721.md at master · ethereum/EIPs
Your CryptoKitty Isn't Forever - Why DApps Aren't as Decentralized as You Think


<<:  【Day 17】从二开始的 Anti-Anti-Debug 生活 - Anti-Anti-Debug

>>:  Native Backup

[Day 02] 在表情资料寻找邂逅是否搞错了甚麽 (Facial Expression Recognition)

表情资料集的介绍与下载 俗话说:「知己知彼,百战百胜」,这句话同样也适合用在资料科学上, 我们必须对...

Day20 让电脑透过数据机和有线、无线网路传递讯息

上一回讲的是透过数据机连结各种电脑周边 今天来分享数据机更强大的功能,传递讯息 可以先查询 mode...

Day24 - 静态模型 part2 (CNN)

在 CNN-based 的架构中,会使用三种不同的 CNN 架构: Basic CNN Multi-...

制作响应式网站-30天学会HTML+CSS,制作精美网站

响应式网页设计是什麽 响应式网页设计(Responsive Web Design)简称RWD,是开发...

Day 26 批次网路影片下载工具 - youtube-dl-server

说到百花齐放的网路影片平台中,若有批次下载离线观看在 Youtube, Facebook, vime...