Skip to content

Commit df35d54

Browse files
authored
Fix(parachain): Add Fallback for Validation Data Retrieval and Adjust Relay Slot (#959)
* fix(parachain): Add fallback for validation data retrieval and adjust relay slot Introduces a fallback mechanism to retrieve validation data from the grandparent block if it fails on the parent, which can occur after a wasm override. Additionally, the relay slot calculation is incremented by an extra `+1` for safety. * fmt * update test snapshots * update test results
1 parent 59831a2 commit df35d54

File tree

8 files changed

+84
-55
lines changed

8 files changed

+84
-55
lines changed

packages/core/src/blockchain/inherent/parachain/validation-data.ts

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { type BN, hexToU8a, u8aConcat, u8aToHex } from '@polkadot/util'
44
import type { HexString } from '@polkadot/util/types'
55
import { blake2AsHex, blake2AsU8a } from '@polkadot/util-crypto'
66
import _ from 'lodash'
7+
import { defaultLogger } from '../../../logger.js'
78
import { compactHex, getCurrentSlot, getParaId } from '../../../utils/index.js'
89
import {
910
dmqMqcHead,
@@ -19,6 +20,8 @@ import type { Block } from '../../block.js'
1920
import type { BuildBlockParams, DownwardMessage, HorizontalMessage } from '../../txpool.js'
2021
import type { InherentProvider } from '../index.js'
2122

23+
const logger = defaultLogger.child({ name: 'parachain-validation-data' })
24+
2225
const MOCK_VALIDATION_DATA = {
2326
validationData: {
2427
relayParentNumber: 1000,
@@ -59,7 +62,7 @@ export type ValidationData = {
5962
}
6063
}
6164

62-
const getValidationData = async (parent: Block) => {
65+
const getValidationData = async (parent: Block, fallback = true): Promise<ValidationData> => {
6366
const meta = await parent.meta
6467
if (parent.number === 0) {
6568
const { trieRootHash, nodes } = await createProof(MOCK_VALIDATION_DATA.relayChainState.trieNodes, [])
@@ -72,17 +75,42 @@ const getValidationData = async (parent: Block) => {
7275
},
7376
}
7477
}
75-
const extrinsics = await parent.extrinsics
76-
const validationDataExtrinsic = extrinsics.find((extrinsic) => {
77-
const firstArg = meta.registry.createType<GenericExtrinsic>('GenericExtrinsic', extrinsic)?.args?.[0]
78-
return firstArg && 'validationData' in firstArg
79-
})
80-
if (!validationDataExtrinsic) {
81-
throw new Error('Missing validation data from block')
78+
try {
79+
const extrinsics = await parent.extrinsics
80+
const validationDataExtrinsic = extrinsics.find((extrinsic) => {
81+
const firstArg = meta.registry.createType<GenericExtrinsic>('GenericExtrinsic', extrinsic)?.args?.[0]
82+
return firstArg && 'validationData' in firstArg
83+
})
84+
if (!validationDataExtrinsic) {
85+
throw new Error('Missing validation data from block')
86+
}
87+
return meta.registry
88+
.createType<GenericExtrinsic>('GenericExtrinsic', validationDataExtrinsic)
89+
.args[0].toJSON() as any as ValidationData
90+
} catch (e) {
91+
logger.warn('Failed to get validation data from block %d %s', parent.number, e)
92+
93+
if (fallback) {
94+
// this could fail due to wasm override that breaks the validation data format
95+
// so we will try parent's parent
96+
const grandParent = await parent.parentBlock
97+
if (grandParent) {
98+
const data = await getValidationData(grandParent, false)
99+
return {
100+
...data,
101+
validationData: {
102+
...data.validationData,
103+
relayParentNumber: data.validationData.relayParentNumber + 2,
104+
},
105+
}
106+
} else {
107+
throw e
108+
}
109+
} else {
110+
// fallback failed, throw error
111+
throw e
112+
}
82113
}
83-
return meta.registry
84-
.createType<GenericExtrinsic>('GenericExtrinsic', validationDataExtrinsic)
85-
.args[0].toJSON() as any as ValidationData
86114
}
87115

88116
export class SetValidationData implements InherentProvider {
@@ -129,7 +157,8 @@ export class SetValidationData implements InherentProvider {
129157
const relayCurrentSlot = decoded[key]
130158
? meta.registry.createType<Slot>('Slot', hexToU8a(decoded[key])).toNumber()
131159
: (await getCurrentSlot(parent)) * relaySlotIncrease
132-
const newSlot = meta.registry.createType<Slot>('Slot', relayCurrentSlot + relaySlotIncrease)
160+
const newSlot = meta.registry.createType<Slot>('Slot', relayCurrentSlot + relaySlotIncrease + 1) // +1 to be safe
161+
logger.debug({ relayCurrentSlot, newSlot: newSlot.toNumber() }, 'Updating relay current slot')
133162
newEntries.push([key, u8aToHex(newSlot.toU8a())])
134163
} else {
135164
newEntries.push([key, decoded[key]])

packages/e2e/src/__snapshots__/author.test.ts.snap

Lines changed: 24 additions & 24 deletions
Large diffs are not rendered by default.

packages/e2e/src/__snapshots__/chain.test.ts.snap

Lines changed: 8 additions & 8 deletions
Large diffs are not rendered by default.

packages/e2e/src/__snapshots__/chopsticks-provider.test.ts.snap

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

packages/e2e/src/block.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ describe('block', async () => {
3535

3636
const head = chain.head
3737
const newBlock = await chain.newBlock()
38-
expect(newBlock.hash).toMatchInlineSnapshot(`"0xfca2b29b2ef3e018b87ce56dfa6200d973201222cbb67dde3aca6db905b440cc"`)
38+
expect(newBlock.hash).toMatchInlineSnapshot(`"0xb20b7e701f6a6e9e700a8f81849d59241f7ae51e08260491292f34bc9d06b2ba"`)
3939

4040
await chain.setHead(head)
4141
await api.tx.system.remark('test').signAndSend(alice)
4242
const newBlock2 = await chain.newBlock()
43-
expect(newBlock2.hash).toMatchInlineSnapshot(`"0xbf570d4c473241efbc4ffe08145e074e3f22b1f40dc2fac8108912bec8ac845e"`)
43+
expect(newBlock2.hash).toMatchInlineSnapshot(`"0x9f8ec5d13ff39c5ab53fd8dc3bf2ce3f65bf5ddf86865eb8e9fea904c0bff45d"`)
4444
})
4545
})

packages/e2e/src/dev.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ describe('dev rpc', async () => {
104104
expect((await api.rpc.chain.getBlockHash()).toHex()).toBe(hash)
105105
await dev.setHead(blockNumber - 3)
106106
expect((await api.rpc.chain.getBlockHash()).toHex()).toMatchInlineSnapshot(
107-
`"0xc67fac55f8f2e1ba8f3b7d277d3097fd796216998bd6b1bfd8fd9aed87da579d"`,
107+
`"0xa9af3bba23e0ffca832dbaa7fc28d04764d50ccbe52370717dcc5c9126060628"`,
108108
)
109109
await dev.setHead(-3)
110110
expect((await api.rpc.chain.getBlockHash()).toHex()).toMatchInlineSnapshot(

packages/e2e/src/storage.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ describe('storage', () => {
7474

7575
tick = next()
7676
expect(await dev.newBlock()).toMatchInlineSnapshot(
77-
`"0x3ee18ba950984f5ed8c6c6d407784c551aea7471ba1000f74998ebd5a3fbc9bf"`,
77+
`"0xd93ac4e1814b874c059e647b9726f38c7f42ec673e171572d8e38992f6072b77"`,
7878
)
7979
await tick
8080

@@ -84,7 +84,7 @@ describe('storage', () => {
8484
unsub()
8585

8686
expect(await dev.newBlock()).toMatchInlineSnapshot(
87-
`"0x1950829c5687d921d786c184dae9eb20ae55d2020b07adafcb1cfb1a5be4212f"`,
87+
`"0xf9c6e17a227e188f64338f72626f44a84a55c3b959d9305db309bbed05f76de1"`,
8888
)
8989

9090
await delay(100)

packages/web-test/tests/index.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ test.describe('index', () => {
3535
})
3636
return block.result.hash
3737
})
38-
expect(savedHash).toBe('0x7403a6c53702bfbace9737a5b3cc84fd02d5f8b30259e718455738ae841d992b')
38+
expect(savedHash).toBe('0x64809750cb08df1076b3470ce42a0d1e1d45984d59bcfc876ce2d3424fd5416d')
3939
})
4040

4141
test('dry run extrinsic', async ({ page }) => {
@@ -63,14 +63,14 @@ test.describe('index', () => {
6363
expect(hightestBlock).toEqual(
6464
expect.objectContaining({
6565
number: 4_000_002,
66-
hash: '0x9db1dc9525d7574ad6aed6b4302c9fb5069c5cd35288d97ebc78a58782f57b0d',
66+
hash: '0xe8657fc0154874e9412aea2c3567743d257384795d99719b900d628763ffb760',
6767
}),
6868
)
6969
const blockByNumber = await page.evaluate(() => globalThis.chain.db?.queryBlockByNumber(4_000_001))
7070
expect(blockByNumber).toEqual(
7171
expect.objectContaining({
7272
number: 4_000_001,
73-
hash: '0x7403a6c53702bfbace9737a5b3cc84fd02d5f8b30259e718455738ae841d992b',
73+
hash: '0x64809750cb08df1076b3470ce42a0d1e1d45984d59bcfc876ce2d3424fd5416d',
7474
}),
7575
)
7676
const blocksCount = await page.evaluate(() => globalThis.chain.db?.blocksCount())
@@ -87,7 +87,7 @@ test.describe('index', () => {
8787
expect(hightestBlock).toEqual(
8888
expect.objectContaining({
8989
number: 4_000_001,
90-
hash: '0x7403a6c53702bfbace9737a5b3cc84fd02d5f8b30259e718455738ae841d992b',
90+
hash: '0x64809750cb08df1076b3470ce42a0d1e1d45984d59bcfc876ce2d3424fd5416d',
9191
}),
9292
)
9393
}

0 commit comments

Comments
 (0)