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

Setup gradual process for migrating to Typescript #495

Merged
merged 10 commits into from
Apr 12, 2019
6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
.vscode
package.json
dist
.nyc_output
*.json
36 changes: 20 additions & 16 deletions lib/bloom/index.js → lib/bloom/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
const assert = require('assert')
const utils = require('ethereumjs-util')
import * as assert from 'assert'
import { zeros, keccak256 } from 'ethereumjs-util'

const BYTE_SIZE = 256

module.exports = class Bloom {
export default class Bloom {
bitvector: Buffer

/**
* Represents a Bloom
* @constructor
* @param {Buffer} bitvector
*/
constructor (bitvector) {
constructor (bitvector: Buffer) {
if (!bitvector) {
this.bitvector = utils.zeros(BYTE_SIZE)
this.bitvector = zeros(BYTE_SIZE)
} else {
assert(bitvector.length === BYTE_SIZE, 'bitvectors must be 2048 bits long')
this.bitvector = bitvector
Expand All @@ -21,10 +23,11 @@ module.exports = class Bloom {
/**
* adds an element to a bit vector of a 64 byte bloom filter
* @method add
* @param {Buffer|Array|String|Number} e the element to add
* @param {Buffer} e the element to add
*/
add (e) {
e = utils.keccak256(e)
add (e: Buffer) {
assert(Buffer.isBuffer(e), 'Element should be buffer')
e = keccak256(e)
const mask = 2047 // binary 11111111111

for (let i = 0; i < 3; i++) {
Expand All @@ -39,11 +42,12 @@ module.exports = class Bloom {
/**
* checks if an element is in the bloom
* @method check
* @param {Buffer|Array|String|Number} e the element to check
* @param {Buffer} e the element to check
* @returns {boolean} Returns {@code true} if the element is in the bloom
*/
check (e) {
e = utils.keccak256(e)
check (e: Buffer): boolean {
assert(Buffer.isBuffer(e), 'Element should be Buffer')
e = keccak256(e)
const mask = 2047 // binary 11111111111
let match = true

Expand All @@ -52,7 +56,7 @@ module.exports = class Bloom {
const loc = mask & first2bytes
const byteLoc = loc >> 3
const bitLoc = 1 << loc % 8
match = (this.bitvector[BYTE_SIZE - byteLoc - 1] & bitLoc)
match = (this.bitvector[BYTE_SIZE - byteLoc - 1] & bitLoc) !== 0
}

return Boolean(match)
Expand All @@ -61,19 +65,19 @@ module.exports = class Bloom {
/**
* checks if multiple topics are in a bloom
* @method multiCheck
* @param {Buffer[]|Array[]|String[]|Number[]} topics
* @param {Buffer[]} topics
* @returns {boolean} Returns {@code true} if every topic is in the bloom
*/
multiCheck (topics) {
return topics.every((t) => this.check(t))
multiCheck (topics: Buffer[]): boolean {
return topics.every((t: Buffer) => this.check(t))
}

/**
* bitwise or blooms together
* @method or
* @param {Bloom} bloom
*/
or (bloom) {
or (bloom: Bloom) {
if (bloom) {
for (let i = 0; i <= BYTE_SIZE; i++) {
this.bitvector[i] = this.bitvector[i] | bloom.bitvector[i]
Copy link
Member

Choose a reason for hiding this comment

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

Looks good (the whole file), super-much a fan of making the API here more strict and restrict to Buffer.

Expand Down
4 changes: 2 additions & 2 deletions lib/evm/loop.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const utils = require('ethereumjs-util')
const { StorageReader } = require('../state')
const PStateManager = require('../state/promisified')
const { ERROR, VmError } = require('../exceptions')
const Memory = require('./memory')
const Stack = require('./stack')
const Memory = require('./memory').default
const Stack = require('./stack').default
const EEI = require('./eei')
const lookupOpInfo = require('./opcodes.js')
const opFns = require('./opFns.js')
Expand Down
26 changes: 13 additions & 13 deletions lib/evm/memory.js → lib/evm/memory.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import * as assert from 'assert'

/**
* Memory implements a simple memory model
* for the ethereum virtual machine.
*/
module.exports = class Memory {
export default class Memory {
_store: number[]

constructor () {
this._store = []
}
Expand All @@ -11,9 +15,9 @@ module.exports = class Memory {
* Extends the memory given an offset and size. Rounds extended
* memory to word-size.
* @param {Number} offset
* @param {size} size
* @param {Number} size
*/
extend (offset, size) {
extend (offset: number, size: number) {
if (size === 0) {
return
}
Expand All @@ -31,18 +35,14 @@ module.exports = class Memory {
* @param {Number} size - How many bytes to write
* @param {Buffer} value - Value
*/
write (offset, size, value) {
write (offset: number, size: number, value: Buffer) {
if (size === 0) {
return
}

if (value.length !== size) {
throw new Error('Invalid value size')
}

if (offset + size > this._store.length) {
throw new Error('Value exceeds memory capacity')
}
assert(value.length === size, 'Invalid value size')
assert(offset + size <= this._store.length, 'Value exceeds memory capacity')
assert(Buffer.isBuffer(value), 'Invalid value type')

for (let i = 0; i < size; i++) {
this._store[offset + i] = value[i]
Expand All @@ -56,7 +56,7 @@ module.exports = class Memory {
* @param {Number} size - How many bytes to read
* @returns {Buffer}
*/
read (offset, size) {
read (offset: number, size: number): Buffer {
const loaded = this._store.slice(offset, offset + size)
// Fill the remaining length with zeros
for (let i = loaded.length; i < size; i++) {
Expand All @@ -66,7 +66,7 @@ module.exports = class Memory {
}
}

const ceil = (value, ceiling) => {
const ceil = (value: number, ceiling: number): number => {
const r = value % ceiling
if (r === 0) {
return value
Copy link
Member

Choose a reason for hiding this comment

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

OK (file).

Expand Down
45 changes: 19 additions & 26 deletions lib/evm/stack.js → lib/evm/stack.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const BN = require('bn.js')
const ethUtil = require('ethereumjs-util')
import BN = require('bn.js')
import { MAX_INTEGER } from 'ethereumjs-util'
const { ERROR, VmError } = require('../exceptions')

/**
* Implementation of the stack used in evm.
*/
module.exports = class Stack {
export default class Stack {
_store: BN[]

constructor () {
this._store = []
}
Expand All @@ -14,24 +16,29 @@ module.exports = class Stack {
return this._store.length
}

push (value) {
if (this._store.length > 1023) {
throw new VmError(ERROR.STACK_OVERFLOW)
push (value: BN) {
if (!BN.isBN(value)) {
throw new VmError(ERROR.INTERNAL_ERROR)
}

if (!this._isValidValue(value)) {
if (value.gt(MAX_INTEGER)) {
throw new VmError(ERROR.OUT_OF_RANGE)
}

if (this._store.length > 1023) {
throw new VmError(ERROR.STACK_OVERFLOW)
}

this._store.push(value)
}

pop () {
pop (): BN {
if (this._store.length < 1) {
throw new VmError(ERROR.STACK_UNDERFLOW)
}

return this._store.pop()
// Length is checked above, so pop shouldn't return undefined
return this._store.pop()!
}

/**
Expand All @@ -40,7 +47,7 @@ module.exports = class Stack {
* @param {Number} num - Number of items to pop
* @returns {Array}
*/
popN (num = 1) {
popN (num: number = 1): BN[] {
if (this._store.length < num) {
throw new VmError(ERROR.STACK_UNDERFLOW)
}
Expand All @@ -56,7 +63,7 @@ module.exports = class Stack {
* Swap top of stack with an item in the stack.
* @param {Number} position - Index of item from top of the stack (0-indexed)
*/
swap (position) {
swap (position: number) {
if (this._store.length <= position) {
throw new VmError(ERROR.STACK_UNDERFLOW)
}
Expand All @@ -73,26 +80,12 @@ module.exports = class Stack {
* Pushes a copy of an item in the stack.
* @param {Number} position - Index of item to be copied (1-indexed)
*/
dup (position) {
dup (position: number) {
if (this._store.length < position) {
throw new VmError(ERROR.STACK_UNDERFLOW)
}

const i = this._store.length - position
this.push(this._store[i])
}

_isValidValue (value) {
if (BN.isBN(value)) {
if (value.lte(ethUtil.MAX_INTEGER)) {
return true
}
} else if (Buffer.isBuffer(value)) {
if (value.length <= 32) {
return true
}
}

return false
}
}
Copy link
Member

Choose a reason for hiding this comment

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

OK (file), yes, makes totally sense to inline this private method.

2 changes: 1 addition & 1 deletion lib/runBlock.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const promisify = require('util.promisify')
const ethUtil = require('ethereumjs-util')
const Bloom = require('./bloom')
const Bloom = require('./bloom').default
const rlp = ethUtil.rlp
const Trie = require('merkle-patricia-tree')
const BN = ethUtil.BN
Expand Down
2 changes: 1 addition & 1 deletion lib/runTx.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const utils = require('ethereumjs-util')
const BN = utils.BN
const Bloom = require('./bloom')
const Bloom = require('./bloom').default
const Block = require('ethereumjs-block')
const Account = require('ethereumjs-account')
const Interpreter = require('./evm/interpreter')
Expand Down
4 changes: 2 additions & 2 deletions lib/state/stateManager.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const Buffer = require('safe-buffer').Buffer
const Set = require('core-js-pure/es/set')
const Trie = require('merkle-patricia-tree/secure.js')
const Common = require('ethereumjs-common').default
const { genesisStateByName } = require('ethereumjs-common/dist/genesisStates')
Expand Down Expand Up @@ -281,7 +281,7 @@ module.exports = class StateManager {
checkpoint (cb) {
this._trie.checkpoint()
this._cache.checkpoint()
this._touchedStack.push(new Set([...this._touched]))
this._touchedStack.push(new Set(Array.from(this._touched)))
this._checkpointCount++
cb()
}
Expand Down
26 changes: 15 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
],
"scripts": {
"coverage": "nyc npm run coverageTests && nyc report --reporter=text-lcov > .nyc_output/lcov.info",
"coverageTests": "tape './tests/api/**/*.js' ./tests/tester.js -s",
"coverageTests": "npm run build:dist && tape './tests/api/**/*.js' ./tests/tester.js -s --dist",
"coveralls": "npm run coverage && if [ -n \"$COVERALLS_REPO_TOKEN\" ]; then coveralls <.nyc_output/lcov.info; fi",
"testVM": "node ./tests/tester -v",
"testStateByzantium": "npm run build:dist && node ./tests/tester -s --fork='Byzantium' --dist",
Expand All @@ -17,12 +17,14 @@
"testBuildIntegrity": "npm run build:dist && node ./tests/tester -s --dist --test='stackOverflow'",
"testBlockchain": "npm run build:dist && node --stack-size=1500 ./tests/tester -b --fork='Petersburg' --dist --excludeDir='GeneralStateTests'",
"testBlockchainGeneralStateTests": "npm run build:dist && node --stack-size=1500 ./tests/tester -b --dist --dir='GeneralStateTests'",
"testAPI": "tape './tests/api/**/*.js'",
"testAPI:browser": "karma start karma.conf.js",
"testAPI": "npm run build:dist && tape './tests/api/**/*.js'",
"testAPI:browser": "npm run build:dist && karma start karma.conf.js",
"test": "echo \"[INFO] Generic test cmd not used. See package.json for more specific test run cmds.\"",
"lint": "standard",
"format": "ethereumjs-config-format",
"format-fix": "ethereumjs-config-format-fix",
"prepublishOnly": "npm run lint && npm run build:dist && npm run testBuildIntegrity",
"build:dist": "babel lib/ -d dist/",
"build:dist": "tsc",
"build:docs": "documentation build ./lib/index.js ./lib/runBlockchain.js ./lib/runBlock.js ./lib/runTx.js ./lib/runCode.js ./lib/runCall.js --format md --shallow > ./docs/index.md",
"formatTest": "node ./scripts/formatTest"
},
Expand All @@ -35,14 +37,14 @@
"VM"
],
"dependencies": {
"@babel/runtime": "^7.4.0",
"async": "^2.1.2",
"async-eventemitter": "^0.2.2",
"core-js-pure": "^3.0.1",
Copy link
Member

Choose a reason for hiding this comment

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

Seems to be ok as a new dependency, see here.

"ethereumjs-account": "^2.0.3",
"ethereumjs-block": "~2.2.0",
"ethereumjs-blockchain": "^3.4.0",
"ethereumjs-common": "^1.1.0",
"ethereumjs-util": "^6.0.0",
"ethereumjs-util": "^6.1.0",
"fake-merkle-patricia-tree": "^1.0.1",
"functional-red-black-tree": "^1.0.1",
"merkle-patricia-tree": "^2.3.2",
Expand All @@ -51,10 +53,9 @@
"util.promisify": "^1.0.0"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.4.0",
"@babel/plugin-transform-runtime": "^7.4.0",
"@babel/preset-env": "^7.4.1",
"@ethereumjs/config-prettier": "^1.1.1",
"@types/bn.js": "^4.11.5",
"@types/node": "^11.13.4",
"browserify": "^16.2.3",
"coveralls": "^3.0.0",
"documentation": "^8.1.2",
Expand All @@ -70,9 +71,12 @@
"level-mem": "^3.0.1",
"minimist": "^1.1.1",
"nyc": "^12.0.2",
"prettier": "^1.16.4",
"rlp": "^2.2.3",
"standard": "^10.0.0",
"tap-spec": "^5.0.0",
"tape": "4.6.3"
"tape": "4.6.3",
"typescript": "^3.4.3"
},
"author": "mjbecze <mjbecze@gmail.com>",
"contributors": [
Expand Down