Skip to content

Commit 91a2c93

Browse files
Merge branch 'master' into client-rpc-payload-limit
2 parents 5e47e75 + 2908c04 commit 91a2c93

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+552
-377
lines changed

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
20

packages/block/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,39 @@ void main()
240240

241241
Starting with v10 this library supports requests to the consensus layer which have been introduced with [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685) (`Hardfork.Prague` or higher). See the `@ethereumjs/util` [Request](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/util#module-request) README section for an overview of current request types.
242242

243+
```ts
244+
// ./examples/clrequests.ts
245+
246+
import { Common, Hardfork, Mainnet } from '@ethereumjs/common'
247+
import { createCLRequest, CLRequestType, hexToBytes, bytesToHex } from '@ethereumjs/util'
248+
import { sha256 } from 'ethereum-cryptography/sha256.js'
249+
250+
import { createBlock, genRequestsRoot } from '../src'
251+
252+
// Enable EIP-7685 to support CLRequests
253+
const common = new Common({ chain: Mainnet, hardfork: Hardfork.Cancun, eips: [7685] })
254+
255+
// Create the three CLRequest types (Deposit, Withdrawal, Consolidation)
256+
const depositData = hexToBytes('0x00...') // Deposit request data
257+
const depositRequest = createCLRequest(depositData)
258+
259+
const withdrawalData = hexToBytes('0x01...') // Withdrawal request data
260+
const withdrawalRequest = createCLRequest(withdrawalData)
261+
262+
const consolidationData = hexToBytes('0x02...') // Consolidation request data
263+
const consolidationRequest = createCLRequest(consolidationData)
264+
265+
// CLRequests must be sorted by type (Deposit=0, Withdrawal=1, Consolidation=2)
266+
const requests = [depositRequest, withdrawalRequest, consolidationRequest]
267+
268+
// Generate the requestsHash
269+
const requestsHash = genRequestsRoot(requests, sha256)
270+
271+
// Create a block with the CLRequests hash
272+
const block = createBlock({ header: { requestsHash } }, { common })
273+
console.log(`Created block with CLRequests hash: 0x${bytesToHex(block.hash())}`)
274+
```
275+
243276
### Consensus Types
244277

245278
### Proof-of-Stake

packages/block/examples/clrequests.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Common, Hardfork, Mainnet } from '@ethereumjs/common'
2+
import { CLRequestType, bytesToHex, createCLRequest, hexToBytes } from '@ethereumjs/util'
3+
import { sha256 } from 'ethereum-cryptography/sha256.js'
4+
5+
import { createBlock, genRequestsRoot } from '../src'
6+
7+
// Enable EIP-7685 to support CLRequests
8+
const common = new Common({ chain: Mainnet, hardfork: Hardfork.Cancun, eips: [7685] })
9+
10+
// Create examples of the three CLRequest types
11+
const createExampleRequests = () => {
12+
// Create a deposit request (type 0)
13+
const depositData = hexToBytes(
14+
'0x00ac842878bb70009552a4cfcad801d6e659c50bd50d7d03306790cb455ce7363c5b6972f0159d170f625a99b2064dbefc010000000000000000000000818ccb1c4eda80270b04d6df822b1e72dd83c3030040597307000000a747f75c72d0cf0d2b52504c7385b516f0523e2f0842416399f42b4aee5c6384a5674f6426b1cc3d0827886fa9b909e616f5c9f61f986013ed2b9bf37071cbae951136265b549f44e3c8e26233c0433e9124b7fd0dc86e82f9fedfc0a179d7690000000000000000',
15+
)
16+
const depositRequest = createCLRequest(depositData)
17+
18+
// Create a withdrawal request (type 1)
19+
const withdrawalData = hexToBytes(
20+
'0x01000000000000000000000000000000000000000001000000000000000000000de0b6b3a7640000',
21+
)
22+
const withdrawalRequest = createCLRequest(withdrawalData)
23+
24+
// Create a consolidation request (type 2)
25+
const consolidationData = hexToBytes('0x020000000100000000000000000000000000000000000001')
26+
const consolidationRequest = createCLRequest(consolidationData)
27+
28+
// CLRequests must be sorted by type (Deposit=0, Withdrawal=1, Consolidation=2)
29+
return [depositRequest, withdrawalRequest, consolidationRequest]
30+
}
31+
32+
// Generate a block with CLRequests
33+
function createBlockWithCLRequests() {
34+
const requests = createExampleRequests()
35+
console.log(`Created ${requests.length} CLRequests:`)
36+
37+
for (const req of requests) {
38+
console.log(
39+
`- Type: ${req.type} (${Object.keys(CLRequestType).find(
40+
(k) => CLRequestType[k as keyof typeof CLRequestType] === req.type,
41+
)})`,
42+
)
43+
}
44+
45+
// Generate the requestsHash by hashing all the CLRequests
46+
const requestsHash = genRequestsRoot(requests, sha256)
47+
console.log(`Generated requestsHash: 0x${bytesToHex(requestsHash)}`)
48+
49+
// Create a block with the CLRequests hash
50+
const block = createBlock({ header: { requestsHash } }, { common })
51+
console.log(`Created block hash: 0x${bytesToHex(block.hash())}`)
52+
53+
return block
54+
}
55+
56+
// Execute
57+
createBlockWithCLRequests()
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import { Common, Hardfork, Mainnet } from '@ethereumjs/common'
2+
import { CLRequestType, createCLRequest, equalsBytes, hexToBytes } from '@ethereumjs/util'
3+
import { sha256 } from 'ethereum-cryptography/sha256.js'
4+
import { assert, describe, it } from 'vitest'
5+
6+
import { createBlock, genRequestsRoot } from '../src/index.ts'
7+
8+
import type { CLRequest } from '@ethereumjs/util'
9+
10+
describe('[Block]: CLRequests tests', () => {
11+
// Common with EIP-7685 enabled (CLRequests)
12+
const common = new Common({ chain: Mainnet, hardfork: Hardfork.Cancun, eips: [7685] })
13+
14+
function createDepositRequest(): CLRequest<CLRequestType> {
15+
// Example deposit data
16+
const sampleDepositRequest = hexToBytes(
17+
'0x00ac842878bb70009552a4cfcad801d6e659c50bd50d7d03306790cb455ce7363c5b6972f0159d170f625a99b2064dbefc010000000000000000000000818ccb1c4eda80270b04d6df822b1e72dd83c3030040597307000000a747f75c72d0cf0d2b52504c7385b516f0523e2f0842416399f42b4aee5c6384a5674f6426b1cc3d0827886fa9b909e616f5c9f61f986013ed2b9bf37071cbae951136265b549f44e3c8e26233c0433e9124b7fd0dc86e82f9fedfc0a179d7690000000000000000',
18+
)
19+
return createCLRequest(sampleDepositRequest)
20+
}
21+
22+
function createWithdrawalRequest(): CLRequest<CLRequestType> {
23+
// Type 1 (Withdrawal) + example data
24+
const withdrawalData = hexToBytes(
25+
'0x01000000000000000000000000000000000000000001000000000000000000000de0b6b3a7640000',
26+
)
27+
return createCLRequest(withdrawalData)
28+
}
29+
30+
function createConsolidationRequest(): CLRequest<CLRequestType> {
31+
// Type 2 (Consolidation) + example data
32+
const consolidationData = hexToBytes('0x020000000100000000000000000000000000000000000001')
33+
return createCLRequest(consolidationData)
34+
}
35+
36+
it('should create a block with deposit request', () => {
37+
const depositRequest = createDepositRequest()
38+
assert.equal(depositRequest.type, CLRequestType.Deposit, 'should be a deposit request')
39+
40+
const requestsHash = genRequestsRoot([depositRequest], sha256)
41+
const block = createBlock(
42+
{
43+
header: { requestsHash },
44+
},
45+
{ common },
46+
)
47+
48+
assert.isDefined(block.header.requestsHash, 'block should have requestsHash')
49+
assert.isTrue(
50+
equalsBytes(block.header.requestsHash!, requestsHash),
51+
'requestsHash should match the expected value',
52+
)
53+
})
54+
55+
it('should create a block with withdrawal request', () => {
56+
const withdrawalRequest = createWithdrawalRequest()
57+
assert.equal(withdrawalRequest.type, CLRequestType.Withdrawal, 'should be a withdrawal request')
58+
59+
const requestsHash = genRequestsRoot([withdrawalRequest], sha256)
60+
const block = createBlock(
61+
{
62+
header: { requestsHash },
63+
},
64+
{ common },
65+
)
66+
67+
assert.isDefined(block.header.requestsHash, 'block should have requestsHash')
68+
assert.isTrue(
69+
equalsBytes(block.header.requestsHash!, requestsHash),
70+
'requestsHash should match the expected value',
71+
)
72+
})
73+
74+
it('should create a block with consolidation request', () => {
75+
const consolidationRequest = createConsolidationRequest()
76+
assert.equal(
77+
consolidationRequest.type,
78+
CLRequestType.Consolidation,
79+
'should be a consolidation request',
80+
)
81+
82+
const requestsHash = genRequestsRoot([consolidationRequest], sha256)
83+
const block = createBlock(
84+
{
85+
header: { requestsHash },
86+
},
87+
{ common },
88+
)
89+
90+
assert.isDefined(block.header.requestsHash, 'block should have requestsHash')
91+
assert.isTrue(
92+
equalsBytes(block.header.requestsHash!, requestsHash),
93+
'requestsHash should match the expected value',
94+
)
95+
})
96+
97+
it('should create a block with multiple CLRequests', () => {
98+
const depositRequest = createDepositRequest()
99+
const withdrawalRequest = createWithdrawalRequest()
100+
const consolidationRequest = createConsolidationRequest()
101+
102+
// Requests should be sorted by type
103+
const requests = [depositRequest, withdrawalRequest, consolidationRequest]
104+
const requestsHash = genRequestsRoot(requests, sha256)
105+
106+
const block = createBlock(
107+
{
108+
header: { requestsHash },
109+
},
110+
{ common },
111+
)
112+
113+
assert.isDefined(block.header.requestsHash, 'block should have requestsHash')
114+
assert.isTrue(
115+
equalsBytes(block.header.requestsHash!, requestsHash),
116+
'requestsHash should match the expected value',
117+
)
118+
})
119+
120+
it('should validate the requests are sorted by type', () => {
121+
const depositRequest = createDepositRequest()
122+
const withdrawalRequest = createWithdrawalRequest()
123+
124+
// Requests in wrong order should throw
125+
const requests = [withdrawalRequest, depositRequest]
126+
127+
assert.throws(
128+
() => genRequestsRoot(requests, sha256),
129+
'requests are not sorted in ascending order',
130+
'should throw when requests are not sorted by type',
131+
)
132+
})
133+
})

