1
1
import { ProofType , createProof } from '@chainsafe/persistent-merkle-tree'
2
- import { bytesToHex , equalsBytes } from '@ethereumjs/util'
2
+ import { bytesToHex , concatBytes , equalsBytes , hexToBytes } from '@ethereumjs/util'
3
+ import { Common } from '@ethereumjs/common'
3
4
import { ssz , sszTypesFor } from '@lodestar/types'
4
5
import jayson from 'jayson/promise/index.js'
5
- import { HistoricalRootsBlockProof , HistoricalSummariesBlockProof , slotToHistoricalBatchIndex } from 'portalnetwork'
6
+ import { BeaconLightClientNetworkContentType , blockFromRpc , blockHeaderFromRpc , BlockHeaderWithProof , getBeaconContentKey , getContentKey , HistoricalRootsBlockProof , HistoricalSummariesBlockProof , HistoricalSummariesKey , HistoricalSummariesWithProof , HistoryNetworkContentType , LightClientBootstrapKey , LightClientFinalityUpdateKey , LightClientOptimisticUpdateKey , slotToHistoricalBatchIndex } from 'portalnetwork'
6
7
import type { SingleProof } from '@chainsafe/persistent-merkle-tree'
7
8
import { computeEpochAtSlot , getChainForkConfigFromNetwork , getCurrentSlot } from '@lodestar/light-client/utils'
8
9
import { mainnetChainConfig } from '@lodestar/config/configs'
9
10
import { readFileSync } from 'fs'
10
11
import { decompressBeaconBlock , getEraIndexes } from '../../era/src/helpers'
11
12
import { readEntry } from '../../era/src/helpers'
12
13
import { decompressBeaconState } from '../../era/src/helpers'
14
+ import { ForkName } from '@lodestar/params'
15
+ import { genesisData } from '@lodestar/config/networks'
16
+ import { createBeaconConfig } from '@lodestar/config'
17
+ import { executionPayloadFromBeaconPayload , BlockHeader , Block } from '@ethereumjs/block'
13
18
14
19
const { Client } = jayson
15
20
16
21
const main = async ( ) => {
17
22
const forkConfig = getChainForkConfigFromNetwork ( 'mainnet' )
18
23
const beaconConfig = mainnetChainConfig
24
+
25
+
19
26
const beaconNode = 'https://lodestar-mainnet.chainsafe.io'
20
- const _ultralight = Client . http ( { host : '127.0.0.1' , port : 8545 } )
27
+ const ultralight = Client . http ( { host : '127.0.0.1' , port : 8545 } )
28
+
29
+ const finalityUpdate = ssz . capella . LightClientFinalityUpdate . fromJson (
30
+ ( await ( await fetch ( beaconNode + '/eth/v1/beacon/light_client/finality_update' ) ) . json ( ) ) . data ,
31
+ )
32
+ const finalityUpdateKey = getBeaconContentKey (
33
+ BeaconLightClientNetworkContentType . LightClientFinalityUpdate ,
34
+ LightClientFinalityUpdateKey . serialize ( {
35
+ finalitySlot : BigInt ( finalityUpdate . finalizedHeader . beacon . slot ) ,
36
+ } ) ,
37
+ )
21
38
22
- const currentSlot = getCurrentSlot ( beaconConfig , 1606824000 )
23
- const currentEpoch = computeEpochAtSlot ( Number ( currentSlot ) )
24
- console . log ( 'Current Epoch: ' , currentEpoch )
39
+ const optimisticUpdate = ssz . deneb . LightClientOptimisticUpdate . fromJson (
40
+ ( await ( await fetch ( beaconNode + '/eth/v1/beacon/light_client/optimistic_update' ) ) . json ( ) ) . data ,
41
+ )
42
+ console . log (
43
+ `Retrieved latest optimistic update for slot ${ BigInt ( optimisticUpdate . signatureSlot ) } ` ,
44
+ )
45
+ const optimisticUpdateKey = getBeaconContentKey (
46
+ BeaconLightClientNetworkContentType . LightClientOptimisticUpdate ,
47
+ LightClientOptimisticUpdateKey . serialize ( {
48
+ signatureSlot : BigInt ( optimisticUpdate . signatureSlot ) ,
49
+ } ) ,
50
+ )
51
+
52
+ const bootstrapSlot = finalityUpdate . finalizedHeader . beacon . slot
53
+ const bootstrapRes = (
54
+ await ( await fetch ( beaconNode + `/eth/v1/beacon/blocks/${ bootstrapSlot } /root` ) ) . json ( )
55
+ )
56
+
57
+ const bootstrapRoot = bootstrapRes . data . root
58
+ const bootstrap = ssz . deneb . LightClientBootstrap . fromJson (
59
+ (
60
+ await (
61
+ await fetch ( beaconNode + `/eth/v1/beacon/light_client/bootstrap/${ bootstrapRoot } ` )
62
+ ) . json ( )
63
+ ) . data ,
64
+ )
65
+
66
+ const forkName = forkConfig . getForkName ( bootstrapSlot )
67
+ const forkDigest = createBeaconConfig ( beaconConfig , hexToBytes ( genesisData . mainnet . genesisValidatorsRoot ) ) . forkName2ForkDigest ( forkName )
68
+ console . log (
69
+ `Retrieved bootstrap for finalized checkpoint ${ bootstrapRoot } ` ,
70
+ )
71
+ let res = await ultralight . request ( 'portal_beaconStore' , [
72
+ bytesToHex ( getBeaconContentKey (
73
+ BeaconLightClientNetworkContentType . LightClientBootstrap ,
74
+ LightClientBootstrapKey . serialize ( { blockHash : hexToBytes ( bootstrapRoot ) } ) ,
75
+ ) ) ,
76
+ bytesToHex (
77
+ concatBytes ( forkDigest , ssz [ forkName ] . LightClientBootstrap . serialize ( bootstrap ) ) ,
78
+ ) ,
79
+ ] )
80
+ console . log ( 'Pushed bootstrap into Portal Network' , res )
81
+
82
+ res = await ultralight . request ( 'portal_beaconStartLightClient' , [
83
+ bootstrapRoot
84
+ ] )
85
+ console . log ( 'Started Beacon Light Client Sync' , res )
86
+
87
+ res = await ultralight . request ( 'portal_beaconStore' , [
88
+ bytesToHex ( optimisticUpdateKey ) ,
89
+ bytesToHex (
90
+ concatBytes (
91
+ forkDigest ,
92
+ ssz . deneb . LightClientOptimisticUpdate . serialize ( optimisticUpdate ) ,
93
+ ) ,
94
+ ) ,
95
+ ] )
25
96
26
- const pastEpochEndSlot = ( currentEpoch * 32 ) - 1
27
- console . log ( 'Past Epoch End Slot: ' , pastEpochEndSlot )
28
97
console . log ( 'Retrieving latest historical summaries...' )
29
- // const res2 = await fetch(beaconNode + `/eth/v1/lodestar/historical_summaries/${pastEpochEndSlot}`)
30
- // const res2Json = await res2.json()
31
- // console.log(res2Json)
32
- // const historicalSummaries = ssz.capella.BeaconState.fields.historicalSummaries.fromJson(res2Json.data.historical_summaries)
98
+ const res2 = await fetch ( beaconNode + `/eth/v1/lodestar/historical_summaries/${ finalityUpdate . finalizedHeader . beacon . slot } ` )
99
+ const res2Json = await res2 . json ( )
100
+ console . log ( res2Json )
101
+ const historicalSummaries = ssz . deneb . BeaconState . fields . historicalSummaries . fromJson ( res2Json . data . historical_summaries )
102
+ const finalityEpoch = computeEpochAtSlot ( finalityUpdate . finalizedHeader . beacon . slot )
103
+ const proof = res2Json . data . proof . map ( ( el ) => hexToBytes ( el ) )
33
104
105
+ res = await ultralight . request ( 'portal_beaconStore' ,
106
+ [ bytesToHex ( getBeaconContentKey ( BeaconLightClientNetworkContentType . HistoricalSummaries , HistoricalSummariesKey . serialize ( { epoch : BigInt ( finalityEpoch ) } ) ) ) ,
107
+ bytesToHex ( concatBytes ( forkDigest , HistoricalSummariesWithProof . serialize ( { epoch : BigInt ( finalityEpoch ) , historicalSummaries, proof } ) ) ) ] )
34
108
console . log ( `Reading era file for period ${ 1320 } ` )
35
109
const eraFile = new Uint8Array ( readFileSync ( `./scripts/eras/mainnet-01320-59f1c8c0.era` ) )
36
110
const indices = getEraIndexes ( eraFile )
@@ -39,12 +113,11 @@ const main = async () => {
39
113
)
40
114
const state = await decompressBeaconState ( stateEntry . data , indices . stateSlotIndex . startSlot )
41
115
const stateFork = forkConfig . getForkName ( indices . stateSlotIndex . startSlot )
42
- const blockRootsRoot = ssz [ stateFork ] . BeaconState . fields . blockRoots . toView ( state . blockRoots ) . node
43
116
for ( let x = 0 ; x < 1 ; x ++ ) {
44
117
try {
45
118
const blockEntry = readEntry ( eraFile . slice ( indices . blockSlotIndex ! . recordStart + indices . blockSlotIndex ! . slotOffsets [ x ] ) )
46
119
const block = await decompressBeaconBlock ( blockEntry . data , indices . blockSlotIndex ! . startSlot )
47
- const blockFork = forkConfig . getForkName ( block . message . slot )
120
+ const blockFork = ForkName . deneb
48
121
const fullBlockJson = await ( await fetch ( beaconNode + `/eth/v2/beacon/blocks/${ block . message . slot } ` ) ) . json ( )
49
122
50
123
const fullBlock = sszTypesFor ( blockFork ) . BeaconBlock . fromJson ( fullBlockJson . data . message )
@@ -63,18 +136,32 @@ const main = async () => {
63
136
const batchIndex = Number ( slotToHistoricalBatchIndex ( BigInt ( block . message . slot ) ) )
64
137
const historicalSummariesPath = ssz [ stateFork ] . BeaconState . fields . blockRoots . getPathInfo ( [ batchIndex ] )
65
138
66
- const historicalSummariesProof = createProof ( ssz [ stateFork ] . BeaconState . fields . blockRoots . toView ( state . blockRoots ) . node , {
139
+ const blockRootsProof = createProof ( ssz [ stateFork ] . BeaconState . fields . blockRoots . toView ( state . blockRoots ) . node , {
67
140
gindex : historicalSummariesPath . gindex ,
68
141
type : ProofType . single ,
69
142
} ) as SingleProof
70
143
71
144
const blockProof = HistoricalSummariesBlockProof . fromJson ( {
72
145
slot : block . message . slot ,
73
- historicalSummariesProof : historicalSummariesProof . witnesses . map ( ( witness ) => bytesToHex ( witness ) ) ,
146
+ historicalSummariesProof : blockRootsProof . witnesses . map ( ( witness ) => bytesToHex ( witness ) ) ,
74
147
beaconBlockProof : beaconBlockProof . witnesses . map ( ( witness ) => bytesToHex ( witness ) ) ,
75
148
beaconBlockRoot : bytesToHex ( ssz [ blockFork ] . BeaconBlock . value_toTree ( fullBlock ) . root ) ,
76
149
} )
77
- console . log ( HistoricalSummariesBlockProof . toJson ( blockProof ) )
150
+ const execPayload = executionPayloadFromBeaconPayload ( fullBlockJson . data . message . body . execution_payload )
151
+ const header = BlockHeader . fromHeaderData ( execPayload , { common : new Common ( { chain : 'mainnet' , hardfork : 'cancun' } ) } )
152
+ const headerWithProof = BlockHeaderWithProof . serialize ( {
153
+ header : header . serialize ( ) ,
154
+ proof : {
155
+ value : blockProof ,
156
+ selector : 3
157
+ }
158
+ } )
159
+ res = await ultralight . request ( 'portal_historyStore' , [
160
+ bytesToHex ( getContentKey ( HistoryNetworkContentType . BlockHeader , fullBlock . body . eth1Data . blockHash ) ) ,
161
+ bytesToHex ( headerWithProof )
162
+ ] )
163
+ console . log ( res )
164
+
78
165
} catch ( err ) {
79
166
console . log ( err )
80
167
}
0 commit comments