亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Solidity的高級特性怎么使用

發布時間:2021-12-07 15:12:15 來源:億速云 閱讀:143 作者:iii 欄目:互聯網科技

這篇文章主要介紹“Solidity的高級特性怎么使用”,在日常操作中,相信很多人在Solidity的高級特性怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Solidity的高級特性怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

前言

FISCO BCOS使用了Solidity語言進行智能合約開發。Solidity是一門面向區塊鏈平臺設計、圖靈完備的編程語言,支持函數調用、修飾器、重載,事件、繼承和庫等多種高級語言的特性。

合理控制函數和變量的類型

基于最少知道原則(Least Knowledge Principle)中經典面向對象編程原則,一個對象應該對其他對象保持最少的了解。優秀的Solidity編程實踐也應符合這一原則:每個合約都清晰、合理地定義函數的可見性,暴露最少的信息給外部,做好對內部函數可見性的管理。

同時,正確地修飾函數和變量的類型,可給合約內部數據提供不同級別的保護,以防止程序中非預期的操作導致數據產生錯誤;還能提升代碼的可讀性與質量,減少誤解和bug;更有利于優化合約執行的成本,提升鏈上資源的使用效率。

守住函數操作的大門:函數可見性

Solidity有兩種函數調用方式:

  • 內部調用:又被稱為『消息調用』。常見的有合約內部函數、父合約的函數以及庫函數的調用。(例如,假設A合約中存在f函數,則在A合約內部,其他函數調用f函數的調用方式為f()。)

  • 外部調用:又被稱為『EVM調用』。一般為跨合約的函數調用。在同一合約內部,也可以產生外部調用。(例如,假設A合約中存在f函數,則在B合約內可通過使用A.f()調用。在A合約內部,可以用this.f()來調用。)。

函數可以被指定為 external ,public ,internal 或者 private標識符來修飾。 Solidity的高級特性怎么使用

基于以上表格,我們可以得出函數的可見性 public > external > internal > private。

另外,如果函數不使用上述類型標識符,那么默認情況下函數類型為 public。

綜上所述,我們可以總結一下以上標識符的不同使用場景:

  • public,公有函數,系統默認。通常用于修飾可對外暴露的函數,且該函數可能同時被內部調用。

  • external,外部函數,推薦只向外部暴露的函數使用。當函數的某個參數非常大時,如果顯式地將函數標記為external,可以強制將函數存儲的位置設置為calldata,這會節約函數執行時所需存儲或計算資源。

  • internal,內部函數,推薦所有合約內不對合約外暴露的函數使用,可以避免因權限暴露被攻擊的風險。

  • private,私有函數,在極少數嚴格保護合約函數不對合約外部開放且不可被繼承的場景下使用。

不過,需要注意的是,無論用何種標識符,即使是private,整個函數執行的過程和數據是對所有節點可見,其他節點可以驗證和重放任意的歷史函數。實際上,整個智能合約所有的數據對區塊鏈的參與節點來說都是透明的。

剛接觸區塊鏈的用戶常會誤解,在區塊鏈上可以通過權限控制操作來控制和保護上鏈數據的隱私。

這是一種錯誤的觀點。事實上,在區塊鏈業務數據未做特殊加密的前提下,區塊鏈同一賬本內的所有數據經過共識后落盤到所有節點上,鏈上數據是全局公開且相同的,智能合約只能控制和保護合約數據的執行權限。

如何正確地選擇函數修飾符是合約編程實踐中的『必修課』,只有掌握此節真諦方可自如地控制合約函數訪問權限,提升合約安全性。

對外暴露最少的必要信息:變量的可見性

與函數一樣,對于狀態變量,也需要注意可見性修飾符。狀態變量的修飾符默認是internal,不能設置為external。此外,當狀態變量被修飾為public,編譯器會生成一個與該狀態變量同名的函數。

具體可參考以下示例:

Solidity的高級特性怎么使用

這個機制有點像Java語言里lombok庫所提供的@Getter注解,默認為一個POJO類變量生成get函數,大大簡化了某些合約代碼的書寫。

