區塊鏈-NFT 的實現原理

作者:林冠宏 / 指尖下的幽靈。轉載者,請: 務必標明出處。

博客://www.cnblogs.com/linguanh/

掘金://juejin.im/user/1785262612681997

GitHub : //github.com/af913337456/

出版的書籍:


NFT (Non-Fungible Token),這2年又火了起來,早在18年已經火過一波。

本文只從寫代碼實現NFT的技術方案層面去介紹 NFT,不從其金融意義、案例,等層面去談,因為這類內容可以隨便在瀏覽器搜索到,而我接下來要談的內容,淺層搜索下,數量不多。

第一步: 製作id

製作id,這是把物質製作成 NFT 的第一步。物質有哪些?一段文字、一張圖片,一件衣服等,誇張的說,現實世界的物質,無論是虛擬的(遊戲裝備)或實質物質,都可以被通證化。

如何操作?

通過第三方技術手段獲取物質的唯一標誌性中間產物。

因此製作 NFT 第一步,廣義於下面等式:

  • id = F(I)
    1. I = 輸入的物質
    2. F = 處理函數,代表一種方法
    3. id 唯一標誌性的中間產物

最簡單的例子就是哈希函數,不考慮哈希碰撞,它就可以根據不同的內容輸出不同的哈希值。思維在這裡不要局限於哈希函數。

獲取圖片的唯一id

這裡用圖片代表一系列的文件類數據。

  1. 我們可以將圖片轉換成 []byte 位元組數組,然後計算其哈希值。這種操作雖然比較簡單,但是圖片別人卻不能訪問,看不到;
  2. 如果我們想向外部任何人提供圖片的讀權限,在計算完 id 後,有兩種做法:
    1. 上傳圖片到文件服務器,任何人可以通過 url 鏈接訪問。這裡的服務器是中心化的;
    2. 增加區塊鏈屬性。上傳文件到 IPFS (ipfs是什麼,自行搜索),如此一來,文件別人能訪問,同時還具備了區塊鏈的去中心化等屬性。其中 IPFS 會在上傳完文件後,會使用它的算法,幫你計算好哈希值返回,可以直接用它的作為id。

獲取衣服的唯一id

這裡用衣服來代表一系列的實際物質。如果獲取它們的唯一id呢?做法可以放飛思維去思考,比如可以:

  • 衣服的出廠信息、掃描內容、照片,等系列關於它的信息,數據化,然後用這些數據製作成文件,最後參考圖片的做法。

第二步:通證化

第一步中獲取了物質的id,現在要把它們通證化。切記一點:目前公認的 NFT 都是基於區塊鏈公鏈的,那麼以後是不是會一直這樣呢?不一定,說不準出來了新的共識。

基於不同公鏈的流程

通證化的流程如下:

  1. 選擇一條區塊鏈公鏈。這裡的選擇會決定後面智能合約等系統組件的技術棧,這一點很核心;
  2. 在所選的公鏈上開發智能合約;
  3. 所開發的智能合約需要遵循一些基礎約定,比如至少能保證物質的id能達到驗證去重,什麼意思呢?意思是,如果 A 在今天上傳了 id=1 到鏈上,明天 B 也上傳同個 id=1 到鏈上,合約要能告訴 B,你不能上傳了,id 已經存在;
  4. 部署智能合約到鏈上,此時它變成 DApp;
  5. 通過發交易的方式,調用該智能合約的方法,將id等相關數據存儲到鏈上。

NFT 的智能合約

NFT 智能合約可以基於不同的公鏈開發,它不局限於任何一條公鏈。不同公鏈的智能合約方案實現也不同,下面以 以太坊 公鏈舉例說明。

