Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core, core/vm: added gas price variance table (EIP #150) #3111

Merged
merged 1 commit into from
Oct 14, 2016

Conversation

obscuren
Copy link
Contributor

@obscuren obscuren commented Oct 9, 2016

This implements 1b of ethereum/EIPs#150 by adding a new GasTable which must be
returned from the RuleSet config method. This table is used to determine
the gas prices for the current epoch.

Please note that when the CreateBySuicide gas price is set it is assumed
that we're in the new epoch phase.

In addition this PR will serve as temporary basis while refactorisation
in being done in the EVM64 PR, which will substentially overhaul the gas
price code.

@obscuren obscuren added the core label Oct 9, 2016
@mention-bot
Copy link

@obscuren, thanks for your PR! By analyzing the history of the files in this pull request, we identified @karalabe, @Gustav-Simonsson and @Arachnid to be potential reviewers.

@obscuren obscuren force-pushed the gas-price-fork branch 4 times, most recently from 7284c57 to a3e87ea Compare October 11, 2016 10:02
@obscuren
Copy link
Contributor Author

@fjl @karalabe @Arachnid PTAL. Left in progress because number needs to be determined.

@obscuren obscuren force-pushed the gas-price-fork branch 2 times, most recently from 80e4bdc to c65acc1 Compare October 12, 2016 09:39
Copy link
Member

@karalabe karalabe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review in progress

@@ -35,6 +35,8 @@ type ChainConfig struct {
DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork)
DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork

HomesteadGasPriceBlock *big.Int `json:"homesteadGasPriceBlock"` // homestead gas price switch block
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is essentially an API, I'd suggest a slight name change to better reflect what's happening. I.e. homesteadGasRepriceBlock. This would make it clearer later on what happened here.

Also please add to the comment what the default (nil and 0) values mean.

@@ -45,3 +47,37 @@ func (c *ChainConfig) IsHomestead(num *big.Int) bool {
}
return num.Cmp(c.HomesteadBlock) >= 0
}

func (c *ChainConfig) GasTable(num *big.Int) vm.GasTable {
Copy link
Member

@karalabe karalabe Oct 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add docs here and to the variable declarations below. Also please emphasize that the caller should not change any values as these are global ones.

}

var (
GasChartHomestead = vm.GasTable{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please move these "constants" to the params package. All other protocol parameters are there, including fork configs so I'd expect to find these there, not in the core package.

CreateBySuicide: nil,
}

GasChartHomesteadGasPriceFork = vm.GasTable{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend naming this similarly to my above suggestion, GasReprice opposed to simply Price. Also please add a link in a doc to the actual EIP with all the rationale so that anyone reading up on this and wondering where the values come from has an explanation.

@@ -26,6 +26,8 @@ import (
// execution of the EVM instructions (e.g. whether it's homestead)
type RuleSet interface {
IsHomestead(*big.Int) bool
// GasChart returns the gas prices for this epoch
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As agreed, please remove mentions of epoch as they are too easy to be confused by the Ethereum notion of 30K block epochs.

@@ -31,6 +31,18 @@ import (
type ruleSet struct{}

func (ruleSet) IsHomestead(*big.Int) bool { return true }
func (ruleSet) GasTable(*big.Int) vm.GasTable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you move these constants from core to params as suggested somewhere above, then you could reuse the same global variable and not have to redeclare the params here (potentially causing issues later down the line).

@@ -23,3 +23,17 @@ type ruleSet struct {
}

func (r ruleSet) IsHomestead(n *big.Int) bool { return n.Cmp(r.hs) >= 0 }
func (r ruleSet) GasTable(*big.Int) GasTable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, you could reuse these numbers from a global variable in params.

CALLCODE: {7, params.CallGas, 1},
DELEGATECALL: {6, params.CallGas, 1},
JUMPDEST: {0, params.JumpdestGas, 0},
//BALANCE: {1, GasExtStep, 1},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't include commented out lines in the patch!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was an accident. Will remove.

DELEGATECALL: {6, params.CallGas, 1},
JUMPDEST: {0, params.JumpdestGas, 0},
//BALANCE: {1, GasExtStep, 1},
BALANCE: {1, Zero, 1},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use a placeholder other than Zero? nil seems more suitable.


import "math/big"

type GasTable struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a map keyed by opcode, and handle CreateBySuicide separately?

@@ -234,7 +236,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {

// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
// the operation. This does not reduce gas or resizes the memory.
func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) {
func calculateGasAndSize(gasTable GasTable, env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're passing in env here, wouldn't it make more sense for it to fetch the gasTable itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because that require us to call the GasTable method again which causes additional overhead and big int comparison.

// (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is
// called. This information is otherwise lost due to the dependency on *current*
// available cost.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/cost/gas/

g.Div(g, n64)
if g.Cmp(callCost) < 0 {
return g
}
Copy link

@Gustav-Simonsson Gustav-Simonsson Oct 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EIP150 currently says:

Define "all but one 64th" of N as N - floor(N / 64) 

This code implements (N * 63) // 64 which compared to the EIP150 formula is off-by-one for some values: https://play.golang.org/p/QUbnDxCcq_

Either this code or EIP150 needs to change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code needs to change. We changed it ~4h ago.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it being the spec :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the code now as well. PTAL

@obscuren obscuren force-pushed the gas-price-fork branch 2 times, most recently from c329845 to 416d8d7 Compare October 12, 2016 19:34
MainNetHomesteadBlock = big.NewInt(1150000) // Mainnet homestead block
TestNetHomesteadBlock = big.NewInt(494000) // Testnet homestead block
MainNetHomesteadBlock = big.NewInt(1150000) // Mainnet homestead block
TestNetHomesteadGasRepriceBlock = big.NewInt(2648000) // Main net gas reprice block
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc -> Testnet

// The cost of gas was changed during the homestead price change HF. To allow for EIP150
// to be implemented. The returned gas is gas - base * 63 / 64.
func callGas(gasTable params.GasTable, availableGas, base, callCost *big.Int) *big.Int {
if gasTable.CreateBySuicide != nil {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add comment @karalabe

contract.UseGas(contract.Gas)
if env.RuleSet().GasTable(env.BlockNumber()).CreateBySuicide != nil {
gas.Div(gas, n64)
gas = gas.Sub(contract.Gas, gas)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove assignment


import "math/big"

type GasTable struct {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

godoc it

@@ -71,4 +71,5 @@ var (
SuicideRefundGas = big.NewInt(24000) // Refunded following a suicide operation.
MemoryGas = big.NewInt(3) // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

This implements 1b & 1c of EIP150 by adding a new GasTable which must be
returned from the RuleSet config method. This table is used to determine
the gas prices for the current epoch.

Please note that when the CreateBySuicide gas price is set it is assumed
that we're in the new epoch phase.

In addition this PR will serve as temporary basis while refactorisation
in being done in the EVM64 PR, which will substentially overhaul the gas
price code.
Copy link
Member

@karalabe karalabe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM 👍

@karalabe karalabe merged commit 81b01f1 into ethereum:develop Oct 14, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants