style: typecasting, formatting and cleanup
This commit is contained in:
parent
40d652fa22
commit
7ffc07f474
|
@ -1,4 +1,5 @@
|
||||||
import {
|
import {
|
||||||
|
Bytes32,
|
||||||
ClientConfig,
|
ClientConfig,
|
||||||
ExecutionInfo,
|
ExecutionInfo,
|
||||||
LightClientUpdate,
|
LightClientUpdate,
|
||||||
|
@ -15,6 +16,7 @@ import {
|
||||||
import {
|
import {
|
||||||
computeSyncPeriodAtSlot,
|
computeSyncPeriodAtSlot,
|
||||||
getCurrentSlot,
|
getCurrentSlot,
|
||||||
|
isValidMerkleBranch,
|
||||||
} from "@lodestar/light-client/utils";
|
} from "@lodestar/light-client/utils";
|
||||||
import {
|
import {
|
||||||
assertValidLightClientUpdate,
|
assertValidLightClientUpdate,
|
||||||
|
@ -22,8 +24,9 @@ import {
|
||||||
} from "@lodestar/light-client/validation";
|
} from "@lodestar/light-client/validation";
|
||||||
import { SyncCommitteeFast } from "@lodestar/light-client";
|
import { SyncCommitteeFast } from "@lodestar/light-client";
|
||||||
import bls, { init } from "@chainsafe/bls/switchable";
|
import bls, { init } from "@chainsafe/bls/switchable";
|
||||||
import { PublicKey } from "@chainsafe/bls/types.js";
|
// @ts-ignore
|
||||||
import { fromHexString } from "@chainsafe/ssz";
|
import type { PublicKey } from "@chainsafe/bls/types.js";
|
||||||
|
import { fromHexString, toHexString } from "@chainsafe/ssz";
|
||||||
import * as phase0 from "@lodestar/types/phase0";
|
import * as phase0 from "@lodestar/types/phase0";
|
||||||
import * as capella from "@lodestar/types/capella";
|
import * as capella from "@lodestar/types/capella";
|
||||||
import NodeCache from "node-cache";
|
import NodeCache from "node-cache";
|
||||||
|
@ -41,7 +44,7 @@ export default class Client {
|
||||||
latestBlockHash?: string;
|
latestBlockHash?: string;
|
||||||
private config: ClientConfig = getDefaultClientConfig();
|
private config: ClientConfig = getDefaultClientConfig();
|
||||||
private genesisCommittee: Uint8Array[] = this.config.genesis.committee.map(
|
private genesisCommittee: Uint8Array[] = this.config.genesis.committee.map(
|
||||||
(pk) => fromHexString(pk)
|
(pk) => fromHexString(pk),
|
||||||
);
|
);
|
||||||
private genesisPeriod = computeSyncPeriodAtSlot(this.config.genesis.slot);
|
private genesisPeriod = computeSyncPeriodAtSlot(this.config.genesis.slot);
|
||||||
private genesisTime = this.config.genesis.time;
|
private genesisTime = this.config.genesis.time;
|
||||||
|
@ -56,7 +59,7 @@ export default class Client {
|
||||||
prover: IProver,
|
prover: IProver,
|
||||||
store: IStore,
|
store: IStore,
|
||||||
beaconUrl: string,
|
beaconUrl: string,
|
||||||
rpcUrl: string
|
rpcUrl: string,
|
||||||
) {
|
) {
|
||||||
this.prover = prover;
|
this.prover = prover;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
|
@ -67,7 +70,7 @@ export default class Client {
|
||||||
private _provider?: VerifyingProvider;
|
private _provider?: VerifyingProvider;
|
||||||
|
|
||||||
get provider(): VerifyingProvider {
|
get provider(): VerifyingProvider {
|
||||||
return this._provider;
|
return this._provider as VerifyingProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _latestPeriod: number = -1;
|
private _latestPeriod: number = -1;
|
||||||
|
@ -102,7 +105,7 @@ export default class Client {
|
||||||
const provider = new VerifyingProvider(
|
const provider = new VerifyingProvider(
|
||||||
this.rpcUrl,
|
this.rpcUrl,
|
||||||
blockNumber,
|
blockNumber,
|
||||||
blockhash
|
blockhash,
|
||||||
);
|
);
|
||||||
this._provider = provider;
|
this._provider = provider;
|
||||||
}
|
}
|
||||||
|
@ -111,25 +114,25 @@ export default class Client {
|
||||||
if (ei && ei.blockhash !== this.latestBlockHash) {
|
if (ei && ei.blockhash !== this.latestBlockHash) {
|
||||||
this.latestBlockHash = ei.blockhash;
|
this.latestBlockHash = ei.blockhash;
|
||||||
}
|
}
|
||||||
this._provider.update(ei.blockhash, ei.blockNumber);
|
this._provider.update(ei?.blockhash as string, ei?.blockNumber as bigint);
|
||||||
}
|
}
|
||||||
|
|
||||||
async syncProver(
|
async syncProver(
|
||||||
startPeriod: number,
|
startPeriod: number,
|
||||||
currentPeriod: number,
|
currentPeriod: number,
|
||||||
startCommittee: Uint8Array[]
|
startCommittee: Uint8Array[],
|
||||||
): Promise<{ syncCommittee: Uint8Array[]; period: number }> {
|
): Promise<{ syncCommittee: Uint8Array[]; period: number }> {
|
||||||
for (let period = startPeriod; period < currentPeriod; period += 1) {
|
for (let period = startPeriod; period < currentPeriod; period += 1) {
|
||||||
try {
|
try {
|
||||||
const update = await this.prover.getSyncUpdate(
|
const update = await this.prover.getSyncUpdate(
|
||||||
period,
|
period,
|
||||||
currentPeriod,
|
currentPeriod,
|
||||||
DEFAULT_BATCH_SIZE
|
DEFAULT_BATCH_SIZE,
|
||||||
);
|
);
|
||||||
const validOrCommittee = await this.syncUpdateVerifyGetCommittee(
|
const validOrCommittee = await this.syncUpdateVerifyGetCommittee(
|
||||||
startCommittee,
|
startCommittee,
|
||||||
period,
|
period,
|
||||||
update
|
update,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!(validOrCommittee as boolean)) {
|
if (!(validOrCommittee as boolean)) {
|
||||||
|
@ -160,7 +163,7 @@ export default class Client {
|
||||||
|
|
||||||
public getCurrentPeriod(): number {
|
public getCurrentPeriod(): number {
|
||||||
return computeSyncPeriodAtSlot(
|
return computeSyncPeriodAtSlot(
|
||||||
getCurrentSlot(this.config.chainConfig, this.genesisTime)
|
getCurrentSlot(this.config.chainConfig, this.genesisTime),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,12 +173,12 @@ export default class Client {
|
||||||
|
|
||||||
async optimisticUpdateVerify(
|
async optimisticUpdateVerify(
|
||||||
committee: Uint8Array[],
|
committee: Uint8Array[],
|
||||||
update: OptimisticUpdate
|
update: OptimisticUpdate,
|
||||||
): Promise<VerifyWithReason> {
|
): Promise<VerifyWithReason> {
|
||||||
try {
|
try {
|
||||||
const { attestedHeader: header, syncAggregate } = update;
|
const { attestedHeader: header, syncAggregate } = update;
|
||||||
const headerBlockRoot = phase0.ssz.BeaconBlockHeader.hashTreeRoot(
|
const headerBlockRoot = phase0.ssz.BeaconBlockHeader.hashTreeRoot(
|
||||||
header.beacon
|
header.beacon,
|
||||||
);
|
);
|
||||||
const committeeFast = this.deserializeSyncCommittee(committee);
|
const committeeFast = this.deserializeSyncCommittee(committee);
|
||||||
try {
|
try {
|
||||||
|
@ -184,7 +187,7 @@ export default class Client {
|
||||||
committeeFast,
|
committeeFast,
|
||||||
syncAggregate,
|
syncAggregate,
|
||||||
headerBlockRoot,
|
headerBlockRoot,
|
||||||
header.beacon.slot
|
header.beacon.slot,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { correct: false, reason: "invalid signatures" };
|
return { correct: false, reason: "invalid signatures" };
|
||||||
|
@ -209,27 +212,27 @@ export default class Client {
|
||||||
|
|
||||||
private isValidLightClientHeader(
|
private isValidLightClientHeader(
|
||||||
config: ChainForkConfig,
|
config: ChainForkConfig,
|
||||||
header: allForks.LightClientHeader
|
header: allForks.LightClientHeader,
|
||||||
): boolean {
|
): boolean {
|
||||||
return isValidMerkleBranch(
|
return isValidMerkleBranch(
|
||||||
config
|
config
|
||||||
.getExecutionForkTypes(header.beacon.slot)
|
.getExecutionForkTypes(header.beacon.slot)
|
||||||
.ExecutionPayloadHeader.hashTreeRoot(
|
.ExecutionPayloadHeader.hashTreeRoot(
|
||||||
(header as capella.LightClientHeader).execution
|
(header as capella.LightClientHeader).execution,
|
||||||
),
|
),
|
||||||
(header as capella.LightClientHeader).executionBranch,
|
(header as capella.LightClientHeader).executionBranch,
|
||||||
EXECUTION_PAYLOAD_DEPTH,
|
EXECUTION_PAYLOAD_DEPTH,
|
||||||
EXECUTION_PAYLOAD_INDEX,
|
EXECUTION_PAYLOAD_INDEX,
|
||||||
header.beacon.bodyRoot
|
header.beacon.bodyRoot,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getNextValidExecutionInfo(
|
public async getNextValidExecutionInfo(
|
||||||
retry: number = 10
|
retry: number = 10,
|
||||||
): Promise<ExecutionInfo> {
|
): Promise<ExecutionInfo> {
|
||||||
if (retry === 0)
|
if (retry === 0)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"no valid execution payload found in the given retry limit"
|
"no valid execution payload found in the given retry limit",
|
||||||
);
|
);
|
||||||
const ei = await this.getLatestExecution();
|
const ei = await this.getLatestExecution();
|
||||||
if (ei) return ei;
|
if (ei) return ei;
|
||||||
|
@ -240,23 +243,23 @@ export default class Client {
|
||||||
|
|
||||||
public async getExecutionFromBlockRoot(
|
public async getExecutionFromBlockRoot(
|
||||||
slot: bigint,
|
slot: bigint,
|
||||||
expectedBlockRoot: Bytes32
|
expectedBlockRoot: Bytes32,
|
||||||
): Promise<ExecutionInfo> {
|
): Promise<ExecutionInfo> {
|
||||||
const res = await handleGETRequest(
|
const res = await handleGETRequest(
|
||||||
`${this.beaconChainAPIURL}/eth/v2/beacon/blocks/${slot}`
|
`${this.beaconChainAPIURL}/eth/v2/beacon/blocks/${slot}`,
|
||||||
);
|
);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
throw Error(`fetching block failed`);
|
throw Error(`fetching block failed`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockJSON = res.data.message.body;
|
const blockJSON = res.data.message.body;
|
||||||
const block = bellatrix.ssz.BeaconBlockBody.fromJson(blockJSON);
|
const block = capella.ssz.BeaconBlockBody.fromJson(blockJSON);
|
||||||
const blockRoot = toHexString(
|
const blockRoot = toHexString(
|
||||||
bellatrix.ssz.BeaconBlockBody.hashTreeRoot(block)
|
capella.ssz.BeaconBlockBody.hashTreeRoot(block),
|
||||||
);
|
);
|
||||||
if (blockRoot !== expectedBlockRoot) {
|
if (blockRoot !== expectedBlockRoot) {
|
||||||
throw Error(
|
throw Error(
|
||||||
`block provided by the beacon chain api doesn't match the expected block root`
|
`block provided by the beacon chain api doesn't match the expected block root`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,13 +295,13 @@ export default class Client {
|
||||||
let startPeriod = this.genesisPeriod;
|
let startPeriod = this.genesisPeriod;
|
||||||
let startCommittee = this.genesisCommittee;
|
let startCommittee = this.genesisCommittee;
|
||||||
console.log(
|
console.log(
|
||||||
`Sync started from period(${startPeriod}) to period(${currentPeriod})`
|
`Sync started from period(${startPeriod}) to period(${currentPeriod})`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { syncCommittee, period } = await this.syncProver(
|
const { syncCommittee, period } = await this.syncProver(
|
||||||
startPeriod,
|
startPeriod,
|
||||||
currentPeriod,
|
currentPeriod,
|
||||||
startCommittee
|
startCommittee,
|
||||||
);
|
);
|
||||||
if (period === currentPeriod) {
|
if (period === currentPeriod) {
|
||||||
return syncCommittee;
|
return syncCommittee;
|
||||||
|
@ -316,7 +319,7 @@ export default class Client {
|
||||||
const { syncCommittee, period } = await this.syncProver(
|
const { syncCommittee, period } = await this.syncProver(
|
||||||
startPeriod,
|
startPeriod,
|
||||||
currentPeriod,
|
currentPeriod,
|
||||||
startCommittee
|
startCommittee as Uint8Array[],
|
||||||
);
|
);
|
||||||
if (period === currentPeriod) {
|
if (period === currentPeriod) {
|
||||||
return syncCommittee;
|
return syncCommittee;
|
||||||
|
@ -327,14 +330,14 @@ export default class Client {
|
||||||
protected async syncUpdateVerifyGetCommittee(
|
protected async syncUpdateVerifyGetCommittee(
|
||||||
prevCommittee: Uint8Array[],
|
prevCommittee: Uint8Array[],
|
||||||
period: number,
|
period: number,
|
||||||
update: LightClientUpdate
|
update: LightClientUpdate,
|
||||||
): Promise<false | Uint8Array[]> {
|
): Promise<false | Uint8Array[]> {
|
||||||
const updatePeriod = computeSyncPeriodAtSlot(
|
const updatePeriod = computeSyncPeriodAtSlot(
|
||||||
update.attestedHeader.beacon.slot
|
update.attestedHeader.beacon.slot,
|
||||||
);
|
);
|
||||||
if (period !== updatePeriod) {
|
if (period !== updatePeriod) {
|
||||||
console.error(
|
console.error(
|
||||||
`Expected update with period ${period}, but recieved ${updatePeriod}`
|
`Expected update with period ${period}, but recieved ${updatePeriod}`,
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -345,7 +348,7 @@ export default class Client {
|
||||||
await assertValidLightClientUpdate(
|
await assertValidLightClientUpdate(
|
||||||
this.config.chainConfig,
|
this.config.chainConfig,
|
||||||
prevCommitteeFast,
|
prevCommitteeFast,
|
||||||
update
|
update,
|
||||||
);
|
);
|
||||||
return update.nextSyncCommittee.pubkeys;
|
return update.nextSyncCommittee.pubkeys;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -356,15 +359,15 @@ export default class Client {
|
||||||
|
|
||||||
protected async getLatestExecution(): Promise<ExecutionInfo | null> {
|
protected async getLatestExecution(): Promise<ExecutionInfo | null> {
|
||||||
const updateJSON = await handleGETRequest(
|
const updateJSON = await handleGETRequest(
|
||||||
`${this.beaconChainAPIURL}/eth/v1/beacon/light_client/optimistic_update`
|
`${this.beaconChainAPIURL}/eth/v1/beacon/light_client/optimistic_update`,
|
||||||
);
|
);
|
||||||
if (!updateJSON) {
|
if (!updateJSON) {
|
||||||
throw Error(`fetching optimistic update failed`);
|
throw Error(`fetching optimistic update failed`);
|
||||||
}
|
}
|
||||||
const update = this.optimisticUpdateFromJSON(updateJSON.data);
|
const update = this.optimisticUpdateFromJSON(updateJSON.data);
|
||||||
const verify = await this.optimisticUpdateVerify(
|
const verify = await this.optimisticUpdateVerify(
|
||||||
this.latestCommittee,
|
this.latestCommittee as Uint8Array[],
|
||||||
update
|
update,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!verify.correct) {
|
if (!verify.correct) {
|
||||||
|
@ -374,12 +377,12 @@ export default class Client {
|
||||||
}
|
}
|
||||||
return this.getExecutionFromBlockRoot(
|
return this.getExecutionFromBlockRoot(
|
||||||
updateJSON.data.attested_header.beacon.slot,
|
updateJSON.data.attested_header.beacon.slot,
|
||||||
updateJSON.data.attested_header.beacon.body_root
|
updateJSON.data.attested_header.beacon.body_root,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private deserializeSyncCommittee(
|
private deserializeSyncCommittee(
|
||||||
syncCommittee: Uint8Array[]
|
syncCommittee: Uint8Array[],
|
||||||
): SyncCommitteeFast {
|
): SyncCommitteeFast {
|
||||||
const pubkeys = this.deserializePubkeys(syncCommittee);
|
const pubkeys = this.deserializePubkeys(syncCommittee);
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -522,7 +522,7 @@ export const mainnetConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BEACON_SYNC_SUPER_MAJORITY = Math.ceil(
|
export const BEACON_SYNC_SUPER_MAJORITY = Math.ceil(
|
||||||
(BEACON_SYNC_COMMITTEE_SIZE * 2) / 3
|
(BEACON_SYNC_COMMITTEE_SIZE * 2) / 3,
|
||||||
);
|
);
|
||||||
|
|
||||||
// These are the rough numbers from benchmark experiments
|
// These are the rough numbers from benchmark experiments
|
||||||
|
|
|
@ -5,7 +5,7 @@ export interface IProver {
|
||||||
getSyncUpdate(
|
getSyncUpdate(
|
||||||
period: number,
|
period: number,
|
||||||
currentPeriod: number,
|
currentPeriod: number,
|
||||||
cacheCount: number
|
cacheCount: number,
|
||||||
): AsyncOrSync<LightClientUpdate>;
|
): AsyncOrSync<LightClientUpdate>;
|
||||||
}
|
}
|
||||||
export interface IStore {
|
export interface IStore {
|
||||||
|
|
|
@ -18,7 +18,7 @@ export class MemoryStore implements IStore {
|
||||||
update: LightClientUpdateSSZ.serialize(update),
|
update: LightClientUpdateSSZ.serialize(update),
|
||||||
nextCommittee: CommitteeSSZ.serialize(update.nextSyncCommittee.pubkeys),
|
nextCommittee: CommitteeSSZ.serialize(update.nextSyncCommittee.pubkeys),
|
||||||
nextCommitteeHash: digest(
|
nextCommitteeHash: digest(
|
||||||
concatUint8Array(update.nextSyncCommittee.pubkeys)
|
concatUint8Array(update.nextSyncCommittee.pubkeys),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,10 @@ export default class Prover implements IProver {
|
||||||
|
|
||||||
async _getSyncUpdates(
|
async _getSyncUpdates(
|
||||||
startPeriod: number,
|
startPeriod: number,
|
||||||
maxCount: number
|
maxCount: number,
|
||||||
): Promise<LightClientUpdate[]> {
|
): Promise<LightClientUpdate[]> {
|
||||||
const res = await handleGETRequest(
|
const res = await handleGETRequest(
|
||||||
`${this.serverUrl}/eth/v1/beacon/light_client/updates?start_period=${startPeriod}&count=${maxCount}`,
|
`${this.serverUrl}/eth/v1/beacon/light_client/updates?start_period=${startPeriod}&count=${maxCount}`,
|
||||||
false
|
|
||||||
);
|
);
|
||||||
return res.map((u: any) => altair.ssz.LightClientUpdate.fromJson(u.data));
|
return res.map((u: any) => altair.ssz.LightClientUpdate.fromJson(u.data));
|
||||||
}
|
}
|
||||||
|
@ -25,7 +24,7 @@ export default class Prover implements IProver {
|
||||||
async getSyncUpdate(
|
async getSyncUpdate(
|
||||||
period: number,
|
period: number,
|
||||||
currentPeriod: number,
|
currentPeriod: number,
|
||||||
cacheCount: number
|
cacheCount: number,
|
||||||
): Promise<LightClientUpdate> {
|
): Promise<LightClientUpdate> {
|
||||||
const _cacheCount = Math.min(currentPeriod - period + 1, cacheCount);
|
const _cacheCount = Math.min(currentPeriod - period + 1, cacheCount);
|
||||||
if (!this.cachedSyncUpdate.has(period)) {
|
if (!this.cachedSyncUpdate.has(period)) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
export const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
|
export const ZERO_ADDR = "0x0000000000000000000000000000000000000000";
|
||||||
// TODO: set the correct gas limit!
|
// TODO: set the correct gas limit!
|
||||||
export const GAS_LIMIT = '0x1c9c380';
|
export const GAS_LIMIT = "0x1c9c380";
|
||||||
export const REQUEST_BATCH_SIZE = 10;
|
export const REQUEST_BATCH_SIZE = 10;
|
||||||
export const MAX_SOCKET = 10;
|
export const MAX_SOCKET = 10;
|
||||||
export const EMPTY_ACCOUNT_EXTCODEHASH =
|
export const EMPTY_ACCOUNT_EXTCODEHASH =
|
||||||
'0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470';
|
"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
|
||||||
export const MAX_BLOCK_HISTORY = BigInt(256);
|
export const MAX_BLOCK_HISTORY = BigInt(256);
|
||||||
export const MAX_BLOCK_FUTURE = BigInt(3);
|
export const MAX_BLOCK_FUTURE = BigInt(3);
|
||||||
export const DEFAULT_BLOCK_PARAMETER = 'latest';
|
export const DEFAULT_BLOCK_PARAMETER = "latest";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { JSONRPCErrorCode, JSONRPCErrorException } from 'json-rpc-2.0';
|
import { JSONRPCErrorCode, JSONRPCErrorException } from "json-rpc-2.0";
|
||||||
|
|
||||||
export class InternalError extends JSONRPCErrorException {
|
export class InternalError extends JSONRPCErrorException {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
|
|
|
@ -35,7 +35,10 @@ import {
|
||||||
MAX_BLOCK_FUTURE,
|
MAX_BLOCK_FUTURE,
|
||||||
DEFAULT_BLOCK_PARAMETER,
|
DEFAULT_BLOCK_PARAMETER,
|
||||||
} from "./constants.js";
|
} from "./constants.js";
|
||||||
import { headerDataFromWeb3Response, blockDataFromWeb3Response } from "./utils";
|
import {
|
||||||
|
headerDataFromWeb3Response,
|
||||||
|
blockDataFromWeb3Response,
|
||||||
|
} from "./utils.js";
|
||||||
|
|
||||||
import { keccak256 } from "ethers";
|
import { keccak256 } from "ethers";
|
||||||
import { InternalError, InvalidParamsError } from "./errors.js";
|
import { InternalError, InvalidParamsError } from "./errors.js";
|
||||||
|
@ -65,14 +68,14 @@ export class VerifyingProvider {
|
||||||
eth_estimateGas: this.estimateGas,
|
eth_estimateGas: this.estimateGas,
|
||||||
eth_sendRawTransaction: this.sendRawTransaction,
|
eth_sendRawTransaction: this.sendRawTransaction,
|
||||||
eth_getTransactionReceipt: this.getTransactionReceipt,
|
eth_getTransactionReceipt: this.getTransactionReceipt,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
providerURL: string,
|
providerURL: string,
|
||||||
blockNumber: bigint | number,
|
blockNumber: bigint | number,
|
||||||
blockHash: Bytes32,
|
blockHash: Bytes32,
|
||||||
chain: bigint | Chain = Chain.Mainnet
|
chain: bigint | Chain = Chain.Mainnet,
|
||||||
) {
|
) {
|
||||||
this._rpc = new RPC({ URL: providerURL });
|
this._rpc = new RPC({ URL: providerURL });
|
||||||
this.common = new Common({
|
this.common = new Common({
|
||||||
|
@ -96,7 +99,7 @@ export class VerifyingProvider {
|
||||||
this.blockHashes[blockNumberHex] !== blockHash
|
this.blockHashes[blockNumberHex] !== blockHash
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
"Overriding an existing verified blockhash. Possibly the chain had a reorg"
|
"Overriding an existing verified blockhash. Possibly the chain had a reorg",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const latestBlockNumber = this.latestBlockNumber;
|
const latestBlockNumber = this.latestBlockNumber;
|
||||||
|
@ -128,7 +131,7 @@ export class VerifyingProvider {
|
||||||
|
|
||||||
private async getBalance(
|
private async getBalance(
|
||||||
addressHex: AddressHex,
|
addressHex: AddressHex,
|
||||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||||
) {
|
) {
|
||||||
const header = await this.getBlockHeader(blockOpt);
|
const header = await this.getBlockHeader(blockOpt);
|
||||||
const address = Address.fromString(addressHex);
|
const address = Address.fromString(addressHex);
|
||||||
|
@ -143,7 +146,7 @@ export class VerifyingProvider {
|
||||||
address,
|
address,
|
||||||
[],
|
[],
|
||||||
header.stateRoot,
|
header.stateRoot,
|
||||||
proof
|
proof,
|
||||||
);
|
);
|
||||||
if (!isAccountCorrect) {
|
if (!isAccountCorrect) {
|
||||||
throw new InternalError("Invalid account proof provided by the RPC");
|
throw new InternalError("Invalid account proof provided by the RPC");
|
||||||
|
@ -162,10 +165,10 @@ export class VerifyingProvider {
|
||||||
|
|
||||||
private async getCode(
|
private async getCode(
|
||||||
addressHex: AddressHex,
|
addressHex: AddressHex,
|
||||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||||
): Promise<HexString> {
|
): Promise<HexString> {
|
||||||
const header = await this.getBlockHeader(blockOpt);
|
const header = await this.getBlockHeader(blockOpt);
|
||||||
const res = await this._rpc.requestBatch([
|
const res: any[] = await this._rpc.requestBatch([
|
||||||
{
|
{
|
||||||
method: "eth_getProof",
|
method: "eth_getProof",
|
||||||
params: [addressHex, [], bigIntToHex(header.number)],
|
params: [addressHex, [], bigIntToHex(header.number)],
|
||||||
|
@ -186,7 +189,7 @@ export class VerifyingProvider {
|
||||||
address,
|
address,
|
||||||
[],
|
[],
|
||||||
header.stateRoot,
|
header.stateRoot,
|
||||||
accountProof
|
accountProof,
|
||||||
);
|
);
|
||||||
if (!isAccountCorrect) {
|
if (!isAccountCorrect) {
|
||||||
throw new InternalError(`invalid account proof provided by the RPC`);
|
throw new InternalError(`invalid account proof provided by the RPC`);
|
||||||
|
@ -194,11 +197,11 @@ export class VerifyingProvider {
|
||||||
|
|
||||||
const isCodeCorrect = await this.verifyCodeHash(
|
const isCodeCorrect = await this.verifyCodeHash(
|
||||||
code,
|
code,
|
||||||
accountProof.codeHash
|
accountProof.codeHash,
|
||||||
);
|
);
|
||||||
if (!isCodeCorrect) {
|
if (!isCodeCorrect) {
|
||||||
throw new InternalError(
|
throw new InternalError(
|
||||||
`code provided by the RPC doesn't match the account's codeHash`
|
`code provided by the RPC doesn't match the account's codeHash`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +210,7 @@ export class VerifyingProvider {
|
||||||
|
|
||||||
private async getTransactionCount(
|
private async getTransactionCount(
|
||||||
addressHex: AddressHex,
|
addressHex: AddressHex,
|
||||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||||
): Promise<HexString> {
|
): Promise<HexString> {
|
||||||
const header = await this.getBlockHeader(blockOpt);
|
const header = await this.getBlockHeader(blockOpt);
|
||||||
const address = Address.fromString(addressHex);
|
const address = Address.fromString(addressHex);
|
||||||
|
@ -223,7 +226,7 @@ export class VerifyingProvider {
|
||||||
address,
|
address,
|
||||||
[],
|
[],
|
||||||
header.stateRoot,
|
header.stateRoot,
|
||||||
proof
|
proof,
|
||||||
);
|
);
|
||||||
if (!isAccountCorrect) {
|
if (!isAccountCorrect) {
|
||||||
throw new InternalError(`invalid account proof provided by the RPC`);
|
throw new InternalError(`invalid account proof provided by the RPC`);
|
||||||
|
@ -234,7 +237,7 @@ export class VerifyingProvider {
|
||||||
|
|
||||||
private async call(
|
private async call(
|
||||||
transaction: RPCTx,
|
transaction: RPCTx,
|
||||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
this.validateTx(transaction);
|
this.validateTx(transaction);
|
||||||
|
@ -274,7 +277,7 @@ export class VerifyingProvider {
|
||||||
|
|
||||||
private async estimateGas(
|
private async estimateGas(
|
||||||
transaction: RPCTx,
|
transaction: RPCTx,
|
||||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
this.validateTx(transaction);
|
this.validateTx(transaction);
|
||||||
|
@ -293,7 +296,7 @@ export class VerifyingProvider {
|
||||||
? 2
|
? 2
|
||||||
: transaction.accessList
|
: transaction.accessList
|
||||||
? 1
|
? 1
|
||||||
: 0
|
: 0,
|
||||||
);
|
);
|
||||||
if (txType == BigInt(2)) {
|
if (txType == BigInt(2)) {
|
||||||
transaction.maxFeePerGas =
|
transaction.maxFeePerGas =
|
||||||
|
@ -359,7 +362,7 @@ export class VerifyingProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getTransactionReceipt(
|
private async getTransactionReceipt(
|
||||||
txHash: Bytes32
|
txHash: Bytes32,
|
||||||
): Promise<JSONRPCReceipt | null> {
|
): Promise<JSONRPCReceipt | null> {
|
||||||
const { result: receipt, success } = await this._rpc.request({
|
const { result: receipt, success } = await this._rpc.request({
|
||||||
method: "eth_getTransactionReceipt",
|
method: "eth_getTransactionReceipt",
|
||||||
|
@ -371,7 +374,7 @@ export class VerifyingProvider {
|
||||||
const header = await this.getBlockHeader(receipt.blockNumber);
|
const header = await this.getBlockHeader(receipt.blockNumber);
|
||||||
const block = await this.getBlock(header);
|
const block = await this.getBlock(header);
|
||||||
const index = block.transactions.findIndex(
|
const index = block.transactions.findIndex(
|
||||||
(tx) => bufferToHex(tx.hash()) === txHash.toLowerCase()
|
(tx) => bufferToHex(tx.hash()) === txHash.toLowerCase(),
|
||||||
);
|
);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
throw new InternalError("the recipt provided by the RPC is invalid");
|
throw new InternalError("the recipt provided by the RPC is invalid");
|
||||||
|
@ -462,7 +465,7 @@ export class VerifyingProvider {
|
||||||
}
|
}
|
||||||
const responses = _.chunk(
|
const responses = _.chunk(
|
||||||
rawResponse.map((r: any) => r.result),
|
rawResponse.map((r: any) => r.result),
|
||||||
2
|
2,
|
||||||
) as [AccountResponse, CodeResponse][];
|
) as [AccountResponse, CodeResponse][];
|
||||||
|
|
||||||
for (let i = 0; i < accessList.length; i++) {
|
for (let i = 0; i < accessList.length; i++) {
|
||||||
|
@ -480,7 +483,7 @@ export class VerifyingProvider {
|
||||||
address,
|
address,
|
||||||
storageKeys,
|
storageKeys,
|
||||||
header.stateRoot,
|
header.stateRoot,
|
||||||
accountProof
|
accountProof,
|
||||||
);
|
);
|
||||||
if (!isAccountCorrect) {
|
if (!isAccountCorrect) {
|
||||||
throw new InternalError(`invalid account proof provided by the RPC`);
|
throw new InternalError(`invalid account proof provided by the RPC`);
|
||||||
|
@ -489,7 +492,7 @@ export class VerifyingProvider {
|
||||||
const isCodeCorrect = await this.verifyCodeHash(code, codeHash);
|
const isCodeCorrect = await this.verifyCodeHash(code, codeHash);
|
||||||
if (!isCodeCorrect) {
|
if (!isCodeCorrect) {
|
||||||
throw new InternalError(
|
throw new InternalError(
|
||||||
`code provided by the RPC doesn't match the account's codeHash`
|
`code provided by the RPC doesn't match the account's codeHash`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,7 +508,7 @@ export class VerifyingProvider {
|
||||||
await vm.stateManager.putContractStorage(
|
await vm.stateManager.putContractStorage(
|
||||||
address,
|
address,
|
||||||
setLengthLeft(toBuffer(storageAccess.key), 32),
|
setLengthLeft(toBuffer(storageAccess.key), 32),
|
||||||
setLengthLeft(toBuffer(storageAccess.value), 32)
|
setLengthLeft(toBuffer(storageAccess.value), 32),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,7 +539,7 @@ export class VerifyingProvider {
|
||||||
throw new InvalidParamsError("specified block is too far in future");
|
throw new InvalidParamsError("specified block is too far in future");
|
||||||
} else if (blockNumber + MAX_BLOCK_HISTORY < this.latestBlockNumber) {
|
} else if (blockNumber + MAX_BLOCK_HISTORY < this.latestBlockNumber) {
|
||||||
throw new InvalidParamsError(
|
throw new InvalidParamsError(
|
||||||
`specified block cannot older that ${MAX_BLOCK_HISTORY}`
|
`specified block cannot older that ${MAX_BLOCK_HISTORY}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return blockNumber;
|
return blockNumber;
|
||||||
|
@ -575,7 +578,7 @@ export class VerifyingProvider {
|
||||||
|
|
||||||
if (!header.hash().equals(toBuffer(blockHash))) {
|
if (!header.hash().equals(toBuffer(blockHash))) {
|
||||||
throw new InternalError(
|
throw new InternalError(
|
||||||
`blockhash doesn't match the blockInfo provided by the RPC`
|
`blockhash doesn't match the blockInfo provided by the RPC`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.blockHeaders[blockHash] = header;
|
this.blockHeaders[blockHash] = header;
|
||||||
|
@ -587,14 +590,14 @@ export class VerifyingProvider {
|
||||||
address: Address,
|
address: Address,
|
||||||
storageKeys: Bytes32[],
|
storageKeys: Bytes32[],
|
||||||
stateRoot: Buffer,
|
stateRoot: Buffer,
|
||||||
proof: GetProof
|
proof: GetProof,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const trie = new Trie();
|
const trie = new Trie();
|
||||||
const key = keccak256(address.toString());
|
const key = keccak256(address.toString());
|
||||||
const expectedAccountRLP = await trie.verifyProof(
|
const expectedAccountRLP = await trie.verifyProof(
|
||||||
stateRoot,
|
stateRoot,
|
||||||
toBuffer(key),
|
toBuffer(key),
|
||||||
proof.accountProof.map((a) => toBuffer(a))
|
proof.accountProof.map((a) => toBuffer(a)),
|
||||||
);
|
);
|
||||||
const account = Account.fromAccountData({
|
const account = Account.fromAccountData({
|
||||||
nonce: BigInt(proof.nonce),
|
nonce: BigInt(proof.nonce),
|
||||||
|
@ -610,12 +613,12 @@ export class VerifyingProvider {
|
||||||
for (let i = 0; i < storageKeys.length; i++) {
|
for (let i = 0; i < storageKeys.length; i++) {
|
||||||
const sp = proof.storageProof[i];
|
const sp = proof.storageProof[i];
|
||||||
const key = keccak256(
|
const key = keccak256(
|
||||||
bufferToHex(setLengthLeft(toBuffer(storageKeys[i]), 32))
|
bufferToHex(setLengthLeft(toBuffer(storageKeys[i]), 32)),
|
||||||
);
|
);
|
||||||
const expectedStorageRLP = await trie.verifyProof(
|
const expectedStorageRLP = await trie.verifyProof(
|
||||||
toBuffer(proof.storageHash),
|
toBuffer(proof.storageHash),
|
||||||
toBuffer(key),
|
toBuffer(key),
|
||||||
sp.proof.map((a) => toBuffer(a))
|
sp.proof.map((a) => toBuffer(a)),
|
||||||
);
|
);
|
||||||
const isStorageValid =
|
const isStorageValid =
|
||||||
(!expectedStorageRLP && sp.value === "0x0") ||
|
(!expectedStorageRLP && sp.value === "0x0") ||
|
||||||
|
@ -648,7 +651,7 @@ export class VerifyingProvider {
|
||||||
BigInt(tx.maxPriorityFeePerGas) > BigInt(tx.maxFeePerGas)
|
BigInt(tx.maxPriorityFeePerGas) > BigInt(tx.maxFeePerGas)
|
||||||
) {
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`maxPriorityFeePerGas (${tx.maxPriorityFeePerGas.toString()}) is bigger than maxFeePerGas (${tx.maxFeePerGas.toString()})`
|
`maxPriorityFeePerGas (${tx.maxPriorityFeePerGas.toString()}) is bigger than maxFeePerGas (${tx.maxFeePerGas.toString()})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -668,13 +671,13 @@ export class VerifyingProvider {
|
||||||
|
|
||||||
if (!block.header.hash().equals(header.hash())) {
|
if (!block.header.hash().equals(header.hash())) {
|
||||||
throw new InternalError(
|
throw new InternalError(
|
||||||
`BN(${header.number}): blockhash doest match the blockData provided by the RPC`
|
`BN(${header.number}): blockhash doest match the blockData provided by the RPC`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await block.validateTransactionsTrie())) {
|
if (!(await block.validateTransactionsTrie())) {
|
||||||
throw new InternalError(
|
throw new InternalError(
|
||||||
`transactionTree doesn't match the transactions provided by the RPC`
|
`transactionTree doesn't match the transactions provided by the RPC`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,7 +700,7 @@ export class VerifyingProvider {
|
||||||
this.blockHashes[parentBlockNumberHex] !== parentBlockHash
|
this.blockHashes[parentBlockNumberHex] !== parentBlockHash
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
"Overriding an existing verified blockhash. Possibly the chain had a reorg"
|
"Overriding an existing verified blockhash. Possibly the chain had a reorg",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.blockHashes[parentBlockNumberHex] = parentBlockHash;
|
this.blockHashes[parentBlockNumberHex] = parentBlockHash;
|
||||||
|
|
|
@ -56,7 +56,7 @@ export class RPC {
|
||||||
throw new Error("method not supported by the provider");
|
throw new Error("method not supported by the provider");
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = [];
|
const res: RPCResponse[] = [];
|
||||||
for (const request of requests) {
|
for (const request of requests) {
|
||||||
const r = await this._retryRequest(request);
|
const r = await this._retryRequest(request);
|
||||||
res.push(r);
|
res.push(r);
|
||||||
|
@ -78,7 +78,7 @@ export class RPC {
|
||||||
method: request.method,
|
method: request.method,
|
||||||
params: request.params,
|
params: request.params,
|
||||||
};
|
};
|
||||||
const hash = this._pluginApi.util.crypto
|
const hash = (this._pluginApi as PluginAPI).util.crypto
|
||||||
.createHash(stringify(tempRequest))
|
.createHash(stringify(tempRequest))
|
||||||
.toString("hex");
|
.toString("hex");
|
||||||
// this._cache.set(hash, response);
|
// this._cache.set(hash, response);
|
||||||
|
@ -97,7 +97,7 @@ export class RPC {
|
||||||
|
|
||||||
private async _retryRequest(
|
private async _retryRequest(
|
||||||
_request: RPCRequest,
|
_request: RPCRequest,
|
||||||
retry = 5
|
retry = 5,
|
||||||
): Promise<RPCResponse> {
|
): Promise<RPCResponse> {
|
||||||
const request = {
|
const request = {
|
||||||
..._request,
|
..._request,
|
||||||
|
@ -114,8 +114,8 @@ export class RPC {
|
||||||
`RPC batch request failed after maximum retries: ${JSON.stringify(
|
`RPC batch request failed after maximum retries: ${JSON.stringify(
|
||||||
request,
|
request,
|
||||||
null,
|
null,
|
||||||
2
|
2,
|
||||||
)} ${JSON.stringify(res, null, 2)}`
|
)} ${JSON.stringify(res, null, 2)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ export class RPC {
|
||||||
return Math.floor(Math.random() * 2 ** 64).toFixed();
|
return Math.floor(Math.random() * 2 ** 64).toFixed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCachedRequest(request: RPCRequest): RPCResponse | null {
|
/* public getCachedRequest(request: RPCRequest): RPCResponse | null {
|
||||||
const hash = this.hashRequest(request);
|
const hash = this.hashRequest(request);
|
||||||
|
|
||||||
if (this.cache.has(hash)) {
|
if (this.cache.has(hash)) {
|
||||||
|
@ -135,7 +135,7 @@ export class RPC {
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
public deleteCachedRequest(request: RPCRequest): void {
|
public deleteCachedRequest(request: RPCRequest): void {
|
||||||
const hash = this.hashRequest(request);
|
const hash = this.hashRequest(request);
|
||||||
|
@ -149,7 +149,7 @@ export class RPC {
|
||||||
params: request.params,
|
params: request.params,
|
||||||
};
|
};
|
||||||
|
|
||||||
return this._pluginApi.util.crypto
|
return (this._pluginApi as PluginAPI).util.crypto
|
||||||
.createHash(stringify(tempRequest))
|
.createHash(stringify(tempRequest))
|
||||||
.toString("hex");
|
.toString("hex");
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ export function headerDataFromWeb3Response(blockInfo: any): HeaderData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function txDataFromWeb3Response(
|
export function txDataFromWeb3Response(
|
||||||
txInfo: any
|
txInfo: any,
|
||||||
): TxData | AccessListEIP2930TxData | FeeMarketEIP1559TxData {
|
): TxData | AccessListEIP2930TxData | FeeMarketEIP1559TxData {
|
||||||
return {
|
return {
|
||||||
...txInfo,
|
...txInfo,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { InvalidParamsError } from './errors';
|
import { InvalidParamsError } from "./errors.js";
|
||||||
|
|
||||||
// Most of the validations are taken from:
|
// Most of the validations are taken from:
|
||||||
// https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/client/lib/rpc/validation.ts
|
// https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/client/lib/rpc/validation.ts
|
||||||
|
@ -30,13 +30,13 @@ export const validators = {
|
||||||
* @param index index of parameter
|
* @param index index of parameter
|
||||||
*/
|
*/
|
||||||
hex(params: any[], index: number) {
|
hex(params: any[], index: number) {
|
||||||
if (typeof params[index] !== 'string') {
|
if (typeof params[index] !== "string") {
|
||||||
throw new InvalidParamsError(
|
throw new InvalidParamsError(
|
||||||
`invalid argument ${index}: argument must be a hex string`,
|
`invalid argument ${index}: argument must be a hex string`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params[index].substr(0, 2) !== '0x') {
|
if (params[index].substr(0, 2) !== "0x") {
|
||||||
throw new InvalidParamsError(
|
throw new InvalidParamsError(
|
||||||
`invalid argument ${index}: hex string without 0x prefix`,
|
`invalid argument ${index}: hex string without 0x prefix`,
|
||||||
);
|
);
|
||||||
|
@ -67,14 +67,14 @@ export const validators = {
|
||||||
blockOption(params: any[], index: number) {
|
blockOption(params: any[], index: number) {
|
||||||
const blockOption = params[index];
|
const blockOption = params[index];
|
||||||
|
|
||||||
if (typeof blockOption !== 'string') {
|
if (typeof blockOption !== "string") {
|
||||||
throw new InvalidParamsError(
|
throw new InvalidParamsError(
|
||||||
`invalid argument ${index}: argument must be a string`,
|
`invalid argument ${index}: argument must be a string`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (['latest', 'earliest', 'pending'].includes(blockOption)) {
|
if (["latest", "earliest", "pending"].includes(blockOption)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.hex([blockOption], 0);
|
return this.hex([blockOption], 0);
|
||||||
|
@ -91,7 +91,7 @@ export const validators = {
|
||||||
* @param index index of parameter
|
* @param index index of parameter
|
||||||
*/
|
*/
|
||||||
bool(params: any[], index: number) {
|
bool(params: any[], index: number) {
|
||||||
if (typeof params[index] !== 'boolean') {
|
if (typeof params[index] !== "boolean") {
|
||||||
throw new InvalidParamsError(
|
throw new InvalidParamsError(
|
||||||
`invalid argument ${index}: argument is not boolean`,
|
`invalid argument ${index}: argument is not boolean`,
|
||||||
);
|
);
|
||||||
|
@ -118,7 +118,7 @@ export const validators = {
|
||||||
transaction(params: any[], index: number) {
|
transaction(params: any[], index: number) {
|
||||||
const tx = params[index];
|
const tx = params[index];
|
||||||
|
|
||||||
if (typeof tx !== 'object') {
|
if (typeof tx !== "object") {
|
||||||
throw new InvalidParamsError(
|
throw new InvalidParamsError(
|
||||||
`invalid argument ${index}: argument must be an object`,
|
`invalid argument ${index}: argument must be an object`,
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,12 +11,12 @@ const MAX_BATCHSIZE = 10000;
|
||||||
export const LightClientUpdateSSZ = capella.ssz.LightClientUpdate;
|
export const LightClientUpdateSSZ = capella.ssz.LightClientUpdate;
|
||||||
export const LightClientUpdatesSSZ = new ListCompositeType(
|
export const LightClientUpdatesSSZ = new ListCompositeType(
|
||||||
LightClientUpdateSSZ as any,
|
LightClientUpdateSSZ as any,
|
||||||
MAX_BATCHSIZE
|
MAX_BATCHSIZE,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const CommitteeSSZ = new VectorCompositeType(
|
export const CommitteeSSZ = new VectorCompositeType(
|
||||||
new ByteVectorType(48),
|
new ByteVectorType(48),
|
||||||
BEACON_SYNC_COMMITTEE_SIZE
|
BEACON_SYNC_COMMITTEE_SIZE,
|
||||||
);
|
);
|
||||||
|
|
||||||
const HashSSZ = new ByteVectorType(32);
|
const HashSSZ = new ByteVectorType(32);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { fromHexString, toHexString } from "@chainsafe/ssz";
|
import { fromHexString } from "@chainsafe/ssz";
|
||||||
import bls from "@chainsafe/bls/switchable";
|
|
||||||
import { createBeaconConfig } from "@lodestar/config";
|
import { createBeaconConfig } from "@lodestar/config";
|
||||||
import { mainnetConfig } from "./constants.js";
|
import { mainnetConfig } from "./constants.js";
|
||||||
import { networksChainConfig } from "@lodestar/config/networks";
|
import { networksChainConfig } from "@lodestar/config/networks";
|
||||||
|
@ -19,7 +18,7 @@ export function concatUint8Array(data: Uint8Array[]) {
|
||||||
export function getDefaultClientConfig() {
|
export function getDefaultClientConfig() {
|
||||||
const chainConfig = createBeaconConfig(
|
const chainConfig = createBeaconConfig(
|
||||||
networksChainConfig.mainnet,
|
networksChainConfig.mainnet,
|
||||||
fromHexString(mainnetConfig.genesis_validator_root)
|
fromHexString(mainnetConfig.genesis_validator_root),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
genesis: {
|
genesis: {
|
||||||
|
@ -34,7 +33,7 @@ export function getDefaultClientConfig() {
|
||||||
|
|
||||||
export async function handleGETRequest(
|
export async function handleGETRequest(
|
||||||
url: string,
|
url: string,
|
||||||
retry: number = 3
|
retry: number = 3,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
if (retry < 0) {
|
if (retry < 0) {
|
||||||
throw Error(`GET request failed: ${url}`);
|
throw Error(`GET request failed: ${url}`);
|
||||||
|
|
22
src/index.ts
22
src/index.ts
|
@ -1,6 +1,4 @@
|
||||||
import type { Plugin, PluginAPI } from "@lumeweb/interface-relay";
|
import type { Plugin, PluginAPI } from "@lumeweb/interface-relay";
|
||||||
import fetch, { Request, RequestInit } from "node-fetch";
|
|
||||||
import NodeCache from "node-cache";
|
|
||||||
import { Client, Prover } from "./client/index.js";
|
import { Client, Prover } from "./client/index.js";
|
||||||
import { MemoryStore } from "./client/memory-store.js";
|
import { MemoryStore } from "./client/memory-store.js";
|
||||||
import { computeSyncPeriodAtSlot } from "@lodestar/light-client/utils";
|
import { computeSyncPeriodAtSlot } from "@lodestar/light-client/utils";
|
||||||
|
@ -55,7 +53,7 @@ const plugin: Plugin = {
|
||||||
api.registerMethod("consensus_committee_hashes", {
|
api.registerMethod("consensus_committee_hashes", {
|
||||||
cacheable: false,
|
cacheable: false,
|
||||||
async handler(
|
async handler(
|
||||||
request: ConsensusCommitteeHashesRequest
|
request: ConsensusCommitteeHashesRequest,
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
if (!(request?.start && typeof request.start == "number")) {
|
if (!(request?.start && typeof request.start == "number")) {
|
||||||
throw new Error('start required and must be a number"');
|
throw new Error('start required and must be a number"');
|
||||||
|
@ -91,7 +89,7 @@ const plugin: Plugin = {
|
||||||
api.registerMethod("consensus_committee_period", {
|
api.registerMethod("consensus_committee_period", {
|
||||||
cacheable: false,
|
cacheable: false,
|
||||||
async handler(
|
async handler(
|
||||||
request: ConsensusCommitteePeriodRequest
|
request: ConsensusCommitteePeriodRequest,
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
if (
|
if (
|
||||||
!(
|
!(
|
||||||
|
@ -110,7 +108,7 @@ const plugin: Plugin = {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
committee = store.getCommittee(
|
committee = store.getCommittee(
|
||||||
request.period === "latest" ? client.latestPeriod : request.period
|
request.period === "latest" ? client.latestPeriod : request.period,
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
await client.sync();
|
await client.sync();
|
||||||
|
@ -119,7 +117,9 @@ const plugin: Plugin = {
|
||||||
if (!committee) {
|
if (!committee) {
|
||||||
try {
|
try {
|
||||||
committee = store.getCommittee(
|
committee = store.getCommittee(
|
||||||
request.period === "latest" ? client.latestPeriod : request.period
|
request.period === "latest"
|
||||||
|
? client.latestPeriod
|
||||||
|
: request.period,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return e;
|
return e;
|
||||||
|
@ -160,7 +160,7 @@ const plugin: Plugin = {
|
||||||
cacheable: false,
|
cacheable: false,
|
||||||
async handler(): Promise<object> {
|
async handler(): Promise<object> {
|
||||||
return await handleGETRequest(
|
return await handleGETRequest(
|
||||||
`${CONSENSUS_RPC_URL}/eth/v1/beacon/light_client/optimistic_update`
|
`${CONSENSUS_RPC_URL}/eth/v1/beacon/light_client/optimistic_update`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -192,11 +192,11 @@ const plugin: Plugin = {
|
||||||
state = await prover.getSyncUpdate(
|
state = await prover.getSyncUpdate(
|
||||||
period,
|
period,
|
||||||
period,
|
period,
|
||||||
DEFAULT_BATCH_SIZE
|
DEFAULT_BATCH_SIZE,
|
||||||
);
|
);
|
||||||
await client.getExecutionFromBlockRoot(
|
await client.getExecutionFromBlockRoot(
|
||||||
request.block as any,
|
request.block as any,
|
||||||
toHexString(state.attestedHeader.beacon.bodyRoot)
|
toHexString(state.attestedHeader.beacon.bodyRoot),
|
||||||
);
|
);
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
@ -204,11 +204,11 @@ const plugin: Plugin = {
|
||||||
if (client.blockCache.has(request.block)) {
|
if (client.blockCache.has(request.block)) {
|
||||||
client.blockCache.ttl(request.block);
|
client.blockCache.ttl(request.block);
|
||||||
|
|
||||||
return client.blockCache.get(request.block);
|
return client.blockCache.get(request.block) as object;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ret = await handleGETRequest(
|
const ret = await handleGETRequest(
|
||||||
`${CONSENSUS_RPC_URL}/eth/v2/beacon/blocks/${request.block}`
|
`${CONSENSUS_RPC_URL}/eth/v2/beacon/blocks/${request.block}`,
|
||||||
);
|
);
|
||||||
client.blockCache.set(request.block, ret);
|
client.blockCache.set(request.block, ret);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue