Skip to content

Move EIP Integration to Common #869

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

Merged
merged 4 commits into from
Sep 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions packages/block/src/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,11 @@ export class BlockHeader {
const blockTs = new BN(this.timestamp)
const parentTs = new BN(parentBlock.header.timestamp)
const parentDif = new BN(parentBlock.header.difficulty)
const minimumDifficulty = new BN(this._common.param('pow', 'minimumDifficulty', hardfork))
const minimumDifficulty = new BN(
this._common.paramByHardfork('pow', 'minimumDifficulty', hardfork),
)
const offset = parentDif.div(
new BN(this._common.param('pow', 'difficultyBoundDivisor', hardfork)),
new BN(this._common.paramByHardfork('pow', 'difficultyBoundDivisor', hardfork)),
)
let num = new BN(this.number)

Expand Down Expand Up @@ -212,7 +214,11 @@ export class BlockHeader {
dif = parentDif.add(offset.mul(a))
} else {
// pre-homestead
if (parentTs.addn(this._common.param('pow', 'durationLimit', hardfork)).cmp(blockTs) === 1) {
if (
parentTs
.addn(this._common.paramByHardfork('pow', 'durationLimit', hardfork))
.cmp(blockTs) === 1
) {
dif = offset.add(parentDif)
} else {
dif = parentDif.sub(offset)
Expand Down Expand Up @@ -252,15 +258,15 @@ export class BlockHeader {
const hardfork = this._getHardfork()

const a = pGasLimit.div(
new BN(this._common.param('gasConfig', 'gasLimitBoundDivisor', hardfork)),
new BN(this._common.paramByHardfork('gasConfig', 'gasLimitBoundDivisor', hardfork)),
)
const maxGasLimit = pGasLimit.add(a)
const minGasLimit = pGasLimit.sub(a)

return (
gasLimit.lt(maxGasLimit) &&
gasLimit.gt(minGasLimit) &&
gasLimit.gte(this._common.param('gasConfig', 'minGasLimit', hardfork))
gasLimit.gte(this._common.paramByHardfork('gasConfig', 'minGasLimit', hardfork))
)
}

Expand Down Expand Up @@ -310,7 +316,7 @@ export class BlockHeader {
}

const hardfork = this._getHardfork()
if (this.extraData.length > this._common.param('vm', 'maxExtraDataSize', hardfork)) {
if (this.extraData.length > this._common.paramByHardfork('vm', 'maxExtraDataSize', hardfork)) {
throw new Error('invalid amount of extra data')
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/eips/EIP2537.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"comment": "BLS12-381 precompiles",
"url": "https://eips.ethereum.org/EIPS/eip-2537",
"status": "Draft",
"minimumHardfork": "chainstart",
"gasConfig": {},
"gasPrices": {
"Bls12381G1AddGas": {
Expand Down
87 changes: 76 additions & 11 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ export interface CommonOpts {
* Limit parameter returns to the given hardforks
*/
supportedHardforks?: Array<string>
/**
* Selected EIPs which can be activated, please use an array for instantiation
* (e.g. `eips: [ 'EIP2537', ]`)
*
* Currently supported:
*
* - [EIP2537](https://eips.ethereum.org/EIPS/eip-2537) - BLS12-381 precompiles
*/
eips?: string[]
}

interface hardforkOptions {
Expand All @@ -37,9 +46,10 @@ interface hardforkOptions {
export default class Common {
readonly DEFAULT_HARDFORK: string = 'petersburg'

private _hardfork: string
private _supportedHardforks: Array<string>
private _chainParams: Chain
private _hardfork: string
private _supportedHardforks: Array<string> = []
private _eips: string[] = []

/**
* Creates a Common object for a custom chain, based on a standard one. It uses all the [[Chain]]
Expand Down Expand Up @@ -91,10 +101,15 @@ export default class Common {
constructor(opts: CommonOpts) {
this._chainParams = this.setChain(opts.chain)
this._hardfork = this.DEFAULT_HARDFORK
this._supportedHardforks = opts.supportedHardforks === undefined ? [] : opts.supportedHardforks
if (opts.supportedHardforks) {
this._supportedHardforks = opts.supportedHardforks
}
if (opts.hardfork) {
this.setHardfork(opts.hardfork)
}
if (opts.eips) {
this.setEIPs(opts.eips)
}
}

/**
Expand Down Expand Up @@ -206,16 +221,60 @@ export default class Common {
return false
}

/**
* Sets the active EIPs
* @param eips
*/
setEIPs(eips: string[] = []) {
for (const eip of eips) {
if (!(eip in EIPs)) {
throw new Error(`${eip} not supported`)
}
const minHF = this.gteHardfork(EIPs[eip]['minimumHardfork'])
if (!minHF) {
throw new Error(
`${eip} cannot be activated on hardfork ${this.hardfork()}, minimumHardfork: ${minHF}`,
)
}
}
this._eips = eips
}

/**
* Returns a parameter for the current chain setup
*
* If the parameter is present in an EIP, the EIP always takes precendence.
* Otherwise the parameter if taken from the latest applied HF with
* a change on the respective parameter.
*
* @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow')
* @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic)
* @returns The value requested or `null` if not found
*/
param(topic: string, name: string): any {
// TODO: consider the case that different active EIPs
// can change the same parameter
let value = null
for (const eip of this._eips) {
value = this.paramByEIP(topic, name, eip)
if (value !== null) {
return value
}
}
return this.paramByHardfork(topic, name, this._hardfork)
}

/**
* Returns the parameter corresponding to a hardfork
* @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow')
* @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic)
* @param hardfork Hardfork name, optional if hardfork set
* @param hardfork Hardfork name
* @returns The value requested or `null` if not found
*/
param(topic: string, name: string, hardfork?: string): any {
paramByHardfork(topic: string, name: string, hardfork: string): any {
hardfork = this._chooseHardfork(hardfork)

let value
let value = null
for (const hfChanges of hardforkChanges) {
if (!hfChanges[1][topic]) {
throw new Error(`Topic ${topic} not defined`)
Expand All @@ -225,9 +284,6 @@ export default class Common {
}
if (hfChanges[0] === hardfork) break
}
if (value === undefined) {
throw new Error(`${topic} value for ${name} not found`)
}
return value
}

Expand All @@ -236,6 +292,7 @@ export default class Common {
* @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow')
* @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic)
* @param eip Name of the EIP (e.g. 'EIP2537')
* @returns The value requested or `null` if not found
*/
paramByEIP(topic: string, name: string, eip: string): any {
if (!(eip in EIPs)) {
Expand All @@ -247,7 +304,7 @@ export default class Common {
throw new Error(`Topic ${topic} not defined`)
}
if (eipParams[topic][name] === undefined) {
throw new Error(`${topic} value for ${name} not found`)
return null
}
let value = eipParams[topic][name].v
return value
Expand All @@ -262,7 +319,7 @@ export default class Common {
paramByBlock(topic: string, name: string, blockNumber: number): any {
const activeHfs = this.activeHardforks(blockNumber)
const hardfork = activeHfs[activeHfs.length - 1]['name']
return this.param(topic, name, hardfork)
return this.paramByHardfork(topic, name, hardfork)
}

/**
Expand Down Expand Up @@ -556,4 +613,12 @@ export default class Common {
networkId(): number {
return (<any>this._chainParams)['networkId']
}

/**
* Returns the active EIPs
* @returns List of EIPs
*/
eips(): string[] {
return this._eips
}
}
34 changes: 34 additions & 0 deletions packages/common/tests/eips.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as tape from 'tape'
import Common from '../src/'

tape('[Common]: Initialization / Chain params', function (t: tape.Test) {
t.test('Correct initialization', function (st: tape.Test) {
const eips = ['EIP2537']
const c = new Common({ chain: 'mainnet', eips })
st.equal(c.eips(), eips, 'should initialize with supported EIP')
st.end()
})

t.test('Initialization errors', function (st: tape.Test) {
let eips = ['NOT_SUPPORTED_EIP']
let msg = 'should throw on not supported EIP'
let f = () => {
new Common({ chain: 'mainnet', eips })
}
st.throws(f, /not supported$/, msg)

/*
// Manual test since no test triggering EIP config available
// TODO: recheck on addition of new EIP configs
// To run manually change minimumHardfork in EIP2537 config to petersburg
eips = [ 'EIP2537', ]
msg = 'should throw on not meeting minimum hardfork requirements'
f = () => {
new Common({ chain: 'mainnet', hardfork: 'byzantium', eips })
}
st.throws(f, /minimumHardfork/, msg)
*/

st.end()
})
})
58 changes: 29 additions & 29 deletions packages/common/tests/params.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
import * as tape from 'tape'
import Common from '../src/'

tape('[Common]: Parameter access', function (t: tape.Test) {
tape('[Common]: Parameter access for param(), paramByHardfork()', function (t: tape.Test) {
t.test('Basic usage', function (st: tape.Test) {
const c = new Common({ chain: 'mainnet' })
const c = new Common({ chain: 'mainnet', eips: ['EIP2537'] })
let msg = 'Should return correct value when HF directly provided'
st.equal(c.param('gasPrices', 'ecAdd', 'byzantium'), 500, msg)
st.equal(c.paramByHardfork('gasPrices', 'ecAdd', 'byzantium'), 500, msg)

c.setHardfork('byzantium')
msg = 'Should return correct value for HF set in class'
st.equal(c.param('gasPrices', 'ecAdd'), 500, msg)

msg = 'Should return null for non-existing value'
st.equal(c.param('gasPrices', 'notexistingvalue'), null, msg)
st.equal(c.paramByHardfork('gasPrices', 'notexistingvalue', 'byzantium'), null, msg)

/*
// Manual test since no test triggering EIP config available
// TODO: recheck on addition of new EIP configs
// To run please manually add an "ecAdd" entry with value 12345 to EIP2537 config
// and uncomment the test
msg = 'EIP config should take precedence over HF config'
st.equal(c.param('gasPrices', 'ecAdd'), 12345, msg)
*/

st.end()
})

t.test('Error cases', function (st: tape.Test) {
t.test('Error cases for param(), paramByHardfork()', function (st: tape.Test) {
let c = new Common({ chain: 'mainnet' })

let f = function () {
c.param('gasPrizes', 'ecAdd', 'byzantium')
c.paramByHardfork('gasPrizes', 'ecAdd', 'byzantium')
}
let msg = 'Should throw when called with non-existing topic'
st.throws(f, /Topic gasPrizes not defined$/, msg)

f = function () {
c.param('gasPrices', 'notexistingvalue', 'byzantium')
}
msg = 'Should throw when called with non-existing value'
st.throws(f, /value for notexistingvalue not found$/, msg)

c.setHardfork('byzantium')
st.equal(c.param('gasPrices', 'ecAdd'), 500, 'Should return correct value for HF set in class')

Expand All @@ -38,7 +45,7 @@ tape('[Common]: Parameter access', function (t: tape.Test) {
supportedHardforks: ['byzantium', 'constantinople'],
})
f = function () {
c.param('gasPrices', 'expByte', 'spuriousDragon')
c.paramByHardfork('gasPrices', 'expByte', 'spuriousDragon')
}
msg = 'Should throw when calling param() with an unsupported hardfork'
st.throws(f, /supportedHardforks$/, msg)
Expand All @@ -54,23 +61,18 @@ tape('[Common]: Parameter access', function (t: tape.Test) {

t.test('Parameter updates', function (st: tape.Test) {
const c = new Common({ chain: 'mainnet' })
const f = function () {
c.param('gasPrices', 'ecAdd', 'spuriousDragon')
}
let msg = 'Should throw for a value set on a later HF'
st.throws(f, /value for ecAdd not found$/, msg)

msg = 'Should return correct value for chain start'
st.equal(c.param('pow', 'minerReward', 'chainstart'), '5000000000000000000', msg)
let msg = 'Should return correct value for chain start'
st.equal(c.paramByHardfork('pow', 'minerReward', 'chainstart'), '5000000000000000000', msg)

msg = 'Should reflect HF update changes'
st.equal(c.param('pow', 'minerReward', 'byzantium'), '3000000000000000000', msg)
st.equal(c.paramByHardfork('pow', 'minerReward', 'byzantium'), '3000000000000000000', msg)

msg = 'Should return updated sstore gas prices for constantinople'
st.equal(c.param('gasPrices', 'netSstoreNoopGas', 'constantinople'), 200, msg)
st.equal(c.paramByHardfork('gasPrices', 'netSstoreNoopGas', 'constantinople'), 200, msg)

msg = 'Should nullify SSTORE related values for petersburg'
st.equal(c.param('gasPrices', 'netSstoreNoopGas', 'petersburg'), null, msg)
st.equal(c.paramByHardfork('gasPrices', 'netSstoreNoopGas', 'petersburg'), null, msg)

st.end()
})
Expand All @@ -89,10 +91,14 @@ tape('[Common]: Parameter access', function (t: tape.Test) {

t.test('EIP param access, paramByEIP()', function (st: tape.Test) {
const c = new Common({ chain: 'mainnet' })

let msg = 'Should return null for non-existing value'
st.equal(c.paramByEIP('gasPrices', 'notexistingvalue', 'EIP2537'), null, msg)

let f = function () {
c.paramByEIP('gasPrices', 'Bls12381G1AddGas', 'NOT_SUPPORTED_EIP')
}
let msg = 'Should throw for using paramByEIP() with a not supported EIP'
msg = 'Should throw for using paramByEIP() with a not supported EIP'
st.throws(f, /not supported$/, msg)

f = function () {
Expand All @@ -101,12 +107,6 @@ tape('[Common]: Parameter access', function (t: tape.Test) {
msg = 'Should throw for using paramByEIP() with a not existing topic'
st.throws(f, /not defined$/, msg)

f = function () {
c.paramByEIP('gasPrices', 'Bls12381G1AddGas_WITH_SPELLING_MISTAKE', 'EIP2537')
}
msg = 'Should throw for using paramByEIP() if value was not found'
st.throws(f, /not found$/, msg)

msg = 'Should return Bls12381G1AddGas gas price for EIP2537'
st.equal(c.paramByEIP('gasPrices', 'Bls12381G1AddGas', 'EIP2537'), 600, msg)
st.end()
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/lib/evm/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ export default class EVM {
* if no such precompile exists.
*/
getPrecompile(address: Buffer): PrecompileFunc {
return getPrecompile(address.toString('hex'), this._vm._common, this._vm)
return getPrecompile(address.toString('hex'), this._vm._common)
}

/**
Expand Down
Loading