-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathbeacon.ts
More file actions
117 lines (108 loc) · 3.63 KB
/
beacon.ts
File metadata and controls
117 lines (108 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { type PrefixedHexString, hexToBytes } from '@ethereumjs/util'
import { RunStatusCode } from '@lodestar/light-client'
import { ssz } from '@lodestar/types'
import {
type BeaconNetwork,
BeaconNetworkContentType,
ContentLookup,
LightClientUpdatesByRangeKey,
NetworkId,
NetworkIdByChain,
type PortalNetwork,
computeLightClientKeyFromPeriod,
encodeBeaconContentKey,
} from 'portalnetwork'
import { INTERNAL_ERROR } from '../error-code.js'
import { middleware, validators } from '../validators.js'
import type { capella } from '@lodestar/types'
import type { Debugger } from 'debug'
const methods = ['beacon_getHead', 'beacon_getFinalized', 'beacon_getLightClientUpdate']
/**
* beacon_* RPC module
* @memberof module:rpc/modules
*/
export class beacon {
private _beacon: BeaconNetwork
private logger: Debugger
/**
* Create beacon_* RPC module
* @param rpcManager RPC client to which the module binds
*/
constructor(client: PortalNetwork, logger: Debugger) {
this._beacon = client.networks.get(NetworkIdByChain[client.chainId].BeaconChainNetwork) as BeaconNetwork
this.logger = logger.extend('beacon')
this.methods = middleware(this.methods.bind(this), 0, [])
this.getHead = middleware(this.getHead.bind(this), 0, [])
this.getFinalized = middleware(this.getFinalized.bind(this), 0, [])
this.getLightClientUpdate = middleware(this.getLightClientUpdate.bind(this), 0, [
[validators.hex],
])
}
async methods(_params: []): Promise<string[]> {
return methods
}
/**
*
* @returns the JSON formatted Light Client Header corresponding to the current head block
* known by the light client
*/
async getHead(): Promise<Record<string, unknown>> {
if (
this._beacon.lightClient === undefined ||
this._beacon.lightClient.status === RunStatusCode.uninitialized
) {
throw {
code: INTERNAL_ERROR,
message: 'light client is not initialized',
}
}
return ssz.capella.LightClientHeader.toJson(
this._beacon.lightClient.getHead() as capella.LightClientHeader,
)
}
/**
* Returns the JSON formatted Light Client Header corresponding to the latest finalized block
* the light client is aware of
*/
async getFinalized() {
if (
this._beacon.lightClient === undefined ||
this._beacon.lightClient.status === RunStatusCode.uninitialized
) {
throw {
code: INTERNAL_ERROR,
message: 'light client is not initialized',
}
}
return ssz.capella.LightClientHeader.toJson(
this._beacon.lightClient.getFinalized() as capella.LightClientHeader,
)
}
async getLightClientUpdate(params: [string]) {
const period = Number(BigInt(params[0]))
const rangeKey = encodeBeaconContentKey(
BeaconNetworkContentType.LightClientUpdate,
hexToBytes(computeLightClientKeyFromPeriod(period) as PrefixedHexString),
)
const update = await this._beacon.retrieve(rangeKey)
if (update !== undefined) {
return ssz.capella.LightClientUpdate.toJson(
ssz.capella.LightClientUpdate.deserialize(hexToBytes(update as PrefixedHexString)),
)
}
const lookup = new ContentLookup(
this._beacon,
encodeBeaconContentKey(
BeaconNetworkContentType.LightClientUpdatesByRange,
LightClientUpdatesByRangeKey.serialize({ startPeriod: BigInt(params[0]), count: 1n }),
),
)
const res = await lookup.startLookup()
if (res !== undefined && 'content' in Object.keys(res)) {
return ssz.capella.LightClientUpdate.toJson(
//@ts-ignore
ssz.capella.LightClientUpdate.deserialize(hexToBytes(res.content)),
)
}
}
}