雖然以太坊本身的技術沒有問題,不代表在其之上寫出的智能合約沒有bug,事實上,已經發生過很多次了。如果寫出健壯的智能合約成為了一個研究方向,沒有bug的程序是不可能存在的,所有健壯性策略的目標都是緊急規避和減小損失,而不是100%安全。
智能合約一些常見的bug
overrun bug
假設一個合約是這么寫的
contract money {
mapping(address=>uint) book
...
function withDraw() {
if(book[msg.sender] > 0){
if(msg.sender.call.value(book[msg.sender])()) {
book[msg.sender] = 0;
}
}
}
}
然后攻擊者是這么寫的
contract attack {
uint times;
function() {
if(times == 0) {
money.withDraw();
}
}
}
然后如果attack主動去call一次money.withDraw(),看看會發生什么?
transaction refuse
假設我們寫了一個拍賣合約,每當當前出價最高者被超過時,就將他所出的份額返還,該怎么寫?
如果寫成:
...
if(被超過){
lastwinner.send(lastbid);
}
而某一個bidder的code是這樣的:
contract bidder {
function() {
throw;
}
}
ok,如果這個bidder不幸的成為了暫時的winner,你就會發現,沒有任何一個人能出價超過它了,因為所有的超過他的出價交易都會被cancel掉
智能合約安全策略
停止開關
這個策略是用一個Emergency的modifier,緊急情況下可以停止某些智能合約功能。code如下:
modifiler stopInEmergency {if (!stopped) _ }
modifier onlyInEmergency {if(stopped) _ }
contract XX {
function normal() stopInEmergency {}
function destroy() onlyInEmergency {}
}
損失最小化
損失最小化策略主要是在合約的各個功能點處設立保護屏障,比如如果你在寫一個涉及轉賬的合約,那么在轉賬功能里就可以設置最大額度,如果超過這個額度,就需要合約管理員去approve,或者延遲發送。
bug獎券
這個是一個很奇妙的策略,就是讓你的智能合約可以很容易被別人部署,然后一旦有bug發現,就會給予發現者一點獎勵。
先檢查,再生效,最后才交互
任何一個函數,首先需要檢查各種條件并盡早報錯,然后讓函數應有功能生效,最后才是去與外界接口交互。
因為如果不提前生效改變自己的狀態,在與外界交互時它們就可能通過進一步觸發用合約不正確的狀態去執行一些操作。
pull over push
假設我們寫了一個拍賣合約,每當當前出價最高者被超過時,就將他所出的份額返還,該怎么寫?
如果寫成:
...
if(被超過){
lastwinner.send(lastbid);
}
而某一個bidder的code是這樣的:
contract bidder {
function() {
throw;
}
}
ok,如果這個bidder不幸的成為了暫時的winner,你就會發現,沒有任何一個人能出價超過它了,因為所有的超過他的出價交易都會被cancel掉。
原因是我們的函數里有對send的依賴,而這個是不安全的,正確的做法是出價被超過時,僅僅將他的出價打個標記,讓出價者自己去call某一個withdraw函數把自己的份額拿回來。
QQ群:654894791
微信公眾號: 94ETH
頭條號: 周期與泡沫