packages/client/src/net/peerpool.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export class PeerPool {
213213
* @emits {@link Event.POOL_PEER_ADDED}
214214
*/
215215
add(peer?: Peer) {
216-
if (peer && peer.id && !this.pool.get(peer.id)) {
216+
if (peer?.id !== undefined && !this.pool.get(peer.id)) {
217217
this.pool.set(peer.id, peer)
218218
peer.pooled = true
219219
this.config.events.emit(Event.POOL_PEER_ADDED, peer)

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,10 @@ export class Admin {
9595
name: peer.rlpxPeer?.['_hello']?.clientId ?? null,
9696
protocols: {
9797
eth: {
98-
head: peer.eth?.updatedBestHeader
99-
? bytesToHex(peer.eth.updatedBestHeader?.hash())
100-
: bytesToHex(peer.eth?.status.bestHash),
98+
head:
99+
peer.eth?.updatedBestHeader !== undefined
100+
? bytesToHex(peer.eth.updatedBestHeader.hash())
101+
: bytesToHex(peer.eth?.status.bestHash ?? new Uint8Array()),
101102
difficulty: peer.eth?.status.td.toString(10),
102103
version: peer.eth?.['versions'].slice(-1)[0] ?? null,
103104
},

packages/client/src/sync/fetcher/accountfetcher.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,10 @@ export class AccountFetcher extends Fetcher<JobTask, AccountData[], AccountData>
337337
const { task, partialResult } = job
338338
const { first } = task
339339
// Snap protocol will automatically pad it with 32 bytes left, so we don't need to worry
340-
const origin = partialResult
341-
? bigIntToBytes(bytesToBigInt(partialResult[partialResult.length - 1].hash) + BIGINT_1)
342-
: bigIntToBytes(first)
340+
const origin =
341+
partialResult !== undefined
342+
? bigIntToBytes(bytesToBigInt(partialResult[partialResult.length - 1].hash) + BIGINT_1)
343+
: bigIntToBytes(first)
343344
return setLengthLeft(origin, 32)
344345
}
345346

@@ -470,9 +471,12 @@ export class AccountFetcher extends Fetcher<JobTask, AccountData[], AccountData>
470471
const fullResult = (job.partialResult ?? []).concat(result)
471472

472473
// update highest known hash
473-
const highestReceivedhash = result.at(-1)?.hash as Uint8Array
474+
const highestReceivedhash = result.at(-1)?.hash
474475
if (this.highestKnownHash) {
475-
if (compareBytes(highestReceivedhash, this.highestKnownHash) > 0) {
476+
if (
477+
highestReceivedhash !== undefined &&
478+
compareBytes(highestReceivedhash, this.highestKnownHash) > 0
479+
) {
476480
this.highestKnownHash = highestReceivedhash
477481
}
478482
} else {

packages/client/test/sync/fetcher/accountfetcher.spec.ts

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -188,20 +188,19 @@ describe('[AccountFetcher]', async () => {
188188
address: 'random',
189189
latest: vi.fn(),
190190
}
191-
const partialResult: any = [
192-
[
193-
{
194-
hash: new Uint8Array(0),
195-
body: [new Uint8Array(0), new Uint8Array(0), new Uint8Array(0), new Uint8Array(0)],
196-
},
197-
{
198-
hash: new Uint8Array(0),
199-
body: [new Uint8Array(0), new Uint8Array(0), new Uint8Array(0), new Uint8Array(0)],
200-
},
201-
],
191+
const partialResult = [
192+
{
193+
hash: new Uint8Array(0),
194+
body: [new Uint8Array(0), new Uint8Array(0), new Uint8Array(0), new Uint8Array(0)],
195+
},
196+
{
197+
hash: new Uint8Array(0),
198+
body: [new Uint8Array(0), new Uint8Array(0), new Uint8Array(0), new Uint8Array(0)],
199+
},
202200
]
203201
const job = { peer, partialResult, task }
204-
const result = (await fetcher.request(job as any)) as any
202+
const result = await fetcher.request(job as any)
203+
assert.isDefined(result)
205204
assert.equal(
206205
JSON.stringify(result[0]),
207206
JSON.stringify({ skipped: true }),
@@ -219,17 +218,15 @@ describe('[AccountFetcher]', async () => {
219218
first: BigInt(1),
220219
count: BigInt(3),
221220
})
222-
const partialResult: any = [
223-
[
224-
{
225-
hash: new Uint8Array(0),
226-
body: [new Uint8Array(0), new Uint8Array(0), new Uint8Array(0), new Uint8Array(0)],
227-
},
228-
{
229-
hash: new Uint8Array(0),
230-
body: [new Uint8Array(0), new Uint8Array(0), new Uint8Array(0), new Uint8Array(0)],
231-
},
232-
],
221+
const partialResult = [
222+
{
223+
hash: new Uint8Array(0),
224+
body: [new Uint8Array(0), new Uint8Array(0), new Uint8Array(0), new Uint8Array(0)],
225+
},
226+
{
227+
hash: new Uint8Array(0),
228+
body: [new Uint8Array(0), new Uint8Array(0), new Uint8Array(0), new Uint8Array(0)],
229+
},
233230
]
234231

235232
const task = { count: 3, first: BigInt(1) }

packages/client/test/sync/fetcher/storagefetcher.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,10 @@ describe('[StorageFetcher]', async () => {
255255
pool,
256256
root: utf8ToBytes(''),
257257
} as StorageFetcherOptions)
258-
const partialResult: any = [
258+
const partialResult = [
259259
[
260-
[{ hash: utf8ToBytes(''), body: utf8ToBytes('') }],
261-
[{ hash: utf8ToBytes(''), body: utf8ToBytes('') }],
260+
{ hash: utf8ToBytes(''), body: utf8ToBytes('') },
261+
{ hash: utf8ToBytes(''), body: utf8ToBytes('') },
262262
],
263263
]
264264

@@ -276,7 +276,7 @@ describe('[StorageFetcher]', async () => {
276276
},
277277
],
278278
}
279-
const resData = RLP.decode(hexToBytes(_storageRangesRLP)) as unknown
279+
const resData = RLP.decode(hexToBytes(_storageRangesRLP))
280280
const res = p.decode(
281281
p.messages.filter((message) => message.name === 'StorageRanges')[0],
282282
resData,

packages/ethash/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"spellcheck": "npm run spellcheck:ts && npm run spellcheck:md",
4545
"spellcheck:ts": "npx cspell --gitignore -c ../../config/cspell-ts.json \"./**/*.ts\" --cache --show-suggestions --show-context",
4646
"spellcheck:md": "npx cspell --gitignore -c ../../config/cspell-md.json \"**.md\" --cache --show-suggestions --show-context",
47-
"test": "npx vitest run -c ../../config/vitest.config.mts",
47+
"test": "npx vitest run -c ./vite.config.ts",
4848
"tsc": "../../config/cli/ts-compile.sh"
4949
},
5050
"dependencies": {

0 commit comments

Comments
 (0)