question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Refactor gas constants

See original GitHub issue

What is wrong?

I noticed that our gas constants are a bit messy and should be reorganized.

Let’s take GAS_BALANCE as an example which is defined as such:

https://github.com/ethereum/py-evm/blob/bf1d3c2ad653b4ed6ab9ffb836735863bb5d8148/eth/constants.py#L43

For someone new to the code base this may seem as if retrieving the balance from some account has a fixed gas cost of 20 when in reality it is 400 as specified with the tangerine whistle fork.

https://github.com/ethereum/py-evm/blob/bf1d3c2ad653b4ed6ab9ffb836735863bb5d8148/eth/vm/forks/tangerine_whistle/constants.py#L13

How can it be fixed

My gut feeling says that only true constants™ belong into eth.constants and that all fork specific constants should live in evm.vm.forks.<fork_name>.constants.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:4
  • Comments:12 (11 by maintainers)

github_iconTop GitHub Comments

2reactions
mratsimcommented, Aug 20, 2018

When porting py-evm to Nim, we first used the same gas costs structure of Py-EVM but then refactored to isolate all gas costs and computation in a single file. See https://github.com/status-im/nimbus/pull/49 and the final implementation.

In the end, we currently have on array per fork that maps the “name” to the gas cost from Yellow Paper Appendix G:

2018-08-20_15-08-17

# Generate the fork-specific gas costs tables
const
  BaseGasFees: GasFeeSchedule = [
    # Fee Schedule at for the initial Ethereum forks
    GasZero:            0'i64,
    GasBase:            2,
    GasVeryLow:         3,
    GasLow:             5,
    GasMid:             8,
    GasHigh:            10,
    GasExtCode:         20,     # Changed to 700 in Tangerine (EIP150)
    GasBalance:         20,     # Changed to 400 in Tangerine (EIP150)
    GasSload:           50,     # Changed to 200 in Tangerine (EIP150)
    GasJumpDest:        1,
    GasSset:            20_000,
    GasSreset:          5_000,
    RefundSclear:       15_000,
    RefundSelfDestruct: 24_000,
    GasSelfDestruct:    0,      # Changed to 5000 in Tangerine (EIP150)
    GasCreate:          32000,
    GasCodeDeposit:     200,
    GasCall:            40,     # Changed to 700 in Tangerine (EIP150)
    GasCallValue:       9000,
    GasCallStipend:     2300,
    GasNewAccount:      25_000,
    GasExp:             10,
    GasExpByte:         10,     # Changed to 50 in Spurious Dragon (EIP160)
    GasMemory:          3,
    GasTXCreate:        32000,
    GasTXDataZero:      4,
    GasTXDataNonZero:   68,
    GasTransaction:     21000,
    GasLog:             375,
    GasLogData:         8,
    GasLogTopic:        375,
    GasSha3:            30,
    GasSha3Word:        6,
    GasCopy:            3,
    GasBlockhash:       20
    # GasQuadDivisor:     100     # Unused, do not confuse with the quadratic coefficient 512 for memory expansion
  ]

# Create the schedule for each forks
func tangerineGasFees(previous_fees: GasFeeSchedule): GasFeeSchedule =
  # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
  result = previous_fees
  result[GasSload]        = 200
  result[GasSelfDestruct] = 5000
  result[GasBalance]      = 400
  result[GasCall]         = 40

func spuriousGasFees(previous_fees: GasFeeSchedule): GasFeeSchedule =
  # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-160.md
  result = previous_fees
  result[GasExpByte]      = 50

const
  TangerineGasFees = BaseGasFees.tangerineGasFees
  SpuriousGasFees = TangerineGasFees.spuriousGasFees
  # Note that later forks are still WIP

# `gasCosts` is a macro that builds an array of gas cost functions
# It takes (Fee schedule, prefix of generated functions, result array of functions)
# as argument.
# The array is a property of vm forks.
gasCosts(BaseGasFees, base, BaseGasCosts)
gasCosts(TangerineGasFees, tangerine, TangerineGasCosts)
# Note that later forks are still WIP

