-
solidity的函數(shù)修改器
函數(shù)修改器可以方便的控制函數(shù)的邏輯屯蹦,比如可以在某個行為執(zhí)行前檢查某個前置條件足画,函數(shù)修改器還支持繼承和重寫】榇伲可能大家會想荣堰,一些檢查行為提升為一個語言級特性到底有必要嗎?由于整個區(qū)塊鏈運行環(huán)境是透明的竭翠,分布式的振坚,且是圖靈完備。為保證其上運行的代碼安全斋扰,勢必存在大量的檢查行為渡八,升級為語言特性可以讓檢查代碼復用,看起來也更簡潔-
定義
在實際情況中传货,我們經(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)-
函數(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
值大小-
函數(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ù)-
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)還不可以-
執(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ù)組之類的引用傳遞,依然沒有效果-
多函數(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; } }
-
重寫
我們可以重寫父類的函數(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ù)量檢查,但是覆寫的修改器只在子類中有效查近,在父類中依然按照父類的修改器-
函數(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ā)展出自己的獨特特性
-
-
solidity的event事件
在介紹事件前,我們先明確事件挽绩,日志這兩個概念膛壹。事件發(fā)生后被記錄到區(qū)塊鏈上成為了日志,總的來說唉堪,事件強調(diào)功能模聋,一種行為;日志強調(diào)儲存唠亚,內(nèi)容链方。
事件是以太坊EVM提供的一種日志基礎設施。事件可以用來做操作記錄趾撵,儲存為日志侄柔。也可以用來實現(xiàn)一些交互功能,比如通過UI占调,返回函數(shù)調(diào)用結(jié)果等-
事件
當定義的事件觸發(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ù)的名稱及類型- 監(jiān)聽事件
由于監(jiān)聽事件需要使用web3.js瞬浓,這里先跳過初婆,在后續(xù)學習web3.js時再回頭來看 - 撿索日志
- Indexed屬性
可以在事件參數(shù)上增加indexed
屬性,最多可以對三個參數(shù)增加這樣的屬性猿棉。加上這個屬性磅叛,可以允許你在web3.js中通過對加了這個屬性的參數(shù)進行值過濾 - 后續(xù)基本都涉及到web3.js,如果沒有學過的可以先跳一下萨赁,學過的弊琴,我這里附上原文鏈接
- 后續(xù)切記補上,因為事件和日志在以太坊中異常重要杖爽。因為它是合約之間敲董,合約與終端之間的溝通橋梁。
- Indexed屬性
-
solidity基礎(4)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門元莫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赖阻,“玉大人,你說我怎么就攤上這事踱蠢』鹋罚” “怎么了?”我有些...
- 文/不壞的土叔 我叫張陵茎截,是天一觀的道長苇侵。 經(jīng)常有香客問我,道長企锌,這世上最難降的妖魔是什么榆浓? 我笑而不...
- 正文 為了忘掉前任,我火速辦了婚禮撕攒,結(jié)果婚禮上陡鹃,老公的妹妹穿的比我還像新娘烘浦。我一直安慰自己,他們只是感情好萍鲸,可當我...
- 文/花漫 我一把揭開白布闷叉。 她就那樣靜靜地躺著,像睡著了一般脊阴。 火紅的嫁衣襯著肌膚如雪握侧。 梳的紋絲不亂的頭發(fā)上,一...
- 文/蒼蘭香墨 我猛地睜開眼盲再,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瓣铣?” 一聲冷哼從身側(cè)響起答朋,我...
- 正文 年R本政府宣布恰力,位于F島的核電站叉谜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏牺勾。R本人自食惡果不足惜正罢,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驻民。 院中可真熱鬧翻具,春花似錦、人聲如沸回还。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽柠硕。三九已至工禾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝗柔,已是汗流浹背闻葵。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- solidity的自定義結(jié)構(gòu)體深入詳解結(jié)構(gòu)體嬉橙,solidity中的自定義類型早直,我們可以使用關(guān)鍵字struct來進行...
- 如果一開始,趙默笙沒有死纏著喜歡何以琛市框,結(jié)局或許會不一樣霞扬,也許她會繼續(xù)執(zhí)著于她的攝影,何以琛或許會與他的妹妹結(jié)婚生...