Skip to content

Commit 1bd8498

Browse files
authored
client: move TxPool to FullEthereumService (#1853)
* move txpool from FullSync to FullEthereumService remove execution from client class * move execution init to service * use pool peer count directly now * nit (dedupe `any` cast)
1 parent 07a6d2e commit 1bd8498

33 files changed

+325
-357
lines changed

packages/client/bin/cli.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Config, DataDirectory } from '../lib/config'
1515
import { Logger, getLogger } from '../lib/logging'
1616
import { startRPCServers, helprpc } from './startRpc'
1717
import type { Chain as IChain, GenesisState } from '@ethereumjs/common/dist/types'
18+
import type { FullEthereumService } from '../lib/service'
1819
const level = require('level')
1920
const yargs = require('yargs/yargs')
2021
const { hideBin } = require('yargs/helpers')
@@ -309,7 +310,9 @@ async function executeBlocks(client: EthereumClient) {
309310
)
310311
process.exit()
311312
}
312-
await client.executeBlocks(first, last, txHashes)
313+
const { execution } = client.services.find((s) => s.name === 'eth') as FullEthereumService
314+
if (!execution) throw new Error('executeBlocks requires execution')
315+
await execution.executeBlocks(first, last, txHashes)
313316
}
314317

315318
/**

packages/client/lib/client.ts

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import { bufferToHex } from 'ethereumjs-util'
21
import { version as packageVersion } from '../package.json'
32
import { MultiaddrLike } from './types'
43
import { Config, SyncMode } from './config'
54
import { FullEthereumService, LightEthereumService } from './service'
65
import { Event } from './types'
7-
import { VMExecution } from './execution'
86
import { Chain } from './blockchain'
97
// eslint-disable-next-line implicit-dependencies/no-implicit
108
import type { LevelUp } from 'levelup'
@@ -57,7 +55,6 @@ export default class EthereumClient {
5755
public config: Config
5856
public chain: Chain
5957
public services: (FullEthereumService | LightEthereumService)[]
60-
public execution: VMExecution | undefined
6158

6259
public opened: boolean
6360
public started: boolean
@@ -70,20 +67,13 @@ export default class EthereumClient {
7067
this.chain = new Chain(options)
7168

7269
if (this.config.syncmode === SyncMode.Full) {
73-
this.execution = new VMExecution({
74-
config: options.config,
75-
stateDB: options.stateDB,
76-
metaDB: options.metaDB,
77-
chain: this.chain,
78-
})
7970
this.services = [
8071
new FullEthereumService({
8172
config: this.config,
8273
chainDB: options.chainDB,
8374
stateDB: options.stateDB,
8475
metaDB: options.metaDB,
8576
chain: this.chain,
86-
execution: this.execution,
8777
}),
8878
]
8979
} else {
@@ -123,7 +113,6 @@ export default class EthereumClient {
123113
this.config.logger.info(`Synchronized blockchain at height=${height}`)
124114
})
125115

126-
await this.execution?.open()
127116
await Promise.all(this.services.map((s) => s.open()))
128117

129118
this.opened = true
@@ -152,7 +141,6 @@ export default class EthereumClient {
152141
return false
153142
}
154143
this.config.events.emit(Event.CLIENT_SHUTDOWN)
155-
await this.execution?.stop()
156144
await Promise.all(this.services.map((s) => s.stop()))
157145
await Promise.all(this.config.servers.map((s) => s.stop()))
158146
this.started = false
@@ -173,62 +161,4 @@ export default class EthereumClient {
173161
server(name: string) {
174162
return this.config.servers.find((s) => s.name === name)
175163
}
176-
177-
/**
178-
* Execute a range of blocks on a copy of the VM
179-
* without changing any chain or client state
180-
*
181-
* Possible input formats:
182-
*
183-
* - Single block, '5'
184-
* - Range of blocks, '5-10'
185-
*
186-
*/
187-
async executeBlocks(first: number, last: number, txHashes: string[]) {
188-
this.config.logger.info('Preparing for block execution (debug mode, no services started)...')
189-
if (!this.execution) throw new Error('executeBlocks requires execution')
190-
const vm = this.execution.vm.copy()
191-
192-
for (let blockNumber = first; blockNumber <= last; blockNumber++) {
193-
const block = await vm.blockchain.getBlock(blockNumber)
194-
const parentBlock = await vm.blockchain.getBlock(block.header.parentHash)
195-
196-
// Set the correct state root
197-
await vm.stateManager.setStateRoot(parentBlock.header.stateRoot)
198-
199-
const td = await vm.blockchain.getTotalDifficulty(block.header.parentHash)
200-
vm._common.setHardforkByBlockNumber(blockNumber, td)
201-
202-
if (txHashes.length === 0) {
203-
const res = await vm.runBlock({ block })
204-
this.config.logger.info(
205-
`Executed block num=${blockNumber} hash=0x${block.hash().toString('hex')} txs=${
206-
block.transactions.length
207-
} gasUsed=${res.gasUsed} `
208-
)
209-
} else {
210-
let count = 0
211-
// Special verbose tx execution mode triggered by BLOCK_NUMBER[*]
212-
// Useful e.g. to trace slow txs
213-
const allTxs = txHashes.length === 1 && txHashes[0] === '*' ? true : false
214-
for (const tx of block.transactions) {
215-
const txHash = bufferToHex(tx.hash())
216-
if (allTxs || txHashes.includes(txHash)) {
217-
const res = await vm.runTx({ block, tx })
218-
this.config.logger.info(
219-
`Executed tx hash=${txHash} gasUsed=${res.gasUsed} from block num=${blockNumber}`
220-
)
221-
count += 1
222-
}
223-
}
224-
if (count === 0) {
225-
if (!allTxs) {
226-
this.config.logger.warn(`Block number ${first} contains no txs with provided hashes`)
227-
} else {
228-
this.config.logger.info(`Block has 0 transactions (no execution)`)
229-
}
230-
}
231-
}
232-
}
233-
}
234164
}

