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

Commit

Permalink
Merge pull request #91 from ethereumjs/refactor
Browse files Browse the repository at this point in the history
Move some db ops to DBManager
  • Loading branch information
holgerd77 authored Feb 21, 2019
2 parents 29a337f + 2caf828 commit 2262597
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 209 deletions.
4 changes: 4 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["@babel/env"],
"plugins": ["@babel/plugin-transform-runtime"]
}
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
language: node_js
node_js:
- "6"
- "8"
- "9"
- "10"
- "11"
env:
- CXX=g++-4.8
addons:
Expand All @@ -18,9 +18,9 @@ matrix:
fast_finish: true
include:
- os: linux
node_js: "6"
node_js: "8"
env: CXX=g++-4.8 TEST_SUITE=coveralls
- os: linux
node_js: "6"
node_js: "8"
env: CXX=g++-4.8 TEST_SUITE=lint
script: npm run $TEST_SUITE
7 changes: 0 additions & 7 deletions babel.config.js

This file was deleted.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"coverage": "nyc npm run test && nyc report --reporter=text-lcov > .nyc_output/lcov.info",
"coveralls": "npm run coverage && coveralls <.nyc_output/lcov.info",
"lint": "standard",
"test": "tape ./test/*.js"
"test": "babel-tape-runner ./test/*.js"
},
"repository": {
"type": "git",
Expand All @@ -29,6 +29,7 @@
},
"homepage": "https://github.com/ethereumjs/ethereumjs-blockchain#readme",
"dependencies": {
"@babel/runtime": "^7.3.1",
"async": "^2.6.1",
"ethashjs": "~0.0.7",
"ethereumjs-block": "~2.2.0",
Expand All @@ -38,12 +39,15 @@
"level-mem": "^3.0.1",
"lru-cache": "^5.1.1",
"safe-buffer": "^5.1.2",
"semaphore": "^1.1.0"
"semaphore": "^1.1.0",
"util": "^0.11.1"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.3.1",
"babel-tape-runner": "^3.0.0",
"coveralls": "^3.0.2",
"nyc": "^13.0.1",
"standard": "^11.0.1",
Expand Down
194 changes: 194 additions & 0 deletions src/dbManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
const BN = require('bn.js')
const level = require('level-mem')
const rlp = require('rlp')
const Block = require('ethereumjs-block')
const Cache = require('./cache')
const {
headsKey,
headHeaderKey,
headBlockKey,
hashToNumberKey,
numberToHashKey,
tdKey,
bodyKey,
headerKey
} = require('./util')

/**
* Abstraction over db to facilitate storing/fetching blockchain-related
* data, such as blocks and headers, indices, and the head block.
*/
module.exports = class DBManager {
constructor (db, common) {
this._db = db
this._common = common
this._cache = {
td: new Cache({ max: 1024 }),
header: new Cache({ max: 512 }),
body: new Cache({ max: 256 }),
numberToHash: new Cache({ max: 2048 }),
hashToNumber: new Cache({ max: 2048 })
}
}

/**
* Fetches iterator heads from the db.
* @returns Promise
*/
getHeads () {
return this.get(headsKey, { valueEncoding: 'json' })
}

/**
* Fetches header of the head block.
* @returns Promise
*/
getHeadHeader () {
return this.get(headHeaderKey)
}

/**
* Fetches head block.
* @returns Promise
*/
getHeadBlock () {
return this.get(headBlockKey)
}

/**
* Fetches a block (header and body), given a block tag
* which can be either its hash or its number.
* @param {Buffer|BN|number} blockTag - Hash or number of the block
* @returns Promise
*/
async getBlock (blockTag) {
// determine BlockTag type
if (Number.isInteger(blockTag)) {
blockTag = new BN(blockTag)
}

let number
let hash
if (Buffer.isBuffer(blockTag)) {
hash = blockTag
number = await this.hashToNumber(blockTag)
} else if (BN.isBN(blockTag)) {
number = blockTag
hash = await this.numberToHash(blockTag)
} else {
throw new Error('Unknown blockTag type')
}

const header = (await this.getHeader(hash, number)).raw
let body
try {
body = await this.getBody(hash, number)
} catch (e) {
body = [[], []]
}

return new Block([header].concat(body), {common: this._common})
}

/**
* Fetches body of a block given its hash and number.
* @param {Buffer} hash
* @param {BN} number
* @returns Promise
*/
async getBody (hash, number) {
const key = bodyKey(number, hash)
return rlp.decode(await this.get(key, { cache: 'body' }))
}

/**
* Fetches header of a block given its hash and number.
* @param {Buffer} hash
* @param {BN} number
* @returns Promise
*/
async getHeader (hash, number) {
const key = headerKey(number, hash)
let encodedHeader = await this.get(key, { cache: 'header' })
return new Block.Header(rlp.decode(encodedHeader), { common: this._common })
}

/**
* Fetches total difficulty for a block given its hash and number.
* @param {Buffer} hash
* @param {BN} number
* @returns Promise
*/
async getTd (hash, number) {
const key = tdKey(number, hash)
const td = await this.get(key, { cache: 'td' })
return new BN(rlp.decode(td))
}

/**
* Performs a block hash to block number lookup.
* @param {Buffer} hash
* @returns Promise
*/
async hashToNumber (hash) {
const key = hashToNumberKey(hash)
return new BN(await this.get(key, { cache: 'hashToNumber' }))
}

/**
* Performs a block number to block hash lookup.
* @param {BN} number
* @returns Promise
*/
async numberToHash (number) {
if (number.ltn(0)) {
throw new level.errors.NotFoundError()
}

const key = numberToHashKey(number)
return this.get(key, { cache: 'numberToHash' })
}

/**
* Fetches a key from the db. If `opts.cache` is specified
* it first tries to load from cache, and on cache miss will
* try to put the fetched item on cache afterwards.
* @param {Buffer} key
* @param {Object} opts - Options and their default values are:
* - {string} [keyEncoding='binary']
* - {string} [valueEncodingr='binary']
* - {string} [cache=undefined] name of cache to use
* @returns Promise
*/
async get (key, opts = {}) {
const dbOpts = {
keyEncoding: opts.keyEncoding || 'binary',
valueEncoding: opts.valueEncoding || 'binary'
}

if (opts.cache) {
if (!this._cache[opts.cache]) {
throw new Error(`Invalid cache: ${opts.cache}`)
}

let value = this._cache[opts.cache].get(key)
if (!value) {
value = await this._db.get(key, dbOpts)
this._cache[opts.cache].set(key, value)
}

return value
}

return this._db.get(key, dbOpts)
}

/**
* Performs a batch operation on db.
* @param {Array} ops
* @returns Promise
*/
batch (ops) {
return this._db.batch(ops)
}
}
Loading

0 comments on commit 2262597

Please sign in to comment.