Solidity語言的七種武功秘籍

前言

FISCO BCOS使用了Solidity語言進行智能合約開發(fā)。在區(qū)塊鏈的江湖中,一直有一種傳言說Solidity是一門面向區(qū)塊鏈平臺設計的圖靈完備的編程語言,支持函數(shù)調用、修飾器、重載,事件、繼承和庫等多種高級語言的特性,在區(qū)塊鏈社區(qū)中,擁有廣泛的影響力和活躍的江湖支持。

但是,對于初入區(qū)塊鏈武林的少俠而言,Solidity又是一門陌生的語言。在本系列之前的兩篇文章中,已經為您介紹了Solidity語言的概念與演變、基礎特性。本文旨在通過介紹Solidity的一些高級的特性,幫助讀者快速見識七種神功秘籍,編寫高質量、可復用的Solidity代碼。

小李飛刀-函數(shù)和變量的類型

沒有人看見過那把飛刀。沒有人能夠說清楚這把刀的樣子。也沒有人知道這把刀是從哪個方位飛過來的。因為所有見過這把刀的人都死了。這就是小李飛刀。小李飛刀,例不虛發(fā)。

在智能合約中,函數(shù)和變量的類型就是這么不起眼,可是一旦出現(xiàn)疏忽,就會露出致命的破綻,輕則智能合約遭受攻擊,重則出現(xiàn)鏈上合約治理崩潰,合約被毀。

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

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

守住函數(shù)操作的大門:函數(shù)可見性

Solidity有兩種函數(shù)調用:

  • 內部調用:又被稱為『消息調用』。常見的有合約內部函數(shù)、父合約的函數(shù)以及庫函數(shù)的調用。(例如,假設A合約中存在f函數(shù),則在A合約內部,其他函數(shù)調用f函數(shù)的調用方式為f()。)
  • 外部調用:又被稱為『EVM調用』。一般為跨合約的函數(shù)調用。在同一合約內部,也可以產生外部調用。(例如,假設A合約中存在f函數(shù),則在B合約內可通過使用A.f()調用。在A合約內部,可以用this.f()來調用。)。

函數(shù)可以被指定為 external ,public ,internal 或者 private標識符來修飾。

標識符 作用
external 不可內部調用,在接收大量數(shù)據時更為高效。
public 同時支持內部和外部調用。
internal 只支持內部調用。
private 僅在當前合約使用,且不可被繼承。

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

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

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

  • public,公有函數(shù),系統(tǒng)默認。通常用于修飾可對外暴露的函數(shù),且該函數(shù)可能同時被內部調用。
  • external,外部函數(shù),推薦在只向外部暴露的函數(shù)的場景下使用。當函數(shù)的某個參數(shù)非常大時,如果顯式地將函數(shù)標記為external,可以強制將函數(shù)存儲的位置設置為calldata,這會節(jié)約函數(shù)執(zhí)行時所需的存儲或計算資源。
  • internal,內部函數(shù),推薦所有合約內不對合約外暴露的函數(shù)使用,可以避免因為權限暴露而被攻擊的風險。
  • private,私有函數(shù),極少數(shù)嚴格保護合約函數(shù)不對合約外部開放且不可被繼承的場景下使用。

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

經常會有剛接觸區(qū)塊鏈的用戶會誤解在區(qū)塊鏈上可以通過權限控制操作來控制和保護上鏈數(shù)據的隱私;但是這種觀點是錯誤的,事實上,在區(qū)塊鏈業(yè)務數(shù)據在未做特殊加密的前提下,區(qū)塊鏈同一賬本內的所有數(shù)據會經過共識后落盤到所有節(jié)點之上,智能合約能控制和保護的只有合約數(shù)據的執(zhí)行權限,而鏈上數(shù)據本身是全局公開和相同的,并在完成共識后落盤。

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

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

同理,對于狀態(tài)變量,也需要注意可見性修飾符。狀態(tài)變量不能設置為 external ,默認是 internal 。此外,當狀態(tài)變量被修飾為public,編譯器會生成一個名為該狀態(tài)變量的函數(shù)。<br />例如:

pragma solidity ^0.4.0;

contract TestContract {
    uint public year = 2020;
}

contract Caller {
    TestContract c = new TestContract();
    function f() public {
        uint local = c.year();
        //expected to be 2020
    }
}

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

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

精確地將函數(shù)分為三六九等:函數(shù)的類型

