Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-智能合約與函數(shù)_第1頁(yè)
Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-智能合約與函數(shù)_第2頁(yè)
Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-智能合約與函數(shù)_第3頁(yè)
Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-智能合約與函數(shù)_第4頁(yè)
Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-智能合約與函數(shù)_第5頁(yè)
已閱讀5頁(yè),還剩114頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

以太坊Solidity智能合約開發(fā)教程智能合約與函數(shù)學(xué)前提示在第3章介紹的實(shí)例中,已經(jīng)涉及到智能合約和函數(shù)的概念以及基本應(yīng)用。智能合約開發(fā)是本書的主題,而智能合約的主要功能是通過函數(shù)實(shí)現(xiàn)的。本章將對(duì)智能合約和函數(shù)編程的細(xì)節(jié)做深入的介紹。知識(shí)要點(diǎn)5.1智能合約編程基礎(chǔ)5.2函數(shù)編程基礎(chǔ)5.3函數(shù)的高級(jí)應(yīng)用5.4外部函數(shù)5.5抽象合約和接口5.6異常處理5.1智能合約編程基礎(chǔ)5.1.1狀態(tài)變量的可見性5.1.2智能合約的構(gòu)造函數(shù)5.1.3智能合約之間的繼承5.1.1狀態(tài)變量的可見性

public,指定公有變量,也就是可以在其他智能合約中訪問的狀態(tài)變量。

private,指定私有變量。私有變量只能在定義它的智能合約中訪問它。在其他智能合約中都不能訪問私有變量,包括派生的智能合約。

internal,指定內(nèi)部變量,也就是可以在定義它的智能合約、以及派生智能合約中訪問的狀態(tài)變量。派生和繼承派生是面向?qū)ο缶幊讨械臋C(jī)制,也可以說是繼承。假定有一個(gè)智能合約A,可以從A派生一個(gè)新的智能合約B。反過來講,也可以說B繼承了A。以使用is關(guān)鍵字指定智能合約之間的派生關(guān)系pragmasolidity^0.5.1;contractA{uinta=10;}contractBisA{//……}getter訪問器對(duì)于公有變量,Solidity提供一個(gè)getter訪問器,用于在智能合約外訪問該變量。getter訪問器是與變量同名的函數(shù),例如,狀態(tài)變量a的getter訪問器是a()。使用a()可以獲取變量a的值,但是不能設(shè)置a的值。

【例5-1】pragmasolidity^0.5.1;//聲明合約contractA{uintpublicdata=10;}

contractB{functiongetValue()publicreturns(uint){Aa=newA();returna.data();}}手續(xù)費(fèi)在以太坊網(wǎng)絡(luò)中,對(duì)智能合約中的狀態(tài)變量的修改是要收取Gas的,因?yàn)闋顟B(tài)變量是記錄在區(qū)塊上的,是需要礦工記賬的,所以要支付手續(xù)費(fèi)。而且部署和執(zhí)行智能合約都是要占用以太坊的資源,因此也是要收取Gas的。選擇要部署的智能合約部署智能合約時(shí)會(huì)扣減當(dāng)前賬號(hào)的以太幣執(zhí)行g(shù)etValue()函數(shù)的交易過程和結(jié)果單擊getValue按鈕,注意觀察“當(dāng)前賬號(hào)”中以太幣的變化。同時(shí),在窗口中間底部的控制臺(tái),會(huì)出現(xiàn)一個(gè)表格,記錄了執(zhí)行g(shù)etValue()函數(shù)的交易過程和結(jié)果具體說明如下·status:交易的狀態(tài)為已經(jīng)被礦工記賬,執(zhí)行成功。當(dāng)然是在虛擬機(jī)環(huán)境下?!ransactionhash:交易的哈希摘要?!rom:支付Gas的以太坊賬戶。這里顯示的是之前選擇的“當(dāng)前賬號(hào)”。·to:接收gas的以太坊賬戶。這里顯示的是0xbbf289d846208c16edc8474705c748aff07732db,也就是說明是因?yàn)閳?zhí)行.getValue()函數(shù)而消耗的gas?!as:顯示智能合約的執(zhí)行者愿意支付的gas上限,因?yàn)橹悄芎霞s可能有bug,比如進(jìn)入死循環(huán)狀態(tài),很可能循環(huán)寫入狀態(tài)變量。如果不設(shè)置上限,就可能會(huì)耗盡賬戶里的以太幣。gas上限默認(rèn)為3000000,可以在窗口右側(cè)的“運(yùn)行”面板中設(shè)置設(shè)置gas上限

