Sub0 開發(fā)者大會 Patract 篇:Wasm 智能合約



Jupiter
Ask!

Redspot
Metis
Europa
Parascan
Himalia
我們中的許多人都玩過 Ink!。然而,WASM 的一大優(yōu)勢是 WASM 支持編譯成它的編程語言。墨水!很好,但它需要開發(fā)人員熟悉 Rust 作為先決條件。因此,我們創(chuàng)建了 Ask! 這是一種類似于ink! 的eDSL。有了 ask!,任何有 typescript 或 AssemblyScript 經(jīng)驗的人都可以輕松開發(fā) WASM 智能合約??偟膩碚f,我們正在努力將 Solidity 風(fēng)格的開發(fā)引入 Substrate。
eDSL
整體布局類似 ink!
AssemblyScript中的語法
Decorator
類似于ink!中的宏,Ask!提供裝飾器。這給出了非常相似的代碼布局。
高水平的抽象,開發(fā)者可以專注于合約邏輯,而不必學(xué)習(xí)如何與主機(jī)函數(shù)和 pallet-contract 進(jìn)行交互。所有復(fù)雜的東西都由 Ask!在引擎蓋下完成。
Storage
SpreadStorableMap
SpreadStorableArray
PackedStorableMap
PackedStorableArray 當(dāng)需要存儲大量數(shù)據(jù)時,應(yīng)該使用 Spread。當(dāng)你存儲少量數(shù)據(jù),并需要訪問大部分內(nèi)容時,比如搜索或統(tǒng)計邏輯,選擇Packed可能會更好。
接口和繼承
Solidity 開發(fā)人員可以很快習(xí)慣使用Ask!
支持類似于 Openzeppelin 的標(biāo)準(zhǔn)合約庫。
正在開發(fā)中
目前我們的版本是 v0.2,很快就會發(fā)布 v0.3。
模板
基于合約標(biāo)準(zhǔn),自動生成合約樣本、部署腳本、測試腳本和 Redspot 配置。例如。npx redspot-new erc20將創(chuàng)建一個帶有 ERC20 代碼、部署和測試的目錄。你不不要手動編寫部署和配置。我們正在將更多的模板集成到 Redspot 中。所以在未來,你可以用一個命令啟動任何合約站。
npx 支持,無需額外設(shè)置。
編譯
包裝 cargo-contract。 npx redspot compile。npx redspot 編譯器將編譯代碼并放入對應(yīng)的目錄進(jìn)行部署。
部署
上傳合約并使用腳本將其實例化。
npx redspot run scripts/deploy.ts --no-compile
測試
使用腳本測試合約方法。 npx redspot test --no-compile
控制臺
用于集成測試的強(qiáng)大 JavaScript 交互式控制臺。
控制區(qū)塊鏈操作。
在編寫詳細(xì)的測試代碼之前,你可以在控制臺中進(jìn)行發(fā)揮,了解 Redspot 的工作原理。了解如何測試你的合約等。
npx redspot explorer
Docker
很多時候,一個合約將部署在多個區(qū)塊鏈上,Redspot 與 Docker 集成,允許一個合約在多個平臺上進(jìn)行測試。 啟動 Docker: npx redspot testnet 在 Docker 上編譯: npx redspot compile --docker true。
插入
不足以滿足你的開發(fā)需求。
用自定義插件擴(kuò)展 Redspot,增加更多功能,與其他開發(fā)工具集成。
通過簡單地編寫你的自定義插件擴(kuò)展類型,來保持與自定義Substrate鏈的兼容
瀏覽器 GUI
@polkadot/apps ,但重點是合約。
與 Redspot 配置完全集成,一旦你設(shè)置了測試區(qū)塊鏈,就不需要更多的操作。
目前在 ink! 開發(fā)時的問題