函數(shù)可以被聲明為pure、view。

函數(shù)類型 作用
pure 承諾不讀取或修改狀態(tài)。
view 保證不修改狀態(tài)。

那么究竟什么是讀取或修改狀態(tài)呢?在FISCO BCOS中,讀取狀態(tài)可能是:

  1. 讀取狀態(tài)變量。
  2. 訪問 block,tx, msg 中任意成員 (除 msg.sig 和 msg.data 之外)。
  3. 調用任何未標記為 pure 的函數(shù)。
  4. 使用包含某些操作碼的內聯(lián)匯編。

而修改狀態(tài)可能是:

  1. 修改狀態(tài)變量。
  2. 產生事件。
  3. 創(chuàng)建其它合約。
  4. 使用 selfdestruct。
  5. 調用任何沒有標記為 view 或者 pure 的函數(shù)。
  6. 使用了底層調用。
  7. 使用包含特定操作碼的內聯(lián)匯編。

簡單來說,讀取或修改了賬本相關的數(shù)據。需要注意的是,在某些版本的編譯器中,并沒有對這兩個關鍵字進行強制的語法檢查。

推薦盡可能地使用pure和view來聲明函數(shù),例如將沒有讀取或修改任何狀態(tài)的庫函數(shù)聲明為pure,這樣在提升代碼可讀性的同時,也使合約代碼更加賞心悅目,何樂而不為呢?

編譯時就確定的值:狀態(tài)常量

所謂的狀態(tài)常量是指被聲明為constant的狀態(tài)變量。一旦一個狀態(tài)變量被聲明為constant,那么該變量的值只能為編譯時確定的值,且無法再被修改。編譯器一般會在編譯狀態(tài)就計算出這個變量的實際值,不會給這個變量預留儲存空間,所以,constant只支持修飾值類型和字符串。

狀態(tài)常量一般旨在定義一些含義明確的業(yè)務常量值。

凌波微步 函數(shù)修飾器(modifier)

凌波微步是一門極上乘的輕功身法,按特定順序踏著卦象方位行進,從第一步到最后一步正好行走一個大圈。此步法精妙異常,優(yōu)美絕倫,神出鬼沒,一旦使出之后便能立于不敗之地。恰似函數(shù)修飾器,近可抽象和簡化代碼,退可校驗和過濾非法操作,實乃用好Solidity編程的一大絕學。

Solidity提供了一個強大的改變函數(shù)行為的語法:函數(shù)修飾器(modifier)。一旦某個函數(shù)加上了修飾器,修飾器內定義的代碼就可以作為函數(shù)的裝飾被執(zhí)行,聽起來非常像其他高級語言中裝飾器的概念。

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

pragma solidity ^0.4.11;

contract owned {
    function owned() public { owner = msg.sender; }
    address owner;

    // 修飾器所修飾的函數(shù)體會被插入到特殊符號 _; 的位置。
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
    
    // 使用onlyOwner修飾器所修飾,執(zhí)行changeOwner函數(shù)前需要首先執(zhí)行onlyOwner"_;"前的語句。
    function changeOwner(address _owner) public onlyOwner {
        owner = _owner;
    }
}

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

所以,代碼的實際執(zhí)行順序變成了:

  1. 執(zhí)行onlyOwner修飾器的語句,先執(zhí)行require語句。(執(zhí)行第9行)
  2. 執(zhí)行changeOwner函數(shù)的語句。(執(zhí)行第15行)

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

并且,修飾器還能傳入參數(shù),例如上述的修飾器也能寫成這樣:

modifier onlyOwner(address sender) {
    require(sender == owner);
    _;
}

function changeOwner(address _owner) public onlyOwner(msg.sender) {
        owner = _owner;
}

同一個函數(shù)可以有多個修飾器,它們之間以空格隔開,修飾器會依次檢查執(zhí)行。此外,修飾器還可以被繼承和重寫。

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

比如,我們可以定義一個跟蹤函數(shù)執(zhí)行的修飾器:

event LogStartMethod();
event LogEndMethod();

modifier logMethod {
    emit LogStartMethod();
    _;
    emit LogEndMethod();
}

這樣,任何用logMethod修飾器來修飾的函數(shù)可以記錄其函數(shù)執(zhí)行前后的日志,實現(xiàn)日志環(huán)繞的效果。如果你已經習慣了使用Spring框架的AOP了,那么快來試試用modifier實現(xiàn)一個簡單的AOP功能了吧。

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

明玉功 事件(Event)

明玉功是移花宮的絕世武學,移花宮歷代宮主修煉的最高內家正宗絕頂心法,神功威力玄妙而且亦可不老長春。大家都知道智能合約編程最大的痛點之一是難于調試,而用好事件機制能夠保住智能合約程序員的頭發(fā),江湖甚至還有傳言說能夠讓程序員們青春常駐。

Solidity的事件機制,是Solidity較為獨有的高級特性之一。事件允許我們方便地使用 EVM 的日志基礎設施。

Solidity的事件有以下作用:

  1. 記錄事件定義的參數(shù),存儲到區(qū)塊鏈交易的日志中,提供廉價的存儲。
  2. 提供一種回調機制,在事件執(zhí)行成功后,由節(jié)點向注冊監(jiān)聽的SDK發(fā)送回調通知,觸發(fā)回調函數(shù)被執(zhí)行。
  3. 提供一個過濾器,支持參數(shù)的檢索和過濾。

事件的使用方法非常簡單,兩步即可玩轉。第一步,使用關鍵字『event』來定義一個事件。例如,我們定義一個函數(shù)調用跟蹤的事件。建議事件的命名以特定的前綴開始或以特定的后綴結束,這樣可以更方便地和函數(shù)區(qū)分。例如,在本文中統(tǒng)一以『Log』前綴來命名事件,以便更加簡潔、清晰地與函數(shù)相區(qū)分。

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

事件在合約中可被繼承。當他們被調用時,會將參數(shù)存儲到交易的日志中。這些日志與地址相關聯(lián),被保存到區(qū)塊鏈中。這里indexed用來標記參數(shù)被搜索,否則,這些參數(shù)被存儲到日志的數(shù)據部分中,而無法被搜索。

第二步,在對應的函數(shù)體內觸發(fā)定義的事件,在事件調用的時候,在事件名前加上『emit』關鍵字:

function f() public {
    emit LogCallTrace(msg.sender, this, true);
}

這樣,當函數(shù)體被執(zhí)行的時候,會觸發(fā)LogCallTrace的執(zhí)行。

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

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

但是,好消息是日志的定義和聲明非常利于在『事后』進行追溯和導出。例如,我們可以在合約的編寫中,定義和埋入足夠的事件,通過WEBASE的數(shù)據導出子系統(tǒng),我們可以將所有的日志導出到MySQL等數(shù)據庫中,這特別適用于復雜的鏈上數(shù)據查詢、數(shù)據分析和數(shù)據報表等功能,例如生成對賬文件、生成報表、復雜業(yè)務場景的OLTP查詢等場景。而數(shù)據導出子系統(tǒng)非常好用,因為我們還提供了一個專用的代碼生成子系統(tǒng)來幫助分析具體的業(yè)務合約,自動生成相應的代碼。

在Solidity中,事件是一個非常有用的機制,極大地方便了智能合約的開發(fā)和測試。如果說智能合約開發(fā)最大的痛點是難于debug,那么善用事件機制可以讓你快速制伏Solidity開發(fā)。

九陽神功 重載

九陽真經的真諦正所謂『他強由他強,清風拂山崗』。不論敵人如何強猛、如何兇惡,盡可當他是清風拂山,明月映江,雖能加于我身,卻不能有絲毫損傷。

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

一個典型的重載語法如下:

pragma solidity ^0.4.25;

contract Test {
    function f(uint _in) public pure returns (uint out) {
        out = 1;
    }

    function f(uint _in, bytes32 _key) public pure returns (uint out) {
        out = 2;
    }
}

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

我們可以想像一個沒有重載的世界,那一定是一個絞盡腦汁給函數(shù)起名的存在,程序員的頭發(fā)又要少幾根了。

吸星大法:繼承

日月神教令人聞風喪膽的內功心法,可以在一瞬之間吸取其他武林高手畢生的修為,為我所用??墒?,吸星大法終究過于霸道,稍有不慎亦有反噬之力。

智能合約的繼承也是如此,既可以在一夜之間直接復用其他成熟的合約,但是假如復用不當,也會產生若干副作用,反過來影響實際的業(yè)務。

Solidity使用關鍵字『is』作為繼承的關鍵字。例如如下代碼所示, 合約B繼承了合約A:

pragma solidity ^0.4.25;

contract A {
}

contract B is A {
}

