Ethereum: The Concept of Gas and its Dangers

Photo by Jules D. on Unsplash
Photo by Jules D. on Unsplash

1. What Is Gas?

Gas Has A Price

Gas Refund

transaction cost = gasUsed * gasPrice
transaction cost = (gasRequired - gasRefund) * gasPrice

Gas Cost VS Real Cost

Gas Estimation

The 2300 Gas Stipend

2. Gas And Contracts Calls

The 1/64 Rule

gas available - (1/64* gas available)

3. Insufficient Gas Griefing Attack

contract Executor {
function execute(address to, bytes calldata data, uint256 gas) external {
(bool success, bytes memory returnData) = to.call.gas(gas)(data);
// do something
}
}
contract Executor {
function execute(address to, bytes calldata data, uint256 gas) external {
require(gasleft() >= gas);
(bool success, bytes memory returnData) = to.call.gas(gas)(data);
// extra operation including the logic to reward relayer for submitting the tx
}
}

Workaround Against “Insuficient Gas Griefing attack”

uint256 gasAvailable = gasleft() - E;
require(gasAvailable - gasAvailable / 64 >= `txGas`, "not enough gas provided")
to.call.gas(txGas)(data); // CALL
to.call.gas(txGas)(data); // CALL
assert(gasleft() > txGas / 63); // "not enough gas left"

Proper Solution Against “Insuficient Gas Griefing attack”

3. Inner Call Out Of Gas Attack

contract Test {
function test() external {
try callNeeding6400000Gas() returns (string message) {
// do something in case of success
} catch {
// do something else in case of failure
}
}
}
contract Auction {
...
ERC20Token token;
address highestBidder;
uint256 highestBid;
function bid(uint256 amount) external {
require(amount < highestBid, "higher bid required");
address oldBidder = highestBidder;
uint256 oldBid = highestBid;
highestBidder = msg.sender;
highestBid = amount;
require(token.transferFrom(msg.sender, address(this), amount), "transfer failed");
if (oldBidder != address(0)) {
try token.transferFrom(address(this), oldBidder, oldBid) {
} catch {}
}
}
}
pragma solidity 0.6.0;contract ERC20Token {
event Transfer(address indexed from, address indexed to, uint256 amount);
mapping (address => uint256) balances;
function transferFrom(address from, address to, uint256 amount) external returns(bool) {
uint256 fromBalance = balances[from];
require(fromBalance >= amount, "not enough balance");
balances[from] -= amount;
balances[to] += amount;
emit Transfer(from, to, amount);
return true;
}
function mint(address to, uint256 amount) external {
balances[to] += amount;
emit Transfer(address(0), to, amount);
}
function balanceOf(address who) external view returns(uint256) {
return balances[who];
}
}
contract Auction { constructor(ERC20Token _token) public {
token = _token;
}
ERC20Token token;
address public highestBidder;
uint256 public highestBid;
function bid(uint256 amount) external {
require(amount > highestBid, "higher bid required");
address oldBidder = highestBidder;
uint256 oldBid = highestBid;
highestBidder = msg.sender;
highestBid = amount;
require(token.transferFrom(msg.sender, address(this), amount), "transfer failed");
if (oldBidder != address(0)) {
try token.transferFrom(address(this), oldBidder, oldBid) {
} catch {}
}
}
}

Conclusion

--

--

Creator of Etherplay, Buidling Ethernal, Mystery Market, and Sandbox

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store