2

I know this sounds confusing so let me explain:

In this case below a transaction will succeed and a contract will be first destroyed and then re-initialized on the same address (yes, I didn't think it was possible...but apparently it is):

contract A
{
  address contractb = // some address here 
  function first() public
  {
    contractb.call.value(1 ether)();
  }
}

contract B
{
  address contractc = //all addresses should be known beforehand btw.
  function () public payable
  {
    if(contractc.value(msg.value)())
    {
      assembly { invalid } // in fact just "throw;" should do the trick...
    }
  }
}

contract C
{
  function () public payable
  {
    selfdestruct(msg.sender);
  }
}

What I thought will happen:

  1. A calls B, sending 1 ether
  2. B forwards this 1 ether to C via yet another call
  3. Upon receiving from B, C selfdestructs and sends all ether it has to B
  4. B calls back A and 'claims' transaction failed.

what really happened:

  1. A called B
  2. B forwarded to C
  3. Now B sends to C which selfdestructs...however then B re-creates the contract on the same address with same transaction history except...nothing was sent so "invalid" in assembly seems the same as revert(). I thought self-destruct can't be undone but here B had to check if transfer succeeds and if it does it sends all steps back to the very beginning so B even changed destroyed contract(C) to be re-initialized (I am getting this from both etherscan and on remix off-chain - yes, before a block is being written...it's all one transaction having several internal transactions).

Back to my original question: is it possible to prevent the full revert since even selfdestruct can't? What if B deploys new contract from within the code? Thanx!

1

If some code reverts/throws the current contract call will have no effects, but not necessarily the entire transaction. The assembly instruction CALL to code that reverted will return false to indicate that it reverted.

The solidity language hides this by reverting everything by default if any CALL failed.

For example, this:

someone.transfer(1 ether);

Actually just compiles to this:

(bool success, ) = contractb.call.value(1 ether).gas(2100)("");
require(success);

If you manually use a low-level .call you don't need to revert when success is false, you can also just ignore it or do something differently. That way you can avoid the entire transaction reverting when just one call reverted.

| improve this answer | |
2

“Revert” is not “rollback”. It does not undo actions performed by transaction one by one. Instead it terminates transactions without actually saving any changes made by it to the blockchain. So it works like “revert” function in text editor, not like “undo” function.

| improve this answer | |
  • I see in any case I was surprised even selfdestruct didn't do the 'trick'...in any case it seems as if only stop (return 0) and revert/throw = complete undo are the only ways to handle it. Or fine: as you called it "Revert" != undo but still keeps my curiosity of how something like above can be achieved. – Robert Ggg Dec 14 '19 at 18:20
  • Transaction that actually succeeded (left any changes in blockchain) cannot claim, that it failed. Many smart contracts rely on the fact that failed transaction is guaranteed to leave no trace in blockchain (no balance changes, no storage changes, no logged events, no new/destroyed smart contracts). Breaking this rule would open an attack vector on such contracts. – Mikhail Vladimirov Dec 14 '19 at 18:32
  • true, though I managed to make a "Failed" (well successful transaction...) that turned out to be with bad instruction overall...the catch? The whole transaction was mix of fails/successes - meaning the important part (aka - taking ether...) succeeded - but the last didn't causing "error" - ultimately this is NOT security issue as of now. I am unable to make a case where money is taken but the result is false for every single subset...which will be the major security issue you are talking about. – Robert Ggg Dec 14 '19 at 20:48

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.