Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safe Math #27

Merged
merged 1 commit into from
Aug 6, 2018
Merged

Safe Math #27

merged 1 commit into from
Aug 6, 2018

Conversation

brandoniles
Copy link
Member

Make all the math safe (I think!)

Also makes the types match the Oracle after this PR

@brandoniles brandoniles self-assigned this Aug 2, 2018
// We cap the supply to avoid overflows in computations.
// Due to the signed math in rebase(), MAX_RATE x MAX_SUPPLY must fit into an int256.
// MAX_SUPPLY = UInt256Lib.getMaxInt256() / MAX_RATE
uint256 private constant MAX_SUPPLY = 578960446186580977117854925043439539266349923328202820197;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

~(uint256(1) << 255) - MAX_RATE instead? I expect that the compiler precomputes it on compilation. So no gas cost.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs are actually not super clear about this.
See here:

The compiler does not reserve a storage slot for these variables, and every occurrence is replaced by the respective constant expression (which might be computed to a single value by the optimizer).

// We cap the rate to avoid overflows in computations.
// 18 decimal fixed point format
// MAX_RATE = 100 * 10**18
uint256 private constant MAX_RATE = 100000000000000000000;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10**20 or 100 * 10**18?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100 * 10**18 makes it clear that the max rate is 100x, so I went with that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to change 100000000000000000000 to 100 * 10**18? I think we can trust the optimizer to get it right.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From all that I've read, I'm still not sure.

For example, this old issue: ethereum/solidity#976

The new issue that addresses it still uses the fuzzy language in the docs: ethereum/solidity#992

the keyword constant on any variable means it cannot be modified (and could be placed into memory or bytecode by the optimiser)

I'm inclined to save this until we can accurately measure gas usage.

function div(int256 a, int256 b) internal pure returns (int256) {
// Prevent overflow when dividing INT256_MIN by -1
// https://github.com/RequestNetwork/requestNetwork/issues/43
assert(!(a == - 2**255 && b == -1));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cheaper and simpler:
assert(!(a == (int256(1)<<255) && b == -1));



/**
* @title SafeMathInt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a TODO to add tests and potentially optimize the methods below. Adding comments below for optimizations.

function mul(int256 a, int256 b) internal pure returns (int256) {
// Prevent overflow when multiplying INT256_MIN with -1
// https://github.com/RequestNetwork/requestNetwork/issues/43
assert(!(a == - 2**255 && b == -1) && !(b == - 2**255 && a == -1));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line below is more efficient, to be added after the multiplication.
assert(c != 1<<255 || ((a & 1<<255) != (b & 1<<255)))

return c;
}

function sub(int256 a, int256 b) internal pure returns (int256) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sub and add are using two different styles. We should finf if either is cheaper and use it for both.
sub can be:
int256 c = a - b; assert((b >= 0 && c <= a) || (b < 0 && c > a));

@brandoniles brandoniles merged commit 680b251 into master Aug 6, 2018
@brandoniles brandoniles deleted the safe-math branch August 6, 2018 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants