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

Define a Blockchain interface #566

Closed
wants to merge 1 commit into from
Closed
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
136 changes: 136 additions & 0 deletions lib/blockchain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import * as util from 'ethereumjs-util'
import BN = require('bn.js')

/**
* This can be removed once
* [this PR](https://github.com/ethereumjs/ethereumjs-block/pull/72/files) gets merged, released,
* and ethereumjs-block is updated here.
*/
export type Block = any

export interface Blockchain {
/**
* Adds a block to the blockchain.
*
* @param block - The block to be added to the blockchain.
* @param cb - The callback. It is given two parameters `err` and the saved `block`
* @param isGenesis - True if block is the genesis block.
*/
putBlock(block: Block, cb: any, isGenesis?: boolean): void

/**
* Returns a block by its hash.
*/
getBlock(hash: Buffer | BN, cb: (err: Error | null, block?: Block) => void): void

/**
* Iterates through blocks starting at the specified iterator head and calls the onBlock function
* on each block.
*
* @param name - Name of the state root head
* @param onBlock - Function called on each block with params (block, reorg, cb)
* @param cb - A callback function
*/
iterator(name: string, onBlock: any, cb: any): void

/**
* Deletes a block from the blockchain. All child blocks in the chain are deleted and any
* encountered heads are set to the parent block.
*
* @param blockHash - The hash of the block to be deleted
* @param cb - A callback.
*/
delBlock(blockHash: Buffer, cb: any): void

/**
* This method is only here for backwards compatibility. It can be removed once
* [this PR](https://github.com/ethereumjs/ethereumjs-block/pull/72/files) gets merged, released,
* and ethereumjs-block is updated here.
*
* The method should just call `cb` with `null` as first argument.
*/
getDetails(_: string, cb: any): void
}

export class MockBlockchain implements Blockchain {
private readonly _blocks: Block[] = []
private readonly _blockNumberByHash: Map<string, number> = new Map()

putBlock(block: any, cb: any): void {
const blockNumber = util.bufferToInt(block.header.number)

if (this._blocks.length !== blockNumber) {
cb(new Error('Invalid block number'))
return
}

this._blocks.push(block)
this._blockNumberByHash.set(util.bufferToHex(block.hash()), blockNumber)

cb(null, block)
}

delBlock(blockHash: Buffer, cb: any): void {
const blockNumber = this._blockNumberByHash.get(util.bufferToHex(blockHash))

if (blockNumber === undefined) {
cb(new Error('Block not found'))
return
}

for (let n = blockNumber; n < this._blocks.length; n++) {
const block = this._blocks[n]

this._blockNumberByHash.delete(util.bufferToHex(block.hash()))
}

this._blocks.splice(blockNumber)
cb(null)
}

getBlock(hashOrBlockNumber: Buffer | BN, cb: (err: Error | null, block?: Block) => void): void {
let blockNumber: number

if (BN.isBN(hashOrBlockNumber)) {
blockNumber = hashOrBlockNumber.toNumber()
} else {
const hash = util.bufferToHex(hashOrBlockNumber)

if (!this._blockNumberByHash.has(hash)) {
cb(new Error('Block not found'))
return
}

blockNumber = this._blockNumberByHash.get(hash)!
}

cb(null, this._blocks[blockNumber])
}

iterator(name: string, onBlock: any, cb: any): void {
let n = 0

const iterate = (err?: Error | null) => {
if (err) {
cb(err)
return
}

if (n >= this._blocks.length) {
cb(null)
return
}

onBlock(this._blocks[n], false, (err?: Error | null) => {
n += 1
iterate(err)
})
}

iterate(null)
}

getDetails(_: string, cb: any): void {
cb(null)
}
}
2 changes: 1 addition & 1 deletion lib/evm/eei.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import BN = require('bn.js')
import { toBuffer } from 'ethereumjs-util'
import Account from 'ethereumjs-account'
import Blockchain from 'ethereumjs-blockchain'
import { Blockchain } from '../blockchain'
import Common from 'ethereumjs-common'
import PStateManager from '../state/promisified'
import { VmError, ERROR } from '../exceptions'
Expand Down
8 changes: 4 additions & 4 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import BN = require('bn.js')
import Account from 'ethereumjs-account'
import Blockchain from 'ethereumjs-blockchain'
import Common from 'ethereumjs-common'
import { StateManager } from './state'
import { default as runCode, RunCodeOpts } from './runCode'
Expand All @@ -9,6 +8,7 @@ import { default as runTx, RunTxOpts, RunTxResult } from './runTx'
import { default as runBlock, RunBlockOpts, RunBlockResult } from './runBlock'
import { EVMResult, ExecResult } from './evm/evm'
import runBlockchain from './runBlockchain'
import { Blockchain, MockBlockchain } from './blockchain'
const promisify = require('util.promisify')
const AsyncEventEmitter = require('async-eventemitter')
const Trie = require('merkle-patricia-tree/secure.js')
Expand All @@ -35,7 +35,7 @@ export interface VMOpts {
*/
state?: any // TODO
/**
* A [blockchain](https://github.com/ethereumjs/ethereumjs-blockchain) object for storing/retrieving blocks
* A blockchain object for storing/retrieving blocks
*/
blockchain?: Blockchain
/**
Expand Down Expand Up @@ -105,7 +105,7 @@ export default class VM extends AsyncEventEmitter {
this.stateManager = new StateManager({ trie, common: this._common })
}

this.blockchain = opts.blockchain || new Blockchain({ common: this._common })
this.blockchain = opts.blockchain || new MockBlockchain()

this.allowUnlimitedContractSize =
opts.allowUnlimitedContractSize === undefined ? false : opts.allowUnlimitedContractSize
Expand All @@ -116,7 +116,7 @@ export default class VM extends AsyncEventEmitter {
*
* This method modifies the state.
*
* @param blockchain - A [blockchain](https://github.com/ethereum/ethereumjs-blockchain) object to process
* @param blockchain - A blockchain object to process
* @param cb - the callback function
*/
runBlockchain(blockchain: any): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion lib/runBlockchain.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Blockchain from 'ethereumjs-blockchain'
import { Blockchain } from './blockchain'
import VM from './index'
const async = require('async')

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
"core-js-pure": "^3.0.1",
"ethereumjs-account": "^3.0.0",
"ethereumjs-block": "~2.2.0",
"ethereumjs-blockchain": "^4.0.1",
"ethereumjs-common": "^1.3.0",
"ethereumjs-tx": "^2.1.0",
"ethereumjs-util": "^6.1.0",
Expand All @@ -74,6 +73,7 @@
"@types/node": "^11.13.4",
"browserify": "^16.2.3",
"coveralls": "^3.0.0",
"ethereumjs-blockchain": "^4.0.1",
"ethereumjs-testing": "git+https://github.com/ethereumjs/ethereumjs-testing.git#v1.2.7",
"husky": "^2.1.0",
"karma": "^4.0.1",
Expand Down