0

Example in this scenario I guess selfdestruct will never get called (also: contract A isn't so important by the way just focus on B onward):

in Contract A:

address contractb = 0x....;

function sending() {
    contractb.call.value(1 ether)();
}

in Contract B:

address contractc = 0x...;

function () public payable {
    if (!contractc.send(msg.value)) {
        throw;
    }
    if (!contractc.send(0)) {
        throw;
    }
}

in Contract C:

address someone = 0x...;

function () public payable {
    selfdestruct(someone);
}

In short:

  1. Contract A sends ether to B using call to have lots of gas...
  2. B forwards the money further to C, the first time it tries it succeeds but C selfdestructs; The 2nd time it fails since C is selfdestructed...
  3. throw should revert to a state without changes, but how can it revert a selfdesctructed contract?

I guess (and I am 99% sure what will happen...about to test now on Ropsten...): nothing will ever reach C since before any execution revert will check if anything can fail and if it can it reverts - speaking of which how can revert be so sure? What if transaction simply lacks gas to be mined say like 3 gas in call.gas(3).value(1)() - surely this will not get mined and maybe revert will prevent anything until mining happens? Thanx!

  • 1. I'm not sure that the selfdestruct operation can complete successfully in this scenario (it would need some gas I suppose, but the function has a stipend of only 2300 units). 2. If it does complete successfully, then your 2nd attempt should fail in a manner similar to calling x.send(msg.value), where x is some bogus address of a non-contract (zero address would probably "do the job" here). So you should end up with the same type of revert IMO. – goodvibration Dec 4 '19 at 11:34
  • I just deployed 3 contracts on ropsten...later when I have more time will give tx link about the result, thanks for shedding more light to it. Actually I just read that my understanding of selfdestruct was a bit off - it seems that selfdestruct will succeed but ehter is lost forever? So it simply remove functionality from contract and the former "contract" is now just a regular wallet? If this is the case i am still curious what will happen when you forcibly throw, example x.send(msg.value); throw; -> this will succeed but throw will revert anything again even if destroyed address can get eth. – Robert Ggg Dec 4 '19 at 11:41
  • and the former contract is now just a regular wallet - not unless you miraculously have the private key of that former contract. – goodvibration Dec 4 '19 at 11:54
  • well of course for which the probability is one in a zillion...assuming one tries to 'collide' brute force the private key.... – Robert Ggg Dec 4 '19 at 12:15
1

You can simplify your setup to only 2 contracts. I've taken the liberty of editing the contracts a bit to make the testing a lot easier and more specific.

You can copy paste them in Remix and test yourself.

contract A {
    B b;

    constructor(B _b) public {
        b = _b;
    }  

    function() external payable {
        (bool success, bytes memory result) = address(b).call.value(msg.value)("");

        revert();
    }
}

contract B {
    function() external payable {
        selfdestruct(msg.sender);
    }

    function alive() public pure returns (bool) {
        return true;
    }
}

The selfdestruct is never finalized because it needs a successful transaction to be completed. The throw / revert() rollsback the selfdestruct, so it never happens.

To test you need to:

  • deploy contract B and copy its address
  • deploy contract A with B's address
  • call the fallback function of A
  • the transaction fails because the execution always fails
  • you can check if B is still alive by calling alive() with returns true

If you want to understand what happens when you send ether to a selfdestructed contract, it's just like sending to a random address. No code is attached to it, the former contract acts like a simple account. It accepts ether and no code is run when it receives it.

  • I just had some issues with remix so i went the longer/more unconvenient route with ropsten...but thanks yes my thoughts throw will revert which leads me to my usual statements from previous questions: there is no way to revert but preserve any change. Though one user here claims it can be done via delegatecall to the contract itself...i don't think it's possible. – Robert Ggg Dec 4 '19 at 11:52
  • By using delegatecall you selfdestruct the first contract, but not the destination one. – cleanunicorn Dec 4 '19 at 11:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.