同樣,變量的可見性也需要被合理地修飾,不該公開的變量果斷用private修飾,使合約代碼更符合『最少知道』的設計原則。

精確地將函數分類:函數的類型

函數可以被聲明為pure、view,兩者的作用可見下圖。

Solidity的高級特性怎么使用

那么,什么是讀取或修改狀態呢?簡單來說,兩個狀態就是讀取或修改了賬本相關的數據。

在FISCO BCOS中,讀取狀態可能是:

  1. 讀取狀態變量。

  2. 訪問 block,tx, msg 中任意成員 (除 msg.sig 和 msg.data 之外)。

  3. 調用任何未標記為 pure 的函數。

  4. 使用包含某些操作碼的內聯匯編。

而修改狀態可能是:

  1. 修改狀態變量。

  2. 產生事件。

  3. 創建其它合約。

  4. 使用 selfdestruct。

  5. 調用任何沒有標記為 view 或者 pure 的函數。

  6. 使用底層調用。

  7. 使用包含特定操作碼的內聯匯編。

需要注意的是,在某些版本編譯器中,并沒有對這兩個關鍵字進行強制的語法檢查。

推薦盡可能使用pure和view來聲明函數,例如將沒有讀取或修改任何狀態的庫函數聲明為pure,這樣既提升了代碼可讀性,也使其更賞心悅目,何樂而不為?

編譯時就確定的值:狀態常量

所謂的狀態常量是指被聲明為constant的狀態變量。

一旦某個狀態變量被聲明為constant,那么該變量值只能為編譯時確定的值,無法被修改。編譯器一般會在編譯狀態計算出此變量實際值,不會給變量預留儲存空間。所以,constant只支持修飾值類型和字符串。

狀態常量一般用于定義含義明確的業務常量值。

面向切片編程:函數修飾器(modifier)

Solidity提供了強大的改變函數行為的語法:函數修飾器(modifier)。一旦某個函數加上了修飾器,修飾器內定義的代碼就可以作為該函數的裝飾被執行,類似其他高級語言中裝飾器的概念。

這樣說起來很抽象,讓我們來看一個具體的例子:

Solidity的高級特性怎么使用

如上所示,定義onlyOwner修飾器后,在修飾器內,require語句要求msg.sender必須等于owner。后面的"_;"表示所修飾函數中的代碼。

所以,代碼實際執行順序變成了:

  1. 執行onlyOwner修飾器的語句,先執行require語句。(執行第9行)

  2. 執行changeOwner函數的語句。(執行第15行)

由于changeOwner函數加上了onlyOwner的修飾,故只有當msg.sender是owner才能成功調用此函數,否則會報錯回滾。

同時,修飾器還能傳入參數,例如上述的修飾器也可寫成:

Solidity的高級特性怎么使用

同一個函數可有多個修飾器,中間以空格間隔,修飾器依次檢查執行。此外,修飾器還可以被繼承和重寫。

由于其所提供的強大功能,修飾器也常被用來實現權限控制、輸入檢查、日志記錄等。

比如,我們可以定義一個跟蹤函數執行的修飾器:

Solidity的高級特性怎么使用

這樣,任何用logMethod修飾器來修飾的函數都可記錄其函數執行前后的日志,實現日志環繞效果。如果你已經習慣了使用Spring框架的AOP,也可以試試用modifier實現一個簡單的AOP功能。

modifier最常見的打開方式是通過提供函數的校驗器。在實踐中,合約代碼的一些檢查語句常會被抽象并定義為一個modifier,如上述例子中的onlyOwner就是個最經典的權限校驗器。這樣一來,連檢查的邏輯也能被快速復用,用戶也不用再為智能合約里到處都是參數檢查或其他校驗類代碼而苦惱。

可以debug的日志:合約里的事件(Event)

介紹完函數和變量,我們來聊聊Solidity其中一個較為獨有的高級特性——事件機制。

