solidity基礎(4)

  1. solidity的函數(shù)修改器
    函數(shù)修改器可以方便的控制函數(shù)的邏輯屯蹦,比如可以在某個行為執(zhí)行前檢查某個前置條件足画,函數(shù)修改器還支持繼承和重寫】榇伲可能大家會想荣堰,一些檢查行為提升為一個語言級特性到底有必要嗎?由于整個區(qū)塊鏈運行環(huán)境是透明的竭翠,分布式的振坚,且是圖靈完備。為保證其上運行的代碼安全斋扰,勢必存在大量的檢查行為渡八,升級為語言特性可以讓檢查代碼復用,看起來也更簡潔

    1. 定義
      在實際情況中传货,我們經(jīng)常需要對調(diào)用者進行一些限制屎鳍,比如,只能是合約的所有者才能改變歸屬问裕,我們一起來看一下如何用函數(shù)修改器實現(xiàn)這一限制:

      pragma solidity ^0.4.18;
      contract Ownable{
        address public owner = msg.sender;
        //限制只有創(chuàng)建者才能訪問
        modifier onlyOwner {
          if (msg.sender != owner) throw;
          _;
        }
        //改變合約的所有者
        function changeOwner(address _newOwner) onlyOwner {
          if (newOwner == 0x0) throw;
          owner = _newOwner;
        }
      }
      

    上述例子中逮壁,首先我們通過關(guān)鍵字modifier后接函數(shù)修改器名onlyOwner,定義了一個函數(shù)修改器僻澎。在函數(shù)修改器代碼塊內(nèi)貌踏,判斷如果不是合約所有者調(diào)用就拋出異常,否則就執(zhí)行占位符_處代碼十饥,_代指的是使用函數(shù)修改器的函數(shù)體窟勃。真正調(diào)用changeOwner()函數(shù)時,由于使用了函數(shù)修改器onlyOwner逗堵,會先判斷調(diào)用者是否為所有者秉氧,如果是,才會執(zhí)行changeOwner()的函數(shù)體蜒秤,允許修改為新所有者
    注意汁咏,0.4.0以后,_必須要寫為_;](https://github.com/ethereum/solidity/releases/tag/v0.4.0)

    1. 函數(shù)修改器支持參數(shù)
      函數(shù)修改器作媚,支持函數(shù)內(nèi)可以訪問的任意符號(包括函數(shù)的入?yún)?攘滩。直接在函數(shù)修改器的參數(shù)中傳入即可,看一下示例:

      pragma solidity ^0.4.18;
      contract Parameter {
        uint balance =10;
        modifier lowerLimit(uint _balance,uint _withdraw) {
          if(_withdraw < 0 || _withdraw > _balance) throw;
          _;
        }
        //含參數(shù)的函數(shù)修改器
        function f(uint withdraw) lowerLimit(balance,withdraw) returns(uint) {
          return balance;
        }
      }
      

    在上面的例子中纸泡,f()函數(shù)漂问,有一個函數(shù)修改器lowerLimit(),傳入了狀態(tài)變量參數(shù)balance,和入?yún)?code>withdraw,以lowerLimit(balance,withdraw)的方式進行調(diào)用蚤假。最后函數(shù)能否正確執(zhí)行取決于輸入的withdraw值大小

    1. 函數(shù)修改器參數(shù)支持表達式
      函數(shù)修改器的參數(shù)支持任意的表達式栏饮,只要在上下文中,可見的符號均可在函數(shù)修改器中使用磷仰。而在函數(shù)修改器中引入的符號袍嬉,在函數(shù)中不可見(因為它們可能因為重載而發(fā)生改變)

      pragma solidity ^0.4.18;
      contract Test {
        modifier m(uint a) {
          if (a > 0)
          _;
        }
        function add(uint a,uint b) private returns(uint) {
          return a+b;
        }
        function f() m(add(1,1)) returns(uint) {
          return 1;
        }
      }
      


    上例中,我們在函數(shù)修改器m中灶平,使用了add()函數(shù)

    1. return
      如果函數(shù)有返回值伺通,但由于函數(shù)修改器判斷不成功,那么將返回對應類型的默認值逢享,下面是一個簡單的例子:

      pragma solidity ^0.4.18;
      contract Return {
        //函數(shù)修改器永遠不成功
        modifier A() {
          if (false)
          _;
        }
      
        //返回默認值
        function uintReturn() A returns(uint) {
          uint a = 10;
          return a;
        }
      
        //返回默認值
        function stringReturn() A returns(string) {
          return "hello,world";
        }
      }
      

    上例中泵殴,我們寫了一個特殊的函數(shù)修改器A,永遠判斷不成功拼苍,故而uintReturn(),stringReturn()中的代碼都將不會執(zhí)行笑诅。上述函數(shù)將分別返回uint,string的默認“零值”
    函數(shù)修改器允許return;(類似于break,中斷當前流程)。但是不允許明確的return值疮鲫,即return 1之類吆你,社區(qū)正在建議能支持返回值,但是目前(2018/10/22)還不可以

    1. 執(zhí)行流程
      函數(shù)體內(nèi)俊犯,或函數(shù)修改器內(nèi)顯示return語句妇多,只會退出當前代碼塊,即退出{}。返回值將被賦值燕侠,但會繼續(xù)執(zhí)行_后續(xù)的邏輯者祖。下面是一個展示執(zhí)行流程的示例:

      pragma solidity ^0.4.18;
      contract Test {
        mapping(bool => uint) public map;
      
        modifier A(mapping(bool => uint) map) {
          if (map[true] == 0) {
            map[true] = 1;
            _;
            map[true] = 3;
            }
          }
          function f() A(map) returns(uint) {
            map[true] = 2;
            return map[ttue];
        }
      }
      

    上面的例子,函數(shù)先執(zhí)行f()绢彤,然后執(zhí)行函數(shù)修改判斷器七问,接著判斷map[true]的值,為0茫舶,執(zhí)行map[true] = 1;械巡,然后執(zhí)行f()的函數(shù)體,執(zhí)行完后回到A中執(zhí)行map[true] = 3;饶氏,合約執(zhí)行完畢
    個人認為讥耗,函數(shù)體執(zhí)行完后就直接返回了,并不是等到整個合約執(zhí)行完后再一起返回疹启,所有返回值任然是2古程,使用數(shù)組之類的引用傳遞,依然沒有效果

    1. 多函數(shù)修改器
      如果一個函數(shù)有多個函數(shù)修改器喊崖,定義時依次填寫挣磨,并用空格隔開菲宴。函數(shù)修改器執(zhí)行時,將按定義順序依次執(zhí)行趋急,下面是一個簡單的示例:

      pragma solidity ^0.4.18;
      contract Test {
        address owner = msg.sender;
        //限制只有創(chuàng)建者才能訪問
        modifier onlyOwner {
          if (msg.sender != owner) throw;
          _;
        }
        //查看狀態(tài)
        modifier inSate(bool state) {
          if (!state) throw;
          _;
        }
        //多個函數(shù)修改器
        function f(bool state) onlyOwner inSate(state) returns(uint) {
          return 1;
        }
      }
      
    2. 重寫
      我們可以重寫父類的函數(shù)修改器喝峦,來改變父類的修改器行為,下面來看一個示例:

      pragma solidity ^0.4.18;
      contract bank{
        modifier transferLimit(uint _withdraw) {
          if (_withdraw > 100) throw;
          _;
        }
      }
      
      contract Test is bank{
        //覆蓋的父類的
        modifier transferLimit(uint _withdraw) {
          if (_withdraw > 10) throw;
          _;
        }
        function f(uint withdraw) transferLimit(withdraw) returns(uint) {
          return withdraw;
        }
      }
      


    上例中呜达,我們在子類中覆寫了父類的函數(shù)修改器谣蠢,加強了對_withdraw的數(shù)量檢查,但是覆寫的修改器只在子類中有效查近,在父類中依然按照父類的修改器

    1. 函數(shù)修改器區(qū)域
      函數(shù)修改器區(qū)域眉踱,是一個全新的特性,目前尚不支持霜威,它允許你同時對多個函數(shù)應用函數(shù)修改器

      //該段代碼是不能執(zhí)行的
      pragma solidity ^0.4.18;
      contract test {
        modifier inState(bool state) {
          if (currentSate != state) throe;
          _;
        }
        using modifier inSate(state.transfer) {
          function f() returns(uint) {return 2;}
          function g() returns(uint) {return 2;}
        }
        using modifier inSate(state.cleanup) {
          function h() returns(uint) {return 2;}
          function i() returns(uint) {return 2;}
        }
      }
      

    上述代碼是將一個表示狀態(tài)的函數(shù)修改器同時應用到多個函數(shù)的例子谈喳。使用函數(shù)修改器區(qū)域的好處是將能比較直觀知道哪些函數(shù)應用了某個函數(shù)修改器,但也引入了復雜性戈泼,以及由于作者不規(guī)范婿禽,超大代碼帶來的不方便閱讀代碼的問題,
    備注:會出現(xiàn)這樣的特性本身說明了傳統(tǒng)程序與智能合約程序的不同大猛。由于智能合約強檢查性的特點扭倾,開始慢慢發(fā)展出自己的獨特特性

  2. solidity的event事件
    在介紹事件前,我們先明確事件挽绩,日志這兩個概念膛壹。事件發(fā)生后被記錄到區(qū)塊鏈上成為了日志,總的來說唉堪,事件強調(diào)功能模聋,一種行為;日志強調(diào)儲存唠亚,內(nèi)容链方。
    事件是以太坊EVM提供的一種日志基礎設施。事件可以用來做操作記錄趾撵,儲存為日志侄柔。也可以用來實現(xiàn)一些交互功能,比如通過UI占调,返回函數(shù)調(diào)用結(jié)果等

    1. 事件
      當定義的事件觸發(fā)時,我們可以將事件儲存到EVM的交易日志中移剪,日志是區(qū)塊中的一種特殊數(shù)據(jù)結(jié)構(gòu)究珊。日志與合約關(guān)聯(lián),與合約的儲存合并存入?yún)^(qū)塊鏈中纵苛,只要某個區(qū)塊可以訪問剿涮,其相關(guān)的日志就可以訪問言津。但在合約中,我們不能直接訪問日志和事件數(shù)據(jù)(即便是創(chuàng)建日志的合約)取试,下面我們來看如何在solidity中實現(xiàn)一個事件:

      pragma solidity ^0.4.18;
      contract Transfer {
        event transfer(address indexed _from,address indexed _to,uint indexed value);
      
        function deposit() payable {
          address current = this;
          uint value = msg.value;
          transfer(msg.sender,current.value);
        }
      
        function getBalance() constant returns(uint) {
          return this.balance;
        }
      }
      

    從上面的例子中悬槽,我們使用event關(guān)鍵字定義一個事件,參數(shù)列表中為要記錄的日志參數(shù)的名稱及類型

    1. 監(jiān)聽事件
      由于監(jiān)聽事件需要使用web3.js瞬浓,這里先跳過初婆,在后續(xù)學習web3.js時再回頭來看
    2. 撿索日志
      • Indexed屬性
        可以在事件參數(shù)上增加indexed屬性,最多可以對三個參數(shù)增加這樣的屬性猿棉。加上這個屬性磅叛,可以允許你在web3.js中通過對加了這個屬性的參數(shù)進行值過濾
      • 后續(xù)基本都涉及到web3.js,如果沒有學過的可以先跳一下萨赁,學過的弊琴,我這里附上原文鏈接
      • 后續(xù)切記補上,因為事件和日志在以太坊中異常重要杖爽。因為它是合約之間敲董,合約與終端之間的溝通橋梁。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末慰安,一起剝皮案震驚了整個濱河市臣缀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌泻帮,老刑警劉巖精置,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锣杂,居然都是意外死亡脂倦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門元莫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赖阻,“玉大人,你說我怎么就攤上這事踱蠢』鹋罚” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵茎截,是天一觀的道長苇侵。 經(jīng)常有香客問我,道長企锌,這世上最難降的妖魔是什么榆浓? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮撕攒,結(jié)果婚禮上陡鹃,老公的妹妹穿的比我還像新娘烘浦。我一直安慰自己,他們只是感情好萍鲸,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布闷叉。 她就那樣靜靜地躺著,像睡著了一般脊阴。 火紅的嫁衣襯著肌膚如雪握侧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天蹬叭,我揣著相機與錄音藕咏,去河邊找鬼。 笑死秽五,一個胖子當著我的面吹牛孽查,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坦喘,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼盲再,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瓣铣?” 一聲冷哼從身側(cè)響起答朋,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棠笑,沒想到半個月后梦碗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蓖救,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年洪规,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片循捺。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡斩例,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出从橘,到底是詐尸還是另有隱情念赶,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布恰力,位于F島的核電站叉谜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏牺勾。R本人自食惡果不足惜正罢,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驻民。 院中可真熱鬧翻具,春花似錦、人聲如沸回还。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柠硕。三九已至工禾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝗柔,已是汗流浹背闻葵。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留癣丧,地道東北人槽畔。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像胁编,于是被迫代替她去往敵國和親厢钧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • solidity的自定義結(jié)構(gòu)體深入詳解結(jié)構(gòu)體嬉橙,solidity中的自定義類型早直,我們可以使用關(guān)鍵字struct來進行...
    Lnhj閱讀 1,106評論 0 0
  • 遠山 薄霧 幾片閑云 一灣溪水東流 綠松 竹海 白鶴群來 坐臥行止隨心
    花少顏閱讀 138評論 0 0
  • 如果一開始,趙默笙沒有死纏著喜歡何以琛市框,結(jié)局或許會不一樣霞扬,也許她會繼續(xù)執(zhí)著于她的攝影,何以琛或許會與他的妹妹結(jié)婚生...
    Dz遇見閱讀 251評論 0 1
  • 夢是想著來的 想并不能夢著想 如果夢和想在一起 你一定能成功 夢想
    04a14b4a4742閱讀 128評論 0 0