Compare commits
11 Commits
v0.1.0-dev
...
v0.1.0-dev
Author | SHA1 | Date |
---|---|---|
semantic-release-bot | 87e85b2387 | |
Derrick Hammer | c3b47e67e7 | |
Derrick Hammer | 977d33b768 | |
Derrick Hammer | 4b9aca2086 | |
Derrick Hammer | 464fb21095 | |
Derrick Hammer | 4be6c339c7 | |
Derrick Hammer | 51d6d23942 | |
Derrick Hammer | 5aa37d4a61 | |
Derrick Hammer | 17cb00231c | |
Derrick Hammer | 76e22fa342 | |
Derrick Hammer | 481757e019 |
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -1,3 +1,14 @@
|
||||||
|
# [0.1.0-develop.28](https://git.lumeweb.com/LumeWeb/libethsync/compare/v0.1.0-develop.27...v0.1.0-develop.28) (2023-07-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add optimisticUpdateCallback to client factory ([c3b47e6](https://git.lumeweb.com/LumeWeb/libethsync/commit/c3b47e67e760aea5c841985ab4d44fb36cff1dae))
|
||||||
|
* add optimisticUpdateCallback to options ([464fb21](https://git.lumeweb.com/LumeWeb/libethsync/commit/464fb2109514b147b25d1d760eb4a7677ac8fea3))
|
||||||
|
* pass client to prover after creating client in factory. don't try to parse thr messages ([481757e](https://git.lumeweb.com/LumeWeb/libethsync/commit/481757e019729ce3790c5cd07cb89c5d7ded7cf4))
|
||||||
|
* simplify logic and use LightClientUpdate.fromJson ([17cb002](https://git.lumeweb.com/LumeWeb/libethsync/commit/17cb00231c44d734cb6f24f48d1a6a045f0c7ae4))
|
||||||
|
* use _client not client ([76e22fa](https://git.lumeweb.com/LumeWeb/libethsync/commit/76e22fa34258c771da281457e983a5addfef440b))
|
||||||
|
|
||||||
# [0.1.0-develop.27](https://git.lumeweb.com/LumeWeb/libethsync/compare/v0.1.0-develop.26...v0.1.0-develop.27) (2023-07-12)
|
# [0.1.0-develop.27](https://git.lumeweb.com/LumeWeb/libethsync/compare/v0.1.0-develop.26...v0.1.0-develop.27) (2023-07-12)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "@lumeweb/libethclient",
|
"name": "@lumeweb/libethclient",
|
||||||
"version": "0.1.0-develop.27",
|
"version": "0.1.0-develop.28",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@lumeweb/libethclient",
|
"name": "@lumeweb/libethclient",
|
||||||
"version": "0.1.0-develop.27",
|
"version": "0.1.0-develop.28",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chainsafe/as-sha256": "^0.3.1",
|
"@chainsafe/as-sha256": "^0.3.1",
|
||||||
"@chainsafe/bls": "7.1.1",
|
"@chainsafe/bls": "7.1.1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@lumeweb/libethsync",
|
"name": "@lumeweb/libethsync",
|
||||||
"version": "0.1.0-develop.27",
|
"version": "0.1.0-develop.28",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -2,20 +2,24 @@ import { ClientConfig, ExecutionInfo, IProver, IStore } from "#interfaces.js";
|
||||||
import { POLLING_DELAY } from "#constants.js";
|
import { POLLING_DELAY } from "#constants.js";
|
||||||
import {
|
import {
|
||||||
computeSyncPeriodAtSlot,
|
computeSyncPeriodAtSlot,
|
||||||
getCurrentSlot,
|
|
||||||
deserializeSyncCommittee,
|
deserializeSyncCommittee,
|
||||||
|
getCurrentSlot,
|
||||||
} from "@lodestar/light-client/utils";
|
} from "@lodestar/light-client/utils";
|
||||||
import { init } from "@chainsafe/bls/switchable";
|
import bls, { init } from "@chainsafe/bls/switchable";
|
||||||
import { Mutex } from "async-mutex";
|
import { Mutex } from "async-mutex";
|
||||||
import { fromHexString, toHexString } from "@chainsafe/ssz";
|
import { fromHexString, toHexString } from "@chainsafe/ssz";
|
||||||
import { deserializePubkeys, getDefaultClientConfig } from "#util.js";
|
import {
|
||||||
import { capella, LightClientUpdate } from "#types.js";
|
deserializePubkeys,
|
||||||
import bls from "@chainsafe/bls/switchable.js";
|
getDefaultClientConfig,
|
||||||
import { assertValidLightClientUpdate } from "@lodestar/light-client/validation.js";
|
optimisticUpdateVerify,
|
||||||
|
} from "#util.js";
|
||||||
|
import { LightClientUpdate, OptimisticUpdateCallback } from "#types.js";
|
||||||
|
import { assertValidLightClientUpdate } from "@lodestar/light-client/validation";
|
||||||
|
|
||||||
export interface BaseClientOptions {
|
export interface BaseClientOptions {
|
||||||
prover: IProver;
|
prover: IProver;
|
||||||
store: IStore;
|
store: IStore;
|
||||||
|
optimisticUpdateCallback: OptimisticUpdateCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default abstract class BaseClient {
|
export default abstract class BaseClient {
|
||||||
|
@ -107,8 +111,19 @@ export default abstract class BaseClient {
|
||||||
|
|
||||||
protected async getLatestExecution(): Promise<ExecutionInfo | null> {
|
protected async getLatestExecution(): Promise<ExecutionInfo | null> {
|
||||||
await this._sync();
|
await this._sync();
|
||||||
const update = capella.ssz.LightClientUpdate.deserialize(
|
const update = await this.options.optimisticUpdateCallback();
|
||||||
this.store.getUpdate(this.latestPeriod),
|
|
||||||
|
const verify = await optimisticUpdateVerify(
|
||||||
|
this.latestCommittee as Uint8Array[],
|
||||||
|
update,
|
||||||
|
);
|
||||||
|
// TODO: check the update agains the latest sync commttee
|
||||||
|
if (!verify.correct) {
|
||||||
|
console.error(`Invalid Optimistic Update: ${verify.reason}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
console.log(
|
||||||
|
`Optimistic update verified for slot ${update.attestedHeader.beacon.slot}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -121,17 +136,20 @@ export default abstract class BaseClient {
|
||||||
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) {
|
|
||||||
try {
|
try {
|
||||||
const updates = await this.options.prover.getSyncUpdate(
|
const updates = await this.options.prover.getSyncUpdate(
|
||||||
period,
|
startPeriod,
|
||||||
currentPeriod,
|
currentPeriod - startPeriod,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let i = 0; i < updates.length; i++) {
|
for (let i = 0; i < updates.length; i++) {
|
||||||
const curPeriod = period + i;
|
const curPeriod = startPeriod + i;
|
||||||
const update = updates[i];
|
const update = updates[i];
|
||||||
|
|
||||||
|
const updatePeriod = computeSyncPeriodAtSlot(
|
||||||
|
update.attestedHeader.beacon.slot,
|
||||||
|
);
|
||||||
|
|
||||||
const validOrCommittee = await this.syncUpdateVerifyGetCommittee(
|
const validOrCommittee = await this.syncUpdateVerifyGetCommittee(
|
||||||
startCommittee,
|
startCommittee,
|
||||||
curPeriod,
|
curPeriod,
|
||||||
|
@ -146,19 +164,17 @@ export default abstract class BaseClient {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.options.store.addUpdate(period, update);
|
await this.options.store.addUpdate(curPeriod, update);
|
||||||
|
|
||||||
startCommittee = validOrCommittee as Uint8Array[];
|
startCommittee = validOrCommittee as Uint8Array[];
|
||||||
period = curPeriod;
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`failed to fetch sync update for period(${period})`);
|
console.error(`failed to fetch sync update for period(${startPeriod})`);
|
||||||
return {
|
return {
|
||||||
syncCommittee: startCommittee,
|
syncCommittee: startCommittee,
|
||||||
period,
|
period: startPeriod,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
syncCommittee: startCommittee,
|
syncCommittee: startCommittee,
|
||||||
period: currentPeriod,
|
period: currentPeriod,
|
||||||
|
|
|
@ -2,16 +2,20 @@ import Client from "./client.js";
|
||||||
import Prover, { ProverRequestCallback } from "../prover.js";
|
import Prover, { ProverRequestCallback } from "../prover.js";
|
||||||
import VerifyingProvider from "./verifyingProvider.js";
|
import VerifyingProvider from "./verifyingProvider.js";
|
||||||
import Store from "#store.js";
|
import Store from "#store.js";
|
||||||
|
import { BaseClientOptions } from "#baseClient.js";
|
||||||
|
import { OptimisticUpdateCallback } from "#types.js";
|
||||||
|
|
||||||
function createDefaultClient(
|
function createDefaultClient(
|
||||||
proverHandler: ProverRequestCallback,
|
proverHandler: ProverRequestCallback,
|
||||||
rpcHandler: Function,
|
rpcHandler: Function,
|
||||||
|
optimisticUpdateHandler: OptimisticUpdateCallback,
|
||||||
): Client {
|
): Client {
|
||||||
return new Client({
|
return new Client({
|
||||||
prover: new Prover(proverHandler),
|
prover: new Prover(proverHandler),
|
||||||
store: new Store(60 * 60),
|
store: new Store(60 * 60),
|
||||||
provider: VerifyingProvider,
|
provider: VerifyingProvider,
|
||||||
rpcHandler,
|
rpcHandler,
|
||||||
|
optimisticUpdateCallback: optimisticUpdateHandler,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,8 @@
|
||||||
import BaseClient, { BaseClientOptions } from "#baseClient.js";
|
import BaseClient, { BaseClientOptions } from "#baseClient.js";
|
||||||
import { ExecutionInfo, IStore } from "#interfaces.js";
|
import { IStore } from "#interfaces.js";
|
||||||
import axios, { AxiosInstance } from "axios";
|
import axios, { AxiosInstance } from "axios";
|
||||||
import axiosRetry from "axios-retry";
|
import axiosRetry from "axios-retry";
|
||||||
import { Bytes32, capella, LightClientUpdate } from "#types.js";
|
import { consensusClient } from "#util.js";
|
||||||
import {
|
|
||||||
consensusClient,
|
|
||||||
deserializePubkeys,
|
|
||||||
getConsensusOptimisticUpdate,
|
|
||||||
optimisticUpdateFromJSON,
|
|
||||||
optimisticUpdateVerify,
|
|
||||||
} from "#util.js";
|
|
||||||
import { toHexString } from "@chainsafe/ssz";
|
|
||||||
import NodeCache from "node-cache";
|
|
||||||
import { DEFAULT_BATCH_SIZE } from "#constants.js";
|
|
||||||
import {
|
|
||||||
computeSyncPeriodAtSlot,
|
|
||||||
deserializeSyncCommittee,
|
|
||||||
} from "@lodestar/light-client/utils";
|
|
||||||
import { assertValidLightClientUpdate } from "@lodestar/light-client/validation";
|
|
||||||
import bls from "@chainsafe/bls/switchable";
|
|
||||||
|
|
||||||
axiosRetry(axios, { retries: 3 });
|
axiosRetry(axios, { retries: 3 });
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,30 @@ import Client from "./client.js";
|
||||||
import Store from "../store.js";
|
import Store from "../store.js";
|
||||||
import Prover from "#prover.js";
|
import Prover from "#prover.js";
|
||||||
import * as capella from "@lodestar/types/capella";
|
import * as capella from "@lodestar/types/capella";
|
||||||
import { consensusClient } from "#util.js";
|
import { consensusClient, getConsensusOptimisticUpdate } from "#util.js";
|
||||||
|
|
||||||
function createDefaultClient(beaconUrl: string): Client {
|
function createDefaultClient(beaconUrl: string): Client {
|
||||||
return new Client({
|
const options = {
|
||||||
store: new Store(),
|
store: new Store(),
|
||||||
prover: new Prover(async (args) => {
|
prover: new Prover(async (args) => {
|
||||||
const res = await consensusClient.get(
|
return (
|
||||||
|
await consensusClient.get(
|
||||||
`/eth/v1/beacon/light_client/updates?start_period=${args.start}&count=${args.count}`,
|
`/eth/v1/beacon/light_client/updates?start_period=${args.start}&count=${args.count}`,
|
||||||
);
|
)
|
||||||
return res.data.map((u: any) =>
|
).data;
|
||||||
capella.ssz.LightClientUpdate.fromJson(u.data),
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
beaconUrl,
|
beaconUrl,
|
||||||
});
|
async optimisticUpdateCallback() {
|
||||||
|
const update = await getConsensusOptimisticUpdate();
|
||||||
|
|
||||||
|
return capella.ssz.LightClientOptimisticUpdate.fromJson(update);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const client = new Client(options);
|
||||||
|
options.prover.client = client;
|
||||||
|
|
||||||
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Client, Prover, Store, createDefaultClient };
|
export { Client, Prover, Store, createDefaultClient };
|
||||||
|
|
|
@ -29,8 +29,8 @@ export default class Prover implements IProver {
|
||||||
count: number,
|
count: number,
|
||||||
): Promise<LightClientUpdate[]> {
|
): Promise<LightClientUpdate[]> {
|
||||||
let end = startPeriod + count;
|
let end = startPeriod + count;
|
||||||
let hasStart = this.client.store.hasUpdate(startPeriod);
|
let hasStart = this._client?.store.hasUpdate(startPeriod);
|
||||||
let hasEnd = this.client.store.hasUpdate(startPeriod + count);
|
let hasEnd = this._client?.store.hasUpdate(startPeriod + count);
|
||||||
|
|
||||||
let trueStart = startPeriod;
|
let trueStart = startPeriod;
|
||||||
let trueCount = count;
|
let trueCount = count;
|
||||||
|
@ -61,12 +61,8 @@ export default class Prover implements IProver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < trueCount; i++) {
|
return updates.concat(
|
||||||
updates.push(
|
res.map((u: any) => capella.ssz.LightClientUpdate.fromJson(u.data)),
|
||||||
capella.ssz.LightClientUpdate.deserialize(res[startPeriod + i]),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return updates;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,3 +18,5 @@ export type VerifyWithReason =
|
||||||
| { correct: false; reason: string };
|
| { correct: false; reason: string };
|
||||||
|
|
||||||
export { capella, phase0 };
|
export { capella, phase0 };
|
||||||
|
|
||||||
|
export type OptimisticUpdateCallback = () => Promise<OptimisticUpdate>;
|
||||||
|
|
Loading…
Reference in New Issue