Skip to content

Commit 9937927

Browse files
authored
Merge pull request #1023 from ethereumjs/client-typesafe
Client: make fetcher more typesafe
2 parents eb2e4c8 + c489c7c commit 9937927

File tree

20 files changed

+11410
-947
lines changed

20 files changed

+11410
-947
lines changed

package-lock.json

Lines changed: 11106 additions & 794 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/client/lib/net/protocol/ethprotocol.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { BN, bufferToInt } from 'ethereumjs-util'
2-
import { Block, BlockHeader, BlockHeaderBuffer } from '@ethereumjs/block'
2+
import { BlockHeader, BlockHeaderBuffer } from '@ethereumjs/block'
33
import { Chain } from './../../blockchain'
44
import { Message, Protocol, ProtocolOptions } from './protocol'
5+
import { BlockBodyBuffer } from '@ethereumjs/block'
56

67
interface EthProtocolOptions extends ProtocolOptions {
78
/* Blockchain */
@@ -24,7 +25,7 @@ type GetBlockHeadersOpts = {
2425
*/
2526
export interface EthProtocolMethods {
2627
getBlockHeaders: (opts: GetBlockHeadersOpts) => Promise<BlockHeader[]>
27-
getBlockBodies: (hashes: Buffer[]) => Promise<Block[]>
28+
getBlockBodies: (hashes: Buffer[]) => Promise<BlockBodyBuffer[]>
2829
}
2930

3031
const messages: Message[] = [

packages/client/lib/rpc/modules/admin.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,18 @@ export class Admin {
3535
* @param {*} [params] An empty array
3636
* @param {*} [cb] A function with an error object as the first argument and the result as the second
3737
*/
38-
async nodeInfo(params: any, cb: Function) {
38+
async nodeInfo(params: [], cb: Function) {
3939
const rlpxInfo = (this._client.server('rlpx') as RlpxServer).getRlpxInfo()
4040
const { enode, id, ip, listenAddr, ports } = rlpxInfo
4141
const { discovery, listener } = ports
4242
const clientName = getClientVersion()
4343

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

5252
const nodeInfo = {

packages/client/lib/rpc/modules/eth.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import { Chain } from '../../blockchain'
22
import { middleware, validators } from '../validation'
33
import { toBuffer, stripHexPrefix, BN } from 'ethereumjs-util'
4+
import { EthereumClient } from '../..'
45

56
/**
67
* eth_* RPC module
78
* @memberof module:rpc/modules
89
*/
910
export class Eth {
1011
private _chain: Chain
11-
public ethVersion: any
12+
public ethVersion: number
1213

1314
/**
1415
* Create eth_* RPC module
1516
* @param {Node} Node to which the module binds
1617
*/
17-
constructor(node: any) {
18+
constructor(node: EthereumClient) {
1819
const service = node.services.find((s: any) => s.name === 'eth')
19-
this._chain = service.chain
20-
const ethProtocol = service.protocols.find((p: any) => p.name === 'eth')
21-
this.ethVersion = Math.max.apply(Math, ethProtocol.versions)
20+
this._chain = service!.chain
21+
const ethProtocol = service!.protocols.find((p: any) => p.name === 'eth')
22+
this.ethVersion = Math.max.apply(Math, ethProtocol!.versions)
2223

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

packages/client/lib/rpc/modules/net.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { EthereumService } from '../../service/ethereumservice'
22
import { middleware } from '../validation'
33
import { addHexPrefix } from 'ethereumjs-util'
4+
import { EthereumClient } from '../..'
45

56
/**
67
* net_* RPC module
@@ -15,8 +16,8 @@ export class Net {
1516
* Create net_* RPC module
1617
* @param {Node} Node to which the module binds
1718
*/
18-
constructor(node: any) {
19-
const service: EthereumService = node.services.find((s: any) => s.name === 'eth')
19+
constructor(node: EthereumClient) {
20+
const service: EthereumService = node.services.find((s: any) => s.name === 'eth')!
2021
this._chain = service.chain
2122
this._node = node
2223
this._peerPool = service.pool

packages/client/lib/rpc/modules/web3.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import { middleware, validators } from '../validation'
22
import { addHexPrefix, keccak, toBuffer } from 'ethereumjs-util'
33
import { getClientVersion } from '../../util'
4+
import { EthereumClient } from '../..'
5+
import { Chain } from '../../blockchain'
46

57
/**
68
* web3_* RPC module
79
* @memberof module:rpc/modules
810
*/
911
export class Web3 {
10-
private _chain: any
12+
private _chain?: Chain
1113

1214
/**
1315
* Create web3_* RPC module
1416
* @param {Node} Node to which the module binds
1517
*/
16-
constructor(node: any) {
18+
constructor(node: EthereumClient) {
1719
const service = node.services.find((s: any) => s.name === 'eth')
18-
this._chain = service.chain
20+
this._chain = service?.chain
1921

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

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,30 @@
1-
import { Fetcher, FetcherOptions } from './fetcher'
21
import { Block, BlockBodyBuffer } from '@ethereumjs/block'
3-
import { BN } from 'ethereumjs-util'
42
import { Peer } from '../../net/peer'
53
import { EthProtocolMethods } from '../../net/protocol'
6-
import { Chain } from '../../blockchain'
7-
8-
export interface BlockFetcherOptions extends FetcherOptions {
9-
/* Blockchain */
10-
chain: Chain
11-
12-
/* Block number to start fetching from */
13-
first: BN
14-
15-
/* How many blocks to fetch */
16-
count: BN
17-
}
4+
import { Job } from './types'
5+
import { BlockFetcherBase, JobTask, BlockFetcherOptions } from './blockfetcherbase'
186

197
/**
208
* Implements an eth/62 based block fetcher
219
* @memberof module:sync/fetcher
2210
*/
23-
export class BlockFetcher extends Fetcher {
24-
protected chain: Chain
25-
protected first: BN
26-
protected count: BN
27-
11+
export class BlockFetcher extends BlockFetcherBase<Block[], Block> {
2812
/**
2913
* Create new block fetcher
3014
* @param {BlockFetcherOptions}
3115
*/
3216
constructor(options: BlockFetcherOptions) {
3317
super(options)
34-
35-
this.chain = options.chain
36-
this.maxPerRequest = options.maxPerRequest ?? 128
37-
this.first = options.first
38-
this.count = options.count
3918
}
4019

4120
/**
4221
* Generate list of tasks to fetch
4322
* @return {Object[]} tasks
4423
*/
45-
tasks(): object[] {
24+
tasks(): JobTask[] {
4625
const { first, count } = this
4726
const max = this.maxPerRequest
48-
const tasks = []
27+
const tasks: JobTask[] = []
4928
while (count.gten(max)) {
5029
tasks.push({ first: first.clone(), count: max })
5130
first.iaddn(max)
@@ -61,18 +40,20 @@ export class BlockFetcher extends Fetcher {
6140
* Requests blocks associated with this job
6241
* @param job
6342
*/
64-
async request(job: any): Promise<any> {
43+
async request(job: Job<JobTask, Block[], Block>): Promise<Block[]> {
6544
const { task, peer } = job
6645
const { first, count } = task
67-
const headers = await (peer.eth as EthProtocolMethods).getBlockHeaders({
46+
const headers = await (peer!.eth as EthProtocolMethods).getBlockHeaders({
6847
block: first,
6948
max: count,
7049
})
71-
const bodies = await peer.eth.getBlockBodies(headers.map((h) => h.hash()))
72-
const blocks = bodies.map(([txsData, unclesData]: BlockBodyBuffer, i: number) =>
50+
const bodies: BlockBodyBuffer[] = <BlockBodyBuffer[]>(
51+
await peer!.eth!.getBlockBodies(headers.map((h) => h.hash()))
52+
)
53+
const blocks: Block[] = bodies.map(([txsData, unclesData]: BlockBodyBuffer, i: number) =>
7354
Block.fromValuesArray([headers[i].raw(), txsData, unclesData], { common: this.config.common })
7455
)
75-
return { blocks }
56+
return blocks
7657
}
7758

7859
/**
@@ -81,18 +62,20 @@ export class BlockFetcher extends Fetcher {
8162
* @param result fetch result
8263
* @return {*} results of processing job or undefined if job not finished
8364
*/
84-
process(job: any, result: any) {
85-
if (result.blocks && result.blocks.length === job.task.count) {
86-
return result.blocks
65+
process(job: Job<JobTask, Block[], Block>, result: Block[]) {
66+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
67+
if (result && result.length === job.task.count) {
68+
return result
8769
}
70+
return
8871
}
8972

9073
/**
9174
* Store fetch result. Resolves once store operation is complete.
9275
* @param {Block[]} blocks fetch result
9376
* @return {Promise}
9477
*/
95-
async store(blocks: Array<any>) {
78+
async store(blocks: Block[]) {
9679
await this.chain.putBlocks(blocks)
9780
}
9881

@@ -102,7 +85,7 @@ export class BlockFetcher extends Fetcher {
10285
* @return {Peer}
10386
*/
10487
// TODO: find out what _job is supposed to be doing here...
105-
peer(_job: any): Peer {
88+
peer(): Peer {
10689
return this.pool.idle((p: any) => p.eth)
10790
}
10891
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Fetcher, FetcherOptions } from './fetcher'
2+
import { BN } from 'ethereumjs-util'
3+
import { Chain } from '../../blockchain'
4+
5+
export interface BlockFetcherOptions extends FetcherOptions {
6+
/* Blockchain */
7+
chain: Chain
8+
9+
/* Block number to start fetching from */
10+
first: BN
11+
12+
/* How many blocks to fetch */
13+
count: BN
14+
}
15+
16+
export type JobTask = {
17+
first: BN
18+
count: number
19+
}
20+
21+
export abstract class BlockFetcherBase<JobResult, StorageItem> extends Fetcher<
22+
JobTask,
23+
JobResult,
24+
StorageItem
25+
> {
26+
protected chain: Chain
27+
protected first: BN
28+
protected count: BN
29+
30+
/**
31+
* Create new block fetcher
32+
* @param {BlockFetcherOptions}
33+
*/
34+
constructor(options: BlockFetcherOptions) {
35+
super(options)
36+
37+
this.chain = options.chain
38+
this.maxPerRequest = options.maxPerRequest ?? 128
39+
this.first = options.first
40+
this.count = options.count
41+
}
42+
43+
/**
44+
* Generate list of tasks to fetch
45+
* @return {Object[]} tasks
46+
*/
47+
tasks(): JobTask[] {
48+
const { first, count } = this
49+
const max = this.maxPerRequest
50+
const tasks: JobTask[] = []
51+
while (count.gten(max)) {
52+
tasks.push({ first: first.clone(), count: max })
53+
first.iaddn(max)
54+
count.isubn(max)
55+
}
56+
if (count.gtn(0)) {
57+
tasks.push({ first: first.clone(), count: count.toNumber() })
58+
}
59+
return tasks
60+
}
61+
}

0 commit comments

Comments
 (0)