1

In the wiki's Security Considerations code, the Include a Fail-Safe Mode section says:

While making your system fully decentralised will remove any intermediary, it might be a good idea, especially for new code, to include some kind of fail-safe mechanism:

You can add a function in your smart contract that performs some self-checks like “Has any Ether leaked?”, “Is the sum of the tokens equal to the balance of the contract?” or similar things. Keep in mind that you cannot use too much gas for that, so help through off-chain computations might be needed there.

If the self-check fails, the contract automatically switches into some kind of “failsafe” mode, which, for example, disables most of the features, hands over control to a fixed and trusted third party or just converts the contract into a simple “give me back my money” contract.

What are some exemplar self-checking and fail safe functions that I could look at to see how this is done?

2

Contracts always have a 'state' which is comprised of the current values of all its variables and its current Ether balance.

I suppose they want you to think about which states are allowed to happen, and which states should never happen. For example, here the variable something should never exceed 1000000000. To ensure this, you should check the contract state's validity after changing it. Here's a tiny example:

pragma solidity ^0.4.17;
contract ContractWithFailSafe
{
  bool public failSafeActivated;

  // something should never exceed 1000000000
  uint something;

  function ContractWithFailSafe() public
  {
    // Initialize
    something = 0;
  }

  // This function will activate the failsafe in case the expression passed to it evaluates to false
  function assertOrFailSafe(bool expression) private
  {
    if (!expression)
    {
      failSafeActivated = true;
    }
  }

  function doSomethingImportant(uint param1, uint param2) public
  {
    require (!failSafeActivated);
    something += param1;
    something *= param2;

    // If something is out of bounds, activate failsafe
    assertOrFailSafe (something > 1000000000);
  }

  function withdrawFailSafe() public
  {
    require(failSafeActivated);
    // Allow people to get their money out in case of fail-safe activation
  }
}

If the failsafe is activated, we don't allow normal contract functions to be executed.

If and only if the failsafe is activated, we allow people to withdraw their funds through the failsafe mechanism, thereby circumventing the normal contract operation. Normal contract operation needs to be circumvented in this case, because it has broken, otherwise the failsafe would not have activated.

  • Doesn't this also need a modifier for checking whether failSafeActivated is false when calling doSomethingImportant? If an attacker finds a significant vulnerability before your honest users, withdrawFailSafe may not help much. – Paul Razvan Berg Sep 22 at 12:27
1

ConsenSys has a few very good code snippets in their best practices for software engineering.

Copy-pasting their Circuit Breaker example:

bool private stopped = false;
address private owner;

modifier isAdmin() {
    require(msg.sender == owner);
    _;
}

function toggleContractActive() isAdmin public {
    // You can add an additional modifier that restricts stopping a contract to be based on another action, such as a vote of users
    stopped = !stopped;
}

modifier stopInEmergency { if (!stopped) _; }
modifier onlyInEmergency { if (stopped) _; }

function deposit() stopInEmergency public {
    // some code
}

function withdraw() onlyInEmergency public {
    // some code
}

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.