Gas

Gas is the internal pricing for running a transaction or contract. When you send tokens, interact with a contract, send RBTC or do anything else on the blockchain, you must pay for that computation. That payment is calculated in Gas and gas in RSK is paid in RBTC.

What is gas?

There are four important concepts:

  • Gas price: the cost of the operation.
  • Gas limit: the maximum gas the operation can afford. It’s an upper limit the user sets to prevent losing gas.
  • Total gas: (or gas used) the gas the operation consumed.
  • Gas is paid in RBTC.

Let’s start with a simple analogy: a car. To drive a car you need gas. Gas price is the money you pay for each gallon. Gas limit is the max amount of gas you accept to consume, the gas you charge. The total gas is the amount you’ve spent at the end of the trip. You can calculate the total gas and set an appropriate gas limit so that our trip does not expend more than expected.

Transactions are quite similar: Gas price is the price you set for operations. The gas limit is the maximum price you are going to pay for the transaction when operated. Then, when transaction is executed, the total gas is the price you finally pay.

Gas is the fee collected by the miner which mines the block that includes the transaction.

Therefore, the resulting fee is:

fee = totalGas * gasPrice

How do I choose an appropriate gas price and limit?

If you want to spend less on a transaction, you can do so by lowering the amount you pay per unit of gas (gas price). Similar to Bitcoin, the price you pay for each unit increases or decreases how quickly your transaction will be mined.

Appropriate gas price

Gas price changes along time. To choose an appropriate gas price you should consider 2 concepts:

  • What is minimum gas price and how it changes
  • How to get that minimum gas price

MinimumGasPrice

The minimumGasPrice is written in the block header by miners and establishes the minimum gas price a transaction should have in order to be included in that block. Negotiated minimum gas price is described in RSKIP-09.

Minimum gas price is written in the block header by miners and describes the minimum gas price a transaction should have to be included in that block. It can change along time: at most 0.01% respect to the previous block. Last block minimum gas price can be obtained using this Web3 method:

web3.eth.getBlock('latest').minimumGasPrice

Appropriate gas limit

Total gas can be estimated using this Web3 method:

myContract.methods.myMethod(param1, param2, ...).estimateGas(options, callback)

Go here for Web3 documentation.

More information

How does gas price change over time?

Each miner can vote to increase or decrease the minGasPrice up to 0.01%. This allows miners to increase the minGasPrice 100% in approximately one day, assuming a block every 10 seconds. Nodes that forward transactions could check that the advertised gas price in a transaction is at least 1% higher than the minimum. This assures the transaction a lifetime of 100 blocks assuming a constantly increasing block minGasPrice. Negotiated minimum gas price is described in RSKIP-09.

What happen if my transaction fails?

You are paying for the computation, regardless of whether your transaction succeeds or fails. Even if it fails, the miners must validate and execute your transaction (computation request) and therefore you must pay for that computation just like you would pay for a successful transaction.

What happen if I run out of gas?

If a transaction reaches the gas limit, all changes will be reverted but the fee is still paid.

Gas in smart contracts

When you compile smart contracts (commonly written in Solidity), they get converted to operation codes, known as ‘opcodes’. These codes (opcodes) are shown with mnemotechnic names as ADD (addition) or MUL (multiplication). Here you can see the price of each opcode. As you can guess, it is important to write smart contracts using the best (cheaper) combination of opcodes. Examples of good practices to write smart contracts:

Avoid declaring variables as var

function payBonus() {
    for (uint i = 0; i < employees.length; i++) {
      address employee = employees[i];
      uint bonus = calculateBonus(employee);
      employee.send(bonus);
    }     
  }

In the code above, the problem is that if the type of i was declared as var, it would be taken as uint8 because this is the smallest type that is required to hold the value 0. If the array has more than 255 elements, the loop will not finish successfully, resulting in wasted gas. You’d better use the explicit type uint for no surprises and higher limits. Avoid declaring variables using var if possible.

Looping large arrays

function soDifficultLooper() {
    for (uint i = 0; i < largeArray.length; i++) {
      address person = largeArray[i];
      uint payment = difficultOperation(largeArray);
      person.send(payment);
    }     
  }

Every function call that modifies state of the smart contract has a gas cost. A loop would spend a lot of gas, which could easily reach the gas limit of a transaction or block. If a transaction reaches the gas limit, all changes will be reverted but the fee is still paid. Be aware of variable gas costs when using loops.