1

Imagine you have a function like this:

function compute(uint256 a, uint256 b) external pure returns (uint256) {
  return a % b;
}

Does it revert when b is 0?

  • 1
    I think you are confusing EVM with Solidity. From the Yellow Paper Appendix H "Virtual Machine Specification" it should never revert. For example go-ethereum follows the specification. – Ismael Sep 15 '19 at 0:59
  • @Ismael Thanks, updated the question's body. – Paul Razvan Berg Sep 15 '19 at 9:56
4

This is answered in the Solidity documentation.

From https://solidity.readthedocs.io/en/v0.5.11/types.html#modulo:

Modulo with zero causes a failing assert.

| improve this answer | |
2

It reverts, but with INVALID opcode (similar to assert) rather than REVERT opcode (similar to require).

In order to impose the latter, you can add require(b != 0) prior to return a % b.

If b is a user-input value, then you should add this require statement.

If b is an internally-generated value in your system and you know that it is never supposed to be 0, then you can add assert(b != 0) prior to return a % b, or you can leave it as is (since, as mentioned above, a % b will yield the exact same behavior).

| improve this answer | |
  • Just discovered an important implication of this. If you let Solidity handle mod 0, the contract call will consume all remaining gas. If you preemptively require the divisor not to be zero, which leaves remaining gas untouched. – Paul Razvan Berg Jun 13 at 9:01
  • This is why OpenZeppelin added a mod function in SafeMath. – Paul Razvan Berg Jun 13 at 9:01
  • @PaulRazvanBerg: This implication is obvious from the answer, because it is well known that require (and more generally, the REVERT opcode) returns the remaining gas to the user, while assert (and more generally, the INVALID opcode) does not. Thus, as explained in my answer, you should use require (OZ function if you will), when dealing with user-input. That's also explained in my answer IMO (or at least implied by it). – goodvibration Jun 13 at 9:54
  • For sure, but you're a seasoned Solidity engineer. Now the gas consumption implications are obvious to anyone stumbling upon this StackExchange thread. – Paul Razvan Berg Jun 13 at 10:00
1

It depends on (1) how you implement the function and (2) how you call it.

As a pure function

This is how it is defined above. The function will NOT revert, since it doesn't end up executed by all the nodes on the network (state-changing methods end up like that).

As a state-changing function

Yes, mod 0 does end up in a reverted tx. This is why OpenZeppelin implemented the mod method in their SafeMath library.

Take this contract as an example:

pragma solidity 0.5.11;

contract ModByZero {

    event LogSomeState(uint256 a, uint256 b);

    function doIt(uint256 a, uint256 b) public returns (uint256) {
        emit LogSomeState(a, b);
        return a % b;
    }
}

And this failed tx on Rinkeby.


See this thread on the Maths StackExchange to learn more about mod 0.

| improve this answer | |
  • The pure function in my test will not revert but cause "invalid opcode". – Ismael Sep 15 '19 at 1:05
  • 1
    If a pure function is called in a transaction, it can certainly cause the transaction to revert. E.g. if this function were called by a contract as part of a transaction. – user19510 Sep 15 '19 at 2:27

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.