transactioncost:交易所花費(fèi)的總的gas,本例中為106094gas。

executioncost:虛擬機(jī)(vm)執(zhí)行計(jì)算所花費(fèi)的gas,本例中為84822gas。executioncost包含在transactioncost中。

hash:交易的哈希摘要,與transactionhash是一樣的。

input:經(jīng)過編碼的交易的輸入數(shù)據(jù)。

decodedinput:解碼后的交易輸入數(shù)據(jù),本例沒有輸入數(shù)據(jù)。

decodedoutput:解碼后的交易輸出數(shù)據(jù),本例的輸出數(shù)據(jù)為一個(gè)uint256類型的數(shù)據(jù)10。

logs:交易的日志信息,本例并沒有記錄日志。

value:交易金額。在窗口右側(cè)的“運(yùn)行”面板中可以設(shè)置愿意支付的交易金額。設(shè)置交易金額5.1.2智能合約的構(gòu)造函數(shù)一個(gè)智能合約中只能有一個(gè)構(gòu)造函數(shù)。構(gòu)造函數(shù)在實(shí)例化智能合約時(shí)會(huì)自動(dòng)被調(diào)用。通??梢酝ㄟ^構(gòu)造函數(shù)為狀態(tài)變量指定初始值??梢允褂胏onstructor關(guān)鍵字定義構(gòu)造函數(shù)。構(gòu)造函數(shù)的例子pragmasolidity^0.5.1;//聲明合約contractA{uinta;

constructor(uint_a)public{a=_a;}}【例5-2】pragmasolidity^0.5.1;contractPurchase{stringpublicname;uintpublicprice;addresspayablepublicseller;

constructor(stringmemory_name,uint_price)public{name=_name;price=_price;seller=msg.sender;}}5.1.3智能合約之間的繼承繼承智能合約后,子合約會(huì)自然擁有父合約中狀態(tài)變量和公有、內(nèi)部函數(shù)的訪問權(quán)。【例5-3】pragmasolidity^0.5.1;contractAnimal{stringpublicname;uintpublicprice;uintinternalage;addressinternalowner;

functionsetName(stringmemory_name)public{name=_name;}

functiongetName()publicviewreturns(stringmemory){returnname;}functionsetPrice(uint_price)public{price=_price;}

functiongetPrice()publicviewreturns(uint){returnprice;}functionbuy()public{owner=msg.sender;}

functiongetOwner()publicviewreturns(address){returnowner;}}contractDogisAnimal{

functionsetAge(uint_age)public{age=_age;}

functiongetAge()publicviewreturns(uint){returnage;}

}子智能合約Dog從Animal繼承的狀態(tài)變量和函數(shù)5.2函數(shù)編程基礎(chǔ)5.2.1定義函數(shù)5.2.2函數(shù)修飾詞5.2.1定義函數(shù)function函數(shù)名(參數(shù)列表)函數(shù)修飾符returns(返回值類型列表){

函數(shù)體

return返回值;}【例5-4】pragmasolidity^0.5.1;contractDemo{functionadd(uint_a,uint_b)publicpurereturns(uint){return_a+_b;}}部署在開發(fā)工具面板中單擊“運(yùn)行”選項(xiàng)卡,單擊“部署”按鈕,在下部的已部署合約中會(huì)出現(xiàn)一個(gè)新的記錄Demoat0x692...77b3a(memory)。單擊此記錄,會(huì)在下面出現(xiàn)一個(gè)文本框和一個(gè)add按鈕。在文本框中輸入1,2,返回結(jié)果如下:

0:uint256:3

