一文帶你讀懂如何在ChainX上部署智慧合約

買賣虛擬貨幣
執行節點1. 接入測試網請參考加入 ChainX 測試網的相關說明:完成相關配置後,應保證節點同步到最新,錢包相應配置完成。2. 執行本地節點請參考 ChainX Dev 模式的相關說明:
完成相應配置後,請保證已經出塊超過150個區塊,因為150個塊後才會對 Alice 發放第一層次獎勵。若需要反覆測試,可以對超過150個塊後的區塊資料進行備份,若需重新啟動,則只需要刪除老資料目錄,使用備份資料目錄替換即可。ChainX 上的 Substrate Contracts 智慧合約平臺Substrate 作為第一個區塊鏈領域的技術框架,讓開發者能夠專注於鏈的執行時邏輯,而不用再花費大量的時間精力構建區塊鏈底層的基礎設施。此外, Substrate 預設提供了很多功能模組,比如 Staking, Consensus, 方便框架使用者根據自己的需求進行自由組合和定製。合約模組就是其中的一個功能模組,不管是任何一條基於 Substrate 技術的獨立鏈,還是未來的平行鏈, 只要整合了合約模組,就可以成為一個智慧合約平臺。本次 ChainX 智慧合約平臺的主要實現方式就是整合 Substrate 的合約模組,並進行適配。ChainX 的合約功能與 Substrate 預設的合約模組主要區別如下:1. 取消合約儲存收費的設計。 合約儲存收費簡單來說就是當合約部署到鏈上以後, 根據該合約在鏈上所佔儲存的大小和該儲存的佔用時間收取一定的費用,當合約賬戶因為餘額不夠無法支援儲存費用時,合約就會被刪除,甚至可能無法恢復。 即使合約被刪除後可以恢復,目前的合約恢復可操作性也是極低,可能會對目前的合約開發造成極大的困擾。因此,我們目前決定暫時取消合約儲存收費,只收取合約呼叫的 Gas 費用, 也就是與目前以太坊的收費設計一致。當合約儲存收費的模型成熟後,可以重新啟用這個設計。
2. 使用適配後的 chainx-org/ink 編寫合約。 chainx-org/ink fork 自 paritytech/ink, 主要改動在於引入了 DefaultXrmlTypes 替代 DefaultRrmlTypes來適配 ChainX 的 runtime:· 關聯型別 Balance 從 u128 改為 u64.· 適配關聯型別 Call 以支援 PCX 轉賬和將跨鏈資產劃轉過去的 XRC20 Token 轉回 ChainX 跨鏈資產, 合約開發者可以基於 PCX 和 ChainX 的跨鏈資產設計自己的 Dapp。除了以上兩點改動,在合約編寫上與 paritytech/ink 保持一致,目前合約寫法仍然採用 ink1.0 的寫法,後續我們將會升級使用 ink2.0.ink 合約編寫相關資源:· substrate-contracts-workshop: ink 官方教程 
· polkaworld-org/workshop: polkaworld 合約相關技術講座與 Gas 相關的引數配置Schedule {    version: 0, // 配置版本    put_code_per_byte_cost: 200, // 設定wasm程式碼時,每位元組需要的Gas    grow_mem_cost: 1,  // 單頁中記憶體增值需要的Gas
    regular_op_cost: 1,  // 普通運算子Op需要的Gas    return_data_per_byte_cost: 1, // 返回值每位元組消耗的Gas,因此對於合約見互相呼叫應仔細設計這個值    event_data_per_byte_cost: 20,  // 合約中 event 每位元組消耗的Gas    event_per_topic_cost: 1, // 合約中 event 每個topic消耗的Gas    event_base_cost: 1, // 合約中每個event要消耗的基礎Gas,例如每打一個event就要先減少這個值的Gas    call_base_cost: 60000, // 呼叫合約或合約呼叫合約消耗的基礎Gas,例如每呼叫一個合約函式需要減少這個值的Gas
    instantiate_base_cost: 200000, // 合約初始化(例項化)消耗的基礎Gas    sandbox_data_read_cost: 1, // 合約中讀取一個位元組消耗的Gas    sandbox_data_write_cost: 1, // 合約中寫入一個位元組消耗的Gas    max_event_topics: 4,  // 一次呼叫中最多可以打的event個數    max_stack_height: 64 * 1024, // 合約中棧的最大值    max_memory_pages: 16, // 合約執行中最大的頁數
    max_table_size: 16 * 1024, // 合約中最大資料結構表數    enable_println: false, // 是否允許合約中出現 print    max_subject_len: 32, // 最大的PRNG subject數}當前 ChainX 中預設的 Gas Price 為5其中請留意put_code_per_byte_cost,call_base_cost,instantiate_base_cost。因此在 ChainX 中:
· 設定 WASM 合約程式碼的代價比較大,因此建議合約開發者仔細設計及模組化自己的合約程式碼,不鼓勵過多的設定合約程式碼· 例項化一個合約的代價稍大,因此建議合約開發者儘量重用已例項化過的合約例項· 呼叫一個合約的代價一般,因此建議合約開發者精簡自己的合約,集中在一個合約中處理邏輯。· Event 最多隻能打4個,因此需要合約開發者小心設計 Event。部署及呼叫合約對於部署及呼叫合約,請參考 ChainX 的錢包相關部分:
· 合約功能部分· 合約開發獨立部署元件開發除錯合約開發除錯合約我們強烈建議:1. 合約開發者在 ChainX Dev 節點下開發除錯合約,因為很多錯誤資訊只會在節點日誌中出現。2. 在 Dev 模式下可以在合約中使用env.println,而在主網和測試網中一定要將合約中的env.println刪除。
3. 合約無論是執行還是方法的返回值都可以透過 RPC 在不打包的情況下呼叫,建議合約開發者可以先使用 rpc 呼叫模擬合約執行情況一些異常錯誤日誌中與合約相關的日誌均含有[runtime|xrml_xcontracts]欄位,因此若只關心合約及合約執行結果,只需要對日誌 grep:· tail -f log/chainx.log | egrep "xcontracts|apply_extrinsic"若設定,部署,呼叫合約不成功,可以參考如下問題列表:1. 設定合約程式碼相關
1. 合約部署時 gas limit 提供的不夠[runtime|chainx_runtime::xexecutive|183L] [apply_extrinsic] failed: there is not enough gas for storing the code因為 ChainX 中put_code_per_byte_cost設定得比較大,因此合約部署者應注意部署合約時提供的 gas limit 是否足夠。一般情況下應大於len(wasm) * put_code_per_byte_cost2. wasm 合約時,在元件間呼叫時因 wasm 過大,導致 wasm 被裁剪,部署不完整 wasm[runtime|chainx_runtime::xexecutive|183L] [apply_extrinsic] failed: Can't decode wasm code此時請檢查元件呼叫是否會裁剪 wasm
3. wasm 合約已經存在於鏈上,對於相同的合約,不應該重複設定程式碼[runtime|chainx_runtime::xexecutive|183L] [apply_extrinsic] failed: the code is already stored on chain開發者自己編寫工具時,請一定在上傳程式碼前透過 sdk 的相關介面檢查合約是否已經在鏈上。4. 合約中含有ext.print,在自己測試能部署,在測試網與主網上不能部署[runtime|chainx_runtime::xexecutive|183L] [apply_extrinsic] failed: module imports `ext_println` but debug features disabled請注意在測試網和主網中,一定要將ext.print從合約中刪除,或者使用條件編譯控制
2. 部署合約程式碼相關1. 合約例項已經存在,請勿重複例項化。[runtime|chainx_runtime::xexecutive|183L] [apply_extrinsic] failed: Alive contract or tombstone already exists在 ChainX 合約(Substrate Contracts)模型中,生成合約地址的方式為:hash(code_hash + hash(input_data) + deployer)因此相同的部署者對於相同的一份合約使用相同的例項化引數,最後的合約結果都是一樣的。若需要用相同的 wasm 程式碼,相同的引數例項化另一個例項,請換一個賬戶
2. 引數傳遞錯誤,或者在例項化過程中崩潰,無法例項化[runtime|chainx_runtime::xexecutive|183L] [apply_extrinsic] failed: during execution|Failed to invoke an exported function for some reason|wrong selector, decode params fail or inner error請檢查引數和合約程式碼,如:· 例項化接收的引數是 u128,但是傳遞過去的是 u64· 合約中的儲存未初始化就進行加減操作/溢位/有 panic 異常...3. 部署達到了 gas limit
錯誤見下文3. 呼叫合約程式碼相關1. 合約呼叫或內部崩潰[runtime|chainx_runtime::xexecutive|183L] [apply_extrinsic] failed: during execution|Failed to invoke an exported function for some reason|wrong selector, decode params fail or inner error· 呼叫合約傳遞的 selector 不匹配,或引數編碼錯誤selector 請一定按照編譯合約生成的的abi.json或者old_abi.json去呼叫,若使用不存在的 selector 則會呼叫不成功。編碼錯誤同理
· 呼叫的方法中出現異常,如使用未初始化儲存struct Incrementer {value: storage::Value<u32>,}impl Deploy for Incrementer {    fn deploy(&mut self) {
        // not init value}}impl Incrementer {   /// Flips the current state of our smart contract.   pub(external) fn inc(&mut self, by: u32) {
       // 在日誌中能看得到這一句日誌       env.println(&format!("Incrementer::inc by = {:?}", by));       self.value += by;  // 呼叫未初始化的儲存   }}因此需要除錯是因為引數 /selector 錯誤還是合約內部出錯,請在合約內部打日誌即可判定
· 溢位或 panic具體請參考程式碼2. 呼叫過程中達到了 gas limit[runtime|chainx_runtime::xexecutive|183L] [apply_extrinsic] failed: during execution|Failed to invoke an exported function for some reason|reach gas limit請透過 rpc 介面chainx_contractCall在非打包過程中去嘗試得到適合的gas limit,建議覆蓋合約執行中最遠的執行分支。透過 grep 日誌:
[runtime|xrml_xcontracts::gas] [refund_unused_gas]|account:88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee (5SjUJPJJ...)|gas_payment:2500000|refund:0|real cost:2500000|gas_spent:500000可以看到這次呼叫中的 gas 耗費,其中注意該部分消耗指的是在合約中的 Gas 執行的消耗,真實支付的 PCX 還要再加上呼叫合約方法的外部手續費。· gas_payment為gas_limit*gas_price的值,是呼叫者暫存的 PCX· refund是執行完成後返回的 PCX· real cost是真實消耗的PCX
· gas_spent是消耗的 gasChainX 智慧合約中的跨鏈資產當前 ChainX 智慧合約中只支援比特幣ChainX 智慧合約中多幣種的實現方式由於 Substrate Contracts 智慧合約平臺模型與以太坊智慧合約模型相似,對於多幣種的處理是“本幣+代幣”模型。針對這種模型,ChainX 的智慧合約上的跨鏈資產採用合約代幣模型,因此在 ChainX 上 PCX 將會類似以太坊一樣對智慧合約提供 gas 及本幣流通的價值,對於 ChainX 上的跨鏈資產以合約代幣的形式引入。
使用代幣模型而不是將多幣種直接引入合約基於如下考慮:1. 以太坊代幣合約已經比較成熟,因此對於合約開發者在代幣模型下可以比較容易的將以太坊合約遷移到 ChainX 智慧合約平臺上。2. 若在合約中引入多幣種的概念,將會極大修改 Substrate Contracts 的模型,容易引入非預期問題。當前 ChainX 實現智慧合約中的比特幣採用 XRC20 模型,根據合約開發者的反饋,將來也可採用其他標準。目前已經考慮的代幣模型有:XRC20 (原以太坊 ERC20)XRC721 (原以太坊 ERC721)
XRC777 (原以太坊 ERC777)ChainX 資產中的多幣種與合約中代幣的轉換ChainX 上的比特幣 X-BTC

當前 X-BTC 對應於智慧合約平臺中採用的代幣模型為 XRC20。使用者可以自由發起交易讓 ChainX 的 X-BTC 與合約平臺中的 XRC20 互相轉換。

其中 ChainX 修改了 ERC20 合約標準(XRC20),新增了issue,destroy兩個介面。並首先將一個合約部署到鏈上並例項化,同時在鏈上唯一指定了這個合約例項,因此除指定的例項以外的代幣例項均不被 ChainX 的 Runtime 承認

其中:

· issue 只能被 Runtime 中的交易convert_to_xrc20呼叫,不可透過直接呼叫合約方法呼叫。透過交易convert_to_xrc20呼叫後,將會把該使用者的資產轉移到合約例項下,並在合約中對該傳送交易的賬戶自動發放相應的金額。

· destroy 能被使用者呼叫,用於將合約中的資產轉移到 ChainX 資產模組中。其中首先銷燬了合約中對應的代幣,然後合約中會自動呼叫convert_to_assets將資產從合約中返回給使用者,而convert_to_assets不可透過外部交易呼叫。

ChainX 上的 XRC20

XRC20 專案

部署於 ChainX 上的 XRC20 專案為:

https://github.com/chainx-org/xrc20

針對 XRC20,ChainX 已經提供了2個對應的 RPC 可進行操作:

· chainx_contractXRCTokenInfo
· chainx_contractXRC20Call

ChainX 錢包匯入 XRC20 abi

當前錢包還未整合 XRC20 的 abi,因此需要開發者手動新增。

1. 獲取鏈上指定的 XRC20-BTC 合約例項地址:
呼叫 rpc chainx_contractXRCTokenInfo 可在返回值中看到鏈上已經存在的 XRC20-BTC 合約地址公鑰

2. 參考[合約功能部分|例項化合約]( wallet#2. 例項化合約(部署合約))部分的第3節,透過“新增已存在的合約”的方式,將該 ERC20-BTC 合約地址的公鑰填入,然後在 XRC20 專案中的target/abi.json的 abi 檔案上傳即可新增該合約例項。

主網與測試網-道

對於主網與測試網-道,該針對 X-BTC 的合約例項已經部署且被設定完成。合約開發者或使用者只需要在合約平臺上匯入該專案中的abi 檔案target/abi.json即可呼叫合約。其中該XRC20的地址可以透過rpc chainx_contractXRCTokenInfo 獲取到。

ChainX Dev 節點

對於 ChainX Dev 節點而言,該合約沒有被內建。因此若需要除錯和智慧合約上的比特幣相關操作,需要:

· 在 ChainX Dev 中設定 XRC20-BTC 合約
· 發放測試使用的假 X-BTC

在xrc20專案中已經提供了一個指令碼執行這兩件事情,詳情請參考 README。

該指令碼預設使用 Alice 的私鑰(見 ChainX Dev 模式的開頭部分)執行。請注意執行該指令碼至少需要等待已經出了150個區塊後( Alice 才會具備資產執行交易)。

若 PCX 不足,該指令碼也提供了從 Alice 驗證者領取獎池的操作。

錢包功能

ChainX 新錢包中提供了 ChainX 的跨鏈資產 X-BTC 與合約中的 XRC20-BTC 互相劃轉的功能,參考 ChainX 錢包連結

ChainX 智慧合約的部署即測試

智慧合約的部署及呼叫請參考 ChainX 錢包部分。

測試請參考 ChainX Dev 模式|除錯合約部分。

相關連結:

ChainX 測試網:
https://github.com/chainx-org/ChainX/wiki/Join-ChainX-Testnet

ChainX 錢包:
https://github.com/chainx-org/ChainX/wiki/wallet#ChainX

ChainX Dev 模式:
https://github.com/chainx-org/ChainX/wiki/ChainX-Dev

幫助開發者部署合約的工具:
https://dapps.chainx.org.cn/contract

chrome 外掛安裝地址:
https://chrome.google.com/webstore/detail/chainx-extension/dffjlgnecfafjfmkknpipapcbgajflge

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;