Skip to content

Commit 7ef2ad9

Browse files
authored
Merge branch 'master' into fix-client-node-tests
2 parents 1784fce + 582b4ef commit 7ef2ad9

32 files changed

+744
-866
lines changed

package-lock.json

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

packages/blockchain/src/index.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -736,15 +736,16 @@ export default class Blockchain implements BlockchainInterface {
736736
*
737737
* @param name - Name of the state root head
738738
* @param onBlock - Function called on each block with params (block, reorg)
739+
* @param maxBlocks - How many blocks to run. By default, run all unprocessed blocks in the canonical chain.
739740
*/
740-
async iterator(name: string, onBlock: OnBlock) {
741-
return this._iterator(name, onBlock)
741+
async iterator(name: string, onBlock: OnBlock, maxBlocks?: number) {
742+
return this._iterator(name, onBlock, maxBlocks)
742743
}
743744

744745
/**
745746
* @hidden
746747
*/
747-
private async _iterator(name: string, onBlock: OnBlock) {
748+
private async _iterator(name: string, onBlock: OnBlock, maxBlocks?: number) {
748749
await this.initAndLock<void>(async () => {
749750
const blockHash = this._heads[name] || this._genesis
750751
let lastBlock: Block | undefined
@@ -753,11 +754,15 @@ export default class Blockchain implements BlockchainInterface {
753754
return
754755
}
755756

757+
if (maxBlocks && maxBlocks < 0) {
758+
throw 'If maxBlocks is provided, it has to be a non-negative number'
759+
}
760+
756761
const number = await this.dbManager.hashToNumber(blockHash)
757762
const blockNumber = number.addn(1)
763+
let blocksRanCounter = 0
758764

759-
// eslint-disable-next-line no-constant-condition
760-
while (true) {
765+
while (maxBlocks !== blocksRanCounter) {
761766
try {
762767
const block = await this._getBlock(blockNumber)
763768

@@ -770,6 +775,7 @@ export default class Blockchain implements BlockchainInterface {
770775
lastBlock = block
771776
await onBlock(block, reorg)
772777
blockNumber.iaddn(1)
778+
blocksRanCounter++
773779
} catch (error) {
774780
if (error.type !== 'NotFoundError') {
775781
throw error
@@ -782,6 +788,19 @@ export default class Blockchain implements BlockchainInterface {
782788
})
783789
}
784790

791+
/**
792+
* Set header hash of a certain `tag`.
793+
* When calling the iterator, the iterator will start running the first child block after the header hash currenntly stored.
794+
* @param tag - The tag to save the headHash to
795+
* @param headHash - The head hash to save
796+
*/
797+
async setHead(tag: string, headHash: Buffer) {
798+
await this.initAndLock<void>(async () => {
799+
this._heads[tag] = headHash
800+
await this._saveHeads()
801+
})
802+
}
803+
785804
/* Methods regarding re-org operations */
786805

787806
/**

packages/blockchain/test/index.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,99 @@ tape('blockchain test', (t) => {
348348
st.end()
349349
})
350350

351+
t.test(
352+
'should iterate through maxBlocks blocks if maxBlocks parameter is provided',
353+
async (st) => {
354+
const { blockchain, blocks, error } = await generateBlockchain(25)
355+
st.error(error, 'no error')
356+
let i = 0
357+
await blockchain.iterator(
358+
'test',
359+
(block: Block) => {
360+
if (block.hash().equals(blocks[i + 1].hash())) {
361+
i++
362+
}
363+
},
364+
5
365+
)
366+
st.equals(i, 5)
367+
st.end()
368+
}
369+
)
370+
371+
t.test(
372+
'should iterate through 0 blocks in case 0 maxBlocks parameter is provided',
373+
async (st) => {
374+
const { blockchain, blocks, error } = await generateBlockchain(25)
375+
st.error(error, 'no error')
376+
let i = 0
377+
await blockchain
378+
.iterator(
379+
'test',
380+
(block: Block) => {
381+
if (block.hash().equals(blocks[i + 1].hash())) {
382+
i++
383+
}
384+
},
385+
0
386+
)
387+
.catch(() => {
388+
st.fail('Promise cannot throw when running 0 blocks')
389+
})
390+
st.equals(i, 0)
391+
st.end()
392+
}
393+
)
394+
395+
t.test('should throw on a negative maxBlocks parameter in iterator', async (st) => {
396+
const { blockchain, blocks, error } = await generateBlockchain(25)
397+
st.error(error, 'no error')
398+
let i = 0
399+
await blockchain
400+
.iterator(
401+
'test',
402+
(block: Block) => {
403+
if (block.hash().equals(blocks[i + 1].hash())) {
404+
i++
405+
}
406+
},
407+
-1
408+
)
409+
.catch(() => {
410+
st.end()
411+
})
412+
// Note: if st.end() is not called (Promise did not throw), then this test fails, as it does not end.
413+
})
414+
415+
t.test('should test setHead method', async (st) => {
416+
const { blockchain, blocks, error } = await generateBlockchain(25)
417+
st.error(error, 'no error')
418+
419+
const headBlockIndex = 5
420+
421+
const headHash = blocks[headBlockIndex].hash()
422+
await blockchain.setHead('myHead', headHash)
423+
const currentHeadBlock = await blockchain.getHead('myHead')
424+
425+
st.ok(headHash.equals(currentHeadBlock.hash()), 'head hash equals the provided head hash')
426+
427+
let i = 0
428+
// check that iterator starts from this head block
429+
await blockchain.iterator(
430+
'myHead',
431+
(block: Block) => {
432+
if (block.hash().equals(blocks[headBlockIndex + 1].hash())) {
433+
i++
434+
}
435+
},
436+
5
437+
)
438+
439+
st.equals(i, 1)
440+
441+
st.end()
442+
})
443+
351444
t.test('should catch iterator func error', async (st) => {
352445
const { blockchain, error } = await generateBlockchain(25)
353446
st.error(error, 'no error')

packages/client/lib/net/peer/libp2ppeer.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { parseMultiaddrs } from '../../util'
55
import { Libp2pSender } from '../protocol/libp2psender'
66
import { Peer, PeerOptions } from './peer'
77
import { Libp2pNode } from './libp2pnode'
8+
import { Protocol } from '../protocol'
9+
import { Libp2pServer } from '../server'
810

911
export interface Libp2pPeerOptions extends Omit<PeerOptions, 'address' | 'transport'> {
1012
/* Multiaddrs to listen on (can be a comma separated string or list) */
@@ -73,7 +75,7 @@ export class Libp2pPeer extends Peer {
7375
* @private
7476
* @return {Promise}
7577
*/
76-
async accept(protocol: any, connection: any, server: any): Promise<void> {
78+
async accept(protocol: Protocol, connection: any, server: Libp2pServer): Promise<void> {
7779
await this.bindProtocol(protocol, new Libp2pSender(connection))
7880
this.inbound = true
7981
this.server = server
@@ -87,7 +89,7 @@ export class Libp2pPeer extends Peer {
8789
* @param {Server} [server] optional server that initiated connection
8890
* @return {Promise}
8991
*/
90-
async bindProtocols(node: any, peerInfo: any, server: any = null): Promise<void> {
92+
async bindProtocols(node: Libp2pNode, peerInfo: any, server?: Libp2pServer): Promise<void> {
9193
await Promise.all(
9294
this.protocols.map(async (p: any) => {
9395
await p.open()

packages/client/lib/net/peer/peer.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,14 @@ export class Peer extends events.EventEmitter {
9999
* @param {Sender} sender Sender instance provided by subclass
100100
* @return {Promise}
101101
* @example
102-
*
103102
* await peer.bindProtocol(ethProtocol, sender)
104103
* // Example: Directly call message name as a method on the bound protocol
105-
* const headers1 = await peer.eth.getBlockHeaders(1, 100, 0, 0)
104+
* const headers1 = await peer.eth.getBlockHeaders({ block: new BN(1), max: 100 })
106105
* // Example: Call request() method with message name as first parameter
107-
* const headers2 = await peer.eth.request('getBlockHeaders', 1, 100, 0, 0)
106+
* const headers2 = await peer.eth.request('getBlockHeaders', { block: new BN(1), max: 100 })
108107
* // Example: Call send() method with message name as first parameter and
109108
* // wait for response message as an event
110-
* peer.eth.send('getBlockHeaders', 1, 100, 0, 0)
109+
* peer.eth.send('getBlockHeaders', { block: new BN(1), max: 100 })
111110
* peer.eth.on('message', ({ data }) => console.log(`Received ${data.length} headers`))
112111
*/
113112
async bindProtocol(protocol: Protocol, sender: Sender): Promise<void> {

packages/client/lib/net/peer/rlpxpeer.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { randomBytes } from 'crypto'
22
import {
33
Capabilities as Devp2pCapabilities,
4-
DPT as Devp2pDPT,
54
ETH as Devp2pETH,
65
LES as Devp2pLES,
76
Peer as Devp2pRlpxPeer,
87
RLPx as Devp2pRLPx,
9-
} from 'ethereumjs-devp2p'
8+
} from '@ethereumjs/devp2p'
109
import { Protocol, RlpxSender } from '../protocol'
1110
import { Peer, PeerOptions } from './peer'
11+
import { RlpxServer } from '../server'
1212

1313
const devp2pCapabilities: any = {
14-
eth62: Devp2pETH.eth62,
1514
eth63: Devp2pETH.eth63,
15+
eth64: Devp2pETH.eth64,
1616
les2: Devp2pLES.les2,
1717
}
1818

@@ -103,9 +103,7 @@ export class RlpxPeer extends Peer {
103103
await Promise.all(this.protocols.map((p) => p.open()))
104104
this.rlpx = new Devp2pRLPx(key, {
105105
capabilities: RlpxPeer.capabilities(this.protocols),
106-
listenPort: null,
107-
dpt: (<unknown>null) as Devp2pDPT, // TODO: required option
108-
maxPeers: (<unknown>null) as number, // TODO: required option
106+
common: this.config.common,
109107
})
110108
await this.rlpx.connect({
111109
id: Buffer.from(this.id, 'hex'),
@@ -143,7 +141,7 @@ export class RlpxPeer extends Peer {
143141
* @private
144142
* @return {Promise}
145143
*/
146-
async accept(rlpxPeer: Devp2pRlpxPeer, server: any): Promise<void> {
144+
async accept(rlpxPeer: Devp2pRlpxPeer, server: RlpxServer): Promise<void> {
147145
if (this.connected) {
148146
return
149147
}
@@ -160,9 +158,9 @@ export class RlpxPeer extends Peer {
160158
async bindProtocols(rlpxPeer: Devp2pRlpxPeer): Promise<void> {
161159
this.rlpxPeer = rlpxPeer
162160
await Promise.all(
163-
rlpxPeer.getProtocols().map((rlpxProtocol: any) => {
161+
rlpxPeer.getProtocols().map((rlpxProtocol) => {
164162
const name = rlpxProtocol.constructor.name.toLowerCase()
165-
const protocol = this.protocols.find((p: any) => p.name === name)
163+
const protocol = this.protocols.find((p) => p.name === name)
166164
if (protocol) {
167165
return this.bindProtocol(protocol, new RlpxSender(rlpxProtocol))
168166
}

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { EventEmitter } from 'events'
2-
import { Protocol } from '../protocol/protocol'
2+
import { Message, Protocol } from '../protocol/protocol'
33
import { Peer } from '../peer/peer'
44
import { Sender } from './sender'
55
import { Config } from '../../config'
@@ -31,7 +31,7 @@ export class BoundProtocol extends EventEmitter {
3131
private versions: number[]
3232
private timeout: number
3333
private _status: any
34-
private resolvers: Map<string, any>
34+
private resolvers: Map<string | number, any>
3535

3636
/**
3737
* Create bound protocol
@@ -80,9 +80,9 @@ export class BoundProtocol extends EventEmitter {
8080
* @param {Object} message message object
8181
* @emits message
8282
*/
83-
handle(incoming: any) {
83+
handle(incoming: Message) {
8484
const messages = this.protocol.messages
85-
const message = messages.find((m: any) => m.code === incoming.code)
85+
const message = messages.find((m) => m.code === incoming.code)
8686
if (!message) {
8787
return
8888
}
@@ -117,16 +117,16 @@ export class BoundProtocol extends EventEmitter {
117117
* @param name message name
118118
* @param args message arguments
119119
*/
120-
send(name: string, args?: any): any {
120+
send(name: string, args?: any) {
121121
const messages = this.protocol.messages
122-
const message = messages.find((m: any) => m.name === name)
122+
const message = messages.find((m) => m.name === name)
123123
if (message) {
124124
const encoded = this.protocol.encode(message, args)
125125
this.sender.sendMessage(message.code, encoded)
126-
return message
127126
} else {
128127
throw new Error(`Unknown message: ${name}`)
129128
}
129+
return message
130130
}
131131

132132
/**
@@ -143,14 +143,14 @@ export class BoundProtocol extends EventEmitter {
143143
resolve: null,
144144
reject: null,
145145
}
146-
if (this.resolvers.get(message.response)) {
146+
if (this.resolvers.get(message.response!)) {
147147
throw new Error(`Only one active request allowed per message type (${name})`)
148148
}
149-
this.resolvers.set(message.response, resolver)
149+
this.resolvers.set(message.response!, resolver)
150150
return new Promise((resolve, reject) => {
151151
resolver.timeout = setTimeout(() => {
152152
resolver.timeout = null
153-
this.resolvers.delete(message.response)
153+
this.resolvers.delete(message.response!)
154154
reject(new Error(`Request timed out after ${this.timeout}ms`))
155155
}, this.timeout)
156156
resolver.resolve = resolve
@@ -163,13 +163,14 @@ export class BoundProtocol extends EventEmitter {
163163
* corresponding response message.
164164
*/
165165
addMethods() {
166-
const messages = this.protocol.messages.filter((m: any) => m.response)
166+
const messages = this.protocol.messages.filter((m) => m.response)
167167
for (const message of messages) {
168-
const name = message.name as string
168+
const name = message.name
169169
const camel = name[0].toLowerCase() + name.slice(1)
170170
;(this as any)[camel] = async (args: any[]) =>
171171
this.request(name, args).catch((error: Error) => {
172172
this.emit('error', error)
173+
return []
173174
})
174175
}
175176
}

0 commit comments

Comments
 (0)