Flow 在半年的時間已經達成了非常多的合作。
2021年11月25日,在第9期BeWater Live 上,Dapper Labs中國技術負責人唐博皞分享了《面向資源編程:Flow Cadence智能合約語言的全新範式》
這場深度且系統的分享,核心內容:
1、Flow概覽
2、中央賬本與Solidity智能合約面臨的風險和挑戰
3、Cadence面向資源的編程範式基礎介紹
– 來自Rust和Move的啟發
– 資源數據
– 存儲形式
– 訪問模型
– 資源數據轉移
4、 Cadence相關工具鏈導覽:
– 開發者工具
– 學習路徑
是水
一、Flow概覽
我們先來介紹一下關於flow和我們Dapper Labs, Dapper Labs 的前世今生大家其實已經非常熟悉非常了解。
現在整個市面上最主流的nft標準,在以太坊包括其他任何二層或者這樣的以太坊鏈上都非常熟悉erc721 這樣一個NFT標準, Dapper Labs就是erc721的編寫者,Flow的CTO 在17年的時候制定了erc721 的標準,並在當年製作了加密貓,應該說是第一款把以太網打爆的這樣一個NFT 項目。
加密貓之後,我們其實沉寂了接幾乎兩年的時間,我們在思考的過程中發現了以太坊上種種問題,然後覺得自身的一些對NFT 未來的暢想無法在以太坊這樣一個網絡上能完成,所以花了兩年的時間進行了非常深邃的研究和開發之後,做出了Flow。
在2020年的時候上線了Flow鏈,同期在年末的時候也在此基礎上製作了NBA TOP shot。我們完成了在Flow鏈上的,包括最第一次的開發的功能性的完善,同時也將其產品化,也讓NFT 更早的進入了大眾的視野之中。
Flow 在半年的時間已經達成了非常多的合作。 Flow應該是做的是整個web3 世界中在web2 世界拓展裡邊做的最好的,我們現在希望以把web2 世界引入web3 世界為我們的宗旨來推廣我們的品牌。
Flow在其他的一些產品上也有它非常有特色的東西。
一個比較重要的嘗試是我們的Dapper Wallet,它是以信用卡支付的方式來讓web2 世界的用戶進行NFT的消費和使用。在這個過程中我們隱藏了全部的加密的技術。當一個消費者玩NBA TS的時候,他根本接觸不到加密或者說區塊鏈相關信息,你就把它當成一個投資品或者說是一個消費品使用就可以了,這也是讓消費者以無門檻的形式進入到區塊鏈世界的一個例子。
然後第二個很大的特色,是我們的Flow本身的區塊鏈,它應該說是目前世界上所有區塊鏈中唯一一個以多功能節點架構設計的區塊鏈模式。它讓可擴展性這件事情變得非常容易。最核心的設計理念是將共識算法和計算節點兩個功能完全分離。
我們一共有4大類的功能性節點:分別為collection節點,它是負責收集節點信息的;然後共識節點完成一塊區塊的打包;計算節點完成所有交易的計算;驗證節點完成對所有交易結果的驗證。最後將這兩塊信息封裝在一個塊中送去,這件事情是以一種流水線的形式完成的。因為讓每個不同的節點類型,負責了自己獨特的一套功能,所以他非常容易的進行針對性的擴展。目前大多數的區塊鏈,它基本上都是某功能涵蓋了所有的內容,因此就只能往上堆資源,或者說多犧牲某些特性,來提高它的性能。 Flow因為它的分離共識和計算節點這樣一套多節點的架構,使這件事情可擴展性變得非常容易。
二、中央賬本與Solidity智能合約面臨的風險和挑戰
今天其實更多的想講的是後面大部分內容想講的是我們在設計為什麼Flow 的時候為什麼沒有選用EVM。因為我們發現了很多中央賬本的問題,
首先第一個問題在哪裡?
我們先舉一個例子看看什麼是以賬本為中心的實現,它存儲的內容始終是在中央賬本中的。這裡是一個很簡單的Token合約的實例,他記錄了一個賬戶裡邊每個賬戶兌了多少錢。他是一個map的形式,將一個balance給記錄下來,同時有一個mint的方法,給這個地址A receiver 添加了多少錢,這就是一個中央賬目的形式。轉賬的時候, 我們就將A 用戶的msg.sender 就是我交易發送方的金額,在我的中央賬本中減去,同時receiver在接收方的中央在賬本里面加上這個錢。
這時候我們再看一下Solidity 的陷阱在哪,我們在所有的過程中其實沒有強加任何數值上的約束。如果一個黑客用一個代碼,將後面的balance給註釋掉,接收方就永遠接收不到錢了,然後這里金額在這個合約裡邊其實就永遠消失掉了。從代碼層從語言層上面我們無法阻止這件事情。所以我們其實經常聽到誰又黑了多少錢。
因為在整個Solidity 設計機制中,只要以中央賬本為設計模型那就不可避免的會因為一些黑客的原因或者是代碼輸入的原因,將你這邊的金額扣掉。編譯器不會對這類的語法做任何的錯誤檢查,也不會有任何的機制來阻止這些情況的發生。
還會碰到很多類似的潛在的問題,一方面從心理上這對智能合約的開發人員也有非常大的責任和壓力。另一方面還有很多底層代碼需要處理(儘管OpenZeppelin 等工具庫解決了一部分)。比如管理數值上下溢出的問題,管理所有權問題,管理多簽問題。這些都是我們在做EVM 一些生態的時候會碰到的問題。
三、Cadence面向資源的編程範式基礎介紹
1、來自Rust和Move的啟發
18年的時候Libra 把一個新的概念引入進來:resource概念。它更加的專注於FT(fungible token)的管理,將資金的轉移做得非常細化。之後19年substrate 在currency 的設計結構上也使用了resource 的設計理念。
Flow 它在整個的設計理念的時候,把resource 引用到了整個語言層面上的設計,完全基於resource 來編程。
當然這部分大家如果熟悉Rust 的話,可能也會比較熟悉,它其實是一種對所有權更加深入的使用。
2、節奏
下面我們引出Cadence ,一個面向資源resource 的智能合約語言,它這邊有一個很獨特的箭頭,是resource 的一個instance 所獨有的賦值標記號,表示的是轉移,這個轉移是resource 最核心的一個賦值的形式。
3、Cadence vs Solidity
資源數據
我們再看看資源類型的一個公共形式。我們這邊的withdraw 他在調用的時候,創建了一個全新的vault 資源,而vault 資源里具有的金額是我們傳進來的金額,這裡已經減掉了,但是我返回的結果必須是一個全新的vault ,為什麼?因為我們的方法強制指定了你必須返回一個資源,如果沒有返回這樣一個資源,代碼編譯不通過,這就是在代碼層面上,我們其實就保護了我們withdraw ,你不可以說我只減了錢,不給另外一個人加錢,雖然我現在還沒加,但是我現在已經返回出來了一個固定的資源,固定資源一定是有這個amount 的錢。至於你這裡邊的錢未來怎麼用,外面會有其他代碼來解決。
當我deposit的時候,就必須要傳入一個有金額的這樣一個資源,因為指定類型balance 新的from 資源里面,必須是有這樣一個balance,它是個強類型的東西。
這時候我的函數方法中沒有返回任何東西,它意味著什麼?意味著我們傳進來這個資源必須被銷毀,因為資源在代碼層面上只有兩種可選行為,一是你這個資源返回出去,到函數之外或者保存到用戶的賬戶裡;二是銷毀掉。只要這樣一個資源類型,它的定義為資源,就必定會有一個最終的歸屬。如果沒有最終的歸屬,這個合約是無法通過。
我們在資源傳入的臨時資源銷毀之後,整個資源的生命週期就已經結束了,這種設計模式中,一切對資源不正確的使用都無法將該合約正常進行,都會導致編譯器報錯。
存儲形式
再回到剛才的我們非常簡單的例子, Solidity 它在存儲的形式上到底有什麼不一樣?我們將Cadence 裡面的resource 依然是做一個vault , vault 是來管理剛才的內容的,我們可以把resource 想像是一種定義。
當我們創建vault 之後,我們創建vault 的實例不是保存在中央賬本中的,而是將這個vault 保存在了用戶的存儲的空間中,存儲的空間它是不是在合約裡面。合約裡只保存了這個定義文件,真正的實例保存在用戶的存儲空間之中。
在Solidity 中,我們所有的記賬模型是以key-value map的形式保存用戶的餘額。但是在Cadence 中我們剛才創建了資源出來之後存到的地方,不是我們的合約,而是account 裡邊storage 指定的一個地方,所以資源永久的存在了用戶的賬戶之中,它是一種以人為本的賬戶模型,讓你真正擁有了自數字資產的所有權,而不是將我數字資產的所有權放在一個別人賬戶的記賬本里面的一行記錄,相當於資產真正意義上的屬於了你。
同時在中心化賬本里面,我們非常難統計到一個特定用戶擁有的所有資產信息。用過Solidity 的人都知道,我要以一個賬戶掃描我這個賬戶裡面所有的ERC20 或者是NFT 是件非常艱難的事情。首先要有一個常見的ERC20 的合約列表,然通過一些形式對於ERC20 的合約,對它的中心化賬本里查詢,我才能收集到一個特定用戶的所有資產信息。但是Cadence 不一樣,Cadence 模型下我們的所有數字資產全都在他賬戶自己的空間裡,所以對於開發者來說,我要查用戶的某些數字資產,那就非常容易的能通過查詢該賬戶,該賬戶下面所有的路徑,所有的資源,然後一個列表直接查詢出來。
訪問模型
對資源的訪問,solidity 需要創建另外一個字段來標記一下它怎麼來使用,這是非常中心化賬本的模式。
而Cadence 我剛才也說到就是說存儲的地方是它有一個Storage ,然後在賬戶的空間下一共有三類的存儲模型,分別為storage、public、private 這三類的存儲路徑,其實分別代表著對於資源的保存路徑。 storage 保存的是我們原始的資源信息。我們可以將這些資源的接口,一些只讀的接口,軟鏈接到一個叫public 的空間中,這個空間裡面其實我任意一個賬戶都是可以去訪問到的,對於合約來說很多地方都使用了這塊。
還有一部分就是我可能我希望我來控制你賬戶裡面的一些錢,他就會把部分的能力以接口的形式做了一個軟鏈接,保存到了private 空間中。軟鏈接就相當於是一個快捷方式,用這樣的形式將我的部分能力交付給了另外一個人。這樣通過更加直觀的交付部分能力的形式,將我的資源的使用權限借出去。
資源數據的轉移
為什麼以太坊或者說其他這種智能合約的交易調一個方法就可以解決,因為他們是中央賬本,他們的交易可能就是一個合約中釋放出來的某個方法,這個方法裡邊傳入某些參數執行的一些事情。
但Cadence 裡摒棄了中央賬本的模式,所以我們在對交易的體現上,交易也改造成了一個富邏輯的代碼片段,而不是Solidity 對於一個函數的簡單執行。同樣的交易本身也是Cadence 語言的一部分,所有的使用所有的代碼編寫,都需要對資源正確的使用,才能正常執行。
我們可以看到這個例子,這是一個非常典型的將某個人的錢轉給另外一個人的實現方式。在這邊my vault 裡邊取出來的10塊錢,到了一個臨時的vault 資源,臨時資源在執行的過程中轉移到了接收方的deposit 方法。臨時資源進去之後,充到receive的賬戶裡面之後就被銷毀了,在整個交易的過程中這個資源正常的被安排到了某個地方,這個交易才能正常執行。如果deposit 最後返回了一些內容的話,這個交易其實是連編譯都沒法通過的。整個的過程它始終要保持資源的正確才可以使用。這也是Cadence 從始至終貫徹的,對於資源需要非常慎重非常嚴格。
2、Cadence的解決方法
所以我們Cadence 是怎麼解決這些問題的?我們資產轉移的過程永遠是安全的,如果資源沒有被正確的使用,Cadence編譯器將拋出錯誤。
如果接收者沒有Vault,無論是因為地址錯誤還是該賬戶不想接收這些類型的數據,交易將會被回滾。所以Flow 上不存在0 地址銷毀。 Flow上的資源要銷毀的話,必須在交易中顯示的顯示的destroy。這樣的話就不存在數據因為發送地址拼寫錯誤而丟失。
五、Cadence相關工具鏈導覽
1、開發者工具
這是我們現在有的一些開發工具,我大概可以給大家過一下
-
第一步入門,playground 是一個非常和友好的面向初學者快速去學習Cadence 的一個網站。還有一個有比較有趣的叫CryptoDappy 的視頻,這個是要有一定的基礎的開發者去學習可能會好一點。
-
第二步可能就要進入到我們的本地開發,本地開發的時候就會涉及到我們的命令行工具,我們的模擬器和我們的VSCode 。模擬器我覺得最值得說的一個點就是他在做其他的合約,或者說其他的鏈的開發的時候,就可能先跑一個測試節點,跑一個測試鏈。然後Flow 為了方便開發者開發其實就規避了這件事情。
我們直接做了一個本地化的工具直接模擬出了區塊鏈的一些節點內容,它具備大多數區塊鏈相同的功能,當你發消息過去的時候,它會將你發過去交易打包成塊,這樣的話好處就是我們不需要有一個非常大的節點始終在那邊跑著,只需要有一個非常類似於節點的環境跑著,然後當我有需要的時候發一筆交易,那邊給你一個反饋就行了,因為本質上區塊鏈就是一個狀態管理的數據庫。
-
第三步完成了功能測試之後,會要使用的一些工具,包括我們的區塊鏈瀏覽flowscan,包括我們的前端接入庫和後端接入庫。這裡面其實我還要特地要說一下FCL 這個東西,就是大家接觸以太坊的人都知道,現在並沒有一個非常標準的規範來說我怎麼來方便的去接入不同的用戶,作為一個應用方,我想接入這些錢包其實是一個很痛苦的事情。所以Flow設計了一套標準FCL。這套FCL的標準不僅僅定義了前端該怎麼接,它同時也定義了錢包該怎麼接。
當我的錢包它提供了足夠的API和對於FCL 兼容的響應請求的內容呈現之後,FCL 就成為了一個連接錢包應用和區塊鏈三位一體連接在中心的一個標準化的框架。在這樣一個框架下,前端應用是不需要關心我後面到底接的是哪個類型的錢包。 FCL 定義好了前端的標準,我只要調用FCL 裡面的特定的一些內容,然後傳一個參數告訴你我要使用哪類型的錢包就行了。
而錢包在接入FCL 的時候,只要完成了FCL 標准定義下的那些要求,錢包也能快速的接入。這樣最大的好處有兩件事情。對於應用方來說,應用方不需要關心我到底是要接哪個錢包,未來只要是能適配到FCL 的都可以用。而對於錢包開發方來說,只要有足夠支持FCL 的應用,這個應該就可以使用他的錢包。
2、學習路徑圖
以上就是我今天的所有分享內容,謝謝大家。
展開全文打開碳鏈價值APP 查看更多精彩資訊