繼承的合約B可以訪問被繼承合約A的所有的非private的函數(shù)和狀態(tài)變量。

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

相比于C++或Java等語言的繼承機制,Solidity的繼承機制更有點類似于Python,Solidity支持和Python類似的多重繼承機制。因此,Solidity中可以使用一個合約來繼承多個合約。不過,在某些高級語言中,比如Java,出于安全性和可靠性方面的考慮,只支持單重繼承,而通過使用接口機制來實現(xiàn)多重繼承。對于大多數(shù)場景而言,單繼承的機制可以滿足需求,解決問題。多繼承會帶來很多復雜的技術問題,例如所謂的『鉆石繼承』等問題,建議在實踐中盡可能規(guī)避復雜的多繼承。

繼承簡化了人們對抽象的合約模型的認識和描述,能清晰體現(xiàn)相關合約間的層次結構關系;繼承提供了軟件復用功能。這種做法能減小代碼和數(shù)據的冗余度,大大增加程序的重用性。

獨孤九劍:抽象類和接口

獨孤九劍,不拘于招式,無招勝有招。等到通曉了這九劍,則無所施而不可,無所不出,無所不入,便是將全部變化盡數(shù)忘記,也不相干。

這恰恰契合編程中依賴倒置的原則,智能合約應該盡可能地面向接口編程,而不依賴具體的實現(xiàn)細節(jié)。

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

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

pragma solidity ^0.4.25;

contract Vehicle {
    //抽象方法
    function brand() public returns (bytes32);
}

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

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

pragma solidity ^0.4.25;

interface Vehicle {
    //抽象方法
    function brand() public returns (bytes32);
}

接口類似于抽象合約,但是它們不能實現(xiàn)任何函數(shù)。還有進一步的限制:

  1. 無法繼承其他合約或接口。
  2. 無法定義構造函數(shù)。
  3. 無法定義變量。
  4. 無法定義結構體
  5. 無法定義枚舉。

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

易筋經 庫(Library)

少林七十二絕技之最為深奧絕妙的內功心法。據說練成者,心動而力發(fā),一攢一放,自然而施,不覺其出而自出,如潮之漲,如雷之發(fā)。

善用庫者,亦是如此,乍看之下不太起眼,可是日積月累,積累的庫和應用能力也水漲船高。在軟件開發(fā)中,有很多經典的原則來提升軟件的質量,其中最為經典的一條原則,就是盡可能復用久經考驗、反復打磨、嚴格測試的高質量代碼。此外,復用成熟的庫代碼還可以提升代碼的可讀性、可維護性,甚至是可擴展性。

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

  • 用戶可以像使用合約一樣使用關鍵詞library來創(chuàng)建合約。
  • 庫既不能繼承也不能被繼承。
  • 庫的internal函數(shù)對調用者都是可見的。
  • 庫是無狀態(tài)的,無法定義狀態(tài)變量,但是可以訪問和修改調用合約所明確提供的狀態(tài)變量。

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

pragma solidity ^0.4.25;

library LibSafeMath {
  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal returns (uint256 c) {
    c = a + b;
    assert(c >= a);
    return c;
  }
}

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

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

pragma solidity ^0.4.25;

import "./LibSafeMath.sol";

contract TestAdd {

  function testAdd(uint256 a, uint256 b) external returns (uint256 c) {
    c = LibSafeMath.add(a,b);
  }
}

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

=============================================================================================
Welcome to FISCO BCOS console(1.0.8)!
Type 'help' or 'h' for help. Type 'quit' or 'q' to quit console.
 ________ ______  ______   ______   ______       _______   ______   ______   ______
|        |      \/      \ /      \ /      \     |       \ /      \ /      \ /      \
| $$$$$$$$\$$$$$|  $$$$$$|  $$$$$$|  $$$$$$\    | $$$$$$$|  $$$$$$|  $$$$$$|  $$$$$$\
| $$__     | $$ | $$___\$| $$   \$| $$  | $$    | $$__/ $| $$   \$| $$  | $| $$___\$$
| $$  \    | $$  \$$    \| $$     | $$  | $$    | $$    $| $$     | $$  | $$\$$    \
| $$$$$    | $$  _\$$$$$$| $$   __| $$  | $$    | $$$$$$$| $$   __| $$  | $$_\$$$$$$\
| $$      _| $$_|  \__| $| $$__/  | $$__/ $$    | $$__/ $| $$__/  | $$__/ $|  \__| $$
| $$     |   $$ \\$$    $$\$$    $$\$$    $$    | $$    $$\$$    $$\$$    $$\$$    $$
 \$$      \$$$$$$ \$$$$$$  \$$$$$$  \$$$$$$      \$$$$$$$  \$$$$$$  \$$$$$$  \$$$$$$

