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; }
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 没有初始值时也会提醒开发者。
|
本文链接: https://dreamerjonson.com/2018/11/25/solidity-52-security-storage/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处!
![solidity智能合约[52]-安全-storage陷阱 solidity智能合约[52]-安全-storage陷阱](/default/index/img?u=aHR0cHM6Ly9jYWNoZS55aXN1LmNvbS91cGxvYWQvaW5mb3JtYXRpb24vMjAyMDAzMTIvNjUvMjM4OTE0LmpwZw==)