Skip to content

Commit 4d8b4cf

Browse files
ScottyPoiacolytec3
andauthored
Electra Historical Summaries (#787)
* beacon: update HistoricalSummariesStateProof ssz type * beacon: use forkConfig to determine ssz types * fix unit tests * fix integration tests --------- Co-authored-by: acolytec3 <17355484+acolytec3@users.noreply.github.com>
1 parent 45a4c8c commit 4d8b4cf

16 files changed

Lines changed: 6245 additions & 1820 deletions

packages/portalnetwork/src/networks/beacon/beacon.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -695,14 +695,13 @@ export class BeaconNetwork extends BaseNetwork {
695695
// TODO: Decide whether it ever makes sense to accept a HistoricalSummaries object if we don't already have a finality update to verify against
696696
// return
697697
} else {
698-
// TODO: Make this future proof with forkConfig
699-
const reconstructedStateMerkleTree = ssz.capella.BeaconState.createFromProof({
698+
const forkName = this.beaconConfig.forkDigest2ForkName(value.slice(0, 4)) as LightClientForkName
699+
const reconstructedStateMerkleTree = ssz[ForkName[forkName]].BeaconState.createFromProof({
700700
type: ProofType.single,
701-
gindex: ssz.capella.BeaconState.getPathInfo(['historicalSummaries']).gindex,
701+
gindex: ssz[ForkName[forkName]].BeaconState.getPathInfo(['historicalSummaries']).gindex,
702702
witnesses: summaries.proof,
703-
leaf: ssz.capella.BeaconState.fields.historicalSummaries
704-
.toView(summaries.historicalSummaries)
705-
.hashTreeRoot(),
703+
leaf: (ssz[ForkName[forkName]].BeaconState.fields as any).historicalSummaries
704+
.hashTreeRoot(summaries.historicalSummaries)
706705
})
707706
if (
708707
equalsBytes(

packages/portalnetwork/src/networks/beacon/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const LightClientOptimisticUpdateKey = new ContainerType({
5252

5353
export const HistoricalSummariesKey = new ContainerType({ epoch: new UintBigintType(8) })
5454

55-
export const HistoricalSummariesStateProof = new VectorCompositeType(Bytes32Type, 5)
55+
export const HistoricalSummariesStateProof = new VectorCompositeType(Bytes32Type, 6)
5656

5757
export const HistoricalSummariesWithProof = new ContainerType<{
5858
epoch: UintBigintType

packages/portalnetwork/test/integration/beacon.spec.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -766,16 +766,16 @@ describe('beacon light client sync tests', () => {
766766
describe('historicalSummaries verification', () => {
767767
it('should sync two light clients to present and then gossip HistoricalSummaries', async () => {
768768
vi.useFakeTimers({ shouldAdvanceTime: true, shouldClearNativeTimers: true })
769-
vi.setSystemTime(1722959051100)
769+
vi.setSystemTime(1747332119000)
770770
const bootstrapJson =
771-
require('./testdata/historicalSummaries/bootstrap0xb7918b28a8e9c6be29467a0771d0ab2693d5061f43d214b6056e8c6a12a5b9f3.json').data
772-
const bootstrap = ssz.deneb.LightClientBootstrap.fromJson(bootstrapJson)
771+
require('./testdata/historicalSummaries/bootstrap.json').data
772+
const bootstrap = ssz.electra.LightClientBootstrap.fromJson(bootstrapJson)
773773

774-
const finalityUpdatejson = require('./testdata/historicalSummaries/finality_update.json').data
775-
const finalityUpdate = ssz.deneb.LightClientFinalityUpdate.fromJson(finalityUpdatejson)
774+
const finalityUpdatejson = require('./testdata/historicalSummaries/finalityUpdateSlot11708998.json').data
775+
const finalityUpdate = ssz.electra.LightClientFinalityUpdate.fromJson(finalityUpdatejson)
776776
const optimisticUpdateJson =
777-
require('./testdata/historicalSummaries/optimistic_update.json').data
778-
const optimisticUpdate = ssz.deneb.LightClientOptimisticUpdate.fromJson(optimisticUpdateJson)
777+
require('./testdata/historicalSummaries/optimisticUpdateSlot11709008.json').data
778+
const optimisticUpdate = ssz.electra.LightClientOptimisticUpdate.fromJson(optimisticUpdateJson)
779779
const initMa: any = multiaddr('/ip4/127.0.0.1/udp/30027')
780780
enr1.setLocationMultiaddr(initMa)
781781
const initMa2: any = multiaddr('/ip4/127.0.0.1/udp/30028')
@@ -808,16 +808,16 @@ describe('historicalSummaries verification', () => {
808808
const network1 = node1.networks.get(NetworkId.BeaconChainNetwork) as BeaconNetwork
809809
const network2 = node2.networks.get(NetworkId.BeaconChainNetwork) as BeaconNetwork
810810

811-
const capellaForkDigest = network1.beaconConfig.forkName2ForkDigest(ForkName.deneb)
812-
811+
const capellaForkDigest = network1.beaconConfig.forkName2ForkDigest(ForkName.electra)
812+
console.log(bytesToHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(bootstrap.header.beacon)))
813813
await network1.store(
814814
getBeaconContentKey(
815815
BeaconNetworkContentType.LightClientBootstrap,
816816
LightClientBootstrapKey.serialize({
817817
blockHash: ssz.phase0.BeaconBlockHeader.hashTreeRoot(bootstrap.header.beacon),
818818
}),
819819
),
820-
concatBytes(capellaForkDigest, ssz.deneb.LightClientBootstrap.serialize(bootstrap)),
820+
concatBytes(capellaForkDigest, ssz.electra.LightClientBootstrap.serialize(bootstrap)),
821821
)
822822

823823
await network1.store(
@@ -843,10 +843,10 @@ describe('historicalSummaries verification', () => {
843843
)
844844

845845
await network1.initializeLightClient(
846-
'0xb7918b28a8e9c6be29467a0771d0ab2693d5061f43d214b6056e8c6a12a5b9f3',
846+
'0xee691ed0308c995e53203ca26fb68e652a172c4356d72002dd0c058d7489ca3a',
847847
)
848848
await network2.initializeLightClient(
849-
'0xb7918b28a8e9c6be29467a0771d0ab2693d5061f43d214b6056e8c6a12a5b9f3',
849+
'0xee691ed0308c995e53203ca26fb68e652a172c4356d72002dd0c058d7489ca3a',
850850
)
851851

852852
await network1.store(
@@ -868,24 +868,23 @@ describe('historicalSummaries verification', () => {
868868
'light client synced to latest epoch successfully',
869869
)
870870

871-
const epoch = BigInt(Math.floor(9677824 / 8192))
872-
const historicalSummariesJson = require('./testdata/historicalSummaries/historicalSummaries_slot_9677824.json')
873-
const historicalSummariesProofJson = require('./testdata/historicalSummaries/historicalSummariesStateProof_slot_9677824.json')
871+
const historicalSummariesJson = require('./testdata/historicalSummaries/historicalSummariesSlot11708928.json')
872+
const epoch = BigInt(Math.floor(Number(historicalSummariesJson.data.slot) / 8192))
874873
const hsWProof = HistoricalSummariesWithProof.fromJson({
875874
epoch: bigIntToHex(epoch),
876-
historical_summaries: historicalSummariesJson,
877-
proof: historicalSummariesProofJson,
875+
historical_summaries: historicalSummariesJson.data.historical_summaries,
876+
proof: historicalSummariesJson.data.proof,
878877
})
879878
await network1.store(
880879
getBeaconContentKey(
881880
BeaconNetworkContentType.HistoricalSummaries,
882881
HistoricalSummariesKey.serialize({ epoch }),
883882
),
884-
concatBytes(network1.forkDigest, HistoricalSummariesWithProof.serialize(hsWProof)),
883+
concatBytes(network1.beaconConfig.forkName2ForkDigest(ForkName.electra), HistoricalSummariesWithProof.serialize(hsWProof)),
885884
)
886885
while (network2.historicalSummaries.length === 0) {
887886
await new Promise((r) => setTimeout(r, 1000))
888887
}
889-
assert.equal(network2.historicalSummariesEpoch, 1181n)
888+
assert.equal(network2.historicalSummariesEpoch, 1429n)
890889
}, 15000)
891890
})

packages/portalnetwork/test/integration/postCapellaHeaderProof.spec.ts

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,27 @@ import { ssz } from '@lodestar/types'
1010
import { multiaddr } from '@multiformats/multiaddr'
1111
import { assert, describe, it, vi } from 'vitest'
1212
import {
13+
type BeaconNetwork,
1314
BeaconNetworkContentType,
14-
BlockHeaderWithProof,
15-
HistoricalSummariesBlockProof,
1615
HistoricalSummariesKey,
1716
HistoricalSummariesWithProof,
1817
HistoryNetworkContentType,
1918
LightClientBootstrapKey,
2019
NetworkId,
2120
createPortalNetwork,
2221
getBeaconContentKey,
23-
getContentKey,
22+
getContentKey
2423
} from '../../src/index.js'
2524

2625
describe('Block Bridge Data Test', () => {
2726
it('should store and retrieve block header data', async () => {
2827
vi.useFakeTimers({ shouldAdvanceTime: true, shouldClearNativeTimers: true })
29-
vi.setSystemTime(1737151319000)
28+
vi.setSystemTime(1747332119000)
3029
const privateKeys = [
3130
'0x0a2700250802122102273097673a2948af93317235d2f02ad9cf3b79a34eeb37720c5f19e09f11783c12250802122102273097673a2948af93317235d2f02ad9cf3b79a34eeb37720c5f19e09f11783c1a2408021220aae0fff4ac28fdcdf14ee8ecb591c7f1bc78651206d86afe16479a63d9cb73bd',
3231
'0x0a27002508021221039909a8a7e81dbdc867480f0eeb7468189d1e7a1dd7ee8a13ee486c8cbd743764122508021221039909a8a7e81dbdc867480f0eeb7468189d1e7a1dd7ee8a13ee486c8cbd7437641a2408021220c6eb3ae347433e8cfe7a0a195cc17fc8afcd478b9fb74be56d13bccc67813130',
3332
]
34-
const pk1 = keys.privateKeyFromProtobuf(hexToBytes(privateKeys[0]).slice(-36))
33+
const pk1 = keys.privateKeyFromProtobuf(hexToBytes(privateKeys[0] as `0x${string}`).slice(-36))
3534
const enr1 = SignableENR.createFromPrivateKey(pk1)
3635
const initMa: any = multiaddr('/ip4/127.0.0.1/udp/5033')
3736

@@ -44,57 +43,52 @@ describe('Block Bridge Data Test', () => {
4443
})
4544
await client.start()
4645

47-
const bootstrapHex = JSON.parse(
48-
readFileSync('./test/integration/testdata/postCapellaData/bootstrap.json', 'utf8'),
49-
)
50-
const historicalSummariesJson = JSON.parse(
51-
readFileSync('./test/integration/testdata/postCapellaData/historical_summaries.json', 'utf8'),
52-
)
46+
const bootstrapJson = await import('./testdata/historicalSummaries/bootstrap.json')
47+
const historicalSummariesJson = await import('./testdata/historicalSummaries/historicalSummariesSlot11708928.json')
5348
const fullBlock = JSON.parse(
5449
readFileSync('./test/integration/testdata/postCapellaData/full_block.json', 'utf8'),
5550
)
5651
const headerWithProof = JSON.parse(
5752
readFileSync('./test/integration/testdata/postCapellaData/header_with_proof.json', 'utf8'),
5853
)
5954

60-
const bootstrap = ssz.deneb.LightClientBootstrap.deserialize(hexToBytes(bootstrapHex.bootstrap))
61-
const bootstrapRoot = '0x47a956b9cd45c73a60dac4c89dc869a5faa46a9d5d802486f31025c74d41ef39'
62-
55+
const bootstrap = ssz.electra.LightClientBootstrap.fromJson((bootstrapJson.data))
56+
const bootstrapRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(bootstrap.header.beacon)
6357
// Get fork info
6458
const forkConfig = getChainForkConfigFromNetwork('mainnet')
6559
const bootstrapSlot = bootstrap.header.beacon.slot
6660
const forkName = forkConfig.getForkName(bootstrapSlot)
6761
const forkDigest = createBeaconConfig(
6862
mainnetChainConfig,
69-
hexToBytes(genesisData.mainnet.genesisValidatorsRoot),
63+
hexToBytes(genesisData.mainnet.genesisValidatorsRoot as `0x${string}`),
7064
).forkName2ForkDigest(forkName)
7165

7266
// Store bootstrap
7367

7468
const bootstrapKey = getBeaconContentKey(
7569
BeaconNetworkContentType.LightClientBootstrap,
76-
LightClientBootstrapKey.serialize({ blockHash: hexToBytes(bootstrapRoot) }),
70+
LightClientBootstrapKey.serialize({ blockHash: bootstrapRoot }),
7771
)
7872
const bootstrapValue = concatBytes(
7973
forkDigest,
80-
ssz.deneb.LightClientBootstrap.serialize(bootstrap),
74+
ssz.electra.LightClientBootstrap.serialize(bootstrap),
8175
)
8276

83-
const beacon = client.network()['0x500c']
77+
const beacon = client.network()['0x500c'] as BeaconNetwork
8478
const history = client.network()['0x500b']
8579

8680
await beacon?.store(bootstrapKey, bootstrapValue)
8781

8882
// Start light client
89-
await beacon?.initializeLightClient(bootstrapRoot)
83+
await beacon?.initializeLightClient(bytesToHex(bootstrapRoot))
9084

9185
const historicalSummariesEpoch = computeEpochAtSlot(bootstrapSlot)
9286

9387
// Store historical summaries
9488
const historicalSummariesObj = HistoricalSummariesWithProof.fromJson({
9589
epoch: historicalSummariesEpoch,
96-
historical_summaries: historicalSummariesJson.historical_summaries,
97-
proof: historicalSummariesJson.proof,
90+
historical_summaries: historicalSummariesJson.data.historical_summaries,
91+
proof: historicalSummariesJson.data.proof,
9892
})
9993
const summariesKey = getBeaconContentKey(
10094
BeaconNetworkContentType.HistoricalSummaries,

0 commit comments

Comments
 (0)