Skip to content

EIP support for the VM and Common #856

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 2 commits into from
Sep 4, 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
47 changes: 47 additions & 0 deletions packages/common/src/eips/EIP2537.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "EIP2537",
"comment": "BLS12-381 precompiles",
"url": "https://eips.ethereum.org/EIPS/eip-2537",
"status": "Draft",
"gasConfig": {},
"gasPrices": {
"Bls12381G1AddGas": {
"v": 600,
"d": "Gas cost of a single BLS12-381 G1 addition precompile-call"
},
"Bls12381G1MulGas": {
"v": 12000,
"d": "Gas cost of a single BLS12-381 G1 multiplication precompile-call"
},
"Bls12381G2AddGas": {
"v": 4500,
"d": "Gas cost of a single BLS12-381 G2 addition precompile-call"
},
"Bls12381G2MulGas": {
"v": 55000,
"d": "Gas cost of a single BLS12-381 G2 multiplication precompile-call"
},
"Bls12381PairingBaseGas": {
"v": 115000,
"d": "Base gas cost of BLS12-381 pairing check"
},
"Bls12381PairingPerPairGas": {
"v": 23000,
"d": "Per-pair gas cost of BLS12-381 pairing check"
},
"Bls12381MapG1Gas": {
"v": 5500,
"d": "Gas cost of BLS12-381 map field element to G1"
},
"Bls12381MapG2Gas": {
"v": 110000,
"d": "Gas cost of BLS12-381 map field element to G2"
},
"Bls12381MultiExpGasDiscount": {
"v": [[1, 1200], [2, 888], [3, 764], [4, 641], [5, 594], [6, 547], [7, 500], [8, 453], [9, 438], [10, 423], [11, 408], [12, 394], [13, 379], [14, 364], [15, 349], [16, 334], [17, 330], [18, 326], [19, 322], [20, 318], [21, 314], [22, 310], [23, 306], [24, 302], [25, 298], [26, 294], [27, 289], [28, 285], [29, 281], [30, 277], [31, 273], [32, 269], [33, 268], [34, 266], [35, 265], [36, 263], [37, 262], [38, 260], [39, 259], [40, 257], [41, 256], [42, 254], [43, 253], [44, 251], [45, 250], [46, 248], [47, 247], [48, 245], [49, 244], [50, 242], [51, 241], [52, 239], [53, 238], [54, 236], [55, 235], [56, 233], [57, 232], [58, 231], [59, 229], [60, 228], [61, 226], [62, 225], [63, 223], [64, 222], [65, 221], [66, 220], [67, 219], [68, 219], [69, 218], [70, 217], [71, 216], [72, 216], [73, 215], [74, 214], [75, 213], [76, 213], [77, 212], [78, 211], [79, 211], [80, 210], [81, 209], [82, 208], [83, 208], [84, 207], [85, 206], [86, 205], [87, 205], [88, 204], [89, 203], [90, 202], [91, 202], [92, 201], [93, 200], [94, 199], [95, 199], [96, 198], [97, 197], [98, 196], [99, 196], [100, 195], [101, 194], [102, 193], [103, 193], [104, 192], [105, 191], [106, 191], [107, 190], [108, 189], [109, 188], [110, 188], [111, 187], [112, 186], [113, 185], [114, 185], [115, 184], [116, 183], [117, 182], [118, 182], [119, 181], [120, 180], [121, 179], [122, 179], [123, 178], [124, 177], [125, 176], [126, 176], [127, 175], [128, 174]],
"d": "Discount gas costs of calls to the MultiExp precompiles with `k` (point, scalar) pair"
}
},
"vm": {},
"pow": {}
}
5 changes: 5 additions & 0 deletions packages/common/src/eips/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { eipsType } from './../types'

export const EIPs: eipsType = {
EIP2537: require('./EIP2537.json'),
}
23 changes: 23 additions & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { buf as crc32Buffer } from 'crc-32'
import { chains as chainParams } from './chains'
import { hardforks as hardforkChanges } from './hardforks'
import { EIPs } from './eips'
import { Chain } from './types'