事件允許我們方便地使用 EVM 的日志基礎設施,而Solidity的事件有以下作用:

  1. 記錄事件定義的參數,存儲到區塊鏈交易的日志中,提供廉價的存儲。

  2. 提供一種回調機制,在事件執行成功后,由節點向注冊監聽的SDK發送回調通知,觸發回調函數被執行。

  3. 提供一個過濾器,支持參數的檢索和過濾。

事件的使用方法非常簡單,兩步即可玩轉。

  • 第一步,使用關鍵字『event』來定義一個事件。建議事件的命名以特定前綴開始或以特定后綴結束,這樣更便于和函數區分,在本文中我們將統一以『Log』前綴來命名事件。下面,我們用『event』來定義一個函數調用跟蹤的事件:

event LogCallTrace(address indexed from, address indexed to, bool result)

事件在合約中可被繼承。當他們被調用時,會將參數存儲到交易的日志中。這些日志被保存到區塊鏈中,與地址相關聯。在上述例子中,用indexed標記參數被搜索,否則,這些參數被存儲到日志的數據中,無法被搜索。

  • 第二步,在對應的函數內觸發定義事件。調用事件的時候,在事件名前加上『emit』關鍵字:

Solidity的高級特性怎么使用

這樣,當函數體被執行的時候,會觸發執行LogCallTrace。

最后,在FISCO BCOS的Java SDK中,合約事件推送功能提供了合約事件的異步推送機制,客戶端向節點發送注冊請求,在請求中攜帶客戶端關注的合約事件參數,節點根據請求參數對請求區塊范圍的Event Log進行過濾,將結果分次推送給客戶端。更多細節可以參考合約事件推送功能文檔。在SDK中,可以根據事件的indexed屬性,根據特定值進行搜索。

合約事件推送功能文檔: https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/sdk/java_sdk.html#id14

不過,日志和事件無法被直接訪問,甚至在創建的合約中也無法被直接訪問。

但好消息是日志的定義和聲明非常利于在『事后』進行追溯和導出。

例如,我們可以在合約的編寫中,定義和埋入足夠的事件,通過WeBASE的數據導出子系統我們可以將所有日志導出到MySQL等數據庫中。這特別適用于生成對賬文件、生成報表、復雜業務的OLTP查詢等場景。此外,WeBASE提供了一個專用的代碼生成子系統幫助分析具體的業務合約,自動生成相應的代碼。

WeBASE的數據導出子系統: https://webasedoc.readthedocs.io/zh_CN/latest/docs/WeBASE-Collect-Bee/index.html 代碼生成子系統: https://webasedoc.readthedocs.io/zh_CN/latest/docs/WeBASE-Codegen-Monkey/index.html

在Solidity中,事件是一個非常有用的機制,如果說智能合約開發最大的難點是debug,那善用事件機制可以讓你快速制伏Solidity開發。

面向對象之重載

重載是指合約具有多個不同參數的同名函數。對于調用者來說,可使用相同函數名來調用功能相同,但參數不同的多個函數。在某些場景下,這種操作可使代碼更清晰、易于理解,相信有一定編程經驗的讀者對此一定深有體會。

下面將展示一個典型的重載語法:

Solidity的高級特性怎么使用

需要注意的是,每個合約只有一個構造函數,這也意味著合約的構造函數是不支持重載的。

我們可以想像一個沒有重載的世界,程序員一定絞盡腦汁、想方設法給函數起名,大家的頭發可能又要多掉幾根。

面向對象之繼承

Solidity使用『is』作為繼承關鍵字。因此,以下這段代碼表示的是,合約B繼承了合約A:

Solidity的高級特性怎么使用

而繼承的合約B可以訪問被繼承合約A的所有非private函數和狀態變量。

在Solidity中,繼承的底層實現原理為:當一個合約從多個合約繼承時,在區塊鏈上只有一個合約被創建,所有基類合約的代碼被復制到創建的合約中。

相比于C++或Java等語言的繼承機制,Solidity的繼承機制有點類似于Python,支持多重繼承機制。因此,Solidity中可以使用一個合約來繼承多個合約。

