Q: `extcodesize` is non-zero after `selfdestruct`

assemblyevmyul

I ran into an EVM edge case. Is it correct that extcodesize(addr) is not zero, after calling selfdestruct on addr in the same transaction?

This behavior seems strange and I could not find any documentation on it.

Best Answer

I was able to reproduce your issue with the following code on Remix (You can check the different behavior between calling extcodesize in the same tx or in a subsequent one)

pragma solidity ^0.8.10;


contract Test {
    SelfDestruct instance;
    
    constructor() {
        redeploy();
    }
    
    function redeploy() public {
        instance = new SelfDestruct();    
    }
    
    function killInstanceAndGetCodeSize() public returns (uint256) {
        killInstance();
        return getCodeSize();
    }
    
    function killInstance() public {
        instance.kill();
    }
    
    function getCodeSize() public view returns (uint256 codeSize) {
        
        address addr = address(instance);
        
        assembly {
             codeSize := extcodesize(addr)
        }
    }  
}

contract SelfDestruct {
  function kill() public {
      selfdestruct(payable(address(0)));
  }
}

The reason for that behavior can be explained by looking at the geth implementation of selfdestruct.

// The account's state object is still available until the state is committed, // getStateObject will return a non-nil account after Suicide.

This is actually a logical behavior, as you have to take the possibility of reverts into account, plus you cannot leave another contract in an unstable state in the middle of a transaction if you decide to self-destruct. Until the state is committed, the self-destructed contract is still fully accessible.

Related Topic