運(yùn)行例5-1的結(jié)果分別用于輸入?yún)?shù)_a和_b多個(gè)返回值在Solidity語言中,函數(shù)是可以有多個(gè)返回值的。只有在returns()中指定多個(gè)返回值的類型,用逗號(hào)(,)分隔。例如,指定返回2個(gè)uint類型的返回值的代碼如下:returns(uint,uint)【例5-5】pragmasolidity^0.5.1;//聲明合約contractDemo{functionswap(uint_x,uint_y)publicpurereturns(uint,uint){return(_y,_x);}}5.2.2函數(shù)修飾詞定義函數(shù)時(shí),在函數(shù)名和參數(shù)后面需要指定函數(shù)修飾詞。函數(shù)修飾詞包括可見性修飾詞、狀態(tài)修飾詞和payable修飾詞和自定義修飾詞(函數(shù)修改器)等類型。1.可見性修飾詞除了public、private和internal外,還可以使用external修飾符指定函數(shù)可以從智能合約的外部調(diào)用該函數(shù)。2.狀態(tài)性修飾詞狀態(tài)性修飾詞說

明pure指定函數(shù)既不向區(qū)塊鏈上寫數(shù)據(jù),也不從區(qū)塊鏈上讀取數(shù)據(jù)。即在函數(shù)中只操作存儲(chǔ)位置為memory的變量,不訪問區(qū)塊鏈view指定函數(shù)不向區(qū)塊鏈上寫數(shù)據(jù),但可以從區(qū)塊鏈上讀取數(shù)據(jù)constant與view的作用相同3.payable修飾詞payable修飾詞允許函數(shù)在被調(diào)用的同時(shí)接收以太幣。接受的以太幣會(huì)存儲(chǔ)在智能合約的賬戶中,可以在函數(shù)的代碼中將以太幣轉(zhuǎn)賬到其他賬戶。例如下面的代碼定義了一個(gè)智能合約OnlineStore,其中包含一個(gè)payable函數(shù)buysometing(),代碼如下:

contractOnlineStore{functionbuySomething()externalpayable{require(msg.value==0.001ether);transferThing(msg.sender);}}require()函數(shù)指定運(yùn)行buysometing()函數(shù)需要支付0.001個(gè)以太幣到智能合約的賬戶。如果調(diào)用者的賬戶中沒有足夠的以太幣,將拋出異常,無法運(yùn)行下面的代碼。msg.value代表調(diào)用者向合約發(fā)送以太幣的數(shù)量。external關(guān)鍵字指定buysometing()函數(shù)是可以被外部調(diào)用的??梢哉{(diào)用transfer()函數(shù)完成支付賬戶地址.transfer(轉(zhuǎn)賬金額);【例5-6】pragmasolidity^0.5.1;contractPayDemo{addresspayableaccount1=0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C;functionpay()payablepublic{account1.transfer(msg.value);}functiongetAccount1Balance()viewpublicreturns(uint){returnaccount1.balance;}//讀取合約發(fā)起方的余額

functiongetOwnerBalance()viewpublicreturns(uint){

addressOwner=msg.sender;returnOwner.balance;}}代碼說明如下·pay()函數(shù):用payable修飾的函數(shù),表明調(diào)用此函數(shù)時(shí)會(huì)向智能合約PayDemo的賬戶里面支付以太幣。然后程序會(huì)調(diào)用account1.transfer(msg.value)函數(shù)將收到的以太幣轉(zhuǎn)賬至賬戶account1。·getAccount1Balance()函數(shù):返回賬戶account1的余額?!etOwnerBalance()函數(shù):返回合約發(fā)起方賬戶余額。EIP-55格式的賬戶地址程序中賬戶account1被設(shè)定為Remix當(dāng)前賬戶下拉框中的一個(gè)測(cè)試賬戶,假定為0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C。這里的地址既包含小寫字母也包含大寫字母,這就是EIP-55格式的賬戶地址。EIP-55格式的賬戶地址自帶地址校驗(yàn)機(jī)制,將地址中的部分字母大寫,與剩余的小寫字母來形成校驗(yàn)和,讓地址擁有自校驗(yàn)的能力。這樣,如果用戶不小心填錯(cuò)了地址中的一個(gè)字母,就會(huì)被及時(shí)發(fā)現(xiàn)。訪問etherscan網(wǎng)站可以將給定的以太網(wǎng)地址轉(zhuǎn)換為EIP-55格式的賬戶地址(1)在Remix窗口左上部的“運(yùn)行”面板中,選擇“當(dāng)前賬號(hào)”下拉框中的一個(gè)余額為100ether地址,單擊后面的圖標(biāo),可以將選中的地址復(fù)制到剪貼板。得到一個(gè)全部都是小寫字母和數(shù)字組成的賬戶地址,例如0x14723a09acff6d2a60dcdf7aa4aff308fddc160c。(2)訪問如下網(wǎng)址,借助etherscan得到EIP-55格式的賬戶地址。

https://etherscan.io/address/0x14723a09acff6d2a60dcdf7aa4aff308fddc160c借助etherscan得到EIP-55格式的賬戶地址例5-3的運(yùn)行結(jié)果4.函數(shù)修改器函數(shù)修改器是執(zhí)行函數(shù)的前提條件,它可以定義一個(gè)條件,只有當(dāng)此條件滿足的情況下,才會(huì)執(zhí)行函數(shù)。定義函數(shù)修改器的方法如下:modifier修改器名{

條件體.._;}在函數(shù)a()上應(yīng)用函數(shù)修改器的方法functiona()修改器名{

函數(shù)體..}【例5-7】pragmasolidity^0.5.1;/***權(quán)限控制*/contractModifierDemo{addresspublicowner=msg.sender;//檢查必須是合約的所有者

modifieronlyOwner{require(msg.sender==owner,"必須是合約的所有者");_;}

//改變合約的擁有者身份

//newOwner是新所有者的地址

functionchangeOwner(address_newOwner)onlyOwner{if(_newOwner==0x0)throw;owner=_newOwner;}}【例5-8】pragmasolidity^0.5.1;contractmodifierDemo{addressseller;

modifierOnlySeller(){require(msg.sender==seller,"必須是賣家");_;}

functionOnSell()public{seller=msg.sender;}//取消交易

functionAbort()viewpublicOnlySeller{

//......}代碼說明如下·seller:用于保存賣家的賬戶地址?!nSell()函數(shù):模擬商品上架。將調(diào)用此函數(shù)的賬戶地址賦值到seller中?!nlySeller()函數(shù)修改器:指定調(diào)用者必須是seller,否則拋出異常?!bort()函數(shù):模擬商品下架,應(yīng)用OnlySeller()函數(shù)修改器,指定調(diào)用者必須是seller,否則拋出異常。5.2.3函數(shù)的參數(shù)1.形參和實(shí)參2.值類型和引用類型1.形參和實(shí)參在定義函數(shù)時(shí)指定的參數(shù)被稱為形參;在調(diào)用函數(shù)時(shí)指定的參數(shù)被稱為實(shí)參。例如,在例5-4中函數(shù)add()的2個(gè)參數(shù)_a和_b都是形參,如果使用add(1,2)調(diào)用函數(shù),則1和2為實(shí)參。也可以使用變量作為實(shí)參。2.值類型和引用類型函數(shù)的參數(shù)可以分為值類型和引用類型2種。在調(diào)用函數(shù)時(shí)需要給值類型參數(shù)傳遞一個(gè)值,也就是將指定的值復(fù)制到值類型參數(shù)變量的地址中,值類型參數(shù)可以是整型、地址、定長(zhǎng)字節(jié)數(shù)組和枚舉類型。在調(diào)用函數(shù)時(shí)需要給引用類型參數(shù)傳遞一個(gè)地址也就是說在函數(shù)中對(duì)參數(shù)進(jìn)行操作,相當(dāng)于直接操作傳遞進(jìn)來的變量,引用類型參數(shù)可以是不定長(zhǎng)字節(jié)數(shù)組、字符串、數(shù)組和結(jié)構(gòu)體,這些數(shù)據(jù)類型的參數(shù)還需要使用memory或storage修飾符指定它是值類型還是引用類型。memory指定參數(shù)為值類型,storage指定參數(shù)為引用類型。例如,如果一個(gè)字符串參數(shù)不指定memory或storage修飾符,會(huì)無法通過編譯?!纠?-9】pragmasolidity^0.5.1;contractParameterDemo{strings="test";

functionSetString(stringstorage_str)internal{bytes(_str)[0]="T";}functionSetStrTest()publicreturns(stringmemory){

SetString(s);returns;}functionGetS()publicviewreturns(stringmemory){returns;}5.3函數(shù)的高級(jí)應(yīng)用5.3.1自毀函數(shù)5.3.2函數(shù)重載5.3.3內(nèi)置函數(shù)5.3.1自毀函數(shù)自毀函數(shù)是一個(gè)特殊的函數(shù)。它有著固定的名稱和固定的參數(shù)。用于銷毀當(dāng)前智能合約,并將當(dāng)前合約賬戶中的余額發(fā)送到指定的地址。自毀函數(shù)的名稱為selfdestruct,它有且只有一個(gè)address參數(shù),用于指定接收當(dāng)前合約賬戶余額的賬戶地址。自毀函數(shù)默認(rèn)存在,不需要顯式定義?!纠?-10】演示自毀函數(shù)的使用方法pragmasolidity^0.5.1;contractselfdestructDemo{constructor()payablepublic{}functionkill(addresspayable_add)public{selfdestruct(_add);}}5.3.2函數(shù)重載函數(shù)重載是指函數(shù)的命名相同,但是函數(shù)的參數(shù)定義不同。參數(shù)定義不同有如下2層含義:(1)參數(shù)的數(shù)量不同。(2)參數(shù)的類型不同。下面代碼定義的2個(gè)fun1()函數(shù)并不是函數(shù)重載contractOverload{//error,重名方法

functionfun1()public{}functionfun1()public{}}下面代碼定義的2個(gè)fun2()函數(shù)也并不是函數(shù)重載,因?yàn)樗鼈冎挥蟹祷刂挡煌琧ontractOverload{//error,重名方法

functionfun2()publicreturns(uint){}functionfun2()publicreturns(string){}}下面代碼定義的2個(gè)fun3()函數(shù)在編譯時(shí)被認(rèn)為是函數(shù)重載,不會(huì)報(bào)錯(cuò)。但是在傳入?yún)?shù)小于256時(shí),程序會(huì)報(bào)錯(cuò),因?yàn)闊o法匹配合適的函數(shù)(2個(gè)函數(shù)都可以匹配)。contractOverload{//error,重名方法

functionfun3(uint_a)public{}functionfun3(uint8_a)public{}}【例5-11】演示函數(shù)重載的情況pragmasolidity^0.5.1;contractOverload{functionfunc1()publicpurereturns(uint){return0;}functionfunc1(uint_a)publicpurereturns(uint){return_a;}}例5-11的部署情況5.3.3內(nèi)置函數(shù)1.獲取區(qū)塊和交易屬性的函數(shù)2.?dāng)?shù)學(xué)和密碼學(xué)相關(guān)函數(shù)1.獲取區(qū)塊和交易屬性的函數(shù)函數(shù)說