在以太坊上面,開發 NFT 智能合約,已經有很多標準,比如 ERC-721 \1155 \998,各有各的特點,但它們的特點是在基礎屬性上拓展而來的。(各標準文檔: //eips.ethereum.org/EIPS/eip-721)

如果選擇 ERC-721 標準開發 NFT 智能合約,在元數據存儲部分,就有 tokenUrl 這項,它相當於物質的唯一id,像下面的樣子, _tokenURIs 存儲的就是通證當前計數id與其對應的 tokenUrl,這裡的tokenUrl 是字符串格式,一般是文件url,存儲在 IPFS 或其他服務上面的文件的鏈接,但不局限於鏈接,也可以是其它的內容。

// 偽代碼
contract MyERC721 is IERC721Metadata, ... {
    ...
    mapping(uint256 => address) private _tokenOwner;
    mapping(uint256 => string) private _tokenURIs;
    
    uint256 public tokenCounter; // 計數,當前總的 NFT 的數量,累增
    
    constructor () public ERC721 ("name", "symbol"){
        tokenCounter = 0;
    }
    // 外部調用方,調用這個函數,傳參數:tokenURI 即物質的id,tokenURI 唯一
    function createNFT(string memory tokenURI) public returns (uint256) {
        uint256 tokenId = tokenCounter;
        _mint(msg.sender, tokenId); // 將交易發送者和當前的 tokenId 綁定
        _setTokenURI(tokenId, tokenURI); // tokenId 映射到 tokenUrl
        tokenCounter = tokenCounter + 1; // 累加
        return tokenId;
    }
    // _exists 函數判斷 tokenId 是否存在,_tokenOwner[tokenId]
    // 根據 id 讀取對應的 url
    function tokenURI(uint256 tokenId) external view returns (string memory) {
        require(_exists(tokenId));
        return _tokenURIs[tokenId];
    }
    // 根據 tokenId 和 url 建立 map 數據關係
    function _setTokenURI(uint256 tokenId, string memory uri) internal {
        require(_exists(tokenId)); // _exists
        _tokenURIs[tokenId] = uri;
    }
    ... // 省略系列接口,包含讀接口
}

上面的 tokenUrl 是標準要求的存儲數據項。整個合約具備下面約束功能:

  1. NFT 持有者,即 msg.sender(owner) 和 tokenId 一對多關係,代表一個人可以擁有多個 NFT;
  2. tokenId 和 tokenUrl 一對一關係,代表每份數據一個鏈上的唯一id,同時 tokenUrl 沒要求是唯一,但在調用方,一般會把 tokenUrl 設置唯一,即使不唯一也沒關係,衝突的時候,tokenId 越小的,其當初被設置的時間就越早;
  3. NFT 持有者在將數據寫入鏈上後,能夠獲取 NFT 的鏈上唯一 id,後續可以根據 id 進行系列的讀寫操作。

一般來說,我們常規的 NFT 有一個和數據建立關係的項就足夠了,但並不局限於此,合約在實現了標準要求的接口後,完全可以自己添加自定義數據項及其讀寫函數。

第三步:展示與修改

展示 NFT 內容

所謂展示,就是對 NFT 的數據進行讀取再展示。一般的流程如下:

  1. 根據當初設置 NFT 數據到鏈上時獲得的 id 去智能合約讀取信息;
  2. 將獲得的信息通過某介質應用還原出原始的 NFT 數據。

比如將圖片 NFT 展示出。(藉助上面的 721 合約標準和 IPFS 結合為例)

  1. 假設調用合約存儲數據時候得到的 tokenId 是 3,那麼使用這個 tokenId 去調用合約的讀數據方法;
  2. 執行完 1 步驟,可以得到 tokenUrl,即文件存儲在 IPFS 中所得到的鏈接;
  3. 直接將 tokenUrl 鏈接在瀏覽器打開,看到圖片。

修改 NFT 內容

修改是一項 NFT 智能合約的拓展功能,可有可無,具體是怎樣的方式,完全看需求的實現。比如:

  1. 允許重置 tokenId 所對應的內容;
  2. 在 NFT 原數據中增加其他字段內容,再允許修改這些字段;
  3. 轉讓 NFT,可以把某 tokenId 對應的 NFT 信息轉讓給其他 owner,達到轉讓目的;
  4. 出售 NFT拍賣 NFT 等操作….

所有權共識

目前 NFT,非同質化通證。本質是想藉助區塊鏈的屬性來標示一種資產的所有權證明。

比如曾拍賣出6000多萬美金的數字作品(圖片)《Everydays: The First 5000 Days》,中標者能獲得原圖 和 該圖的 NFT。這兩樣東西,一樣是實質的作品,一樣是它的所有權者的證明。

我們假設下,如果持有某作品的人,是一位匿名者A,過了多年後,該作品本身不小心被盜並被找回。那麼如何證明 A 是真正的擁有者,此時 A 只需要展示他對該作品的 NFT 擁有權,就可以證明。

那麼 NFT 是不是類似於我們現實中的證書?不全是,分兩點:

  1. NFT 和證書都能證明某資產的所有權;
  2. 對比的存儲介質 與 永恆時效:
    1. 證書可能要找個保險柜保養放着,但它終究佔據一方土地,僅受一方土地容納的保險柜保證安全,在時過境遷的影響下,持續性存儲下去的時間會較短;
    2. NFT 存儲在區塊鏈上,受整個互聯網的鏈節點所保護。它能夠存活到整個鏈網絡垮掉那天,對於節點數量眾多的公鏈來說,這個概率幾乎等同於互聯網終結那天。

第三方平台

現在已經有很多的第三方的 NFT 製作與發佈平台。比如 opensea、rarible 等,這些平台自己實現了 NFT 的智能合約 和 NFT 展示應用(介質應用—網站),方便大眾 0 代碼基礎體會 NFT。但也有一些門檻,需要具備錢包和發交易的油費。