缺乏標(biāo)準(zhǔn)庫使得智能合約不安全。由于智能合約中的錯誤,2016 年的 DAO 攻擊竊取了 360 萬個 ETH。這次攻擊對以太坊主網(wǎng)非標(biāo)準(zhǔn)化合約強(qiáng)制硬分叉,造成了巨大的經(jīng)濟(jì)損失,并進(jìn)一步影響區(qū)塊鏈的共識。想象一下,在 2021 年,人們真的會質(zhì)疑你的區(qū)塊鏈的安全性,即使那是由合約開發(fā)者造成的。
開發(fā)者必須手動復(fù)制/粘貼現(xiàn)有的實現(xiàn)
源代碼可能是未經(jīng)審計的,且使用起來不安全。 想象一下從另一個智能合約項目復(fù)制代碼。他們的合約可能有尚未被注意到的錯誤。肆無忌憚地復(fù)制他們的代碼可能會在未來造成巨大的問題。
在此過程中費(fèi)時費(fèi)力,且容易出錯。 復(fù)制粘貼時可能會漏掉一些邏輯。
或者你誤解了他們的邏輯,因為他們可能沒有正確地命名他們的函數(shù)。
你浪費(fèi)了大量時間來更新他們的合約,每次發(fā)布都重復(fù)復(fù)制和粘貼
介紹 Metis
為了徹底解決上述問題,我們創(chuàng)建了 Metis。
基于可重復(fù)使用的組件的標(biāo)準(zhǔn)合約庫。 與 Openzeppelin 的繼承模型不同,Metis 是基于組件的,這意味著用戶不會直接繼承標(biāo)準(zhǔn)實現(xiàn)。相反,Metis 提供了一組可重用的組件供用戶組裝。
Metis vs OpenZepplin
繼承——由 Openzeppelin 使用 優(yōu)點:簡單—— 最小化為開發(fā)人員編寫的代碼。
缺點:模糊性——隱藏方法的定義;不確定的繼承樹與多個繼承關(guān)系。 例如,在 OpenZepplin 中,當(dāng)你有多個繼承時,你可能很難確定該方法是從哪個父合約中繼承的。
組合——由 Metis 使用 優(yōu)點:明確性——提高代碼可讀性和可聽性,用戶可以交互的所有功能都被編碼到位,這使得代碼審計更容易。
缺點:重復(fù)性——為現(xiàn)有實現(xiàn)重復(fù)編寫相同的代碼。
MCCI 架構(gòu)
數(shù)據(jù)模型——存儲。
組件——實現(xiàn)。
控制器——結(jié)合不同的組件,ERC20Pausbale -> ERC20, pausable, ownable。
接口——不可變和可變功能,用戶交互。

Metis—vs Native ink?。⊿torage)
用戶不再需要自己聲明變量了。
標(biāo)準(zhǔn)化數(shù)據(jù)結(jié)構(gòu)。 讓 Dapp 的開發(fā)者更容易熟悉接口。

Metis—vs Native ink?。?/span>Constructor)
跳過變量初始化的過程。
無需手動觸發(fā)事件。 開發(fā)者可能會忘記觸發(fā)事件,這將導(dǎo)致區(qū)塊鏈瀏覽器無法捕捉更改,并讓用戶很難驗證他們的交易。

Metis—vs 原生 ink!(Event)
由于 ink! 的當(dāng)前設(shè)計,Event 的寫法幾乎保持不變。在不久的將來會有所緩解。 我們將使用宏來自動生成基于 Metis 組件的事件。例如,如果你有一個名為 ERC20Pausable 的合約,我們將生成包括在存儲聲明中的所有事件。

ink!Metis—vs 原生 ink?。∕essage)
Metis實現(xiàn)包含默認(rèn)方法實現(xiàn),確保余額轉(zhuǎn)移的安全性。 例如,檢查余額。 注意實現(xiàn)中可能存在的所有注意事項。
允許開發(fā)者更多地關(guān)注他們的核心邏輯。

設(shè)計原則
在軟件設(shè)計中重寫函數(shù)顯得很愚蠢。
在右側(cè)寫代碼。 更加自然。
跳過編寫所有冗余的代碼。
實例化是指在區(qū)塊鏈上創(chuàng)建一個智能合約的實例。
調(diào)用另一個實例的方法意味著調(diào)用另一個合約方法。
跨合約調(diào)用以最終會產(chǎn)生錯誤的結(jié)果。

多個組件的組成
無需在存儲中列出所有需要的變量。
按需組合,創(chuàng)造更多可能性。