=============================================================================================
[group:1]> deploy TestAdd
contract address: 0xe2af1fd7ecd91eb7e0b16b5c754515b775b25fd2

[group:1]> call TestAdd 0xe2af1fd7ecd91eb7e0b16b5c754515b775b25fd2 testAdd 2000 20
transaction hash: 0x136ce66603aa6e7fd9e4750fcf25302b13171abba8c6b2109e6dd28111777d54
---------------------------------------------------------------------------------------------
Output
function: testAdd(uint256,uint256)
return type: (uint256)
return value: (2020)
---------------------------------------------------------------------------------------------

[group:1]>

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

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

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

pragma solidity ^0.4.25;

import "./LibSafeMath.sol";

contract TestAdd {
  // 添加using ... for ... 語句,庫 LibSafeMath 中的函數(shù)被附加在uint256的類型上
  using LibSafeMath for uint256;

  function testAdd(uint256 a, uint256 b) external returns (uint256 c) {
        //c = LibSafeMath.add(a,b);
        c = a.add(b);
        //對象a直接被作為add方法的首個參數(shù)傳入。
  }
}

我們可以驗證一下結果依然是正確的。

=============================================================================================
Welcome to FISCO BCOS console(1.0.8)!
Type 'help' or 'h' for help. Type 'quit' or 'q' to quit console.
 ________ ______  ______   ______   ______       _______   ______   ______   ______
|        |      \/      \ /      \ /      \     |       \ /      \ /      \ /      \
| $$$$$$$$\$$$$$|  $$$$$$|  $$$$$$|  $$$$$$\    | $$$$$$$|  $$$$$$|  $$$$$$|  $$$$$$\
| $$__     | $$ | $$___\$| $$   \$| $$  | $$    | $$__/ $| $$   \$| $$  | $| $$___\$$
| $$  \    | $$  \$$    \| $$     | $$  | $$    | $$    $| $$     | $$  | $$\$$    \
| $$$$$    | $$  _\$$$$$$| $$   __| $$  | $$    | $$$$$$$| $$   __| $$  | $$_\$$$$$$\
| $$      _| $$_|  \__| $| $$__/  | $$__/ $$    | $$__/ $| $$__/  | $$__/ $|  \__| $$
| $$     |   $$ \\$$    $$\$$    $$\$$    $$    | $$    $$\$$    $$\$$    $$\$$    $$
 \$$      \$$$$$$ \$$$$$$  \$$$$$$  \$$$$$$      \$$$$$$$  \$$$$$$  \$$$$$$  \$$$$$$

=============================================================================================
[group:1]> deploy TestAdd
contract address: 0xf82c19709a9057d8e32c19c23e891b29b708c01a

[group:1]> call TestAdd 0xf82c19709a9057d8e32c19c23e891b29b708c01a testAdd 2000 20
transaction hash: 0xcc44a80784404831d8522dde2a8855606924696957503491eb47174c9dbf5793
---------------------------------------------------------------------------------------------
Output
function: testAdd(uint256,uint256)
return type: (uint256)
return value: (2020)
---------------------------------------------------------------------------------------------

[group:1]>

綜上所述,我們已經介紹了如何更好地使用Solidity library的機制,來更好地復用代碼。除了Solidity社區(qū)提供的大量開源、高質量的代碼庫以外,F(xiàn)ISCO BCOS社區(qū)也計劃準備推出一個全新的Solidity代碼庫,開放給社區(qū)的用戶,敬請期待。當然,您也可以自己動手,編寫可復用的代碼庫組件,并分享到社區(qū)。

總結

本文介紹了Solidity合約編寫的若干高級語法特性,旨在拋磚引玉,幫助讀者快速沉浸到Solidity編程的世界。

想要編寫高質量、可復用的Solidity代碼的訣竅就和學習其他技術一樣,多看看社區(qū)優(yōu)秀的代碼,多動手實踐編碼,多多總結并不斷進化。期待更多的朋友到我們的社區(qū)來分享寶貴的經驗和精彩的故事,have fun :)

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容