interface hardforkOptions {
Expand Down Expand Up @@ -196,6 +197,28 @@ export default class Common {
return value
}

/**
* Returns a parameter corresponding to an EIP
* @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')
*/
paramByEIP(topic: string, name: string, eip: string): any {
if (!(eip in EIPs)) {
throw new Error(`${eip} not supported`)
}

const eipParams = EIPs[eip]
if (!(topic in eipParams)) {
throw new Error(`Topic ${topic} not defined`)
}
if (eipParams[topic][name] === undefined) {
throw new Error(`${topic} value for ${name} not found`)
}
let value = eipParams[topic][name].v
return value
}

/**
* Returns a parameter for the hardfork active on block number
* @param topic Parameter topic
Expand Down
4 changes: 4 additions & 0 deletions packages/common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export interface Chain {
bootstrapNodes: BootstrapNode[]
}

export interface eipsType {
[key: string]: any
}

export interface GenesisBlock {
hash: string
timestamp: string | null
Expand Down
25 changes: 25 additions & 0 deletions packages/common/tests/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,31 @@ tape('[Common]: Parameter access', function (t: tape.Test) {
st.end()
})

t.test('EIP param access, paramByEIP()', function (st: tape.Test) {
const c = new Common('mainnet')
let f = function () {
c.paramByEIP('gasPrices', 'Bls12381G1AddGas', 'NOT_SUPPORTED_EIP')
}
let msg = 'Should throw for using paramByEIP() with a not supported EIP'
st.throws(f, /not supported$/, msg)

f = function () {
c.paramByEIP('notExistingTopic', 'Bls12381G1AddGas', 'EIP2537')
}
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()
})

t.test('Custom chain usage', function (st: tape.Test) {
const mainnetCommon = new Common('mainnet')

Expand Down
30 changes: 29 additions & 1 deletion packages/vm/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export interface VMOpts {
*/
state?: any // TODO
/**
* A [blockchain](https://github.com/ethereumjs/ethereumjs-blockchain) object for storing/retrieving blocks
* A [blockchain](https://github.com/ethereumjs/ethereumjs-vm/packages/blockchain) object for storing/retrieving blocks
*/
blockchain?: Blockchain
/**
Expand All @@ -55,7 +55,21 @@ export interface VMOpts {
* Allows unlimited contract sizes while debugging. By setting this to `true`, the check for contract size limit of 24KB (see [EIP-170](https://git.io/vxZkK)) is bypassed
*/
allowUnlimitedContractSize?: boolean
/**
* Use a [common](https://github.com/ethereumjs/ethereumjs-vm/packages/common) instance or a combination
* on the `chain` and `hardfork` options if you want to change the network setup
*/
common?: Common
/**
* Selected EIPs which can be activated on the VM, please use an array for instantiation
* (e.g. `eips: [ 'EIP2537', ])
*
* Currently supported:
* `EIP2537` (`beta`) - BLS12-381 precompiles ([specification](https://eips.ethereum.org/EIPS/eip-2537))
*
* Note: EIPs annotated with `beta` can change its behaviour or can be removed on minor version bumps of the VM
*/
eips?: string[]
}

/**
Expand All @@ -67,6 +81,7 @@ export interface VMOpts {
export default class VM extends AsyncEventEmitter {
opts: VMOpts
_common: Common
_activatedEIPs: string[] = []
stateManager: StateManager
blockchain: Blockchain
allowUnlimitedContractSize: boolean
Expand Down Expand Up @@ -126,7 +141,20 @@ export default class VM extends AsyncEventEmitter {
this._common = new Common(chain, hardfork, supportedHardforks)
}

// EIPs
if (opts.eips) {
const supportedEIPs = ['EIP2537']
for (const eip of opts.eips) {
if (supportedEIPs.includes(eip)) {
this._activatedEIPs.push(eip)
} else {
throw new Error(`${eip} is not supported by the VM`)
}
}
}

// Set list of opcodes based on HF
// TODO: make this EIP-friendly
this._opcodes = getOpcodesForHF(this._common)

if (opts.stateManager) {
Expand Down
17 changes: 17 additions & 0 deletions packages/vm/tests/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,23 @@ tape('VM with default blockchain', (t) => {
st.end()
})

t.test('should accept a supported EIP', async (st) => {
st.doesNotThrow(() => { new VM({ eips: [ 'EIP2537', ] }) })
st.end()
})

t.test('should correctly set _activatedEIPs', async (st) => {
const vm = new VM({ eips: [ 'EIP2537', ] })

st.deepEqual(vm._activatedEIPs, [ 'EIP2537', ])
st.end()
})

t.test('should not accept a not supported EIP', async (st) => {
st.throws(() => { new VM({ eips: [ 'NOT_SUPPORTED_EIP', ] }) })
st.end()
})

t.test('should run blockchain without blocks', async (st) => {
const vm = new VM()
await vm.runBlockchain()
Expand Down