Skip to content

Commit

Permalink
add: gas strict inequalities
Browse files Browse the repository at this point in the history
  • Loading branch information
dbale-altoros committed Mar 1, 2024
1 parent 5258609 commit 6a29713
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 0 deletions.
1 change: 1 addition & 0 deletions conf/rulesets/solhint-all.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module.exports = Object.freeze({
'gas-indexed-events': 'warn',
'gas-multitoken1155': 'warn',
'gas-small-strings': 'warn',
'gas-strict-inequalities': 'warn',
'gas-struct-packing': 'warn',
'comprehensive-interface': 'warn',
quotes: ['error', 'double'],
Expand Down
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ title: "Rule Index of Solhint"
| [gas-indexed-events](./rules/gas-consumption/gas-indexed-events.md) | Suggest indexed arguments on events for uint, bool and address | | |
| [gas-multitoken1155](./rules/gas-consumption/gas-multitoken1155.md) | ERC1155 is a cheaper non-fungible token than ERC721 | | |
| [gas-small-strings](./rules/gas-consumption/gas-small-strings.md) | Keep strings smaller than 32 bytes | | |
| [gas-strict-inequalities](./rules/gas-consumption/gas-strict-inequalities.md) | Suggest Strict Inequalities over non Strict ones | | |
| [gas-struct-packing](./rules/gas-consumption/gas-struct-packing.md) | Suggest to re-arrange struct packing order when it is inefficient | | |

Expand Down
40 changes: 40 additions & 0 deletions docs/rules/gas-consumption/gas-strict-inequalities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
warning: "This is a dynamically generated file. Do not edit manually."
layout: "default"
title: "gas-strict-inequalities | Solhint"
---

# gas-strict-inequalities
![Category Badge](https://img.shields.io/badge/-Gas%20Consumption%20Rules-informational)
![Default Severity Badge warn](https://img.shields.io/badge/Default%20Severity-warn-yellow)

## Description
Suggest Strict Inequalities over non Strict ones

## Options
This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Default to warn.

### Example Config
```json
{
"rules": {
"gas-strict-inequalities": "warn"
}
}
```

### Notes
- Strict inequality does not always saves gas. It is dependent on the context of the surrounding opcodes
- [source 1](https://coinsbench.com/comprehensive-guide-tips-and-tricks-for-gas-optimization-in-solidity-5380db734404) of the rule initiative (see Less/Greater Than vs Less/Greater Than or Equal To)
- [source 2](https://www.rareskills.io/post/gas-optimization?postId=c9db474a-ff97-4fa3-a51d-fe13ccb8fe3b#viewer-7b77t) of the rule initiative

## Examples
This rule does not have examples.

## Version
This rule is introduced in the latest version.

## Resources
- [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/gas-consumption/gas-strict-inequalities.js)
- [Document source](https://github.com/protofire/solhint/tree/master/docs/rules/gas-consumption/gas-strict-inequalities.md)
- [Test cases](https://github.com/protofire/solhint/tree/master/test/rules/gas-consumption/gas-strict-inequalities.js)
46 changes: 46 additions & 0 deletions lib/rules/gas-consumption/gas-strict-inequalities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const BaseChecker = require('../base-checker')

const ruleId = 'gas-strict-inequalities'
const meta = {
type: 'gas-consumption',

docs: {
description: 'Suggest Strict Inequalities over non Strict ones',
category: 'Gas Consumption Rules',
notes: [
{
note: 'Strict inequality does not always saves gas. It is dependent on the context of the surrounding opcodes',
},
{
note: '[source 1](https://coinsbench.com/comprehensive-guide-tips-and-tricks-for-gas-optimization-in-solidity-5380db734404) of the rule initiative (see Less/Greater Than vs Less/Greater Than or Equal To)',
},
{
note: '[source 2](https://www.rareskills.io/post/gas-optimization?postId=c9db474a-ff97-4fa3-a51d-fe13ccb8fe3b#viewer-7b77t) of the rule initiative',
},
],
},

isDefault: false,
recommended: false,
defaultSetup: 'warn',

schema: null,
}

class GasStrictInequalities extends BaseChecker {
constructor(reporter) {
super(reporter, ruleId, meta)
}

BinaryOperation(node) {
if (node.operator === '>=' || node.operator === '<=') {
this.reportError(node)
}
}

reportError(node) {
this.error(node, `GC: Non strict inequality found. Try converting to a strict one`)
}
}

module.exports = GasStrictInequalities
2 changes: 2 additions & 0 deletions lib/rules/gas-consumption/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const GasIndexedEvents = require('./gas-indexed-events')
const GasCalldataParameters = require('./gas-calldata-parameters')
const GasIncrementByOne = require('./gas-increment-by-one')
const GasStructPacking = require('./gas-struct-packing')
const GasStrictInequalities = require('./gas-strict-inequalities')

module.exports = function checkers(reporter, config) {
return [
Expand All @@ -13,5 +14,6 @@ module.exports = function checkers(reporter, config) {
new GasCalldataParameters(reporter, config),
new GasIncrementByOne(reporter, config),
new GasStructPacking(reporter, config),
new GasStrictInequalities(reporter, config),
]
}
94 changes: 94 additions & 0 deletions test/rules/gas-consumption/gas-strict-inequalities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
const assert = require('assert')
const linter = require('../../../lib/index')
const { funcWith } = require('../../common/contract-builder')

const ERROR_MSG = 'GC: Non strict inequality found. Try converting to a strict one'

describe('Linter - gas-strict-inequalities', () => {
it('should raise error on non strict equalities 1', () => {
const code = funcWith(`
uint256 a;
uint256 b;
uint256 c;
uint256 d;
if (a >= b) { }
if (c <= d) { }
if (c < d) { }
if (c > d) { }`)

const report = linter.processStr(code, {
rules: { 'gas-strict-inequalities': 'error' },
})

assert.equal(report.errorCount, 2)
assert.equal(report.messages[0].message, ERROR_MSG)
assert.equal(report.messages[1].message, ERROR_MSG)
})

it('should raise error on non strict equalities 2', () => {
const code = funcWith(`
uint256 a;
uint256 b;
uint256 c;
uint256 d;
while (a >= b) {
}
if (c < d) { }`)

const report = linter.processStr(code, {
rules: { 'gas-strict-inequalities': 'error' },
})

assert.equal(report.errorCount, 1)
assert.equal(report.messages[0].message, ERROR_MSG)
// assert.equal(report.errorCount, 0)
})

it('should raise error on non strict equalities 3', () => {
const code = funcWith(`
uint256 a;
uint256 b;
uint256 c;
uint256 d;
while (a >= b) {
}
if ((c < d) && (a <= b) && (d >= a)) { }`)

const report = linter.processStr(code, {
rules: { 'gas-strict-inequalities': 'error' },
})

assert.equal(report.errorCount, 3)
assert.equal(report.messages[0].message, ERROR_MSG)
assert.equal(report.messages[1].message, ERROR_MSG)
assert.equal(report.messages[2].message, ERROR_MSG)
// assert.equal(report.errorCount, 0)
})

it('should NOT raise error on strict equalities', () => {
const code = funcWith(`
uint256 a;
uint256 b;
uint256 c;
uint256 d;
while (a > b) {
}
if ((c < d) && (a < b) && (d > a)) { }`)

const report = linter.processStr(code, {
rules: { 'gas-strict-inequalities': 'error' },
})

assert.equal(report.errorCount, 0)
})
})

0 comments on commit 6a29713

Please sign in to comment.