在某些高級語言中,比如Java,出于安全性和可靠性的考慮,只支持單重繼承,通過使用接口機制來實現多重繼承。對于大多數場景而言,單繼承的機制就可以滿足需求了。

多繼承會帶來很多復雜的技術問題,例如所謂的『鉆石繼承』等,建議在實踐中盡可能規避復雜的多繼承。

繼承簡化了人們對抽象合約模型的認識和描述,清晰體現了相關合約間的層次結構關系,并且提供軟件復用功能。這樣,能避免代碼和數據冗余,增加程序的重用性。

面向對象之抽象類和接口

根據依賴倒置原則,智能合約應該盡可能地面向接口編程,而不依賴具體實現細節。

Solidity支持抽象合約和接口的機制。

如果一個合約,存在未實現的方法,那么它就是抽象合約。例如:

Solidity的高級特性怎么使用

抽象合約無法被成功編譯,但可以被繼承。

接口使用關鍵字interface,上面的抽象也可以被定義為一個接口。

Solidity的高級特性怎么使用

接口類似于抽象合約,但不能實現任何函數,同時,還有進一步的限制:

  1. 無法繼承其他合約或接口。

  2. 無法定義構造函數。

  3. 無法定義變量。

  4. 無法定義結構體

  5. 無法定義枚舉。

合適地使用接口或抽象合約有助于增強合約設計的可擴展性。但是,由于區塊鏈EVM上計算和存儲資源的限制,切忌過度設計,這也是從高級語言技術棧轉到Solidity開發的老司機常常會陷入的天坑。

避免重復造輪子:庫(Library)

在軟件開發中,很多經典原則可以提升軟件的質量,其中最為經典的就是盡可能復用久經考驗、反復打磨、嚴格測試的高質量代碼。此外,復用成熟的庫代碼還可以提升代碼的可讀性、可維護性,甚至是可擴展性。

和所有主流語言一樣,Solidity也提供了庫(Library)的機制。Solidity的庫有以下基本特點:

  1. 用戶可以像使用合約一樣使用關鍵詞library來創建合約。

  2. 庫既不能繼承也不能被繼承。

  3. 庫的internal函數對調用者都是可見的。

  4. 庫是無狀態的,無法定義狀態變量,但是可以訪問和修改調用合約所明確提供的狀態變量。

接下來,我們來看一個簡單的例子,以下是FISCO BCOS社區中一個LibSafeMath的代碼庫。我們對此進行了精簡,只保留了加法的功能:

Solidity的高級特性怎么使用

我們只需在合約中import庫的文件,然后使用L.f()的方式來調用函數,(例如LibSafeMath.add(a,b))。

接下來,我們編寫調用這個庫的測試合約,合約內容如下:

Solidity的高級特性怎么使用

在FISCO BCOS控制臺中,我們可以測試合約的結果(控制臺的介紹文章詳見FISCO BCOS 控制臺詳解,飛一般的區塊鏈體驗),運行結果如下:

Solidity的高級特性怎么使用

通過以上示例,我們可清晰了解在Solidity中應如何使用庫。

類似Python,在某些場景下,指令『using A for B;』可用于附加庫函數(從庫 A)到任何類型(B)。這些函數將接收到調用它們的對象作為第一個參數(像 Python 的 self 變量)。這個功能使庫的使用更加簡單、直觀。

例如,我們對代碼進行如下簡單修改:

Solidity的高級特性怎么使用

驗證一下結果依然是正確的。

Solidity的高級特性怎么使用

到此,關于“Solidity的高級特性怎么使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

拜城县| 中阳县| 家居| 东兰县| 顺昌县| 宁津县| 抚远县| 容城县| 徐州市| 浙江省| 深泽县| 平江县| 潼南县| 东城区| 根河市| 庆元县| 衡南县| 高要市| 宜君县| 于田县| 石屏县| 夹江县| 德阳市| 桃源县| 定陶县| 阳新县| 芜湖市| 南江县| 凌云县| 德化县| 四子王旗| 固镇县| 墨玉县| 金堂县| 毕节市| 洪洞县| 钟祥市| 舒城县| 泰安市| 连南| 东海县|