Skip to content

Commit

Permalink
Stop instrumenting receive() for statements / fns (to save gas) (#517)
Browse files Browse the repository at this point in the history
  • Loading branch information
cgewecke authored Jun 10, 2020
1 parent 1ba04ac commit f1fb8a0
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 3 deletions.
8 changes: 7 additions & 1 deletion lib/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,15 @@ parse.ForStatement = function(contract, expression) {
parse.FunctionDefinition = function(contract, expression) {
parse.Modifiers(contract, expression.modifiers);
if (expression.body) {
register.functionDeclaration(contract, expression);
// Skip fn & statement instrumentation for `receive` methods to
// minimize gas distortion
(expression.name === null && expression.isReceiveEther)
? register.trackStatements = false
: register.functionDeclaration(contract, expression);

parse[expression.body.type] &&
parse[expression.body.type](contract, expression.body);
register.trackStatements = true;
}
};

Expand Down
8 changes: 7 additions & 1 deletion lib/registrar.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
*/
class Registrar {

constructor(){}
constructor(){
// Sometimes we don't want to inject statements
// because they're an unnecessary expense. ex: `receive`
this.trackStatements = true;
}

/**
* Adds injection point to injection points map
Expand All @@ -27,6 +31,8 @@ class Registrar {
* @param {Object} expression AST node
*/
statement(contract, expression) {
if (!this.trackStatements) return;

const startContract = contract.instrumented.slice(0, expression.range[0]);
const startline = ( startContract.match(/\n/g) || [] ).length + 1;
const startcol = expression.range[0] - startContract.lastIndexOf('\n') - 1;
Expand Down
24 changes: 24 additions & 0 deletions test/integration/projects/solc-6/contracts/B_Wallet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma solidity ^0.6.0;

contract B_Wallet {

event Deposit(address indexed _sender, uint _value, bytes data);

receive() external payable
{
if (msg.value > 0)
emit Deposit(msg.sender, msg.value, msg.data);
}

function transferPayment(uint payment, address payable recipient) public {
recipient.transfer(payment);
}

function sendPayment(uint payment, address payable recipient) public {
require(recipient.send(payment), 'sendPayment failed');
}

function getBalance() public view returns(uint){
return address(this).balance;
}
}
30 changes: 30 additions & 0 deletions test/integration/projects/solc-6/test/b_wallet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const Wallet = artifacts.require('B_Wallet');

contract('B_Wallet', accounts => {
it('should should allow transfers and sends', async () => {
const walletA = await Wallet.new();
const walletB = await Wallet.new();

await walletA.sendTransaction({
value: web3.utils.toBN(500), from: accounts[0],
});

await walletA.sendPayment(50, walletB.address, {
from: accounts[0],
});

await walletA.transferPayment(50, walletB.address, {
from: accounts[0],
});

// Also try transferring 0, for branch hit
await walletA.transferPayment(0, walletB.address, {
from: accounts[0],
});

// Throws invalid opcode if compiled w/ solc >= 0.5.14 & default EVM version
const balance = await walletB.getBalance();
assert.equal(balance.toNumber(), 100);
});
});

7 changes: 6 additions & 1 deletion test/units/buidler/standard.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,12 @@ describe('Buidler Plugin: standard use cases', function() {
{
file: mock.pathToContract(buidlerConfig, 'ContractB.sol'),
pct: 0,
}
},
{
file: mock.pathToContract(buidlerConfig, 'B_Wallet.sol'),
pct: 100,
},

];

verify.lineCoverage(expected);
Expand Down

0 comments on commit f1fb8a0

Please sign in to comment.