開箱即用的本地測試網(wǎng)
Europa 是 Subtrate 區(qū)塊鏈的另一個實現(xiàn),特別關(guān)注于智能合約的開發(fā)。
為了更好的開發(fā)體驗,我們?nèi)サ袅斯沧R。原因是當(dāng)我們使用 Canvas 開發(fā)合約時,我們發(fā)現(xiàn)自動生成的區(qū)塊真的很困擾我們。因此,Europa 只有在收到新的用戶簽名交易時才會生成區(qū)塊。
沒有 Wasm Runtime 。雖然 Wasm Runtime 很好,因為它不允許硬分叉區(qū)塊鏈升級,但它給調(diào)試合約執(zhí)行帶來了更多困難。
狀態(tài) KV 數(shù)據(jù)庫。當(dāng)新的區(qū)塊被挖掘時,這個額外的數(shù)據(jù)庫會跟蹤所有的狀態(tài)變化。當(dāng)我們在調(diào)試智能合約時非常有用,因為我們可以確定合約真正改變了區(qū)塊鏈的底層狀態(tài)。
修改 contract-pallet。現(xiàn)在,運(yùn)行 Wasm 智能合約對于合約開發(fā)者來說就像一個黑匣子,因為它不會打印出所有的執(zhí)行細(xì)節(jié)。因此,我們修改contract-pallet ,允許節(jié)點打印出所有執(zhí)行細(xì)節(jié)。

Europa UI

Europa UI - 演示
檢查所有狀態(tài)變化。
進(jìn)行 RPC 調(diào)用。
使用跟蹤進(jìn)行 RPC 調(diào)用,以獲取更多關(guān)于合約執(zhí)行的見解。
嵌套合約調(diào)用可能非?;靵y。
清楚地說明了跨合約調(diào)用的工作原理。

Europa CLI
自定義 RPC europa_forwardToHeight:將區(qū)塊鏈轉(zhuǎn)發(fā)到一個指定的高度。
europa_backwardToHeight:將區(qū)塊鏈還原到一個指定高度,并刪除該高度之后的所有區(qū)塊鏈狀態(tài)。
europa_modifiedStateKvs:獲取所有區(qū)塊鏈狀態(tài)變化。
自定義命令 狀態(tài) - kv:與 RPC 相同:europa_modifiedStateKvs -> 獲取所有區(qū)塊鏈狀態(tài)變化。
工作區(qū) - 允許開發(fā)者針對不同的測試場景切換到不同的工作區(qū)。
合約執(zhí)行的詳細(xì)日志記錄: 它將在合約執(zhí)行期間跟蹤和打印所有參數(shù)和區(qū)塊鏈變化。
提供 Wasm panic 回溯以準(zhǔn)確定位智能合約中發(fā)生錯誤的位置。

演示

npx redspot-new erc20
記得修改cargo.toml中的依賴關(guān)系,從crate.io拉取,否則會與polkadot.js產(chǎn)生兼容問題。ink!更新速度很快,如果我們直接從 ink! git 拉取,會產(chǎn)生兼容問題。我們也看到 Polkadot/app 的問題,但通常它很快就會被修復(fù)。
ink_primitives = { version = "3.0.0-rc5", default-features = false }ink_metadata = { version = "3.0.0-rc5", default-features = false, features = ["derive"], optional = true }ink_env = { version = "3.0.0-rc5", default-features = false }ink_storage = { version = "3.0.0-rc5", default-features = false }ink_lang = { version = "3.0.0-rc5", default-features = false }
redspot.config.ts: 包含 Redspot 的所有配置,例如網(wǎng)絡(luò)配置。
scripts/deploy.ts: 是將合約部署到區(qū)塊鏈的部署腳本。
tests: 包含所有為集成測試編寫的測試。
Windows 10 (21H1 及以上) europa-ui-v0.3.32-x86_64-win.exe(https://github.com/patractlabs/europa-ui/releases/download/v0.3.32/europa-ui-v0.3.32-x86_64-win.exe)。
MacOS(10.15.7 及以上)europa-ui-v0.3.32-x86_64-darwin.dmg(https://github.com/patractlabs/europa-ui/releases/download/v0.3.32/europa-ui-v0.3.32-x86_64-darwin.dmg)。
Ubuntu(20.04 及以上)europa-ui-v0.3.32-x86_64-linux.AppImage(https://github.com/patractlabs/europa-ui/releases/download/v0.3.32/europa-ui-v0.3.32-x86_64-linux.AppImage)。
對于 Ubuntu,記得給它權(quán)限
chmod +x europa-ui-v0.3.32-x86_64-linux.AppImage。
只需雙擊該圖標(biāo)即可啟動它。確保默認(rèn)端口沒有被占用。
單擊開始以啟動節(jié)點。
px redspot run scripts/deploy.ts
打開 Europa-UI,你應(yīng)該可以看到合約已經(jīng)部署成功。
你可以使用back to Block 來恢復(fù)區(qū)塊鏈并刪除已部署的測試合約。
cp -R contracts ink_contracts讓我們細(xì)致的研究下引入metis后合約代碼實現(xiàn)的區(qū)別: Cargo.toml:導(dǎo)入我們將使用的 Metis 組件。注意 metis_lang 是使用 Metis 的項目的必備條件。另外,注意我們使用的是分支,因為 ink! 的更新非常頻繁,為了與 ink! 保持兼容,我們有相應(yīng)的 Metis 版本。 lib.rs: 我們從 Metis 導(dǎo)入所有依賴項,而不僅僅是use ink_lang as ink;
Storage:我們不再聲明我們自己的變量,而是復(fù)合了多個 Metis 組件。
Event:不幸的是,我們?nèi)匀恍枰獮槭录帉懰写a。在 Metis 的下一個版本中,我們將使 Metis 生成這些事件,只要我們在存儲中聲明了它們。
Message:我們不再需要自己去實現(xiàn)函數(shù),我們可以使用 Metis 的默認(rèn)植入方式。
Constructor:這些函數(shù)沒有暴露給區(qū)塊鏈上的用戶,Metis 的宏會自動生成其中的大部分。所以我們不再需要自己編寫它們。
Metis 的組成特點:
正如我們在PPT中提到的,Metis 允許用戶根據(jù)需要輕松地將不同的組件組合起來。 擴(kuò)展: hook:你可能會問為什么我們沒有在我們的方法實現(xiàn)中添加特定的邏輯來暫停傳輸。那是因為我們在 Metis 中使用 hook,并且對于每個組件,我們都有一個實現(xiàn) hook 的擴(kuò)展列表。
ERC20 擴(kuò)展:https://github.com/patractlabs/metis/blob/main/crates/components/token/erc20/src/extensions/pausable.rs。該擴(kuò)展覆蓋了before_token_transferhook ,并在其中添加了邏輯。所以我們不再需要在擁有的每個傳遞函數(shù)中實現(xiàn)可暫停的邏輯。
cd contractscargo +nightly contract build --keep-debug-symbols --optimization-passes=0
這將在調(diào)試模式下構(gòu)建合約并保留所有調(diào)試符號。
mkdir ../artifactscp ./target/ink/erc20_pausable.contract ../artifacts/cp ./target/ink/metadata.json ../artifacts/erc20_pausable.json
7.編寫部署腳本。
從deploy.ts復(fù)制代碼。
npx redspot run scripts/deploy.ts --no-compile打開 Europa-UI, 查看合約是否部署成功。
從test(https://github.com/bonanyuan/sub0_erc20_pausable/blob/main/tests)中復(fù)制所有代碼文件。 npx redspot test ./tests/erc20_pausable_init.test.ts --no-compile 測試合約實例化。 npx redspot test ./tests/erc20_pausable_ownable.test.ts --no-compile所有者被初始化為發(fā)件人的地址。 非所有者將能夠放棄所有權(quán)。 所有者應(yīng)該能夠放棄所有權(quán)。 非所有者不能夠轉(zhuǎn)讓所有權(quán)。 所有者可以轉(zhuǎn)讓其所有權(quán)。 npx redspot test ./tests/erc20_pausable_init.test.ts --no-compile默認(rèn)暫停狀態(tài)為 false。 非所有者應(yīng)該能夠暫停。 所有者應(yīng)該能夠暫停。 所有者可以取消暫停。 沒有暫停的傳輸應(yīng)該是成功的。 有暫停的傳輸應(yīng)該是失敗的。

從EVM到Wasm的范式轉(zhuǎn)換,為什么波卡會成為公鏈的常青樹?

