Closed 0xA5DF closed 2 years ago
This directly contradicts what has been observed in https://github.com/foundry-rs/foundry/issues/1543 so I'm not entirely sure what the behavior is
I tested the other bug, and they both exists on my machine. It seems like forge is resetting the storage, but not deleting the code of the contract.
Here's the modified test code (also made x
public in the contract code):
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "forge-std/console.sol";
import "../contracts/Destruct.sol";
contract ContractTest is Test {
function setUp() public {}
function testExample() public {
Proxy p = new Proxy();
uint x = p.runDestoryMe(payable(address(this)));
uint32 pSize = getSize(address(p));
console.log("Proxy size is: ", pSize);
x = p.x();
console.log("p.x is: ",x);
assertEq(x, 5);
}
function getSize(address c) public view returns (uint32) {
uint32 size;
assembly {
size := extcodesize(c)
}
return size;
}
}
And here's the output:
$ forge test -vv
warning: Unknown section [default] found in foundry.toml. This notation for profiles has been deprecated and may result in the profile not being registered in future versions. Please use [profile.default] instead or run `forge config --fix`.
[⠰] Compiling...
No files changed, compilation skipped
Running 1 test for test/Contract.t.sol:ContractTest
[FAIL. Reason: Undefined.] testExample() (gas: 270484)
Logs:
Proxy size is: 487
p.x is: 0
Error: a == b not satisfied [uint]
Expected: 5
Actual: 0
Test result: FAILED. 0 passed; 1 failed; finished in 671.49µs
Failing tests:
Encountered 1 failing test in test/Contract.t.sol:ContractTest
[FAIL. Reason: Undefined.] testExample() (gas: 270484)
Encountered a total of 1 failing tests, 0 tests succeeded
P.S. The code also works fine, I've added the following function to the contract and it just returns the same value
function add(uint y) public returns(uint) {
return x+y;
}
This test will output added is: 30
:
Proxy p = new Proxy();
uint x = p.runDestoryMe(payable(address(this)));
uint32 pSize = getSize(address(p));
console.log("Proxy size is: ", pSize);
uint added = p.add(30);
console.log("added is: ",added);
x = p.x();
console.log("p.x is: ",x);
@rakita Storage seems to be reset before the transaction ends, but not the account code. Is this the intended behavior of selfdestruct
according to spec?
Account code needs to be reset with storage.
They both should reset, but only once tx completes, beforehand it should still operate and have no change to storage.
Ethereum yellow paper definition for selfdestruct
:
Halt execution and register account for later deletion
And on the 'Transaction Execution' section:
The final state, σ', is reached after deleting all accounts that either appear in the self-destruct set or are touched and empty.
Also, as said above, I've tested this on the Rinkeby test chain, and it shows that the storage hasn't changed between the selfdestruct
to the end of the tx.
(before tx ends) i missed this. I am not 100% sure as selfdestruct logic is not that great, but I think you are right. I have one failing eth/tests (recently added) with selfdestruct that is probably related: https://github.com/bluealloy/revm/blob/0ae75553776071288d56852372c09bff7a6d268d/bins/revme/src/statetest/runner.rs#L96
@0xA5DF thank you for pointing this out!
I rewrote that part of revm to simplify it and correct the wrong behaviour, in the first implementation I overthought things. It should be correct now. https://github.com/bluealloy/revm/commit/6d04a7f9856e0c05c3787ce57944380bfe1dc705
@onbjerg integration should only be in the renaming of subroutine
to journaled_state
and you probably will need to integrate this return of ExecutionResult
: https://github.com/bluealloy/revm/commit/0ae75553776071288d56852372c09bff7a6d268d
I will not push a new release as I want to add some additional changes as in db returning Result<Option<..
that we talked about.
closed via #2877
Component
Forge
Have you ensured that all of these are up to date?
What version of Foundry are you on?
forge 0.2.0 (92f8951 2022-08-08T00:03:54.483346829Z)
What command(s) is the bug in?
forge test
Operating System
Linux
Describe the bug
The
selfdestruct
opcode shouldn't destroy the contract till the tx ends, that means that if in the same tx we call the contract again it should function with no difference.When running
forge test
on a contract that self-destroys (via delegate call) and then reads storage varx
, the value of that var is zero instead of 5 (it shows both in the event emitted and in the return value).When running the same code on Rinkeby testnet, it indeed emits the value 5 (here's the tx ).
Contract code (
contracts/Destruct.sol
):Test code:
Command output