proc forkToSchedule*(fork: Fork): GasCosts =
  if fork < FkTangerine:
    BaseGasCosts
  else:
    TangerineGasCosts
  # Note that later forks are still WIP
1reaction
cburgdorfcommented, Aug 20, 2018

@mratsim thanks for chiming in here and sharing your code from the nimbus client 👍 I had written up a big comment right before the internet had an outage (traveling) but I think it’s well aligned with what you wrote. Here it goes:

As promised to @glaksmono in chat, here’s me elaborating on the issue. Let’s look at how the constants are used to day and the things that may be wrong with that.

Let’s consider GAS_BALANCE as an example. This constant was introduced to be used as a gas price for the opcode that reads the balance from an account. It was set to 20. We can see it being used here to set the gas price of that opcode for the frontier code.

https://github.com/ethereum/py-evm/blob/931e91531389c1a5f26f8f0690d04a7bca65e24a/eth/constants.py#L44

However, retrieving the balance doesn’t actually cost 20 gas anymore. It costs 400 as specified in the tangerine whistle fork. However, there was a new constant GAS_BALANCE_EIP150 being introduced for that which lives in the tangerine whistle specific constants.

https://github.com/ethereum/py-evm/blob/931e91531389c1a5f26f8f0690d04a7bca65e24a/eth/vm/forks/tangerine_whistle/constants.py#L13

My initial reaction was: Let’s clean up eth.constants and move all things that are only used within a specific fork into the constants of that specific fork. But I think there’s a problem with that approach as well.

There are more generic constants such as GAS_VERYLOW which are used by many different forks. But then GAS_LOW which falls into the same category is only used in the frontier fork. That’s more or less random which means, just looking at the usage side doesn’t give us a strong indicator of how to organize these constants.

And then there’s another category. A constant such as GAS_SSET isn’t used by any fork but inside eth.vm.logic instead.

With that in mind, let’s try something else.

Let’s create a new class BaseConstants in eth.vm.forks.core and define it as such:


class BaseConstants:

    GAS_LOW = 5
    ...
    GAS_BALANCE = 20
    ...

And then instead of the forks maintaining plain old constants in a separate file, let them have their inherited versions of the BaseConstants.


class TangerineWhistleConstants(BaseConstants):

    GAS_BALANCE = 400

Instead of introducing a new, different constant to adjust the gas price of the balance opcode, the fork would just redefine GAS_BALANCE with a different value.

With that in mind, let’s derive some rules on how to use organize constants under that model.

  1. Every constant that has been used in the very first version (Frontier) already, goes into BaseConstants

  2. Constants that just redefine existing constants get dropped (e.g. GAS_BALANCE_EIP150) and instead, in the inherited ForknameConstants, the value of the original constant is overwritten.

  3. New constants may be introduced in ForknameConstants if they describe things that would not make sense in BaseConstants as they aren’t generic and rather describe fork specific things.

  4. The ForknameConstants family of classes must never be imported outside of eth.vm.forks. E.g. eth.vm.logic can only import BaseConstants but not TangerineWhistleConstants

  5. If a function inside eth.vm.logic wants to import from a fork specific constant, then that is a clear signal that the function either needs to be moved into a fork specific place (which is what @pipermerriam was suggesting) or that it needs to be refactored to accept the right constants to get injected.

@pipermerriam does that feel alright to you?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Gas constant - Wikipedia
The gas constant is the constant of proportionality that relates the energy scale in physics to the temperature scale and the scale used...
Read more >
Specific gas constant for two gases - Chemistry Stack Exchange
I'm trying to find the specific gas constant of the mixture. Rsp=RM. I thought it might be M=0.1703418+0.03478.
Read more >
Universal and Individual Gas Constants
The Individual Gas Constant depends on the particular gas and is related to the molecular weight of the gas. The value is independent...
Read more >
"constants" expressions are expressions, not constants. #9232
Constant expressions are left as expressions, not constants. ... Use of constant keccak variables results in extra hashing (and so gas).
Read more >
Refactor compound density logic - Theory - Thrive Development ...
Hello everyone, While working on my global compound diffusion model, I realised that the gaseous compounds in the patches (nitrogen/dioxygen/carbon dioxyde) ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found