1. 程式人生 > >solidity智慧合約[52]-安全-storage陷阱

solidity智慧合約[52]-安全-storage陷阱

storage陷阱

下面的合約是一個鎖定金額的合約,使用者將資金儲存在此合約中,只有當過了一段時間時候才能夠提取出來。
下面的案例是為了說明storage屬性預設性帶來的陷阱。payIn函式是當用戶儲存金額時呼叫的函式。傳遞的引數似乎解鎖的時間。在合約payIn中,HoldRecord newRecord; 其實預設為storage型別,並且,當不為storage變數賦值的時候,變數預設引用的位置是storage空間中的0號位置。這也意味著在當前的案例中,newRecord指標指向了ownerAmount,當對newRecord 執行newRecord.amount += msg.value; 實則將ownerAmount即合約擁有者的金額增加了。 這時,合約擁有者就可以呼叫ownerWithdrawal將使用者儲存在合約的錢轉移出來。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
pragma solidity ^0.4.23;

contract HodlFraud {
   uint public ownerAmount;  //合約擁有者的金錢
   uint public  numberOfPayouts; //次數
   address public owner;  //合約的擁有者


   struct HoldRecord {
       uint amount;  //儲存的金錢
       uint unlockTime;  //解鎖的時間
   }

   mapping (address => HoldRecord) public balance;  //地址  => 儲存的金錢,時間

   //建構函式初始化
   function HodlFraud
() public payable
{

       owner = msg.sender;
       ownerAmount = msg.value;
   }

   //某一個使用者儲存金錢,
   //@param  holdTime 代表的是解鎖時間
   function payIn(uint holdTime) public payable {
       require(msg.value > 0);


       HoldRecord  newRecord;


       newRecord.amount += msg.value;
       newRecord.unlockTime = now + holdTime;
       balance[msg.sender] = newRecord;
   }

   //轉賬,使用這筆錢
   function withdraw () public {
       require(balance[msg.sender].unlockTime < now && balance[msg.sender].amount > 0);

       msg.sender.transfer(balance[msg.sender].amount);

       balance[msg.sender].amount = 0;
       numberOfPayouts++;
   }

   //合約的擁有著,轉移自己的錢
   function ownerWithdrawal () public {
       require(msg.sender == owner && ownerAmount > 0);
       msg.sender.transfer(ownerAmount);
       ownerAmount = 0;
   }
}

解決辦法

HoldRecord newRecord 修改為 HoldRecord memory newRecord

總結

1
2
3
// 這個例子是要舉出在 smart contract 中 storage 預設行為的危險性。其實只要維持一個原則就可以避免這個問題。
// 養成明確定義使用 storage 還是 memory 的好習慣
// 一般來說,指定 storage 時就直接給初始值;而在 function 裡面需要用到的快取器都用 memory,除非想要直接修改鏈上的值。現在 compiler 都會很聰明的提醒開發者要定義 storage 還是 memory,而當 storage pointer 沒有初始值時也會提醒開發者。

image.png