Compare commits

..

11 Commits

Author SHA1 Message Date
semantic-release-bot 87e85b2387 chore(release): 0.1.0-develop.28 [skip ci]
# [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](c3b47e67e7))
* add optimisticUpdateCallback to options ([464fb21](464fb21095))
* pass client to prover after creating client in factory. don't try to parse thr messages ([481757e](481757e019))
* simplify logic and use LightClientUpdate.fromJson ([17cb002](17cb00231c))
* use _client not client ([76e22fa](76e22fa342))
2023-07-13 06:55:11 +00:00
Derrick Hammer c3b47e67e7
fix: add optimisticUpdateCallback to client factory 2023-07-13 02:53:23 -04:00
Derrick Hammer 977d33b768
refactor: make optimisticUpdateCallback a dedicated type 2023-07-13 02:53:00 -04:00
Derrick Hammer 4b9aca2086
Merge remote-tracking branch 'origin/develop' into develop 2023-07-13 02:43:34 -04:00
Derrick Hammer 464fb21095
fix: add optimisticUpdateCallback to options 2023-07-13 02:33:07 -04:00
Derrick Hammer 4be6c339c7
chore: cleanup imports 2023-07-13 02:32:46 -04:00
Derrick Hammer 51d6d23942
refactor: getLatestExecution needs to actually call optimistic update, but add a callback in the client options to avoid creating a subclass 2023-07-13 02:25:05 -04:00
Derrick Hammer 5aa37d4a61
refactor: don't use un-needed for loop 2023-07-13 01:46:45 -04:00
Derrick Hammer 17cb00231c
fix: simplify logic and use LightClientUpdate.fromJson 2023-07-13 01:45:43 -04:00
Derrick Hammer 76e22fa342
fix: use _client not client 2023-07-13 01:44:26 -04:00
Derrick Hammer 481757e019
fix: pass client to prover after creating client in factory. don't try to parse thr messages 2023-07-13 01:44:25 -04:00
9 changed files with 101 additions and 79 deletions

View File

@ -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)

4
npm-shrinkwrap.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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,

View File

@ -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,
}); });
} }

View File

@ -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 });

View File

@ -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 };

View File

@ -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;
}
} }

View File

@ -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>;