Skip to content

Commit

Permalink
Merge pull request #1023 from ethereumjs/client-typesafe
Browse files Browse the repository at this point in the history
Client: make fetcher more typesafe
  • Loading branch information
holgerd77 committed Jan 2, 2021
2 parents eb2e4c8 + c489c7c commit 9937927
Show file tree
Hide file tree
Showing 20 changed files with 11,410 additions and 947 deletions.
11,900 changes: 11,106 additions & 794 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions packages/client/lib/net/protocol/ethprotocol.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BN, bufferToInt } from 'ethereumjs-util'
import { Block, BlockHeader, BlockHeaderBuffer } from '@ethereumjs/block'
import { BlockHeader, BlockHeaderBuffer } from '@ethereumjs/block'
import { Chain } from './../../blockchain'
import { Message, Protocol, ProtocolOptions } from './protocol'
import { BlockBodyBuffer } from '@ethereumjs/block'

interface EthProtocolOptions extends ProtocolOptions {
/* Blockchain */
Expand All @@ -24,7 +25,7 @@ type GetBlockHeadersOpts = {
*/
export interface EthProtocolMethods {
getBlockHeaders: (opts: GetBlockHeadersOpts) => Promise<BlockHeader[]>
getBlockBodies: (hashes: Buffer[]) => Promise<Block[]>
getBlockBodies: (hashes: Buffer[]) => Promise<BlockBodyBuffer[]>
}

const messages: Message[] = [
Expand Down
8 changes: 4 additions & 4 deletions packages/client/lib/rpc/modules/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,18 @@ export class Admin {
* @param {*} [params] An empty array
* @param {*} [cb] A function with an error object as the first argument and the result as the second
*/
async nodeInfo(params: any, cb: Function) {
async nodeInfo(params: [], cb: Function) {
const rlpxInfo = (this._client.server('rlpx') as RlpxServer).getRlpxInfo()
const { enode, id, ip, listenAddr, ports } = rlpxInfo
const { discovery, listener } = ports
const clientName = getClientVersion()

// TODO version not present in reference..
// const ethVersion = Math.max.apply(Math, this._ethProtocol.versions)
const latestHeader = (this._chain as any)._headers.latest
const difficulty = latestHeader?.difficulty ?? 0 // should be number
const latestHeader = await this._chain.getLatestHeader()
const difficulty = latestHeader.difficulty
const genesis = bufferToHex(this._chain.genesis.hash)
const head = bufferToHex(latestHeader?.mixHash ?? null)
const head = bufferToHex(latestHeader.mixHash)
const network = this._chain.networkId

const nodeInfo = {
Expand Down
11 changes: 6 additions & 5 deletions packages/client/lib/rpc/modules/eth.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { Chain } from '../../blockchain'
import { middleware, validators } from '../validation'
import { toBuffer, stripHexPrefix, BN } from 'ethereumjs-util'
import { EthereumClient } from '../..'

/**
* eth_* RPC module
* @memberof module:rpc/modules
*/
export class Eth {
private _chain: Chain
public ethVersion: any
public ethVersion: number

/**
* Create eth_* RPC module
* @param {Node} Node to which the module binds
*/
constructor(node: any) {
constructor(node: EthereumClient) {
const service = node.services.find((s: any) => s.name === 'eth')
this._chain = service.chain
const ethProtocol = service.protocols.find((p: any) => p.name === 'eth')
this.ethVersion = Math.max.apply(Math, ethProtocol.versions)
this._chain = service!.chain
const ethProtocol = service!.protocols.find((p: any) => p.name === 'eth')
this.ethVersion = Math.max.apply(Math, ethProtocol!.versions)

this.blockNumber = middleware(this.blockNumber.bind(this), 0)

Expand Down
5 changes: 3 additions & 2 deletions packages/client/lib/rpc/modules/net.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { EthereumService } from '../../service/ethereumservice'
import { middleware } from '../validation'
import { addHexPrefix } from 'ethereumjs-util'
import { EthereumClient } from '../..'

/**
* net_* RPC module
Expand All @@ -15,8 +16,8 @@ export class Net {
* Create net_* RPC module
* @param {Node} Node to which the module binds
*/
constructor(node: any) {
const service: EthereumService = node.services.find((s: any) => s.name === 'eth')
constructor(node: EthereumClient) {
const service: EthereumService = node.services.find((s: any) => s.name === 'eth')!
this._chain = service.chain
this._node = node
this._peerPool = service.pool
Expand Down
8 changes: 5 additions & 3 deletions packages/client/lib/rpc/modules/web3.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { middleware, validators } from '../validation'
import { addHexPrefix, keccak, toBuffer } from 'ethereumjs-util'
import { getClientVersion } from '../../util'
import { EthereumClient } from '../..'
import { Chain } from '../../blockchain'

/**
* web3_* RPC module
* @memberof module:rpc/modules
*/
export class Web3 {
private _chain: any
private _chain?: Chain

/**
* Create web3_* RPC module
* @param {Node} Node to which the module binds
*/
constructor(node: any) {
constructor(node: EthereumClient) {
const service = node.services.find((s: any) => s.name === 'eth')
this._chain = service.chain
this._chain = service?.chain

this.clientVersion = middleware(this.clientVersion.bind(this), 0, [])

Expand Down
55 changes: 19 additions & 36 deletions packages/client/lib/sync/fetcher/blockfetcher.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,30 @@
import { Fetcher, FetcherOptions } from './fetcher'
import { Block, BlockBodyBuffer } from '@ethereumjs/block'
import { BN } from 'ethereumjs-util'
import { Peer } from '../../net/peer'
import { EthProtocolMethods } from '../../net/protocol'
import { Chain } from '../../blockchain'

export interface BlockFetcherOptions extends FetcherOptions {
/* Blockchain */
chain: Chain

/* Block number to start fetching from */
first: BN

/* How many blocks to fetch */
count: BN
}
import { Job } from './types'
import { BlockFetcherBase, JobTask, BlockFetcherOptions } from './blockfetcherbase'

/**
* Implements an eth/62 based block fetcher
* @memberof module:sync/fetcher
*/
export class BlockFetcher extends Fetcher {
protected chain: Chain
protected first: BN
protected count: BN

export class BlockFetcher extends BlockFetcherBase<Block[], Block> {
/**
* Create new block fetcher
* @param {BlockFetcherOptions}
*/
constructor(options: BlockFetcherOptions) {
super(options)

this.chain = options.chain
this.maxPerRequest = options.maxPerRequest ?? 128
this.first = options.first
this.count = options.count
}

/**
* Generate list of tasks to fetch
* @return {Object[]} tasks
*/
tasks(): object[] {
tasks(): JobTask[] {
const { first, count } = this
const max = this.maxPerRequest
const tasks = []
const tasks: JobTask[] = []
while (count.gten(max)) {
tasks.push({ first: first.clone(), count: max })
first.iaddn(max)
Expand All @@ -61,18 +40,20 @@ export class BlockFetcher extends Fetcher {
* Requests blocks associated with this job
* @param job
*/
async request(job: any): Promise<any> {
async request(job: Job<JobTask, Block[], Block>): Promise<Block[]> {
const { task, peer } = job
const { first, count } = task
const headers = await (peer.eth as EthProtocolMethods).getBlockHeaders({
const headers = await (peer!.eth as EthProtocolMethods).getBlockHeaders({
block: first,
max: count,
})
const bodies = await peer.eth.getBlockBodies(headers.map((h) => h.hash()))
const blocks = bodies.map(([txsData, unclesData]: BlockBodyBuffer, i: number) =>
const bodies: BlockBodyBuffer[] = <BlockBodyBuffer[]>(
await peer!.eth!.getBlockBodies(headers.map((h) => h.hash()))
)
const blocks: Block[] = bodies.map(([txsData, unclesData]: BlockBodyBuffer, i: number) =>
Block.fromValuesArray([headers[i].raw(), txsData, unclesData], { common: this.config.common })
)
return { blocks }
return blocks
}

/**
Expand All @@ -81,18 +62,20 @@ export class BlockFetcher extends Fetcher {
* @param result fetch result
* @return {*} results of processing job or undefined if job not finished
*/
process(job: any, result: any) {
if (result.blocks && result.blocks.length === job.task.count) {
return result.blocks
process(job: Job<JobTask, Block[], Block>, result: Block[]) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (result && result.length === job.task.count) {
return result
}
return
}

/**
* Store fetch result. Resolves once store operation is complete.
* @param {Block[]} blocks fetch result
* @return {Promise}
*/
async store(blocks: Array<any>) {
async store(blocks: Block[]) {
await this.chain.putBlocks(blocks)
}

Expand All @@ -102,7 +85,7 @@ export class BlockFetcher extends Fetcher {
* @return {Peer}
*/
// TODO: find out what _job is supposed to be doing here...
peer(_job: any): Peer {
peer(): Peer {
return this.pool.idle((p: any) => p.eth)
}
}
61 changes: 61 additions & 0 deletions packages/client/lib/sync/fetcher/blockfetcherbase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Fetcher, FetcherOptions } from './fetcher'
import { BN } from 'ethereumjs-util'
import { Chain } from '../../blockchain'

export interface BlockFetcherOptions extends FetcherOptions {
/* Blockchain */
chain: Chain

/* Block number to start fetching from */
first: BN

/* How many blocks to fetch */
count: BN
}

export type JobTask = {
first: BN
count: number
}

export abstract class BlockFetcherBase<JobResult, StorageItem> extends Fetcher<
JobTask,
JobResult,
StorageItem
> {
protected chain: Chain
protected first: BN
protected count: BN

/**
* Create new block fetcher
* @param {BlockFetcherOptions}
*/
constructor(options: BlockFetcherOptions) {
super(options)

this.chain = options.chain
this.maxPerRequest = options.maxPerRequest ?? 128
this.first = options.first
this.count = options.count
}

/**
* Generate list of tasks to fetch
* @return {Object[]} tasks
*/
tasks(): JobTask[] {
const { first, count } = this
const max = this.maxPerRequest
const tasks: JobTask[] = []
while (count.gten(max)) {
tasks.push({ first: first.clone(), count: max })
first.iaddn(max)
count.isubn(max)
}
if (count.gtn(0)) {
tasks.push({ first: first.clone(), count: count.toNumber() })
}
return tasks
}
}
Loading

0 comments on commit 9937927

Please sign in to comment.