泰岳联盟链,智能合约中的安全

call调用

contract auction {
  address highestBidder;
  uint highestBid;
  function bid() {
    if (msg.value < highestBid) throw;
    if (highestBidder != 0)
      highestBidder.send(highestBid); // refund previous bidder
    highestBidder = msg.sender;
    highestBid = msg.value;
  }
}

由于最大堆栈深度为1024,因此新投标人可以始终将堆栈大小增加到1023,然后再进行呼叫bid(),这将导致send(highestBid)呼叫默默失败(即,先前的投标人将不会获得退款),但是新投标人仍将是最高的投标人。检查是否send成功的一种方法是检查其返回值:

if (highestBidder != 0)
  if (!highestBidder.send(highestBid))
    throw;

防止这两种情况的唯一方法是通过让接收者控制转移,将发送模式转换为撤回模式:

contract auction {
  address highestBidder;
  uint highestBid;
  mapping(address => uint) refunds;
  function bid() {
    if (msg.value < highestBid) throw;
    if (highestBidder != 0)
      refunds[highestBidder] += highestBid;
    highestBidder = msg.sender;
    highestBid = msg.value;
  }
  function withdrawRefund() {
    if (msg.sender.send(refunds[msg.sender]))
      refunds[msg.sender] = 0;
  }
}

为什么在合同上方仍然说“负面例子”?由于天然气技术的原因,合同实际上是可以的,但它仍然不是一个很好的例子。原因是不可能阻止作为发送的一部分在接收者处执行代码。这意味着在发送功能仍在进行中时,收件人可以回拨到withdrawRefund。那时,退款金额仍然相同,因此他们将再次获得退款,依此类推。在此特定示例中,它不起作用,因为接收者仅获得汽油津贴(2100gas),并且无法用此数量的gas执行另一次发送。下面的代码,虽然是容易受到这种攻击:

msg.sender.call.value(refunds[msg.sender])()

以下代码可以解决

contract auction {
  address highestBidder;
  uint highestBid;
  mapping(address => uint) refunds;
  function bid() {
    if (msg.value < highestBid) throw;
    if (highestBidder != 0)
      refunds[highestBidder] += highestBid;
    highestBidder = msg.sender;
    highestBid = msg.value;
  }
  function withdrawRefund() {
    uint refund = refunds[msg.sender];
    refunds[msg.sender] = 0;
    if (!msg.sender.send(refund))
     refunds[msg.sender] = refund;
  }
}

Gas的限制

一个区块中可以消耗多少天然气是有限制的。这个限制是灵活的,但是很难增加它。这意味着在所有(合理)情况下,合同中的每个功能都应保持在一定量的gas以下。以下是投票合同的不良示例:

contract Voting {
  mapping(address => uint) voteWeight;
  address[] yesVotes;
  uint requiredWeight;
  address beneficiary;
  uint amount;
  function voteYes() { yesVotes.push(msg.sender); }
  function tallyVotes() {
    uint yesVotes;
    for (uint i = 0; i < yesVotes.length; ++i)
      yesVotes += voteWeight[yesVotes[i]];
    if (yesVotes > requiredWeight)
      beneficiary.send(amount);
  }
}

合同实际上有几个问题,但是我想在这里强调的是循环问题:假设投票权重像令牌一样是可转让和可拆分的(以DAO令牌为例)。这意味着您可以创建任意数量的自己的克隆。创建此类克隆将增加tallyVotes函数中循环的长度,直到消耗的gas超过单个块中可用的gas为止。

这适用于使用循环的任何内容,也适用于合同中未明确显示循环的情况,例如,在存储内部复制数组或字符串时。同样,如果循环的长度是由调用者控制的,例如,如果您遍历作为函数参数传递的数组,则可以使用任意长度的循环。但是,切勿创建这样一种情况:环路长度受一方控制,而一方不是唯一遭受失败的一方。

附带说明一下,这就是为什么我们现在在DAO合同中拥有冻结帐户的概念的原因之一:投票权重是在投票开始时计算的,以防止循环陷入困境以及是否投票在投票期结束之前,权重是固定的,您可以通过只转移令牌然后再次投票来进行第二次投票。

Throw操作

row语句通常非常方便,可以在调用过程中恢复对状态所做的任何更改(或整个事务,具体取决于调用函数的方式)。但是,您必须知道,它还会导致所有gas都被消耗掉,因此很昂贵,并且有可能使对当前函数的调用停止。因此,我建议仅在以下情况下建议使用它:

1. send

如果某个函数不是要以当前状态或当前参数接收以太币,则应使用throw拒绝。由于gas和堆栈深度问题,使用throw是可靠地发送的唯一方法:接收者的回退功能可能有错误,该功能占用了太多的gas,因此无法接收以太坊,或者该功能可能是在恶意软件中调用的堆栈深度过高的上下文(可能甚至在调用函数之前)。

2.恢复调用函数的效果

如果在其他合同上调用函数,则永远无法知道它们是如何实现的。这意味着这些调用的效果也不知道,因此还原这些效果的唯一方法是使用throw。当然,如果您知道必须恢复效果,则应该始终写合同时不要一开始就调用这些函数,但是在某些用例中,事后才知道。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354