Skip to content

Commit affe8b4

Browse files
authored
Setup gradual process for migrating to Typescript (ethereumjs#495)
* Drop babel deps, add initial typescript config * Add prettier as dep, add format scripts * Mv bloom/index.js to bloom/index.ts * Migrate bloom to ts, limit its api to buffers * Mv lib/evm/stack.js to lib/evm/stack.ts * Migrate stack to ts, limit it to BN * Mv lib/evm/memory.js to lib/evm/memory.ts * Migrate evm memory to ts * Build:dist before coverage and api browser tests * Use tester dist flag for coverage tests
1 parent 484a339 commit affe8b4

24 files changed

+124
-110
lines changed

.prettierignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules
2+
.vscode
3+
package.json
4+
dist
5+
.nyc_output
6+
*.json

lib/bloom/index.js renamed to lib/bloom/index.ts

+20-16
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
const assert = require('assert')
2-
const utils = require('ethereumjs-util')
1+
import * as assert from 'assert'
2+
import { zeros, keccak256 } from 'ethereumjs-util'
33

44
const BYTE_SIZE = 256
55

6-
module.exports = class Bloom {
6+
export default class Bloom {
7+
bitvector: Buffer
8+
79
/**
810
* Represents a Bloom
911
* @constructor
1012
* @param {Buffer} bitvector
1113
*/
12-
constructor (bitvector) {
14+
constructor (bitvector: Buffer) {
1315
if (!bitvector) {
14-
this.bitvector = utils.zeros(BYTE_SIZE)
16+
this.bitvector = zeros(BYTE_SIZE)
1517
} else {
1618
assert(bitvector.length === BYTE_SIZE, 'bitvectors must be 2048 bits long')
1719
this.bitvector = bitvector
@@ -21,10 +23,11 @@ module.exports = class Bloom {
2123
/**
2224
* adds an element to a bit vector of a 64 byte bloom filter
2325
* @method add
24-
* @param {Buffer|Array|String|Number} e the element to add
26+
* @param {Buffer} e the element to add
2527
*/
26-
add (e) {
27-
e = utils.keccak256(e)
28+
add (e: Buffer) {
29+
assert(Buffer.isBuffer(e), 'Element should be buffer')
30+
e = keccak256(e)
2831
const mask = 2047 // binary 11111111111
2932

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

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

5862
return Boolean(match)
@@ -61,19 +65,19 @@ module.exports = class Bloom {
6165
/**
6266
* checks if multiple topics are in a bloom
6367
* @method multiCheck
64-
* @param {Buffer[]|Array[]|String[]|Number[]} topics
68+
* @param {Buffer[]} topics
6569
* @returns {boolean} Returns {@code true} if every topic is in the bloom
6670
*/
67-
multiCheck (topics) {
68-
return topics.every((t) => this.check(t))
71+
multiCheck (topics: Buffer[]): boolean {
72+
return topics.every((t: Buffer) => this.check(t))
6973
}
7074

7175
/**
7276
* bitwise or blooms together
7377
* @method or
7478
* @param {Bloom} bloom
7579
*/
76-
or (bloom) {
80+
or (bloom: Bloom) {
7781
if (bloom) {
7882
for (let i = 0; i <= BYTE_SIZE; i++) {
7983
this.bitvector[i] = this.bitvector[i] | bloom.bitvector[i]

lib/evm/loop.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ const utils = require('ethereumjs-util')
44
const { StorageReader } = require('../state')
55
const PStateManager = require('../state/promisified')
66
const { ERROR, VmError } = require('../exceptions')
7-
const Memory = require('./memory')
8-
const Stack = require('./stack')
7+
const Memory = require('./memory').default
8+
const Stack = require('./stack').default
99
const EEI = require('./eei')
1010
const lookupOpInfo = require('./opcodes.js')
1111
const opFns = require('./opFns.js')

lib/evm/memory.js renamed to lib/evm/memory.ts

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import * as assert from 'assert'
2+
13
/**
24
* Memory implements a simple memory model
35
* for the ethereum virtual machine.
46
*/
5-
module.exports = class Memory {
7+
export default class Memory {
8+
_store: number[]
9+
610
constructor () {
711
this._store = []
812
}
@@ -11,9 +15,9 @@ module.exports = class Memory {
1115
* Extends the memory given an offset and size. Rounds extended
1216
* memory to word-size.
1317
* @param {Number} offset
14-
* @param {size} size
18+
* @param {Number} size
1519
*/
16-
extend (offset, size) {
20+
extend (offset: number, size: number) {
1721
if (size === 0) {
1822
return
1923
}
@@ -31,18 +35,14 @@ module.exports = class Memory {
3135
* @param {Number} size - How many bytes to write
3236
* @param {Buffer} value - Value
3337
*/
34-
write (offset, size, value) {
38+
write (offset: number, size: number, value: Buffer) {
3539
if (size === 0) {
3640
return
3741
}
3842

39-
if (value.length !== size) {
40-
throw new Error('Invalid value size')
41-
}
42-
43-
if (offset + size > this._store.length) {
44-
throw new Error('Value exceeds memory capacity')
45-
}
43+
assert(value.length === size, 'Invalid value size')
44+
assert(offset + size <= this._store.length, 'Value exceeds memory capacity')
45+
assert(Buffer.isBuffer(value), 'Invalid value type')
4646

4747
for (let i = 0; i < size; i++) {
4848
this._store[offset + i] = value[i]
@@ -56,7 +56,7 @@ module.exports = class Memory {
5656
* @param {Number} size - How many bytes to read
5757
* @returns {Buffer}
5858
*/
59-
read (offset, size) {
59+
read (offset: number, size: number): Buffer {
6060
const loaded = this._store.slice(offset, offset + size)
6161
// Fill the remaining length with zeros
6262
for (let i = loaded.length; i < size; i++) {
@@ -66,7 +66,7 @@ module.exports = class Memory {
6666
}
6767
}
6868

69-
const ceil = (value, ceiling) => {
69+
const ceil = (value: number, ceiling: number): number => {
7070
const r = value % ceiling
7171
if (r === 0) {
7272
return value
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
const BN = require('bn.js')
2-
const ethUtil = require('ethereumjs-util')
1+
import BN = require('bn.js')
2+
import { MAX_INTEGER } from 'ethereumjs-util'
33
const { ERROR, VmError } = require('../exceptions')
44

55
/**
66
* Implementation of the stack used in evm.
77
*/
8-
module.exports = class Stack {
8+
export default class Stack {
9+
_store: BN[]
10+
911
constructor () {
1012
this._store = []
1113
}
@@ -14,24 +16,29 @@ module.exports = class Stack {
1416
return this._store.length
1517
}
1618

17-
push (value) {
18-
if (this._store.length > 1023) {
19-
throw new VmError(ERROR.STACK_OVERFLOW)
19+
push (value: BN) {
20+
if (!BN.isBN(value)) {
21+
throw new VmError(ERROR.INTERNAL_ERROR)
2022
}
2123

22-
if (!this._isValidValue(value)) {
24+
if (value.gt(MAX_INTEGER)) {
2325
throw new VmError(ERROR.OUT_OF_RANGE)
2426
}
2527

28+
if (this._store.length > 1023) {
29+
throw new VmError(ERROR.STACK_OVERFLOW)
30+
}
31+
2632
this._store.push(value)
2733
}
2834

29-
pop () {
35+
pop (): BN {
3036
if (this._store.length < 1) {
3137
throw new VmError(ERROR.STACK_UNDERFLOW)
3238
}
3339

34-
return this._store.pop()
40+
// Length is checked above, so pop shouldn't return undefined
41+
return this._store.pop()!
3542
}
3643

3744
/**
@@ -40,7 +47,7 @@ module.exports = class Stack {
4047
* @param {Number} num - Number of items to pop
4148
* @returns {Array}
4249
*/
43-
popN (num = 1) {
50+
popN (num: number = 1): BN[] {
4451
if (this._store.length < num) {
4552
throw new VmError(ERROR.STACK_UNDERFLOW)
4653
}
@@ -56,7 +63,7 @@ module.exports = class Stack {
5663
* Swap top of stack with an item in the stack.
5764
* @param {Number} position - Index of item from top of the stack (0-indexed)
5865
*/
59-
swap (position) {
66+
swap (position: number) {
6067
if (this._store.length <= position) {
6168
throw new VmError(ERROR.STACK_UNDERFLOW)
6269
}
@@ -73,26 +80,12 @@ module.exports = class Stack {
7380
* Pushes a copy of an item in the stack.
7481
* @param {Number} position - Index of item to be copied (1-indexed)
7582
*/
76-
dup (position) {
83+
dup (position: number) {
7784
if (this._store.length < position) {
7885
throw new VmError(ERROR.STACK_UNDERFLOW)
7986
}
8087

8188
const i = this._store.length - position
8289
this.push(this._store[i])
8390
}
84-
85-
_isValidValue (value) {
86-
if (BN.isBN(value)) {
87-
if (value.lte(ethUtil.MAX_INTEGER)) {
88-
return true
89-
}
90-
} else if (Buffer.isBuffer(value)) {
91-
if (value.length <= 32) {
92-
return true
93-
}
94-
}
95-
96-
return false
97-
}
9891
}

lib/runBlock.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const promisify = require('util.promisify')
22
const ethUtil = require('ethereumjs-util')
3-
const Bloom = require('./bloom')
3+
const Bloom = require('./bloom').default
44
const rlp = ethUtil.rlp
55
const Trie = require('merkle-patricia-tree')
66
const BN = ethUtil.BN

lib/runTx.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const utils = require('ethereumjs-util')
22
const BN = utils.BN
3-
const Bloom = require('./bloom')
3+
const Bloom = require('./bloom').default
44
const Block = require('ethereumjs-block')
55
const Account = require('ethereumjs-account')
66
const Interpreter = require('./evm/interpreter')

lib/state/stateManager.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const Buffer = require('safe-buffer').Buffer
1+
const Set = require('core-js-pure/es/set')
22
const Trie = require('merkle-patricia-tree/secure.js')
33
const Common = require('ethereumjs-common').default
44
const { genesisStateByName } = require('ethereumjs-common/dist/genesisStates')
@@ -281,7 +281,7 @@ module.exports = class StateManager {
281281
checkpoint (cb) {
282282
this._trie.checkpoint()
283283
this._cache.checkpoint()
284-
this._touchedStack.push(new Set([...this._touched]))
284+
this._touchedStack.push(new Set(Array.from(this._touched)))
285285
this._checkpointCount++
286286
cb()
287287
}

package.json

+15-11
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
],
99
"scripts": {
1010
"coverage": "nyc npm run coverageTests && nyc report --reporter=text-lcov > .nyc_output/lcov.info",
11-
"coverageTests": "tape './tests/api/**/*.js' ./tests/tester.js -s",
11+
"coverageTests": "npm run build:dist && tape './tests/api/**/*.js' ./tests/tester.js -s --dist",
1212
"coveralls": "npm run coverage && if [ -n \"$COVERALLS_REPO_TOKEN\" ]; then coveralls <.nyc_output/lcov.info; fi",
1313
"testVM": "node ./tests/tester -v",
1414
"testStateByzantium": "npm run build:dist && node ./tests/tester -s --fork='Byzantium' --dist",
@@ -17,12 +17,14 @@
1717
"testBuildIntegrity": "npm run build:dist && node ./tests/tester -s --dist --test='stackOverflow'",
1818
"testBlockchain": "npm run build:dist && node --stack-size=1500 ./tests/tester -b --fork='Petersburg' --dist --excludeDir='GeneralStateTests'",
1919
"testBlockchainGeneralStateTests": "npm run build:dist && node --stack-size=1500 ./tests/tester -b --dist --dir='GeneralStateTests'",
20-
"testAPI": "tape './tests/api/**/*.js'",
21-
"testAPI:browser": "karma start karma.conf.js",
20+
"testAPI": "npm run build:dist && tape './tests/api/**/*.js'",
21+
"testAPI:browser": "npm run build:dist && karma start karma.conf.js",
2222
"test": "echo \"[INFO] Generic test cmd not used. See package.json for more specific test run cmds.\"",
2323
"lint": "standard",
24+
"format": "ethereumjs-config-format",
25+
"format-fix": "ethereumjs-config-format-fix",
2426
"prepublishOnly": "npm run lint && npm run build:dist && npm run testBuildIntegrity",
25-
"build:dist": "babel lib/ -d dist/",
27+
"build:dist": "tsc",
2628
"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",
2729
"formatTest": "node ./scripts/formatTest"
2830
},
@@ -35,14 +37,14 @@
3537
"VM"
3638
],
3739
"dependencies": {
38-
"@babel/runtime": "^7.4.0",
3940
"async": "^2.1.2",
4041
"async-eventemitter": "^0.2.2",
42+
"core-js-pure": "^3.0.1",
4143
"ethereumjs-account": "^2.0.3",
4244
"ethereumjs-block": "~2.2.0",
4345
"ethereumjs-blockchain": "^3.4.0",
4446
"ethereumjs-common": "^1.1.0",
45-
"ethereumjs-util": "^6.0.0",
47+
"ethereumjs-util": "^6.1.0",
4648
"fake-merkle-patricia-tree": "^1.0.1",
4749
"functional-red-black-tree": "^1.0.1",
4850
"merkle-patricia-tree": "^2.3.2",
@@ -51,10 +53,9 @@
5153
"util.promisify": "^1.0.0"
5254
},
5355
"devDependencies": {
54-
"@babel/cli": "^7.2.3",
55-
"@babel/core": "^7.4.0",
56-
"@babel/plugin-transform-runtime": "^7.4.0",
57-
"@babel/preset-env": "^7.4.1",
56+
"@ethereumjs/config-prettier": "^1.1.1",
57+
"@types/bn.js": "^4.11.5",
58+
"@types/node": "^11.13.4",
5859
"browserify": "^16.2.3",
5960
"coveralls": "^3.0.0",
6061
"documentation": "^8.1.2",
@@ -70,9 +71,12 @@
7071
"level-mem": "^3.0.1",
7172
"minimist": "^1.1.1",
7273
"nyc": "^12.0.2",
74+
"prettier": "^1.16.4",
75+
"rlp": "^2.2.3",
7376
"standard": "^10.0.0",
7477
"tap-spec": "^5.0.0",
75-
"tape": "4.6.3"
78+
"tape": "4.6.3",
79+
"typescript": "^3.4.3"
7680
},
7781
"author": "mjbecze <mjbecze@gmail.com>",
7882
"contributors": [

0 commit comments

Comments
 (0)