diff --git a/.github/ISSUE_TEMPLATE/package--ethereumjs-era.md b/.github/ISSUE_TEMPLATE/package--ethereumjs-era.md new file mode 100644 index 00000000000..920f1f7b80f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/package--ethereumjs-era.md @@ -0,0 +1,7 @@ +--- +name: 'Package: @ethereumjs/era' +about: Create issue for @ethereumjs/era package +title: '' +labels: 'package: era' +assignees: '' +--- diff --git a/config/cspell-md.json b/config/cspell-md.json index 816a794cf06..f57f1d73dc3 100644 --- a/config/cspell-md.json +++ b/config/cspell-md.json @@ -329,6 +329,7 @@ "Unsnappy", "unsnappy", "ethportal", - "bytevector" + "bytevector", + "eraSync" ] } diff --git a/config/cspell-ts.json b/config/cspell-ts.json index f77135582ab..c0cebf3dfba 100644 --- a/config/cspell-ts.json +++ b/config/cspell-ts.json @@ -634,6 +634,7 @@ "unsnappy", "ethportal", "bytevector", - "blobschedule" + "blobschedule", + "eraSync" ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f41860f91ad..d60ed860321 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17420,6 +17420,7 @@ "@ethereumjs/blockchain": "8.0.0-alpha.1", "@ethereumjs/common": "5.0.0-alpha.1", "@ethereumjs/devp2p": "7.0.0-alpha.1", + "@ethereumjs/era": "1.0.0-alpha.1", "@ethereumjs/ethash": "4.0.0-alpha.1", "@ethereumjs/evm": "4.0.0-alpha.1", "@ethereumjs/genesis": "0.3.0-alpha.1", diff --git a/packages/client/bin/cli.ts b/packages/client/bin/cli.ts index ad8412e770e..7bf7cae787b 100755 --- a/packages/client/bin/cli.ts +++ b/packages/client/bin/cli.ts @@ -11,6 +11,8 @@ import { Level } from 'level' import { EthereumClient } from '../src/client.js' import { DataDirectory } from '../src/config.js' import { LevelDB } from '../src/execution/level.js' +import { eraSync } from '../src/sync/erasync.js' +import { type ClientOpts } from '../src/types.js' import { generateVKTStateRoot } from '../src/util/vkt.js' import { helpRPC, startRPCServers } from './startRPC.js' @@ -19,7 +21,6 @@ import { generateClientConfig, getArgs } from './utils.js' import type { Config } from '../src/config.js' import type { Logger } from '../src/logging.js' import type { FullEthereumService } from '../src/service/index.js' -import type { ClientOpts } from '../src/types.js' import type { RPCArgs } from './startRPC.js' import type { Block, BlockBytes } from '@ethereumjs/block' import type { ConsensusDict } from '@ethereumjs/blockchain' @@ -219,7 +220,9 @@ async function startClient( ...dbs, }) await client.open() - + if (args.loadBlocksFromEra1 !== undefined) { + await eraSync(client, config, { loadBlocksFromEra1: args.loadBlocksFromEra1 }) + } if (args.loadBlocksFromRlp !== undefined) { // Specifically for Hive simulator, preload blocks provided in RLP format const blocks: Block[] = [] diff --git a/packages/client/bin/utils.ts b/packages/client/bin/utils.ts index 8825b3ac03d..bfc2163f3f5 100644 --- a/packages/client/bin/utils.ts +++ b/packages/client/bin/utils.ts @@ -422,6 +422,11 @@ export function getArgs(): ClientOpts { string: true, array: true, }) + .option('loadBlocksFromEra1', { + describe: 'path to a directory of era1 files', + string: true, + optional: true, + }) .option('pruneEngineCache', { describe: 'Enable/Disable pruning engine block cache (disable for testing against hive etc)', diff --git a/packages/client/package.json b/packages/client/package.json index 902fda15187..caeec270d45 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -54,6 +54,7 @@ "@ethereumjs/devp2p": "7.0.0-alpha.1", "@ethereumjs/ethash": "4.0.0-alpha.1", "@ethereumjs/evm": "4.0.0-alpha.1", + "@ethereumjs/era": "1.0.0-alpha.1", "@ethereumjs/genesis": "0.3.0-alpha.1", "@ethereumjs/mpt": "7.0.0-alpha.1", "@ethereumjs/rlp": "6.0.0-alpha.1", diff --git a/packages/client/src/sync/erasync.ts b/packages/client/src/sync/erasync.ts new file mode 100644 index 00000000000..4433bc93292 --- /dev/null +++ b/packages/client/src/sync/erasync.ts @@ -0,0 +1,36 @@ +import { blockFromTuple, parseBlockTuple, readBinaryFile, readERA1 } from '@ethereumjs/era' +import { readdirSync } from 'fs' + +import { DBKey } from '../util/metaDBManager.js' + +import type { Config, EthereumClient } from '../index.js' +// import type { Block } from '@ethereumjs/block' + +export async function eraSync( + client: EthereumClient, + config: Config, + args: { loadBlocksFromEra1: string }, +) { + await client.chain.open() + const service = client.service + await service.execution.open() + const eraDir = readdirSync(args.loadBlocksFromEra1) + .filter((file) => file.endsWith('.era1')) + .sort() + for (const file of eraDir) { + config.logger.info(`Loading era1 file ${file}`) + const era1File = readBinaryFile(args.loadBlocksFromEra1 + '/' + file) + const blockTuples = await readERA1(era1File) + for await (const tuple of blockTuples) { + const { header, body, receipts } = await parseBlockTuple(tuple) + const block = blockFromTuple({ header, body }) + await client.chain.blockchain.putBlock(block) + if (config.saveReceipts && service.execution.receiptsManager) { + await service.execution.receiptsManager?.put(DBKey.Receipts, block.hash(), receipts) + void service.execution.receiptsManager['updateIndex'](0, 0, block) + } + } + await client.chain.update(false) + await service.execution.run() + } +} diff --git a/packages/client/src/sync/index.ts b/packages/client/src/sync/index.ts index a998571ae03..58503f8f0aa 100644 --- a/packages/client/src/sync/index.ts +++ b/packages/client/src/sync/index.ts @@ -4,6 +4,7 @@ // need this weird re-export for vitest to be able to mock reverseblockfetcher in test/sync/beaconsync.spec.ts export * from '../service/skeleton.js' export * from './beaconsync.js' +export * from './erasync.js' export * from './fullsync.js' export * from './snapsync.js' export * from './sync.js' diff --git a/packages/client/src/types.ts b/packages/client/src/types.ts index ae93351dcdf..0404f870b37 100644 --- a/packages/client/src/types.ts +++ b/packages/client/src/types.ts @@ -138,6 +138,7 @@ export interface ClientOpts { vmProfileBlocks?: boolean vmProfileTxs?: boolean loadBlocksFromRlp?: string[] + loadBlocksFromEra1?: string pruneEngineCache?: boolean savePreimages?: boolean verkleGenesisStateRoot?: Uint8Array diff --git a/packages/client/tsconfig.prod.esm.json b/packages/client/tsconfig.prod.esm.json index a8c3f98a158..f6b01dfd2bd 100644 --- a/packages/client/tsconfig.prod.esm.json +++ b/packages/client/tsconfig.prod.esm.json @@ -12,6 +12,7 @@ { "path": "../blockchain/tsconfig.prod.esm.json" }, { "path": "../common/tsconfig.prod.esm.json" }, { "path": "../devp2p/tsconfig.prod.esm.json" }, + { "path": "../era/tsconfig.prod.esm.json" }, { "path": "../rlp/tsconfig.prod.esm.json" }, { "path": "../mpt/tsconfig.prod.esm.json" }, { "path": "../tx/tsconfig.prod.esm.json" },