明blockhash(uintblockNumber)returns(bytes32)返回指定區(qū)塊的哈希block.coinbase(address)returns(address)返回幣基地址,也就是挖出當(dāng)前區(qū)塊的礦工地址block.difficulty(uint)returns(uint)返回當(dāng)前區(qū)塊難度Block.getGasLimit()returns(uint)返回當(dāng)前區(qū)塊Gas上限block.number()returns(uint)返回當(dāng)前區(qū)塊號(hào)block.timestampreturns(uint)返回當(dāng)前區(qū)塊的時(shí)間戳gasleft()returns(uint256)返回剩余的Gasmsg.sender()返回消息的發(fā)送者,調(diào)用函數(shù)的賬戶地址msg.value()返回隨消息發(fā)送的wei的數(shù)量now()block.timestamp的別名tx.gasprice()返回交易的Gas價(jià)格tx.origin()返回交易的發(fā)起者2.?dāng)?shù)學(xué)和密碼學(xué)相關(guān)函數(shù)函數(shù)說

明addmod(uintx,uinty,uintk)returns(uint)計(jì)算

(x+y)%kmulmod(uintx,uinty,uintk)returns(uint)計(jì)算(x*y)%kkeccak256((bytesmemory)returns(bytes32)計(jì)算Keccak-256哈希sha256(bytesmemory)returns(bytes32)計(jì)算參數(shù)的SHA-256哈希ripemd160(bytesmemory)returns(bytes20)計(jì)算參數(shù)的RIPEMD-160哈希ecrecover(bytes32hash,uint8v,bytes32r,bytes32s)returns(address)利用橢圓曲線簽名恢復(fù)與公鑰相關(guān)的地址,如果出現(xiàn)錯(cuò)誤則返回05.4外部函數(shù)在其他Solidity文件中定義的函數(shù)被稱為外部函數(shù)。5.4.1導(dǎo)入外部函數(shù)5.4.2函數(shù)庫(kù)5.4.3Fallback函數(shù)5.4.1導(dǎo)入外部函數(shù)假定在一個(gè)智能合約Test中定義一個(gè)測(cè)試函數(shù)add(),代碼如下:pragmasolidity^0.5.1;contractTest{constructor()payablepublic{

}

functionadd(uint_a,uint_b)publicpurereturns(uint){return_a+_b;}}在另一個(gè)智能合約中ImportTest中導(dǎo)入外部函數(shù)add()的方法如下import"./test.sol";//導(dǎo)入外部的sol文件。(Test合約)

pragmasolidity^0.5.1;import"./test.sol";//導(dǎo)入外部的sol文件。(Test合約)

contractImportTest{

functiontest()publicreturns(uint){Testt=newTest();returnt.add(1,2);//調(diào)用Test合約中的add()函數(shù)

}}調(diào)用外部函數(shù)add()的執(zhí)行結(jié)果5.4.2函數(shù)庫(kù)在Solidity中,函數(shù)庫(kù)(Libraries)是函數(shù)的集合。它類似于智能合約,也對(duì)應(yīng)一個(gè)地址,但是函數(shù)庫(kù)只能部署一次。在智能合約中可以通過DELEGATECALL方式調(diào)用庫(kù)中的函數(shù)。此時(shí)函數(shù)是在智能合約的上下文環(huán)境中運(yùn)行的。在函數(shù)庫(kù)中,可以使用this指向調(diào)用它的智能合約,但是只能訪問調(diào)用合約明確提供的狀態(tài)變量。使用library關(guān)鍵字定義函數(shù)庫(kù)library<函數(shù)庫(kù)名>{

函數(shù)1定義函數(shù)2定義

………

函數(shù)n定義}【例5-12】pragmasolidity^0.5.1;libraryMath{functionadd(uint_x,uint_y)publicpurereturns(uint){return_x+_y;}functionminus(uint_x,uint_y)publicpurereturns(uint){return_x-_y;}functionmultiple(uint_x,uint_y)publicpurereturns(uint){return_x*_y;}functiondivide(uint_x,uint_y)publicpurereturns(uint){return_x/_y;}}函數(shù)庫(kù)Math保存為math.sol。創(chuàng)建智能合約TestMath,其中調(diào)用函數(shù)庫(kù)Mathpragmasolidity^0.5.1;import"./math.sol";contractTestMath{usingMathforuint;functionTestAdd()publicpurereturns(uint){uinta=1;returna.add(2);}functionTestMinus()publicpurereturns(uint){uinta=10;returna.minus(2);}functionTestMultiple()publicpurereturns(uint){uinta=10;returna.multiple(2);}functionTestDivide()publicpurereturns(uint){uinta=10;returna.divide(2);}}例5-6的運(yùn)行結(jié)果例5-6的計(jì)算過程函數(shù)調(diào)用函數(shù)庫(kù)Math中的函數(shù)計(jì)算過程結(jié)果TestAdd()add(1,2)1+23TestMinus()minus(10,2)10-28TestMultiple()multiple(10,2)10*220TestAdd()divide(10,2)10/255.4.3Fallback函數(shù)所謂Fallback函數(shù)也叫做回退函數(shù)。Fallback函數(shù)沒有函數(shù)名,也沒有參數(shù)和返回值。一個(gè)智能合約只能包含一個(gè)Fallback函數(shù)。以下兩種情況下會(huì)調(diào)用Fallback函數(shù)(1)調(diào)用合約時(shí),沒有匹配上任何一個(gè)函數(shù)。在編譯的過程中,Solidity會(huì)對(duì)程序的語法進(jìn)行檢查。因此,不可能顯式地調(diào)用一個(gè)不存在的函數(shù)。但是可以使用Solidity提供的底層函數(shù)address.call()來模擬這種情況。(2)智能合約在接收以太幣時(shí)。1.調(diào)用不存在的函數(shù)使用底層函數(shù)address.call()可以模擬調(diào)用一個(gè)不存在的函數(shù)的情形。使用address.call()函數(shù)的方法如下:address.call(<函數(shù)選擇器,參數(shù)列表>)函數(shù)選擇器函數(shù)選擇器可以看做是函數(shù)的標(biāo)識(shí),具體情況將在第6章中介紹。這里只需要了解通過下面的方法可以的得到函數(shù)選擇器:函數(shù)選擇器=abi.encodeWithSignature("<函數(shù)名>(參數(shù)類型列表)"));實(shí)際上就是對(duì)函數(shù)名及其參數(shù)類型列表進(jìn)行哈希運(yùn)算后取前4個(gè)字節(jié)。【例5-13】pragmasolidity^0.5.1;contractExecuteFallback{functioncallNonExistFunc()publicreturns(bool){bytesmemoryfuncIdentifier=abi.encodeWithSignature("functionNotExist()");(boolsuccess,bytesmemoryreturnData)=address(this).call(funcIdentifier);returnsuccess;例5-13的日志2.智能合約接受以太幣時(shí)需要定義Fallback函數(shù)智能合約在接受以太幣時(shí),會(huì)自動(dòng)調(diào)用Fallback函數(shù)。一個(gè)沒有定義回退函數(shù)的合約。如果接收以太幣,會(huì)觸發(fā)異常,并返還以太幣。所以如果智能合約要接收以太幣,就需要定義Fallback函數(shù)。而且此時(shí)Fallback函數(shù)必須要有payable修飾符?!纠?-14】

//使用send()發(fā)送ether,觀察會(huì)觸發(fā)fallback函數(shù)

functionsendEther()public{boolresult=address(this).send(1);//從合約地址的余額中發(fā)送1wei給它自己,所以其balance不會(huì)變,只是會(huì)消耗msg.sender賬戶gasemitSendEvent(address(this),1,result);}}SendEvent事件eventSendEvent(addressto,uintvalue,boolresult);智能合約SendFallback中定義一個(gè)Fallback函數(shù)

//fallback函數(shù)及其事件

eventFallbackTrigged(bytesdata);function()publicpayable{//一定要聲明為payable,否則send()執(zhí)行結(jié)果將會(huì)始終為falseemitFallbackTrigged(msg.data);}getBalance()函數(shù)functiongetBalance()publicviewreturns(uint){returnaddress(this).balance;}初始化時(shí)調(diào)用sendEther()函數(shù)的日志deposit()函數(shù)functiondeposit()publicpayable{}智能合約的賬戶中有足夠余額時(shí)調(diào)用sendEther()函數(shù)的日志5.5抽象合約和接口5.5.1抽象合約5.5.2接口5.5.3繼承5.5.1抽象合約抽象合約指包含抽象函數(shù)的智能合約。抽象函數(shù)沒有函數(shù)體,函數(shù)聲明頭以;結(jié)束。例如,下面就是一個(gè)抽象合約的定義,其中包含一個(gè)抽象函數(shù)cry()。contractPet{functioncry()publicreturns(stringmemory);}抽象合約也可以包含非抽象函數(shù)例如,抽象合約Pet中可以定義一個(gè)run()函數(shù),代碼如下:pragmasolidity^0.5.1;contractPet{functioncry()publicreturns(stringmemory);functionrun()publicreturns(stringmemory){return"run";}}抽象合約不能被部署5.5.2接口接口類似于抽象合約,也包含抽象函數(shù)。但是接口中不包含非抽象函數(shù)。例如5.5.1節(jié)中介紹的run函數(shù)就不能包含在接口中。接口具有如下特性·接口不能繼承其他智能合約和接口。·接口中不能定義變量?!そ涌诓荒芏x構(gòu)造函數(shù)?!そ涌诓荒芏x結(jié)構(gòu)體?!そ涌谥胁荒芏x枚舉類型。使用interface關(guān)鍵字定義接口interfacePet{functioncry(stringmemory)public;}5.5.3繼承可以使用is關(guān)鍵字定義智能

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論