Solidity

代理模式委託呼叫的奇怪還原

  • November 9, 2020

在使用 zeppelin 的可升級合約模式之前,我使用過可升級合約。但是,我發現如果我嘗試通過合約呼叫來獲取實現合約地址,我會得到意外的還原。

pragma solidity >=0.6.0;

contract Proxy {
   address registry = 0xc5c97AAd92a962396229cbC8392e62585B04DfB3; // assume this is registry address

   function implementation() public view returns(address) {
       return Registry(registry).getImplementationAddress();
   }

   fallback() external payable {
       address implementationAddress = implementation();
       assembly {
           let ptr := mload(0x40)
           calldatacopy(ptr, returndatasize(), calldatasize())
           let result := delegatecall(gas(), implementationAddress, ptr, calldatasize(), returndatasize(), returndatasize())
           returndatacopy(ptr, 0, returndatasize())

           switch result
           case 0 {revert(ptr, returndatasize())}
           default {return(ptr, returndatasize())}
       }
   } 
}

contract Registry {
   address public implementationAddress = 0x8750c1719E32294260e596c80a04818533e2C643; // assume this is impl address

   function getImplementationAddress() public view returns(address) {
       return implementationAddress;
   }
}

contract Foo { // assume this is implementation contract
   uint256 public a;
   uint256 public b;
   function setA(uint256 val) external {
       a = val;
   } 
   function setB(uint256 val) external {
       b = val;
   } 
   function getA() external view returns(uint256) { 
       return a;
   } 
   function getB() external view returns(uint256) {
      return b;
   } 
}

Foo. 但是,如果我使該行address registry = 0xc5c97AAd92a962396229cbC8392e62585B04DfB3 保持不變,它將不再恢復。有沒有人對導致還原的原因有任何見解?

在 Solc 版本 0.6.13、0.7.4 上複製。

想通了,在更改返回數據大小之前呼叫另一個合約。

引用自:https://ethereum.stackexchange.com/questions/89991