Open acolytec3 opened 1 week ago
This script is a working proof of concept.
const { readFileSync } = await import('fs')
const { createCommonFromGethGenesis, parseGethGenesis } = await import('@ethereumjs/common')
const { createInlineClient } = await import('./test/sim/simutils.ts')
const { Config } = await import('./src/config.ts')
const { getLogger } = await import('./src/logging.ts')
const { startRPCServers } = await import('./bin/startRPC.ts')
const genesisFile = JSON.parse(readFileSync('./genesis.json', 'utf-8'))
const chainName = 'pectra'
const common = createCommonFromGethGenesis(genesisFile, {
chain: chainName,
})
const config = new Config({ common, logger: getLogger({ logLevel: 'debug' }), saveReceipts: true, enableSnapSync: true })
const client = await createInlineClient(config, common, {}, '', true)
const servers = startRPCServers(client, {
rpc: true,
rpcAddr: '0.0.0.0',
rpcPort: 8545,
ws: false,
wsPort: 0,
wsAddr: '0.0.0.0',
rpcEngine: true,
rpcEngineAddr: '0.0.0.0',
rpcEnginePort: 8551,
wsEngineAddr: '0.0.0.0',
wsEnginePort: 8552,
rpcDebug: 'eth',
rpcDebugVerbose: 'false',
helpRPC: false,
jwtSecret: '',
rpcEngineAuth: false,
rpcCors: '',
})
To see in action:
1) Copy the above snippet into script.ts
2) Run npx tsx
in the same directory where script.ts
is
3) Type .load script.ts
(this runs the script as though you were typing it in directly)
Behold your inline client.
[Uploading Screencast from 10-29-2024 04:01:37 PM.webm…]()
And if you want to create an actual custom javascript console for our client, here's another variant.
import repl from 'repl'
const setupClient = async () => {
const { readFileSync } = await import('fs')
const { createCommonFromGethGenesis, parseGethGenesis } = await import('@ethereumjs/common')
const { createInlineClient } = await import('./test/sim/simutils.ts')
const { Config } = await import('./src/config.ts')
const { getLogger } = await import('./src/logging.ts')
const { startRPCServers } = await import('./bin/startRPC.ts')
const genesisFile = JSON.parse(readFileSync('./genesis.json', 'utf-8'))
const chainName = 'pectra'
const common = createCommonFromGethGenesis(genesisFile, {
chain: chainName,
})
const config = new Config({
common,
logger: getLogger({ logLevel: 'info' }),
saveReceipts: true,
enableSnapSync: true,
})
const client = await createInlineClient(config, common, {}, '', true)
const servers = startRPCServers(client, {
rpc: true,
rpcAddr: '0.0.0.0',
rpcPort: 8545,
ws: false,
wsPort: 0,
wsAddr: '0.0.0.0',
rpcEngine: true,
rpcEngineAddr: '0.0.0.0',
rpcEnginePort: 8551,
wsEngineAddr: '0.0.0.0',
wsEnginePort: 8552,
rpcDebug: 'eth',
rpcDebugVerbose: 'false',
helpRPC: false,
jwtSecret: '',
rpcEngineAuth: false,
rpcCors: '',
})
return client
}
const client = await setupClient()
const replServer = repl.start({
prompt: 'EthJS > ',
ignoreUndefined: true,
})
replServer.context.client = client
console.log('Custom console started. Type .help for available commands.')
Just run npx tsx script.ts
and away we go.
Interesting. 👀
Thanks for the write up, super helpful! 🙂🙏
(guess a lot of API work still to be done though…)
One thing that might make troubleshooting the client on devnets and the like easier would be to be able to run it in a REPL so we can have direct access to the client object as its running, similarly to how geth has their javascript console.
We already have a createInlineClient function available to us that accepts the entire configuration object available to the client so it shouldn't be too hard to expand this a bit to allow a user to pass in a geth genesis.json and start a client entirely within a REPL.
The piece that isn't built yet would be hooking it up to the RPC. We have a startRPCServers function that we could pass the instantiated "inline" client to and then just grab a reference to it in the REPL so we can be sure to not lose it.
This could also be an interesting "community showcase" idea.