packages/client/lib/config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Common, { Hardfork } from '@ethereumjs/common'
22
import VM from '@ethereumjs/vm'
33
import { genPrivateKey } from '@ethereumjs/devp2p'
4-
import { Address } from 'ethereumjs-util'
4+
import { Address, BN } from 'ethereumjs-util'
55
import { Multiaddr } from 'multiaddr'
66
import { Logger, getLogger } from './logging'
77
import { Libp2pServer, RlpxServer } from './net/server'
@@ -253,6 +253,8 @@ export class Config {
253253

254254
public synchronized: boolean
255255
public lastSyncDate: number
256+
/** Best known block height */
257+
public syncTargetHeight?: BN
256258

257259
public readonly chainCommon: Common
258260
public readonly execCommon: Common

packages/client/lib/execution/vmexecution.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
} from '@ethereumjs/blockchain/dist/db/helpers'
77
import { ConsensusType, Hardfork } from '@ethereumjs/common'
88
import VM from '@ethereumjs/vm'
9+
import { bufferToHex } from 'ethereumjs-util'
910
import { DefaultStateManager } from '@ethereumjs/vm/dist/state'
1011
import { SecureTrie as Trie } from 'merkle-patricia-tree'
1112
import { short } from '../util'
@@ -292,4 +293,60 @@ export class VMExecution extends Execution {
292293
await super.stop()
293294
return true
294295
}
296+
297+
/**
298+
* Execute a range of blocks on a copy of the VM
299+
* without changing any chain or client state
300+
*
301+
* Possible input formats:
302+
*
303+
* - Single block, '5'
304+
* - Range of blocks, '5-10'
305+
*/
306+
async executeBlocks(first: number, last: number, txHashes: string[]) {
307+
this.config.logger.info('Preparing for block execution (debug mode, no services started)...')
308+
const vm = this.vm.copy()
309+
310+
for (let blockNumber = first; blockNumber <= last; blockNumber++) {
311+
const block = await vm.blockchain.getBlock(blockNumber)
312+
const parentBlock = await vm.blockchain.getBlock(block.header.parentHash)
313+
314+
// Set the correct state root
315+
await vm.stateManager.setStateRoot(parentBlock.header.stateRoot)
316+
317+
const td = await vm.blockchain.getTotalDifficulty(block.header.parentHash)
318+
vm._common.setHardforkByBlockNumber(blockNumber, td)
319+
320+
if (txHashes.length === 0) {
321+
const res = await vm.runBlock({ block })
322+
this.config.logger.info(
323+
`Executed block num=${blockNumber} hash=0x${block.hash().toString('hex')} txs=${
324+
block.transactions.length
325+
} gasUsed=${res.gasUsed} `
326+
)
327+
} else {
328+
let count = 0
329+
// Special verbose tx execution mode triggered by BLOCK_NUMBER[*]
330+
// Useful e.g. to trace slow txs
331+
const allTxs = txHashes.length === 1 && txHashes[0] === '*' ? true : false
332+
for (const tx of block.transactions) {
333+
const txHash = bufferToHex(tx.hash())
334+
if (allTxs || txHashes.includes(txHash)) {
335+
const res = await vm.runTx({ block, tx })
336+
this.config.logger.info(
337+
`Executed tx hash=${txHash} gasUsed=${res.gasUsed} from block num=${blockNumber}`
338+
)
339+
count += 1
340+
}
341+
}
342+
if (count === 0) {
343+
if (!allTxs) {
344+
this.config.logger.warn(`Block number ${first} contains no txs with provided hashes`)
345+
} else {
346+
this.config.logger.info(`Block has 0 transactions (no execution)`)
347+
}
348+
}
349+
}
350+
}
351+
}
295352
}

