摘要:本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接智能合約語言教程系列錯(cuò)誤處理原文已更新,請(qǐng)讀者前往原文閱讀這是教程系列文章第篇介紹錯(cuò)誤處理。如果合約沒有修飾符的的函數(shù)在接收以太幣時(shí)包括構(gòu)造函數(shù),和回退函數(shù)。如果合約通過一個(gè)的函數(shù)接收以太幣。
本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)
原文鏈接:智能合約語言 Solidity 教程系列9 - 錯(cuò)誤處理原文已更新,請(qǐng)讀者前往原文閱讀
這是Solidity教程系列文章第9篇介紹Solidity 錯(cuò)誤處理。
Solidity系列完整的文章列表請(qǐng)查看分類-Solidity。
Solidity 是以太坊智能合約編程語言,閱讀本文前,你應(yīng)該對(duì)以太坊、智能合約有所了解,
如果你還不了解,建議你先看以太坊是什么
歡迎訂閱區(qū)塊鏈技術(shù)專欄閱讀更全面的分析文章。
什么是錯(cuò)誤處理錯(cuò)誤處理是指在程序發(fā)生錯(cuò)誤時(shí)的處理方式,Solidity處理錯(cuò)誤和我們常見的語言不一樣,Solidity是通過回退狀態(tài)的方式來處理錯(cuò)誤。發(fā)生異常時(shí)會(huì)撤消當(dāng)前調(diào)用(及其所有子調(diào)用)所改變的狀態(tài),同時(shí)給調(diào)用者返回一個(gè)錯(cuò)誤標(biāo)識(shí)。注意捕捉異常是不可能的,因此沒有try ... catch...。
為什么Solidity處理錯(cuò)誤要這樣設(shè)計(jì)呢?
我們可以把區(qū)塊鏈理解為是全球共享的分布式事務(wù)性數(shù)據(jù)庫。全球共享意味著參與這個(gè)網(wǎng)絡(luò)的每一個(gè)人都可以讀寫其中的記錄。如果想修改這個(gè)數(shù)據(jù)庫中的內(nèi)容,就必須創(chuàng)建一個(gè)事務(wù),事務(wù)意味著要做的修改(假如我們想同時(shí)修改兩個(gè)值)只能被完全的應(yīng)用或者一點(diǎn)都沒有進(jìn)行。
學(xué)習(xí)過數(shù)據(jù)庫的同學(xué),應(yīng)該理解事務(wù)的含義,如果你對(duì)事務(wù)一詞不是很理解,建議你搜索一下“數(shù)據(jù)庫事務(wù)“。
Solidity錯(cuò)誤處理就是要保證每次調(diào)用都是事務(wù)性的。
Solidity提供了兩個(gè)函數(shù)assert和require來進(jìn)行條件檢查,如果條件不滿足則拋出異常。assert函數(shù)通常用來檢查(測(cè)試)內(nèi)部錯(cuò)誤,而require函數(shù)來檢查輸入變量或合同狀態(tài)變量是否滿足條件以及驗(yàn)證調(diào)用外部合約返回值。
另外,如果我們正確使用assert,有一個(gè)Solidity分析工具就可以幫我們分析出智能合約中的錯(cuò)誤,幫助我們發(fā)現(xiàn)合約中有邏輯錯(cuò)誤的bug。
除了可以兩個(gè)函數(shù)assert和require來進(jìn)行條件檢查,另外還有兩種方式來觸發(fā)異常:
revert函數(shù)可以用來標(biāo)記錯(cuò)誤并回退當(dāng)前調(diào)用
使用throw關(guān)鍵字拋出異常(從0.4.13版本,throw關(guān)鍵字已被棄用,將來會(huì)被淘汰。)
當(dāng)子調(diào)用中發(fā)生異常時(shí),異常會(huì)自動(dòng)向上“冒泡”。 不過也有一些例外:send,和底層的函數(shù)調(diào)用call, delegatecall,callcode,當(dāng)發(fā)生異常時(shí),這些函數(shù)返回false。
注意:在一個(gè)不存在的地址上調(diào)用底層的函數(shù)call,delegatecall,callcode 也會(huì)返回成功,所以我們?cè)谶M(jìn)行調(diào)用時(shí),應(yīng)該總是優(yōu)先進(jìn)行函數(shù)存在性檢查。
在下面通過一個(gè)示例來說明如何使用require來檢查輸入條件,以及assert用于內(nèi)部錯(cuò)誤檢查:
pragma solidity ^0.4.0; contract Sharer { function sendHalf(address addr) public payable returns (uint balance) { require(msg.value % 2 == 0); // 僅允許偶數(shù) uint balanceBeforeTransfer = this.balance; addr.transfer(msg.value / 2); // 如果失敗,會(huì)拋出異常,下面的代碼就不是執(zhí)行 assert(this.balance == balanceBeforeTransfer - msg.value / 2); return this.balance; } }
我們實(shí)際運(yùn)行下,看看異常是如何發(fā)生的:
首先打開Remix,貼入代碼,點(diǎn)擊創(chuàng)建合約。如下圖:
運(yùn)行測(cè)試1:附加1wei (奇數(shù))去調(diào)用sendHalf,這時(shí)會(huì)發(fā)生異常,如下圖:
運(yùn)行測(cè)試2:附加2wei 去調(diào)用sendHalf,運(yùn)行正常。
運(yùn)行測(cè)試3:附加2wei以及sendHalf參數(shù)為當(dāng)前合約本身,在轉(zhuǎn)賬是發(fā)生異常,因?yàn)楹霞s無法接收轉(zhuǎn)賬,錯(cuò)誤提示上圖類似。
assert類型異常在下述場(chǎng)景中自動(dòng)產(chǎn)生assert類型的異常:
如果越界,或負(fù)的序號(hào)值訪問數(shù)組,如i >= x.length 或 i < 0時(shí)訪問x[i]
如果序號(hào)越界,或負(fù)的序號(hào)值時(shí)訪問一個(gè)定長的bytesN。
被除數(shù)為0, 如5/0 或 23 % 0。
對(duì)一個(gè)二進(jìn)制移動(dòng)一個(gè)負(fù)的值。如:5<
整數(shù)進(jìn)行可以顯式轉(zhuǎn)換為枚舉時(shí),如果將過大值,負(fù)值轉(zhuǎn)為枚舉類型則拋出異常
如果調(diào)用未初始化內(nèi)部函數(shù)類型的變量。
如果調(diào)用assert的參數(shù)為false
require類型異常在下述場(chǎng)景中自動(dòng)產(chǎn)生require類型的異常:
調(diào)用throw
如果調(diào)用require的參數(shù)為false
如果你通過消息調(diào)用一個(gè)函數(shù),但在調(diào)用的過程中,并沒有正確結(jié)束(gas不足,沒有匹配到對(duì)應(yīng)的函數(shù),或被調(diào)用的函數(shù)出現(xiàn)異常)。底層操作如call,send,delegatecall或callcode除外,它們不會(huì)拋出異常,但它們會(huì)通過返回false來表示失敗。
如果在使用new創(chuàng)建一個(gè)新合約時(shí)出現(xiàn)第3條的原因沒有正常完成。
如果調(diào)用外部函數(shù)調(diào)用時(shí),被調(diào)用的對(duì)象不包含代碼。
如果合約沒有payable修飾符的public的函數(shù)在接收以太幣時(shí)(包括構(gòu)造函數(shù),和回退函數(shù))。
如果合約通過一個(gè)public的getter函數(shù)(public getter funciton)接收以太幣。
如果.transfer()執(zhí)行失敗
當(dāng)發(fā)生require類型的異常時(shí),Solidity會(huì)執(zhí)行一個(gè)回退操作(指令0xfd)。
當(dāng)發(fā)生assert類型的異常時(shí),Solidity會(huì)執(zhí)行一個(gè)無效操作(指令0xfe)。
在上述的兩種情況下,EVM都會(huì)撤回所有的狀態(tài)改變。是因?yàn)槠谕慕Y(jié)果沒有發(fā)生,就沒法繼續(xù)安全執(zhí)行。必須保證交易的原子性(一致性,要么全部執(zhí)行,要么一點(diǎn)改變都沒有,不能只改變一部分),所以需要撤銷所有操作,讓整個(gè)交易沒有任何影響。
注意assert類型的異常會(huì)消耗掉所有的gas, 而require從大都會(huì)版本(Metropolis, 即目前主網(wǎng)所在的版本)起不會(huì)消耗gas。
參考視頻我們也推出了目前市面上最全的視頻教程:深入詳解以太坊智能合約語言Solidity
目前我們也在招募體驗(yàn)師,可以點(diǎn)擊鏈接了解。
Solidity 錯(cuò)誤處理
? 深入淺出區(qū)塊鏈 - 系統(tǒng)學(xué)習(xí)區(qū)塊鏈,打造最好的區(qū)塊鏈技術(shù)博客。
? 我的知識(shí)星球為各位解答區(qū)塊鏈技術(shù)問題,歡迎加入討論。
? 關(guān)注公眾號(hào)“深入淺出區(qū)塊鏈技術(shù)”第一時(shí)間獲取區(qū)塊鏈技術(shù)信息。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/24107.html
摘要:引言給迷失在如何學(xué)習(xí)區(qū)塊鏈技術(shù)的同學(xué)一個(gè)指引,區(qū)塊鏈技術(shù)是隨比特幣誕生,因此要搞明白區(qū)塊鏈技術(shù),應(yīng)該先了解下比特幣。但區(qū)塊鏈技術(shù)不單應(yīng)用于比特幣,還有非常多的現(xiàn)實(shí)應(yīng)用場(chǎng)景,想做區(qū)塊鏈應(yīng)用開發(fā),可進(jìn)一步閱讀以太坊系列。 本文始發(fā)于深入淺出區(qū)塊鏈社區(qū), 原文:區(qū)塊鏈技術(shù)學(xué)習(xí)指引 原文已更新,請(qǐng)讀者前往原文閱讀 本章的文章越來越多,本文是一個(gè)索引帖,方便找到自己感興趣的文章,你也可以使用左側(cè)...
摘要:狀態(tài)變量合約內(nèi)聲明的公有變量還有一個(gè)存儲(chǔ)位置是,用來存儲(chǔ)函數(shù)參數(shù),是只讀的,不會(huì)永久存儲(chǔ)的一個(gè)數(shù)據(jù)位置。稱這個(gè)為狀態(tài)改變,這也是合約級(jí)變量稱為狀態(tài)變量的原因。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:智能合約語言 Solidity 教程系列4 - 數(shù)據(jù)存儲(chǔ)位置分析原文已更新,請(qǐng)讀者前往原文閱讀 Solidity教程系列第4篇 - Solidity數(shù)據(jù)位置分析。 寫在前面 Solidity...
摘要:還需注意的一點(diǎn)是,定長數(shù)組,不能與變長數(shù)組相互賦值,我們來看下面的代碼無法編譯已經(jīng)計(jì)劃在未來移除這樣的限制。的變長數(shù)組,可以通過給賦值調(diào)整數(shù)組長度。的變長數(shù)組不支持。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:智能合約語言Solidity教程系列5 - 數(shù)組介紹原文已更新,請(qǐng)讀者前往原文閱讀 Solidity 教程系列第5篇 - Solidity 數(shù)組介紹。Solidity 系列完整的文章...
摘要:如果想對(duì)輸入的變量說明其不同的單位,可以使用下面的方式參考視頻我們也推出了目前市面上最全的視頻教程深入詳解以太坊智能合約語言目前我們也在招募體驗(yàn)師,可以點(diǎn)擊鏈接了解。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:智能合約語言 Solidity 教程系列7 - 以太單位及時(shí)間單位原文已更新,請(qǐng)讀者前往原文閱讀 這是Solidity教程系列文章第7篇介紹以太單位及時(shí)間單位,系列帶你全面深入理解S...
摘要:本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接智能合約語言教程系列結(jié)構(gòu)體與映射原文已更新,請(qǐng)讀者前往原文閱讀教程系列第篇結(jié)構(gòu)體與映射。不能聲明一個(gè)同時(shí)將自身作為成員,這個(gè)限制是基于結(jié)構(gòu)體的大小必須是有限的。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:智能合約語言Solidity教程系列6 - 結(jié)構(gòu)體與映射原文已更新,請(qǐng)讀者前往原文閱讀 Solidity 教程系列第6篇 - Solidity 結(jié)構(gòu)體與...
閱讀 3482·2021-11-19 09:40
閱讀 1499·2021-10-13 09:41
閱讀 2673·2021-09-29 09:35
閱讀 2718·2021-09-23 11:21
閱讀 1711·2021-09-09 11:56
閱讀 838·2019-08-30 15:53
閱讀 852·2019-08-30 15:52
閱讀 605·2019-08-30 12:47