Different proxy code to upgrade smart contract and reentrancy attacks

Oct 15 2020

I am trying to upgrade smart contract in ethereum. I found that proxy pattern can help me with this. In the openzeppelin docs, I should add the following code in fallback function in my contract:

assembly {
  let ptr := mload(0x40)

  // (1) copy incoming call data
  calldatacopy(ptr, 0, calldatasize)

  // (2) forward call to logic contract
  let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
  let size := returndatasize

  // (3) retrieve return data
  returndatacopy(ptr, 0, size)

  // (4) forward return data back to caller
  switch result
  case 0 { revert(ptr, size) }
  default { return(ptr, size) }
}

It seems that I should forward call and retrieve the return data. However, in some contracts, they just upgrade the contract with code like this:

/**
     * Resolves asset implementation contract for the caller and forwards there transaction data,
     * along with the value. This allows for proxy interface growth.
     */
    function () payable {
        _getAsset().__process.value(msg.value)(msg.data, msg.sender);
    }

I have two questions:

  1. Can the second code also upgrade the smart contract?
  2. I think add the first code in fallback function in my contract can lead to reentrancy attack, is it true? Thanks!

Odpowiedzi

Ismael Oct 16 2020 at 22:59

They are two ways to make a contract upgradeable.

  • Pierwsza używa kodu operacji DELEGATECALL. Nie zmienia to msg.sender. Musi użyć zestawu, aby odzyskać zwróconą wartość. Mają pewne ograniczenia, o których musisz wiedzieć przed ich użyciemhttps://blog.openzeppelin.com/the-transparent-proxy-pattern/, https://blog.openzeppelin.com/proxy-patterns/.
  • Drugi używa zwykłego kodu operacji CALL. Zmienia msg.sender, więc kod musi się do tego dostosować. Nie obsługuje funkcji pobierających, ponieważ ignoruje zwracaną wartość.

Żadna opcja nie zapewnia ochrony przed atakami ponownego wejścia, zależy to od implementacji.