packages/client/lib/miner/miner.ts

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { BN } from 'ethereumjs-util'
44
import { ConsensusType, Hardfork } from '@ethereumjs/common'
55
import { Event } from '../types'
66
import { Config } from '../config'
7-
import { FullSynchronizer } from '../sync'
7+
import { FullEthereumService } from '../service'
88
import { VMExecution } from '../execution'
99

1010
const level = require('level-mem')
@@ -13,9 +13,8 @@ export interface MinerOptions {
1313
/* Config */
1414
config: Config
1515

16-
/* FullSynchronizer */
17-
synchronizer: FullSynchronizer
18-
execution: VMExecution
16+
/* FullEthereumService */
17+
service: FullEthereumService
1918
}
2019

2120
/**
@@ -31,7 +30,7 @@ export class Miner {
3130
private _nextAssemblyTimeoutId: NodeJS.Timeout | undefined /* global NodeJS */
3231
private _boundChainUpdatedHandler: (() => void) | undefined
3332
private config: Config
34-
private synchronizer: FullSynchronizer
33+
private service: FullEthereumService
3534
private execution: VMExecution
3635
private assembling: boolean
3736
private period: number
@@ -46,8 +45,8 @@ export class Miner {
4645
*/
4746
constructor(options: MinerOptions) {
4847
this.config = options.config
49-
this.synchronizer = options.synchronizer
50-
this.execution = options.execution
48+
this.service = options.service
49+
this.execution = this.service.execution
5150
this.running = false
5251
this.assembling = false
5352
this.period = (this.config.chainCommon.consensusConfig().period ?? this.DEFAULT_PERIOD) * 1000 // defined in ms for setTimeout use
@@ -61,7 +60,7 @@ export class Miner {
6160
* Convenience alias to return the latest block in the blockchain
6261
*/
6362
private latestBlockHeader(): BlockHeader {
64-
return (this.synchronizer as any).chain.headers.latest
63+
return this.service.chain.headers.latest!
6564
}
6665

6766
/**
@@ -86,7 +85,7 @@ export class Miner {
8685
// EIP-225 spec: If the signer is out-of-turn,
8786
// delay signing by rand(SIGNER_COUNT * 500ms)
8887
const [signerAddress] = this.config.accounts[0]
89-
const { blockchain } = (this.synchronizer as any).chain
88+
const { blockchain } = this.service.chain
9089
const inTurn = await blockchain.cliqueSignerInTurn(signerAddress)
9190
if (!inTurn) {
9291
const signerCount = blockchain.cliqueActiveSigners().length
@@ -175,7 +174,7 @@ export class Miner {
175174
_boundSetInterruptHandler = setInterrupt.bind(this)
176175
this.config.events.once(Event.CHAIN_UPDATED, _boundSetInterruptHandler)
177176

178-
const parentBlock = (this.synchronizer as any).chain.blocks.latest
177+
const parentBlock = this.service.chain.blocks.latest!
179178
const number = parentBlock.header.number.addn(1)
180179
let { gasLimit } = parentBlock.header
181180

@@ -186,7 +185,7 @@ export class Miner {
186185
{ number },
187186
{ common: this.config.chainCommon, cliqueSigner }
188187
)
189-
if ((this.synchronizer as any).chain.blockchain.cliqueCheckRecentlySigned(header)) {
188+
if ((this.service.chain.blockchain as any).cliqueCheckRecentlySigned(header)) {
190189
this.config.logger.info(`Miner: We have too recently signed, waiting for next block`)
191190
this.assembling = false
192191
return
@@ -258,10 +257,7 @@ export class Miner {
258257
},
259258
})
260259

261-
const txs = await this.synchronizer.txPool.txsByPriceAndNonce(
262-
vmCopy.stateManager,
263-
baseFeePerGas
264-
)
260+
const txs = await this.service.txPool.txsByPriceAndNonce(baseFeePerGas)
265261
this.config.logger.info(
266262
`Miner: Assembling block from ${txs.length} eligible txs ${
267263
baseFeePerGas ? `(baseFee: ${baseFeePerGas})` : ''
@@ -304,9 +300,9 @@ export class Miner {
304300
this.assembling = false
305301
if (interrupt) return
306302
// Put block in blockchain
307-
await this.synchronizer.handleNewBlock(block)
303+
await this.service.synchronizer.handleNewBlock(block)
308304
// Remove included txs from TxPool
309-
this.synchronizer.txPool.removeNewBlockTxs([block])
305+
this.service.txPool.removeNewBlockTxs([block])
310306
this.config.events.removeListener(Event.CHAIN_UPDATED, _boundSetInterruptHandler)
311307
}
312308

packages/client/lib/miner/pendingBlock.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { TxReceipt } from '@ethereumjs/vm/dist/types'
44
import type { BlockBuilder } from '@ethereumjs/vm/dist/buildBlock'
55
import type { Block, HeaderData } from '@ethereumjs/block'
66
import type { TypedTransaction } from '@ethereumjs/tx'
7-
import type { TxPool } from '../sync/txpool'
7+
import type { TxPool } from '../service/txpool'
88
import type { Config } from '../config'
99

1010
interface PendingBlockOpts {
@@ -67,7 +67,7 @@ export class PendingBlock {
6767
this.pendingPayloads.push([payloadId, builder])
6868

6969
// Add current txs in pool
70-
const txs = await this.txPool.txsByPriceAndNonce(vm.stateManager, baseFeePerGas)
70+
const txs = await this.txPool.txsByPriceAndNonce(baseFeePerGas)
7171
this.config.logger.info(
7272
`Pending: Assembling block from ${txs.length} eligible txs (baseFee: ${baseFeePerGas})`
7373
)
@@ -123,10 +123,7 @@ export class PendingBlock {
123123

124124
// Add new txs that the pool received
125125
const txs = (
126-
await this.txPool.txsByPriceAndNonce(
127-
(builder as any).vm.stateManager,
128-
(builder as any).headerData.baseFeePerGas
129-
)
126+
await this.txPool.txsByPriceAndNonce((builder as any).headerData.baseFeePerGas)
130127
).filter(
131128
(tx) =>
132129
!(builder as any).transactions.some((t: TypedTransaction) => t.hash().equals(tx.hash()))

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export class EthProtocol extends Protocol {
9999
decode: ([txs]: [Buffer[]]) => {
100100
// TODO: add proper Common instance (problem: service not accesible)
101101
//const common = this.config.chainCommon.copy()
102-
//common.setHardforkByBlockNumber(this.service.synchronizer.syncTargetHeight, this.chain.headers.td)
102+
//common.setHardforkByBlockNumber(this.config.syncTargetHeight, this.chain.headers.td)
103103
return txs.map((txData) => TransactionFactory.fromBlockBodyData(txData))
104104
},
105105
},
@@ -210,7 +210,7 @@ export class EthProtocol extends Protocol {
210210
new BN(reqId),
211211
// TODO: add proper Common instance (problem: service not accesible)
212212
//const common = this.config.chainCommon.copy()
213-
//common.setHardforkByBlockNumber(this.service.synchronizer.syncTargetHeight)
213+
//common.setHardforkByBlockNumber(this.config.syncTargetHeight)
214214
txs.map((txData) => TransactionFactory.fromBlockBodyData(txData)),
215215
],
216216
},

0 commit comments

Comments
 (0)