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