Skip to content
This repository was archived by the owner on Apr 6, 2020. It is now read-only.

Commit 2262597

Browse files
authored
Merge pull request #91 from ethereumjs/refactor
Move some db ops to DBManager
2 parents 29a337f + 2caf828 commit 2262597

File tree

7 files changed

+300
-209
lines changed

7 files changed

+300
-209
lines changed

.babelrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"presets": ["@babel/env"],
3+
"plugins": ["@babel/plugin-transform-runtime"]
4+
}

.travis.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
language: node_js
22
node_js:
3-
- "6"
43
- "8"
5-
- "9"
4+
- "10"
5+
- "11"
66
env:
77
- CXX=g++-4.8
88
addons:
@@ -18,9 +18,9 @@ matrix:
1818
fast_finish: true
1919
include:
2020
- os: linux
21-
node_js: "6"
21+
node_js: "8"
2222
env: CXX=g++-4.8 TEST_SUITE=coveralls
2323
- os: linux
24-
node_js: "6"
24+
node_js: "8"
2525
env: CXX=g++-4.8 TEST_SUITE=lint
2626
script: npm run $TEST_SUITE

babel.config.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"coverage": "nyc npm run test && nyc report --reporter=text-lcov > .nyc_output/lcov.info",
1313
"coveralls": "npm run coverage && coveralls <.nyc_output/lcov.info",
1414
"lint": "standard",
15-
"test": "tape ./test/*.js"
15+
"test": "babel-tape-runner ./test/*.js"
1616
},
1717
"repository": {
1818
"type": "git",
@@ -29,6 +29,7 @@
2929
},
3030
"homepage": "https://github.com/ethereumjs/ethereumjs-blockchain#readme",
3131
"dependencies": {
32+
"@babel/runtime": "^7.3.1",
3233
"async": "^2.6.1",
3334
"ethashjs": "~0.0.7",
3435
"ethereumjs-block": "~2.2.0",
@@ -38,12 +39,15 @@
3839
"level-mem": "^3.0.1",
3940
"lru-cache": "^5.1.1",
4041
"safe-buffer": "^5.1.2",
41-
"semaphore": "^1.1.0"
42+
"semaphore": "^1.1.0",
43+
"util": "^0.11.1"
4244
},
4345
"devDependencies": {
4446
"@babel/cli": "^7.2.3",
4547
"@babel/core": "^7.2.2",
48+
"@babel/plugin-transform-runtime": "^7.2.0",
4649
"@babel/preset-env": "^7.3.1",
50+
"babel-tape-runner": "^3.0.0",
4751
"coveralls": "^3.0.2",
4852
"nyc": "^13.0.1",
4953
"standard": "^11.0.1",

src/dbManager.js

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
const BN = require('bn.js')
2+
const level = require('level-mem')
3+
const rlp = require('rlp')
4+
const Block = require('ethereumjs-block')
5+
const Cache = require('./cache')
6+
const {
7+
headsKey,
8+
headHeaderKey,
9+
headBlockKey,
10+
hashToNumberKey,
11+
numberToHashKey,
12+
tdKey,
13+
bodyKey,
14+
headerKey
15+
} = require('./util')
16+
17+
/**
18+
* Abstraction over db to facilitate storing/fetching blockchain-related
19+
* data, such as blocks and headers, indices, and the head block.
20+
*/
21+
module.exports = class DBManager {
22+
constructor (db, common) {
23+
this._db = db
24+
this._common = common
25+
this._cache = {
26+
td: new Cache({ max: 1024 }),
27+
header: new Cache({ max: 512 }),
28+
body: new Cache({ max: 256 }),
29+
numberToHash: new Cache({ max: 2048 }),
30+
hashToNumber: new Cache({ max: 2048 })
31+
}
32+
}
33+
34+
/**
35+
* Fetches iterator heads from the db.
36+
* @returns Promise
37+
*/
38+
getHeads () {
39+
return this.get(headsKey, { valueEncoding: 'json' })
40+
}
41+
42+
/**
43+
* Fetches header of the head block.
44+
* @returns Promise
45+
*/
46+
getHeadHeader () {
47+
return this.get(headHeaderKey)
48+
}
49+
50+
/**
51+
* Fetches head block.
52+
* @returns Promise
53+
*/
54+
getHeadBlock () {
55+
return this.get(headBlockKey)
56+
}
57+
58+
/**
59+
* Fetches a block (header and body), given a block tag
60+
* which can be either its hash or its number.
61+
* @param {Buffer|BN|number} blockTag - Hash or number of the block
62+
* @returns Promise
63+
*/
64+
async getBlock (blockTag) {
65+
// determine BlockTag type
66+
if (Number.isInteger(blockTag)) {
67+
blockTag = new BN(blockTag)
68+
}
69+
70+
let number
71+
let hash
72+
if (Buffer.isBuffer(blockTag)) {
73+
hash = blockTag
74+
number = await this.hashToNumber(blockTag)
75+
} else if (BN.isBN(blockTag)) {
76+
number = blockTag
77+
hash = await this.numberToHash(blockTag)
78+
} else {
79+
throw new Error('Unknown blockTag type')
80+
}
81+
82+
const header = (await this.getHeader(hash, number)).raw
83+
let body
84+
try {
85+
body = await this.getBody(hash, number)
86+
} catch (e) {
87+
body = [[], []]
88+
}
89+
90+
return new Block([header].concat(body), {common: this._common})
91+
}
92+
93+
/**
94+
* Fetches body of a block given its hash and number.
95+
* @param {Buffer} hash
96+
* @param {BN} number
97+
* @returns Promise
98+
*/
99+
async getBody (hash, number) {
100+
const key = bodyKey(number, hash)
101+
return rlp.decode(await this.get(key, { cache: 'body' }))
102+
}
103+
104+
/**
105+
* Fetches header of a block given its hash and number.
106+
* @param {Buffer} hash
107+
* @param {BN} number
108+
* @returns Promise
109+
*/
110+
async getHeader (hash, number) {
111+
const key = headerKey(number, hash)
112+
let encodedHeader = await this.get(key, { cache: 'header' })
113+
return new Block.Header(rlp.decode(encodedHeader), { common: this._common })
114+
}
115+
116+
/**
117+
* Fetches total difficulty for a block given its hash and number.
118+
* @param {Buffer} hash
119+
* @param {BN} number
120+
* @returns Promise
121+
*/
122+
async getTd (hash, number) {
123+
const key = tdKey(number, hash)
124+
const td = await this.get(key, { cache: 'td' })
125+
return new BN(rlp.decode(td))
126+
}
127+
128+
/**
129+
* Performs a block hash to block number lookup.
130+
* @param {Buffer} hash
131+
* @returns Promise
132+
*/
133+
async hashToNumber (hash) {
134+
const key = hashToNumberKey(hash)
135+
return new BN(await this.get(key, { cache: 'hashToNumber' }))
136+
}
137+
138+
/**
139+
* Performs a block number to block hash lookup.
140+
* @param {BN} number
141+
* @returns Promise
142+
*/
143+
async numberToHash (number) {
144+
if (number.ltn(0)) {
145+
throw new level.errors.NotFoundError()
146+
}
147+
148+
const key = numberToHashKey(number)
149+
return this.get(key, { cache: 'numberToHash' })
150+
}
151+
152+
/**
153+
* Fetches a key from the db. If `opts.cache` is specified
154+
* it first tries to load from cache, and on cache miss will
155+
* try to put the fetched item on cache afterwards.
156+
* @param {Buffer} key
157+
* @param {Object} opts - Options and their default values are:
158+
* - {string} [keyEncoding='binary']
159+
* - {string} [valueEncodingr='binary']
160+
* - {string} [cache=undefined] name of cache to use
161+
* @returns Promise
162+
*/
163+
async get (key, opts = {}) {
164+
const dbOpts = {
165+
keyEncoding: opts.keyEncoding || 'binary',
166+
valueEncoding: opts.valueEncoding || 'binary'
167+
}
168+
169+
if (opts.cache) {
170+
if (!this._cache[opts.cache]) {
171+
throw new Error(`Invalid cache: ${opts.cache}`)
172+
}
173+
174+
let value = this._cache[opts.cache].get(key)
175+
if (!value) {
176+
value = await this._db.get(key, dbOpts)
177+
this._cache[opts.cache].set(key, value)
178+
}
179+
180+
return value
181+
}
182+
183+
return this._db.get(key, dbOpts)
184+
}
185+
186+
/**
187+
* Performs a batch operation on db.
188+
* @param {Array} ops
189+
* @returns Promise
190+
*/
191+
batch (ops) {
192+
return this._db.batch(ops)
193+
}
194+
}

0 commit comments

Comments
 (0)