diff --git a/Cargo.lock b/Cargo.lock index d00ee19475a..e323c319415 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4061,7 +4061,7 @@ dependencies = [ [[package]] name = "fc-api" version = "1.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "async-trait", "fp-storage", @@ -4073,7 +4073,7 @@ dependencies = [ [[package]] name = "fc-consensus" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "async-trait", "fp-consensus", @@ -4089,7 +4089,7 @@ dependencies = [ [[package]] name = "fc-db" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "async-trait", "ethereum", @@ -4119,7 +4119,7 @@ dependencies = [ [[package]] name = "fc-mapping-sync" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "fc-db", "fc-storage", @@ -4142,7 +4142,7 @@ dependencies = [ [[package]] name = "fc-rpc" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "ethereum", "ethereum-types", @@ -4196,7 +4196,7 @@ dependencies = [ [[package]] name = "fc-rpc-core" version = "1.1.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "ethereum", "ethereum-types", @@ -4212,7 +4212,7 @@ dependencies = [ [[package]] name = "fc-rpc-v2-api" version = "0.1.0" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "ethereum-types", "fc-rpc-v2-types", @@ -4222,7 +4222,7 @@ dependencies = [ [[package]] name = "fc-rpc-v2-types" version = "0.1.0" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "const-hex", "ethereum-types", @@ -4233,7 +4233,7 @@ dependencies = [ [[package]] name = "fc-storage" version = "1.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "ethereum", "ethereum-types", @@ -4426,7 +4426,7 @@ dependencies = [ [[package]] name = "fp-account" version = "1.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "hex", "impl-serde", @@ -4444,7 +4444,7 @@ dependencies = [ [[package]] name = "fp-consensus" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "ethereum", "parity-scale-codec", @@ -4455,7 +4455,7 @@ dependencies = [ [[package]] name = "fp-ethereum" version = "1.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "ethereum", "ethereum-types", @@ -4467,7 +4467,7 @@ dependencies = [ [[package]] name = "fp-evm" version = "3.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "environmental", "evm", @@ -4483,7 +4483,7 @@ dependencies = [ [[package]] name = "fp-rpc" version = "3.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "ethereum", "ethereum-types", @@ -4499,7 +4499,7 @@ dependencies = [ [[package]] name = "fp-self-contained" version = "1.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "frame-support", "parity-scale-codec", @@ -4511,7 +4511,7 @@ dependencies = [ [[package]] name = "fp-storage" version = "2.0.0" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "parity-scale-codec", "serde", @@ -9738,7 +9738,7 @@ dependencies = [ [[package]] name = "pallet-ethereum" version = "4.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "environmental", "ethereum", @@ -9793,7 +9793,7 @@ dependencies = [ [[package]] name = "pallet-evm" version = "6.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "cumulus-primitives-storage-weight-reclaim", "environmental", @@ -9818,7 +9818,7 @@ dependencies = [ [[package]] name = "pallet-evm-chain-id" version = "1.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "frame-support", "frame-system", @@ -9896,7 +9896,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-blake2" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "fp-evm", ] @@ -9904,7 +9904,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-bls12381" version = "1.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "ark-bls12-381 0.4.0", "ark-ec 0.4.2", @@ -9916,7 +9916,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-bn128" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "fp-evm", "sp-core", @@ -10071,7 +10071,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-modexp" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "fp-evm", "num", @@ -10272,7 +10272,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-sha3fips" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "fp-evm", "frame-support", @@ -10283,7 +10283,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-simple" version = "2.0.0-dev" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "fp-evm", "ripemd", @@ -13126,7 +13126,7 @@ dependencies = [ [[package]] name = "precompile-utils" version = "0.1.0" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "derive_more 1.0.0", "environmental", @@ -13155,7 +13155,7 @@ dependencies = [ [[package]] name = "precompile-utils-macro" version = "0.1.0" -source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#29be929e37829e5bb23a633b0afc3707b6483664" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-stable2506#a6703ef38c16caf7f2974b036f0bd29fde628972" dependencies = [ "case", "num_enum 0.7.3", diff --git a/test/suites/smoke/test-eth-subscribe-newheads.ts b/test/suites/smoke/test-eth-subscribe-newheads.ts new file mode 100644 index 00000000000..22b299136f9 --- /dev/null +++ b/test/suites/smoke/test-eth-subscribe-newheads.ts @@ -0,0 +1,155 @@ +import "@moonbeam-network/api-augment"; +import { describeSuite, beforeAll, expect } from "@moonwall/cli"; +import { type PublicClient, createPublicClient, webSocket } from "viem"; + +// Configuration for the test +const LISTEN_DURATION_MS = 60_000; // Listen for 60 seconds +const MIN_BLOCKS_EXPECTED = 3; // Minimum blocks expected in the listen period + +describeSuite({ + id: "S28", + title: "eth_subscribe newHeads - Block sequence continuity", + foundationMethods: "read_only", + testCases: ({ context, it, log }) => { + let client: PublicClient; + let wsEndpoint: string; + + beforeAll(async () => { + // Get the WebSocket endpoint from the context + // viem transport URL might be http, convert to ws + const httpUrl = context.viem().transport.url; + wsEndpoint = httpUrl.replace("http://", "ws://").replace("https://", "wss://"); + log(`Using WebSocket endpoint: ${wsEndpoint}`); + }); + + it({ + id: "C100", + title: "should deliver continuous block headers with valid parent references", + timeout: LISTEN_DURATION_MS + 30_000, // Add buffer for setup/teardown + test: async function () { + const transport = webSocket(wsEndpoint); + client = createPublicClient({ transport }); + + const receivedBlocks: Array<{ number: bigint; hash: string; parentHash: string }> = []; + const receivedHashes = new Set(); + const skippedBlocks: Array<{ expected: bigint; received: bigint }> = []; + const missingParents: Array<{ + blockNumber: bigint; + blockHash: string; + parentHash: string; + }> = []; + + log(`Starting newHeads subscription for ${LISTEN_DURATION_MS / 1000} seconds...`); + + await new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + unwatch(); + resolve(); + }, LISTEN_DURATION_MS); + + const unwatch = client.watchBlocks({ + onBlock: (block) => { + const blockInfo = { + number: block.number, + hash: block.hash, + parentHash: block.parentHash, + }; + receivedBlocks.push(blockInfo); + log(`Received block #${block.number} (${block.hash.slice(0, 10)}...)`); + + // Check for gaps with the previous block + if (receivedBlocks.length > 1) { + const prevBlock = receivedBlocks[receivedBlocks.length - 2]; + const expectedNumber = prevBlock.number + 1n; + + if (block.number !== expectedNumber) { + skippedBlocks.push({ + expected: expectedNumber, + received: block.number, + }); + log( + `⚠️ GAP DETECTED: Expected block #${expectedNumber}, ` + + `received #${block.number} (skipped ${block.number - expectedNumber} blocks)` + ); + } + + // Verify parent hash was delivered (skip for first block) + if (!receivedHashes.has(block.parentHash)) { + missingParents.push({ + blockNumber: block.number, + blockHash: block.hash, + parentHash: block.parentHash, + }); + log( + `⚠️ MISSING PARENT at block #${block.number}: ` + + `parent ${block.parentHash.slice(0, 10)}... was never delivered` + ); + } + } + + receivedHashes.add(block.hash); + }, + onError: (error) => { + clearTimeout(timeoutId); + reject(error); + }, + }); + }); + + log(`\nSubscription summary:`); + log(` - Total blocks received: ${receivedBlocks.length}`); + log(` - Unique block hashes: ${receivedHashes.size}`); + if (receivedBlocks.length > 0) { + log(` - First block: #${receivedBlocks[0].number}`); + log(` - Last block: #${receivedBlocks[receivedBlocks.length - 1].number}`); + } + + // Verify we received enough blocks + expect( + receivedBlocks.length, + `Expected at least ${MIN_BLOCKS_EXPECTED} blocks, received ${receivedBlocks.length}` + ).toBeGreaterThanOrEqual(MIN_BLOCKS_EXPECTED); + + // Check for skipped blocks + if (skippedBlocks.length > 0) { + log(`\n❌ SKIPPED BLOCKS DETECTED:`); + for (const skip of skippedBlocks) { + const gapSize = skip.received - skip.expected; + log( + ` - Gap at block #${skip.expected}: jumped to #${skip.received} (${gapSize} blocks missing)` + ); + } + } else { + log(`\n✓ No gaps detected in block sequence`); + } + + // Check for missing parent blocks + if (missingParents.length > 0) { + log(`\n❌ MISSING PARENT BLOCKS DETECTED:`); + for (const missing of missingParents) { + log( + ` - Block #${missing.blockNumber} (${missing.blockHash.slice(0, 10)}...): ` + + `parent ${missing.parentHash.slice(0, 18)}... was never delivered` + ); + } + } else { + log(`\n✓ All parent hashes reference previously delivered blocks`); + } + + // The test should fail if any blocks were skipped + expect( + skippedBlocks, + `newHeads subscription skipped blocks: ${skippedBlocks + .map((s) => `expected #${s.expected}, got #${s.received}`) + .join("; ")}` + ).toHaveLength(0); + + // The test should fail if any parent blocks were never delivered + expect( + missingParents, + `Missing parent blocks detected: ${missingParents.length} blocks reference parents that were never delivered` + ).toHaveLength(0); + }, + }); + }, +});