*Switch to new optimistic proxy approach based on kevlar and patronum

This commit is contained in:
Derrick Hammer 2023-03-29 00:02:16 -04:00
parent 8501074b25
commit 2f66fc332a
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
10 changed files with 1249 additions and 19 deletions

330
src/client/client.ts Normal file
View File

@ -0,0 +1,330 @@
import {
Bytes32,
ClientConfig,
ExecutionInfo,
LightClientUpdate,
OptimisticUpdate,
VerifyWithReason,
} from "./types.js";
import { getDefaultClientConfig, handleGETRequest } from "./utils.js";
import { IProver, IStore } from "./interfaces.js";
import {
BEACON_SYNC_SUPER_MAJORITY,
DEFAULT_BATCH_SIZE,
POLLING_DELAY,
} from "./constants.js";
import {
computeSyncPeriodAtSlot,
getCurrentSlot,
} from "@lodestar/light-client/utils";
import {
assertValidLightClientUpdate,
assertValidSignedHeader,
} from "@lodestar/light-client/validation";
import { SyncCommitteeFast } from "@lodestar/light-client";
import bls from "@chainsafe/bls/switchable";
import { PublicKey } from "@chainsafe/bls/types.js";
import { fromHexString, toHexString } from "@chainsafe/ssz";
import { AsyncOrSync } from "ts-essentials";
import * as altair from "@lodestar/types/altair";
import * as phase0 from "@lodestar/types/phase0";
import * as bellatrix from "@lodestar/types/bellatrix";
import { init } from "@chainsafe/bls/switchable";
import NodeCache from "node-cache";
export default class Client {
latestCommittee?: Uint8Array[];
latestBlockHash?: string;
private config: ClientConfig = getDefaultClientConfig();
private genesisCommittee: Uint8Array[] = this.config.genesis.committee.map(
(pk) => fromHexString(pk)
);
private genesisPeriod = computeSyncPeriodAtSlot(this.config.genesis.slot);
private genesisTime = this.config.genesis.time;
private prover: IProver;
private boot = false;
private beaconChainAPIURL: string;
private store: IStore;
constructor(prover: IProver, store: IStore, beaconUrl: string) {
this.prover = prover;
this.store = store;
this.beaconChainAPIURL = beaconUrl;
}
private _latestPeriod: number = -1;
get latestPeriod(): number {
return this._latestPeriod;
}
private _blockCache = new NodeCache({ stdTTL: 60 * 60 * 12 });
get blockCache(): NodeCache {
return this._blockCache;
}
private _blockHashCache = new NodeCache();
get blockHashCache(): NodeCache {
return this._blockHashCache;
}
public get isSynced() {
return this._latestPeriod === this.getCurrentPeriod();
}
public async sync(): Promise<void> {
await init("herumi");
await this._sync();
await this.getNextValidExecutionInfo();
if (!this.boot) {
this.subscribe();
this.boot = true;
}
}
async syncProver(
startPeriod: number,
currentPeriod: number,
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
);
const validOrCommittee = await this.syncUpdateVerifyGetCommittee(
startCommittee,
period,
update
);
if (!(validOrCommittee as boolean)) {
console.log(`Found invalid update at period(${period})`);
return {
syncCommittee: startCommittee,
period,
};
}
await this.store.addUpdate(period, update);
startCommittee = validOrCommittee as Uint8Array[];
} catch (e) {
console.error(`failed to fetch sync update for period(${period})`);
return {
syncCommittee: startCommittee,
period,
};
}
}
return {
syncCommittee: startCommittee,
period: currentPeriod,
};
}
// returns the prover info containing the current sync
public getCurrentPeriod(): number {
return computeSyncPeriodAtSlot(
getCurrentSlot(this.config.chainConfig, this.genesisTime)
);
}
public async subscribe() {
setInterval(async () => {
try {
await this._sync();
const ei = await this.getLatestExecution();
if (ei && ei.blockhash !== this.latestBlockHash) {
this.latestBlockHash = ei.blockhash;
}
} catch (e) {
console.error(e);
}
}, POLLING_DELAY);
}
optimisticUpdateFromJSON(update: any): OptimisticUpdate {
return altair.ssz.LightClientOptimisticUpdate.fromJson(update);
}
async optimisticUpdateVerify(
committee: Uint8Array[],
update: OptimisticUpdate
): Promise<VerifyWithReason> {
const { attestedHeader: header, syncAggregate } = update;
const headerBlockRoot = phase0.ssz.BeaconBlockHeader.hashTreeRoot(
header.beacon
);
const committeeFast = this.deserializeSyncCommittee(committee);
try {
await assertValidSignedHeader(
this.config.chainConfig,
committeeFast,
syncAggregate,
headerBlockRoot,
header.beacon.slot
);
} catch (e) {
return { correct: false, reason: "invalid signatures" };
}
const participation =
syncAggregate.syncCommitteeBits.getTrueBitIndexes().length;
if (participation < BEACON_SYNC_SUPER_MAJORITY) {
return { correct: false, reason: "insufficient signatures" };
}
return { correct: true };
}
public async getNextValidExecutionInfo(
retry: number = 10
): Promise<ExecutionInfo> {
if (retry === 0)
throw new Error(
"no valid execution payload found in the given retry limit"
);
const ei = await this.getLatestExecution();
if (ei) return ei;
// delay for the next slot
await new Promise((resolve) => setTimeout(resolve, POLLING_DELAY));
return this.getNextValidExecutionInfo(retry - 1);
}
public async getExecutionFromBlockRoot(
slot: bigint,
expectedBlockRoot: Bytes32
): Promise<ExecutionInfo> {
const res = await handleGETRequest(
`${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 blockRoot = toHexString(
bellatrix.ssz.BeaconBlockBody.hashTreeRoot(block)
);
if (blockRoot !== expectedBlockRoot) {
throw Error(
`block provided by the beacon chain api doesn't match the expected block root`
);
}
this._blockCache.set(slot as any, res);
this._blockHashCache.set(slot as any, expectedBlockRoot);
return {
blockhash: blockJSON.execution_payload.block_hash,
blockNumber: blockJSON.execution_payload.block_number,
};
}
protected async _sync() {
const currentPeriod = this.getCurrentPeriod();
if (currentPeriod > this._latestPeriod) {
this.latestCommittee = await this.syncFromGenesis();
this._latestPeriod = currentPeriod;
}
}
// committee and prover index of the first honest prover
protected async syncFromGenesis(): Promise<Uint8Array[]> {
// get the tree size by currentPeriod - genesisPeriod
const currentPeriod = this.getCurrentPeriod();
let startPeriod = this.genesisPeriod;
let startCommittee = this.genesisCommittee;
console.log(
`Sync started from period(${startPeriod}) to period(${currentPeriod})`
);
const { syncCommittee, period } = await this.syncProver(
startPeriod,
currentPeriod,
startCommittee
);
if (period === currentPeriod) {
return syncCommittee;
}
throw new Error("no honest prover found");
}
protected async syncUpdateVerifyGetCommittee(
prevCommittee: Uint8Array[],
period: number,
update: LightClientUpdate
): Promise<false | Uint8Array[]> {
const updatePeriod = computeSyncPeriodAtSlot(
update.attestedHeader.beacon.slot
);
if (period !== updatePeriod) {
console.error(
`Expected update with period ${period}, but recieved ${updatePeriod}`
);
return false;
}
const prevCommitteeFast = this.deserializeSyncCommittee(prevCommittee);
try {
// check if the update has valid signatures
await assertValidLightClientUpdate(
this.config.chainConfig,
prevCommitteeFast,
update
);
return update.nextSyncCommittee.pubkeys;
} catch (e) {
console.error(e);
return false;
}
}
protected async getLatestExecution(): Promise<ExecutionInfo | null> {
const updateJSON = await handleGETRequest(
`${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
);
if (!verify.correct) {
// @ts-ignore
console.error(`Invalid Optimistic Update: ${verify?.reason}`);
return null;
}
console.log(
`Optimistic update verified for slot ${updateJSON.data.attested_header.beacon.slot}`
);
return this.getExecutionFromBlockRoot(
updateJSON.data.attested_header.beacon.slot,
updateJSON.data.attested_header.beacon.body_root
);
}
private deserializeSyncCommittee(
syncCommittee: Uint8Array[]
): SyncCommitteeFast {
const pubkeys = this.deserializePubkeys(syncCommittee);
return {
pubkeys,
aggregatePubkey: bls.PublicKey.aggregate(pubkeys),
};
}
private deserializePubkeys(pubkeys: Uint8Array[]): PublicKey[] {
return pubkeys.map((pk) => bls.PublicKey.fromBytes(pk));
}
}

532
src/client/constants.ts Normal file
View File

@ -0,0 +1,532 @@
export const BEACON_SYNC_COMMITTEE_SIZE = 512;
export const mainnetConfig = {
genesis_time: "1606824023",
genesis_validator_root:
"0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95",
slot: "6046691",
committee_pk: [
"0xac2154953fb292a27604162a2952f95d20b2438acb1d460b0d4ccb5899788b8d33437e38f3434ad87bcb5141f853be70",
"0xac61b1d8baac8251fc13bb71992f7ded3b92a596c37ff616eac136f73f3e0d46bc18dd5a7e3bef23f2b094f78adfe6af",
"0x89bd0a7ff808295f7ad77356a20d58252c4cafc38c1bfdf57a6675bacd192a549c80b6c0f0e67fdf647e8f31e5b9cf8d",
"0xb2a024a13871b071dec5b6c6cfbdaa5791646cb1f60f2b077dba7d732fcc6d6b806ed7e39af1218a0a6f94892702c953",
"0x9983a8af711066bbcc9986db271cc7b41d64a1dfe9fed0593c3d904c9503333b7c23058637ecb94fb5b4769626a4757b",
"0x8700b39fc4738816227440f20fd8b22a52d9fa1da598fc1509969073beae34e23fb0f963e1007907b47801ac9b3aa30e",
"0x891e56d074bf4500ab2ba55ff77a08eae23009473bea1f8db5a8479246ede43132f2957cff657c97f00b3310ddf6d202",
"0xa398b7effac7defb1cf0a17e968de79b8c78deebd8a5b549055ff077c028ff3b7063310e0eb9183f26fb2ce89963aaac",
"0x860c7c608d467a81503a6337d058ff2981aa8cc2426f644b896faa57a6ac56627a02be2c3ee4cdddbca85a39f395d439",
"0xb3f6f13b1da0e8cb469f5709fb724001319ee0cb80c9f2b39438a696357dc782a63f1189a86e2cb7520badb421f256a2",
"0x8870e0b2e695ede2785e6278edd355da579210e84154b5425ccb7eafccee66781f0fe34ce7bac217969b7af51609579c",
"0x988255fc7b6802706be2ab708bb9bc8e78ba655640862d84ed37eee3f28489a221079c37bb7656039edfa2982cd719fc",
"0x9014f806cc97abfba9a33d0740b236fb8d64d7433a525cef08e1725758e7a0c02beb072d2053873580b4a6104e1df68b",
"0xb186fa4fdbabfff3cdb1feb35633e36db451a535427c504fc56a61d3759b3511e665a2020d4fa7387bb7ddaf7a45c173",
"0x8511d7d04df823ba159b586f4e0cec92304af11c10ced9a4453e87e65c1e31292e2b972084477b52debbda2be15f5912",
"0x972ad915f0f83c933fded9937ab79ef34e1a2932aab1e8dca73c922100033b68f6ee53260feba9aa65bdfcbaa2f2e96d",
"0x87081ab9ed37e7f9c901beaeb90eba808134c74d1268011cd589785a8862523913438ecd620fb41958f1dcbf5bc48438",
"0xab0f051952cbcbae0a21f38f17ae6e3243a230ce894dcbbb60a8ef1147e9b7590963a68e4e9261fab684b2dbe735cc29",
"0x96f42c3c4eb39a8a27126928a781a1bad82fc9b8440d04d4fbfa1df30be22a478fb6f607bfd00d357eef8982996fbd16",
"0x90e26a69f3c9328889da4dee470c025be883e102ea1e48fc1d86697b70361820960b5d01563b1a5ab78001c117408f2b",
"0x9153f1e511e569c534d663a45153bb22cd1741ad0033425450a2958a314e2613ccbbe2c395e408ea77de629d86c3526a",
"0xa083abb8336f02926a9ac2b4901bc227d4affb7778fedd6c3c81e445e7ac40a7fc475d9126e31541849d7fbcd0afb3d4",
"0x906fd4d31cb160d1c53d0b0b61a51efa5dc7e50cfc3ae982ab16d3f6153b4a5c114e7acd0c6e72c1572bb1b80ab74358",
"0xac20f0e8975789e4b17754c189ee1464d6bb7a8078225c60137964c26f36a2e4c4cac643a01467731f6f48e2ed44a69e",
"0xb517743ccea6f77054da3855193eb02e4bb823be3c624bfcfd306e3080c1a1b469b802381442376770a729d920ce2700",
"0x82ef4787c3ea79599517c403f7390fb78bd1d75bae536237d7cb5c55a0b9245d8ffe1a1c63612c5a1bd2ce216b29abca",
"0x93747d6bee6108f5a57dfa965510a99a331f6a366530cf1b2386f00978f562744fe3ad1960d7f48b0a0c9e5f2d65766a",
"0x851341d5eccd7901dd1e28096cba68040fa5aa15fa17de157b74f5a9af738b8c822beb8767e936c97273bd365e421c46",
"0xaccbf842d8ac35db1129847e9d50692df0d83674b1ac38ae35f56e53c66f72845e728c95fb8f73a400b55c6204a7f322",
"0x91f096011b8f9cb23070481a90919956a10b8f507769c57861e25470021954601747ebb8a88aa47bdfe13f2ae500dd12",
"0xb31dc69d3f3a9afda62111094b6753065dea87f3c47b03276312524223e910b707c7e079b0b199bef2b8dc84063c4bea",
"0x824f23ceb4afcc36d59b0d6d50d7e234ffeec2373272e8dac353a7200a15b739a3a957b0a8fa5adb233be467e2357480",
"0x89c183fef67ad8433568f261ae98974da9ebc5c51b337f18a65ba739fcf019d0290da0a5df982f1de598d3ddb364bb4e",
"0x95fd442553d2d190848f2f206862bedcceada9b0d68e4de017f8fa61f4dc11ffbe3615d569865f2d57b4b3bcaef2f0a0",
"0x836761fd5f9a83ba5c531b0c50703b47b92b5588a03ac5a6de9283023b48950fade6685f4120d29db2efe655f9d4e5f2",
"0xadb1a2f31adf106d4a2539b3991f32a5b4f4c7d215ef46784615ebfcc1dcbf077a8d9431d055d9736d0326138570e978",
"0xab19a893f46fe84a1b003ddd992b4c0b50beb2b979e9237203e984f237b6499081fc8cc4966c78115aeaf054684d308c",
"0xa1ef5ad999d1b3665de4cd5d516c8bf8cb831ad52344af359268d317d4abcdb3f32e804189a8c091871dd5a418cfce61",
"0x98f1f219f616b36a75e6418608b4729fb8859a098b9785191ea19a887137e9fb0658a4e0134db0d15e0c6f955a0b5829",
"0xaef97324a64f1f67ef706f261b44c1b90ad8a1a533b2ca15ea6b9faa5d681cb30c1622da558adb6ffb90515c87558c06",
"0xab8b378bf27f7ef6eb5e22979c1dc3905e1ecfcdfbbe58e73ce7f1f5734cf1006a0224ab499941b12c24584a42d67139",
"0x8aa197f39520416779ae2c5487deae4e91df104fecc5ac496ae2993dcd908e43a8003e88d4c7eb232f81a4fc3e453dcb",
"0xab4a54b7d3b839f4c97fe2dae8ef149983a16cb15feb13b4e2dfaa97374ff99aaade102a585b772d717f165d8f421365",
"0xa34e5130334a98865a2b8a5e0f0ebb847247974fbc7105374ecc819de25f070c1cf7650b0f7825eec2be7d0d31486a3f",
"0xa5e926709eb027938329dd00a22a122c9e68104c6fb6751724a26625ea55482bb7581964bfa2fcbe9d0af8096a88312c",
"0xadb295586f2fac8a503e6c7c53183f2eb96e05cb6c38b34c5b939a1a413282503464d782f6b6ce5350459f561ff27588",
"0x83066cd4554e51138948e354b7e3e018eddf02b71fd0106effc3a099296422b7316198b70194cff15708cf862f873c06",
"0xa3a661f075c844111c98c62c24dc25ebafded96689ad4f40e4d0bb1365aac01098c90f7f76f6f7e01663dadcd29433d5",
"0x80a28cac5cc54fbbf0c0c37c0ba968a3d5f2ea7ea46b7ffb3102cdd1371efb5b65d93380c6b5edfb84e274913508bdae",
"0xb0edc7b534b6cbab420d76392a83d3a8f26eab4a8d3696b29476ee7e6f89c5dd6f3eae16514785ae8366e8535822f0f0",
"0x8aaaab7f3b8fe248a57109978f5f8016b5be4d525d9ecb2c7e712141cf958edbb6bde18e79c6b928f469569584b0d108",
"0x8f44d63f1f09856673d34726eaa49d6f49165d0e0a1a67f15fefc2b3dc51bae41c365d03309c05f5893d286f4b81b14f",
"0x8d2fb449742a5d0ec18c91e72ec6de33ee1117af59593d80a5d2b940df8e2d05e7437a3582ad677262930f7524bd99a4",
"0xaa821c73859d570b79629d697598ab48a9cc816bcf9e0487ec6c6febfedc50325293877400c49255b4ceec07e2ddcace",
"0xa7e622511de149e700f230c730b68dbebf5afe6a627693619da2fb3b059db155806a206862c1432cc39638d00b368cb6",
"0xa7282c90faef292531548d1a221b5a07d99aeb37184f5a7715205c75479bbc908fcc67bc07b4ebdfec7b6fb2229aabd7",
"0x97c32344bdad6fea1550faccd633d767dd7c3116e09c453ef6ac7ba6740f80b4ebebb4dbdfae9125cd90076535dc5d16",
"0xa3fb5ea7195d98dd1b8990abc5ec16e8978f9d1705883fa0a665d05aee7983228ed5995a3f5bc24416dcf9204f1c12d2",
"0xa5cf59aef5755678b4c54bb486110c7708ab13f7e5f642f605830ea2a285b884d871de4c398c0ecdabfd73081fe8a443",
"0x85c11bae0968c4296c00ba0216d5abf39d670d64e84820edf761dc066295867082f8aec6fdc94a4617e3c3e211c2c115",
"0x8d9dd55203011e3d80ad08bffbc285f95a30dd1ebc4e11870e581d6b24d4682338c683b407a93e24cf3e50b71b6aa4a3",
"0xa1574a499db213c033928d728eda7812acdbe83971e4380d1d3ac50ca9747d1024a0b95837f940cf84f0271fcefcb579",
"0x833247d97973aa04ee8143af434215e9ed43c809dc232915cd13a05354bec29186bcffa427f4a2cb75278d1302194145",
"0x992761cb86061d188e4fd0340dbe074e389121afd821eca03ecadd378dbc1ef92839ec8407e9c5fdb6a4180e1e354651",
"0x8e035b52f2759a7c90f936cf7e4eeb9481ce3ddc036eabb5ecaaa8e2f40fe28f949f9a6730fac7189c64aa19066c7242",
"0xb970ccc4584826668fb1289ef45bb92eab0f4fd856281c28f771d1545f4494934a3ede1e215c441e8ab14c030b9f8470",
"0xb4a474fc617fcc54e08abc40ed41ea09241fe6894b79f3e9356be85889d98fd9d4063cced43103b8c3fd0013e1909503",
"0xa0e21ccf14e8f609ab7be489141c5519b157f135345b2ffbfca61f83ee69ce71da543261833c523c017896e193b8d03b",
"0xa53599ac336908004b0380938f8fdf90bce83666b948708273b399e0c4e07824a033ec6725f329a5cdd572e04a06801a",
"0x88ecd5e25ddb207748cc24f4f3a5a32cf7aa0054a94af9fb5742dcd46883fc71809532998cb289344e2818bdbd60e05d",
"0xa641713311a1f14e2e20eb7f992bb3dd14aeb404ff0a8648ec6451a04cc428ffb9de3ed984a49f00949ac3ba3c2d75b2",
"0xb91a617a603bdeb2df2d9c363093bfe8c398af726546c38deaa1652c5abf13b596be7dadeab2aaf7263af907602ce7f6",
"0x917c45d61c9f887d505183519b7af37541715d2516e358ff22f2205e7466073d33589ce32b562e1e892a249e14f89982",
"0x83b738c49524eb38c7d7b57df1a5a9da6791f353070a6fe9f472702a6637b419db69556e57903b7ef32f42d35c55658a",
"0xa20623e777764d3859c0003991de2a56d067d4a21757ce9535e0809b73d8f1dda76dbb9ce8e80097794f3d0ef17aba56",
"0x8a3333a9316c348daef2acb393834b3094cb9b1dfbba6c93c51f04608ded0b3b00474cda55c7bf4a9c1846fc5261eab0",
"0x8fa103b69145c967a4a239f5b47b5fdc44c7904309e44e4da13cac5563f942417519870414731855a9a77a9d17f72641",
"0xa47ea87110df9e182e7416197510d6ca41ad4d21f7ab4bc5b1e24236df3d273c0a3d4abff17b522dfc7c7decea37bb51",
"0x8869b20929e093a8509ad6d7c464b56a319648daae13de12587e99bc63a9faff8f1510af24831b3f60bb7d106802655e",
"0xb22f852eb5ed2e76c8ab238cd680bf0f5f6a1748a1fed5582cc854debea3001fe1d55e2a82d8a8dcac55d67736496feb",
"0xb96b07b3a4a8173d172f67686e806a4f0c91bd85315e7dd593f9c61e6e86149a90eec25048b3725d594e88e271b579fc",
"0x9815a947bdce59b25f839a033bc6144b4daf3715e9301e3087a4cb781d0b2ffb69ac6ee53d62f39e25edcecea0c3ca00",
"0xad6c6b59f52efd7e5a07db59689a7d324cc9176220a93a4a25b8acc0f9865fa8af59a464f32354d71d2c46d0f07f772a",
"0x9732d7d58462fb7097d96698a71f13cc6fe44eec925ded9662b9cd27328895155fa9c6ef54daaa60a6c9d22c33752fdc",
"0x8242d1e2ac762cd37065969d388e636bec4cb9615ff9d5ae166800fbfc8969b306e0e50361a75b25f34db97a5fb1ff92",
"0xb0d9b515a9c689fc5b74e61577d3bbe6528a1ef49a9850e4f0af67a356ea6cbf144848154d89468543b200849edc04cb",
"0xb1998d029255ec9ca9c409c11259609a6b4b93d20b499fafa480d6287e2d11080b79b21d898f2b021468f98e87e737fe",
"0x948cbd5c8571d051b6fb411d3a3cabb2eae0971f3eb7407f242409fd6c4852a8ba76c1f4016cb26d20e7e06423062f3e",
"0xad9f16b12ab53039f424e12d65e47a1d63b1173b10cfd34607d0e7a010c46d9bccf451a6cefeb9b42de0ccbb88b15ccf",
"0x91f8575a367423a90ec6170d1ee55196beaa3cd2a2cfa98a6ba90c1758cb4fa9b03414b58e19a5d3e82d66f8187ad283",
"0x87fd9c53a7b1e2f748a3d5a498ff3f5760a7c5733b41de295baef349b673c246661535f04b36a64b7556eaaa8a7a2797",
"0x83ea795760338e322b6ae9081d0a6e3484bc7be696641aa5dcc502ecdbf1d586fdd69f2278847f791056df2f99477a1f",
"0xa37d999b8ed427f793143b74acd528f623a7f1954848e1b7d2c7964166a6910de5922ede1d1ec838abe9bdb45f871834",
"0x99887d6143a50745a00bceeaeb8b13d7777b902b4e4aa8c8499926767b2f340a732fae66f19f423f981bfaef020729b9",
"0x8637794599b358a153589e8da1b151d856d02db7f10be662595566abf3896bd32f6c8236b8a514ea2f8de8d41d305ada",
"0x97f61eedbf869f6b91e185114f4a838b55900b9797e5ce3764c68398261a319da5093749afa144b0128e28b111cddcf0",
"0xa8b761700bbb4aacc9aece0802ef779e1bef851fc43d0b5ed1c683aa299cc3ebabf65855bbbe10ae7466f4ecbc5b96ac",
"0x84623e341c2e3604e301673123ab1c342ee7a434a24ff60bc24a1004e4e698cba5835e67da176b1d547d64e7695c8e2a",
"0xa3ceab358e670a5c188d3f9420966bdf223434360cb3f10763670b166fd857522961cfe6cb832c5908aee3b4e10b38bd",
"0x97eafebaa31ece76781bb8b3ee3d5bfc6f1be8094b3e976c3cb87daa9f79a5a45b27cc4d3ad0a94627a775ed46cb5e56",
"0xb3733f5030f84c373e2481a2ecfbf1c6ad691a05ea48b64064e3abb51d38c369a1a290e17254c5fddd21d6062c074905",
"0xb1611842d97187057010278b81b9a0ffdc7aaf8ef1ddf2fd8d69eedf1f8dc3702843b5adbb1aa0fa05ee39dfbd582ab8",
"0xa94f7d93b520e5d063df8b3fd5dc11ae847474f6c62a37824856ee230697376ac21a7ab9e2c8f7e2d6ed87ed1bafeb73",
"0x9671f924d0bce9cd26d27075e52b460a9451922ac800142e4dcdbdf1e041b906bd3f87bec6de2fe12d7511c0064c9b2c",
"0x8e1b6985c7b0bfbaef75cab9f4a9b001747b3a028510d1e1128c306e6e5939367e1a0abde6e5a79ab0d336bced0e8426",
"0xa116d6223f13df96d086c07ae371cf5417d1ecf6ecc749cf2d73be54c7877e58768d7df26dd664dbb267ec53460bdc39",
"0x868a7d95670b8e24d31bfeae9d958070a5bd389caeea3a41e54a3b4021d0801658baa83e71219d6670a13cdf0105ba6c",
"0xb7c43d53ab11a34d2a1e487c3a2c44def71e8c63d7c7447e940907bd26dc6c4850f6bbfc01c5175e84c9702be99942b2",
"0xab3d91789f9c2e0bbed3fb58033bbd3bc28c077a0cacb9c7a5ef0e308c2d0da0edf2b6deac21df98b25381a617f725da",
"0xb1cc0cba5b487e49402fcdc02f20bce9c44c2afae1816ad60361025486b629ae68c02355d91a2804bbebdbe091312a4c",
"0x81abb5f3d5aa066bae2742d3bcdbc8a8b96ae2d2e62f78827d51bf52fa57b9fd4bdecc9ded211407ffedff45998cc931",
"0x90e8bd7bb48a0b486a8797995cdf3cc0b33941dfe83ca61bf286c14b5cfe744321899b4863032063c9f5792c9fb40f79",
"0x98f4ca7bc46de1e9cd9de0e180c779d332c13740470253d84fc3c055a6b291d036916d8d5ec477e383134dc0371da8c2",
"0xb08da88d8030d724768ae59b17a7d8a22bc1b3a1426c9fa1f4b63fd84699c58e813b3ac83ad842a74b0c6f1179e703ee",
"0x835ea95d07d13a5a8e1e419c46ac34ecd30bf0a849da204cf9ef168d8312243706c12cfce3276f408e70ba55e148f61a",
"0xb91664052346378b7a29d4ea9e02be301f7d659ef819a94c9d0dc7b14776e416c9f0e6ba721cc89c714f6659f9839a9e",
"0xb4341164dd17e68a2dc4b845d3f0e532096eaaebd7820fe3c87fc75e1e5741569d1386bdbad2909f3d6038bf194f780f",
"0x8014ecc0c97f5a477814b964547e87d77e4288a229efbadfb06bfcaf7650964e21bfa0cb2f3cc356d53b66c9e5c047c7",
"0xb9247aced49425bec5bf1c5d94b346266cbcbd11c74287567a39530749cd537bf1c5cde011f61432eb79b8c40dcabab3",
"0x8a3a77d5b570c7fb5bb804f9de87febc3545287f22588d1d48a0f4e9b43dd83717a79693faf913b78f435d0af531cba2",
"0x91acad3ae695588b5b388df0afe9a4a33859c8846adb4b53ce6bb968bf2f486c4b3e93d5c52dacbedc13e89b58d546ee",
"0xa55d11d5bf9774088c7e979f8c8e211fd0c971217ac5c314a3bd8934e40bc518b001f317564a09992a1e163fcdfe0a84",
"0xb543d2855a4bdb4c25f10370844966b21d523a8cf6c838983e7b4966c1ca3d9785b3c893f9b5d088e1d056545e7798ac",
"0x8f762a160728304223e74a89e9a20dbd2cbf736f8fe44e570a929814d3d39dfde17991cfabce2a6b498cc07cecffde60",
"0x822c22863f22e3e5045283e8b6895e0769ca44e057fe75634b3e73d3dd97966a7efc464d35b6f4ed21a49585cf2fb383",
"0xb49894c21b0e9ca2acbc8a7023b36c3c582557a785c9d64cd5c70a06d286e4b707a16b18ffbc43dd1439e2d45b7cc446",
"0xb0b64b13a4b4aef474da021b6fc5358a85f3c5d3e2c94170c8163dc9e6513046c21f6b0f3f1bfa993a7e9646727d91f9",
"0xa0db5843ef5d20a387be71821a914150a520b98d2e82b48678c476493469db48ecf9bac4f75718f2dde05d9d85f664ac",
"0xb1570013916bc729000d46927590f17e0533c04331ef372ef0770ca18db143377706b1a034831918720fb8912d2e4a68",
"0x9563b2e364939721b26c504441714e09194581c3ab63ede45e9b6ee959ebfe6a540946170b4720d3afa3d507837864c2",
"0xb98ee9dc5718cbbd2575e99c79579b226f270e66966088f31a0a500f15b117dcbfa1bc834b380c45eb92f7f48dd414c4",
"0xa7041b50a55303f55d8e33f78e86b36f8e447043791caa409abf6aee00a73bb46abdc63b118592d2527dc95e0dd910f4",
"0xaba4a6a4f1730cdb5732f81463357cef916e76181d2c8bea181f1d50f67d78ac22302503acee53704d4a4477723cc8f1",
"0xabc0fa4979a4b5c3f98ff7ee60fe2958b66a5208751d32a24a340010e3f668a17639852be6866f7b780d03634a8e690b",
"0xac73b575b07a562995875b93f4a5d286f4695fa8b3197eddc240af98af65cf14cce6515fab4ec149c9c3062b31f59a71",
"0xa12141f2a0e7e28ec563bd2183979b323b2db2ace46634caa7654fa9e78a7d227d5499108d9b824bbf41bb0a7eb36206",
"0xa837d99607e21452882d4b6e8137430773b58f6e737ea95429fcba5d212d6aa521efc4d852a2bd87319d3132414f9ad9",
"0x8f9cc360fccba60728885da856b77ea759c72f74e6159feb9efacdb6d9d0a3f405b45bbd3e4b2a1f19e7a7050e4db188",
"0xa9f934fc0fb5f079cea74c9cc635b9c9f7e90102de2862f1a2e513cd4ff270027e979db00393c38ba938159486ca6466",
"0x883efd70660f9cdeccf8d43172cebb6793344587a9615f15b13acf63218e517193c9e1d8a4a9e7543ac4ec340ecb3f57",
"0xb255febbc7c93fadfa3a54090d1af2faa64c81d65f21a5901a6e44bddf9f6bdc04e6ac9e415bb852f8f8e1a66c9b9e1f",
"0xa83d55b1120c0d67f02b04bdcbdfd31bc391b1a10332d3745a2b497718027dec6fec99019969f11bd2f2c702953531d1",
"0xa1ecfb8d9ae9ffbf62e288e359125f5c9b36486b208aae354ee4d4c07d5b390cd104c51ccd845a5cc59ed71d277114bf",
"0x92f80073ffe7a8fce1d65ff69fd16b28a5951c53bc1a7fd79da23e7092c58de49f1e2a2e69c8d6b38db390551bb4c79f",
"0x91d9c03413bd2c546b4c2f00f2f1c686a8d7ab9340bd844d25adf6452d464d38cc5f520149c05b2ce2b6cb530838dd83",
"0x83a268bcdd59a4e1c5248fa9557dde8ebfb2b629f9a52cbe5b7a32ccb58cb3ceea068e513b1e531df67cd611a703cbc6",
"0x939c12bf71339290bf4b2fb5804d49ef93abe39082c9ee192d722ba6760d5943e06190f0bd95debd5c2130beb6f48477",
"0xa915ebb7ca912935af76ea0254ce30e84ead705a94e822e4dc52cf2db90ff1dda8fbe6c8a1da75e185c839f14ab17343",
"0xae1e55695fcfd95d64048767d52bd4149d69fa0a8775368e55d03e46fd2d90768f6c6bc82b80917dc58159ce6ecaa450",
"0x8d86df85b0af7a02634bbe2a586486569ee2d68c5311c8f580590523e249b82f4ec623b58daa79e745e1b841ddb5c67a",
"0x8496e1fdd84b6092f713da75c1e9cfd1b9ddee43c8d068dd29b4d26ea850a29876ef5948f26d55096507f1b7ef34c34f",
"0xaf0775c01072b6e26024e5b161ec9df52c5b5c8962610e34627a43c064d08813f3387fc9e6cae9cffa7599d3670dfa77",
"0x98f7659504c4e23589634ba13a065dfc41cf125b1f005dad2fc871238b5d8644d0fbb146461ad3d5a3c847ed67f0148c",
"0xaa6f5faefd96263bc8d489f5f7ce90b83e5b845ebafaaa068cd3ad80bab63cef688d54e47f244af733a6259492238170",
"0x9545334a457fa6de1bcffe1bfe55022ae17c483f9642f4df00f3f8037ce48c41c85c3856fe588ce5f1d066b449a322e6",
"0x82de827fa10a7f01d3745f1541bc2cd87913b7035c25bd000a7c10a4361a3ad85c8481aba46395b333797357ee15eddc",
"0x8619b0b264edfe61ba2f59b227d83789d17c628a0917f83cda02ec944f9501904b90542de28652d46d61e3533752aecb",
"0x8fe39cac7d857db0adb6d65cc6c2f3f79714fb8c6e07c4260ba75631850347af3fd49c70bf608d7429b7ee5ed17a7da8",
"0xae7872e385a04bfc3184d20e1b3b216a54da60b2d7d1d2df86e7d0e70ca1ce6c3ba6d33e0f8edebb828b463208db2835",
"0x8c9fad22431036ab8063cdd5ab4f0cc0064fbdb8a7d29e0d6c17877b013629a84114573f3a3e8912f9ca07a99f7e1c81",
"0x8601ccc5f8bea862cb7796d055c7094e3066ea42f01b8298cbac64c3b2fc17d8a8bec8a7c36632839352ebd8634e8c82",
"0x876568c4084a5d7a2c9fe51ca57781768d6ffdb325b8a0f632dc496e5e604cf982c8fadf53cd69db90217a3c1d733211",
"0x93a7b92211c21df28effeb352670d7bebb89064d4c7f489d6c9547c88864d41197a629f4995f6bafd6b90cd30632bf56",
"0x8dfd5323ecdb747995d960e2276de05d7b67e07fbc7f5a517928eb9e66a6ceb60076e6dd52ca3c11249dbcd50720338a",
"0x8f298743b93de69a023023991a1349d24b5ac437ec1ddf0abee9735ded134af1e50e0d1b98dbb4aa801c1e2b93ae3ac6",
"0x980ae9e57e236c382611dff680cc860694466db10598fc899aa75d380a9874b39e742dcb28df1155157d8ab8d764931d",
"0xa081115929d1676c832d49e4d51d0a6d9b4e097ac6c2f5f26eb40b5c197beda528f1bfadcaf5d21d6add367894d5ce86",
"0x8916e596ae84e5e216f51d17df8c668b243584358a9d1c2499cd538f2249ed3a0ca82b1453db1556f8696f6033d35f25",
"0x8a666e822d514f50320d95b540b9d5877e416cbd19f2296b561f2ef8528cda431afa49b069859afd9df064c75f781e09",
"0x96e286b5f5de90ad128750ebe305c4d78e8385eae0294f69f4b28c8e5fce4231a88fbff18cfb36861d064707b4cb3905",
"0xb57d9c68dd7c3c3681e40d8a0e5f7cd577e9488973d2174bea24a45c0b3ebe5436e738f36984b94593d61ad770baa791",
"0x96595459c3114841657593e67ee1822843b758f78d58ce8047ad4020fee5827ef5471ab5f1c5f7511137787a6410daba",
"0xa4edabfff449887ba41646db82cd7d267c3a2805c1abf3edadba6dfc8e36a0db8db93c4a9bb3e8a8c324e89090b7ab5e",
"0xaf54272ac4a0747fc35628eb3b9109ce8ba8409789784357a3513615bda340e5f76bcc34a4079d31cb2eda99f358c011",
"0x99c358228a324e6fec8fbfbe7e35964a65868d6194ea33f8022340e3e577dc37c8783e2108aa866b9a45ef46832896dc",
"0x9527829bf297fba0e4877058dd97ec3f967da844397768abcf94e90a804efa4640449e90adc05eb5c85404a7f2268e31",
"0xb6c5b5476235f02e413a6142bd1596ab852c35ddad45957efc747044c410bd7b04e9e9c1f4b8e0626c4471447f270071",
"0x8cd884d1ca3091da6084dfa5227be0cc573d3a37341c36ba1a4b2498b191b82b618b190c42ef7cf0949f38c6ba57265b",
"0x86580f91e3ce6a90f80c2ab23d3a9ae52cd19a5eca452e20ffd1e3332f120693f15275da28595c5f02dc097c3dffb217",
"0xb72dc29f39ec8e6677ee45d3e75b3646ba57d5954b5079cb525442b817b29970c721f89d8f0ad557c3eb3ba9d5648b14",
"0xb9adb4e972519f60b95ba981001b40774ee4e4447939f0e271a110290a188c24a0dcd9042bd7b2b7f6a6bbe2e7bd63cc",
"0xb130f9a7e924c7cb6abfe000fbc0ea83cfd74070878e76a011d5b8c674ca28c29a71cbaf430961d5d4e2552d33a0e313",
"0x9590cb923931b445705f9b4fc27ca474473eb01807ea789c68d7abf5e54226e7a0ec75b66b7789bd207b4b5567e5daf9",
"0xb80811d7e7bb576dadb412fd71990c4b647bbe946bc362a826fcafbfb55e3332c7615525ecd58c69d2f3f458129f5d88",
"0xb324fbad7df9c0281cccb260221d9c1e4efd32eed76c4a4fa5342d744e1bd5642f174007d4841a9e10f8eb8850385db8",
"0xa89116f74e03bd7694f1196cd8fc168bcc69c9e63aa70e78a704cb611818b254fab5b88397630b577f5a4cffb848c11f",
"0xb41d2c7b0678b6d31a64493cac2c1eb13f469cc7fb46585fe19962cec2898db4beec7222f26d0da3a67d2f4c8203e307",
"0x97753e75861780b97f27d4d6ea26d23417b4eb5be4c3e5b731480837367e02fb9835488f5365dc5ea62405aedec71369",
"0x83f18f444c843c756d76cfb4765eb38d7f89145b604fd4dc55ad02ad2ee2fde80fd1e8752e798f797653d66b9f958860",
"0xb68df85bd2417ed55d6022c2d5dfe9d0070d597c6b0dabff18cdfe646802d550be43c3ee95aed5450b4cadaaa1f2d7df",
"0xad84f26182b45ce04592e363c50b66bbc02265a4297907463f4692efb5265adb55b47158fef19cdf248964960356ca4b",
"0x84a18ebeaa1d9f89acaa4c66b4ca5e4efa643fab924272e0a3af956ad045b09a0cc4ae0e753c60845f3fd0455a8e3fd6",
"0x82d6cb2c04f8e044deef66e2e8af816b8e21da7c911aa22b63f9c494d0c9bebf2b93f35557228d841a637a4bf1533d3b",
"0xb8c6d0180c3102790cf379f081f1d0a373021f4071c13769cc969f4811e1c854bc8c7e423c98c26f4b7da57cce05e185",
"0x8949cc9effd22c232b4b21d07945c67330bb5e084fcfdf0e0b49447faba3a58e3e17d12bfb87207461a34800032f5f3e",
"0xb41b0c34be70f5dd026bf1114860d4ff4ea161785e9af054ee6c7c38f50838d35fed32c4c0d9a0ac910380ea77d191a6",
"0x981e006c0e3443e271b142b10d313457332cfd95b964876afde94740f86cba4f6dbd91746ff937363e457932495069f2",
"0x86cb5c8a1f920d57c5f4da7f5e631015c036c8826dd0788dd9837f2ae9415eaaa852217572f2b5e7d145b1765f6b3eb3",
"0x96723623c1b113ce39f918cf7b4708f140a42250272fed41e07f2a615f57106ca28162dc3f451e0c0d85e5f7ad91afab",
"0xb2406d733dab79f487a2e95a24d679850aa2d7154e1c0d50c6747d89bc02f3f52aa3daae533326d520f8274e0f880c35",
"0xb9604ef0d08f2e898ade26efa2ab6d0df159ca988974d34a2ceff0531e7e3c3b9acdd19f77338fcc6600dcedad5526f2",
"0xa55736f126c5e737c88fdb30d26fcfc9b078063087efd415f1edad91b039bae96cecbfeae2385285532edbd95f1f27a9",
"0xb9ff6cbdd93bb5f6e3f7d661ded098cc569f80763ced9b2f9e60c74731bd73ea4632aac6006e17153f8b7e4bab10aba7",
"0x8676096fa6c7479c9093a7424f2a6e637dcf93fc1ccd9b129d63d744e18e715fab9c611254cdbd15be8575ed191f04ce",
"0xb6aedd69f984a61d3f0482243d56f52461f549f075d2d1ccc04cd46983f739e36927f27b2e7b484d200ef4f6578b7c78",
"0xac3bc467cc084c697ff00105c2ae9d55fe1e92169508318c62a4c68c05141901473b7a00533713b2b574bd5a4381cfa7",
"0x81f88b8b7103f7571f65e23e214c2d6c3b044b37da7421c79d6a9d43ef51e1f0b0ccd697984d104feede6302ef2ba212",
"0x8e9dad29aa820c97cf4dded47a4a32a1772762961258253c42072c65ffc09fb84ecb2059f7fa77ac0536c2089efacac8",
"0xae4121b16427a7a605bd049daae88b93512837f5d5113ccc8d284cc8bf71dbf66d87cbd326aed2368b269b7f423ae080",
"0x9622c73b30b11692e07b95a7c219e5aa0a2007f6455350d5a7b9dc3f61f8e913c792f7c53b5e9f2bd9b1a4b99d3e1ee3",
"0x8e24420eb5401792339a36f9d120308ec10f1a4ddcfb7d9ceea205a44323ec5e48c0464915cbeeb7106dd370cfc917af",
"0x91bba3831ba25069709a7ca087e4a784fc9133cadeade3d3be3ba5bc1ece13201bc6a7f80ccbafc87490d9a1a0305e0e",
"0xb547a5676e091bd1117c8ed3e6343657d31e906d63a59e05364b0036d7a667b5303f10d3d46e8e5482b47b62cc4036d1",
"0xb432e610f1faa9fd5ac8ecb201ad2c94d04360911515e5c3c336de357a4e7a0023778896ae86459ae2b30da20d45bc54",
"0xb68c2ab1148a7ac9d99a6190ffa95f07b0d3899289284fc65069651949fe7ae1b15e3e9b7dc69f4f76b0900e19fb91b4",
"0x807dd739bb3a17694c64d729a0be67ebf4a641d946c3b748e5f03ba21d838d080636f3d0ddeb97d64e805a042114ebd0",
"0x8dd0c94eecc613d181972f7d68f20ed881bc554a5bee23933e431a3559bfc8fe6ee27b15bf74270dbc3aa9c3513edfab",
"0xb31b68f503864861cade9a774d9b726da57695819104a2cc696db8c95e5babfdfe24b2c613f8dc37d99488fd57509fa3",
"0xa05252194362b210b0f90c95c86207cd6f077a0f6bb39beed9d19fbe91702aa552e2520e4b7e204243b5fadab7867205",
"0x82f7cdba450ab0236e82e1af46055ebcd3e330d30c62abc2f1642e6681c930d589db6ac3161efeb421fe727b9a64ac67",
"0x97e7c20d3acd90bb98217ac6511e9fb032b237b7032ea43786f6f2835820eb1e6da08e02fff569a176354295b8cae69f",
"0xa7e3598a7be22d5d16dec750ce70b85b99cc3c157d162d8bc82a936ee23d8255888cb0768e8272176a45cb5d07f8e0d6",
"0xb4b6fd5bd128023043f59f4de579ecb8eec9c82e3d240a832df26dc3a37debd4348fa54c9dff1029af08d476f788f023",
"0xadc70781571a5beb7d0a41ea498a2a8a56e7bde3b1eb981efc2b40582e0f394dce279652b3ca75469ab48fc2257b0b1d",
"0xa10cd3466bf695c56c40886c70ea7e12a10284cef22a009a3eb0fdb1179b19c8102f1ae963579bca3b3535fecd3d998d",
"0xb4b8d86d95a07b64e7976c864c10f892604d68f858d75be9db333cdd75cea7f3e2067859ad5ef8abe3df2bbb92106010",
"0xa0bcb84b05db4917b2ab54e7d9e52e9ebe7c89d9c72b1fdb93ef2d74a8a26fa5961e40a3aadfffe1b6a68d9b896d0a74",
"0x95de5f528448ead998f9381c7ba8b3c4676385e2b3d6ab4e30a28e35b527909d7c9ff9284671a264b581c763d3762f89",
"0xb87fbb72b912fc64e4b93f07299f2bd19affa141780110f0165d9691a2d4088b8c0ae3ef56e17d08d71b595c27d583ab",
"0xa1dc246ec9f56457ddb9c586d290e4da3b6421f9067c710fae053d54fb58f26190144397c1eeb1491459c0996bf72849",
"0xa35f2c15c9629029115107e90c3c97c0d72d39470b94be851750cd035de64c80429cb0e04e5d0fa50f82dc76c36ef07b",
"0xb637ba26fefc8d11ce926462cec2a3fb8e8a6a5c5cc703888e856e991052befe980896ac9a2d9ccf8fd8ee45092aa72d",
"0xafc0a8ecf326b584c7538cd8b92cbca05484c9f2eeb53bfc9ea2e2eb7346e258fc62954276c4cac7e725e2266c400196",
"0xa6c61c2a24daa23a7aa36c7c82a0242b421fdd1af88fab33a58f2509a7c4cb0580ed69fb864cb24e851c56feecedd793",
"0xabe214470c1caa57eeb54541099d96cde259e75ecb01858325570ac0e2c9401490f7c1d1b3e0f24485afdad55c2cd582",
"0xa9d5177ad1a8f4c0ba3fc9258d3e77aa90a6e57d3bcfc8c0a6cc901543be661089a6659268061f1124c6fc315c289a56",
"0xb63ed1c605cd2ca6f4004b5e5fe79c9590731ce30845eb4a4bd6695b6043e19ad3684840af8e1d54766eb33314753fe9",
"0x94cd4be5bc7faeec17b643bf40481dd542d90955e6b51bca4d3128fb1e37694d3f7e3bc4ee75d6542ca24a8bad0b81d4",
"0x934a5a60b44968c0b8cc377632761b278881b421d99323439c5e707d0e106c5f72ddd33103d77600bc1b3d11f62557b7",
"0xacb14a044ff75ed7cc39f30e4e3a5c0c54b1c83c28e83cfb473fc32e386a769bf429307ba0e55a1bb2eeb06dd3d8014c",
"0x8a758539aa5a82f078763c6e45078b4e2baca3b98c018718075260ffc8e83c0642597ae604dd2063b51c83e6070d524f",
"0x8c9a7814738275922c035dcd39659514c937468af95d6d7301de4dacd9be071fd62af650a0728ab4e0a5fc53a2771865",
"0x8a4430d659cebbc1a1ec92f89c07fd6591ba55b09f625cd21ef66ef9e7390ae7a7d6c2c63ca050d8684cf05d2a5eac7f",
"0xa82330828d91dcfa446e8a0a642b82e3d4380d745e25fa740a07c687cf4bc5b660377dd287afcf93ca6471d55e8a26d6",
"0x827d4686c0f3b60bfeb16cac7e47527f4a2caa5058dc3dbc465d8e0de2537f6479cac676582fe4cde5647ec4706c9f53",
"0xad6f422e7c363c017f61dfbd9311d5b28da4fc7ae7f5c8d0cab3e15f7f12f026239ba08a04a6f9131766562361904a26",
"0x84813fd754154488ef00e2ca76d1951a5fb86be8554245419d5e19eba5eb4b9e8630765359de82f8b27eb177b73c2d40",
"0xa209756879441808476a412190c23d18492f2c581878fae2cca6a68582cbe55dc8eaf5e72b7574ba0bcd3c12d1b685c8",
"0x82b49e6ba3bd37f12063236eb7c4b7f10085551e127422fa457f6170917de1c805e197a8d1344fb8b2a6f4155ad393c3",
"0x8a74a9b04c0dc06c040ba03768a3a05dc73453fd4d5b5589ba64e1f485ac5cd44f10c71527cfd2e59b056e121688a9d4",
"0x934fe36c50ef79bfd2954b96240d1fa5407e9c17d2795db45ed1e1173064c7702710d8e722c74b95f51e0c164cdb8332",
"0x94355110229eff7e4a51c35e958cefde3de8d8d1ec17f06363a78ce8c6282278403fac5ff2c12a1857c7565fb65f68b9",
"0x87a24b2de472d97a5bb1d7729f8020c9a1c680c36f89d907a8118c6596e5f32eb9f474ff095ebb5fccb02b957b0979bc",
"0xae594a794c1668eb8356a2a7482a2513f181f2b986b792d22d785415fdaccbc4f70a13407fbd4703acefd48d4ed1e41b",
"0xa3dcce76ae232ffd62175eb1460cb8b2013df7607ba3fba680c0e62c52b30b7b8edf1c851b0c5afa8ea4156688e2a6ce",
"0xa32f076cf300be187f4afbb1d929fec74cb8c376436487c36783fa8297d7af0574447be2f7304e9cb6fa3e3e0bc89f78",
"0xb415ad89cd032270ddab84d700da9cad7e8eb28842b06ec73e82e96d740b2021953eee83d68ecc62d918c3e5ca77a3df",
"0x8fd8b27c4d90609875bddced8ed73d5a64bd258118a48793f563b7da839e3ed94a4b9570a02d7b37403acda6690085fb",
"0x91da0fa939b8a6b5b1e29cf1e9eabe3c0a9c8afd8f145187d077835aa50cb2d2ea817e0acb5c456025de0f1a1cd674cc",
"0xb587eb341325856a61809c7b3a8af866176daf5299fbd1e17b5f1fcbdda935e4d50addabc0d81b6363705a14356799a4",
"0x816b79903a2639e203fd4fa3aa29a9a7836cfc8326502364bed8de8a0c039fd0bae249716d4cf8758b822ee37cde1435",
"0xa22cb4d1e5d5a06c722a38a1c399b6a5d494ce0b8b0308e7958bea4822dbf17273dbc789944c6806fcb5669ecaa60ccd",
"0x98cf1afcd4ce98c7c839469ff82db707f02cfac06eb9c72cf54540a2d1cad6ed5a5f0698542a0fb42d22e0b5f4a3ec88",
"0x82edeb395ae976e25a4b870422e485523da63704ba6e20aff3b98d789890ac0b0da82fc9e81365d7166abf70a4aed8a8",
"0xa8a88fdf51a32af50d316aafe119b6a691e7094325a6b59094791f813cde9c7033d5cafb5d3ea635ef2f909f1b29ebdc",
"0x995b5ad21caace500daffac9ed0333d4038563be8dcc75271853bbd1a19f548780bbe1e8f2be4bc06bc0133877b3cb14",
"0xaf4b7a224fcad45141cf4eb11590225f7f182ef4d7d17c5b09de589646ece2467ba9f54616cb9996532c0a6acd545693",
"0x9257a35c42a9ce29c0be75e7fbadd6b458c3425a284f9ed5e1b2ba516ac19156e11109b9581fbc00c53ebe1230298b89",
"0x8b07e83e3b5a0885efba901fadf118fa84c0b65d4f9873c64ee0e3a28e5d9e64621449965419740b9545e2faad97a6fe",
"0xac2722717498b65093041dc75d94ea415f185827897a807ac3dcd09556cef011142a2a9326fe02ff29991a1d243598b2",
"0x95b6a0ba65d368b38852e56a2610921b0015a2551804e4369a94853f28ea0e0cce3902e349fb87b844430e66fc4ce9f7",
"0xb2a8cf6762383d86b958b09773b29ba01bf6e40439f31b7c1a157bb4c49503235a486c2e5d5d41589878a917a8c1e2e9",
"0x8d25ca690bfb7cc52903d090b35043e8027d8208d44c2dce7f0088c1e829976c7da893f2a80a43d4c85c8a30bad1c29a",
"0x86d16ce7d78031e049e6e158cde89915b61dc589b42d6ce4bd4969ebb248a37003d88e984366073d1253630ce60a1ab5",
"0x942bf83cd771a10c9bcf184da509ba0cc3dc53a1941dbd40cb710430f8d0bea53f4ee31765921ac53097bae8f3ae0b29",
"0x87e10721d75870e42e3181ae86058476f377413af8723a4d8352bf72d14663d8f9362995e244e0b6849ba8b118b9fc15",
"0x9834a7a9999068ab9ba2e9069c75d9e62f402f7aee7154870b4d543d370a1b91f70e0ba9e04af710e9b5977f9d0bfbf9",
"0x8e51f7d284eed64da1a72f3e69e4c35b0f8954637817b26a1fade27fe767dea3a0b45d2d0ebc95c27defd1958fc68aae",
"0x9815160312b5a373d360cae2506aa196f46d69904ff079be7b45437725f3bd1fee5492329d7de3a79533cad990b8b78f",
"0xad582ef0368263a1042fd552bbe03e196fe763ff9c4be7b2d2bc57c559c983b6244decd5101503ab3afc66a6c1b78e9a",
"0x8dabd55463321b05aa560ddafdcd4cbed6dfce4ad64d24d29b745b9a7be0b05dcfc75a4ecab4e4e6927e70fc533c613d",
"0xa5e327aa97fc38256435e77e946c4d0d4d0cea2288db876f12f4a644456b0e43fbed1ee1b5dcfc84687f5cf50d0aced9",
"0xad5e5e6b387e05074d06ea98c2eb33b3928f07c3d78756d33ba1ebef5545e005baddf385a090ce09eb0c1b9e073282f7",
"0xabdb15fbfd6de62b6d05fb9743813c8195ff247f42b7b55bdb1cad40e75c5da07723ed2f396695e9b7768eb0034e6e4a",
"0x8c679beebc7df210a07fca2af8bd519f53764ebba48042eb208eb3023fe601e43eb78de16c7e01ac691deb8d45a3771d",
"0xb7eaee984d4cf2f5118ab3073a305dff539f71ab2fbf278bb2381e3a7474909ddcf9c48268b887bba0ddeee8f85368aa",
"0xa32fe0ded8f04b8b01dfd5927cdc49bb4bf8f81a0feb0e9c3352e0bfbda2e0a47ebc889efa51d532395d4e1f55b12e40",
"0x910e68b8910bcf72db94d86903cb933405724d0e5471761f844d5e8032425f4cbf5edc4764cac0c97e202ff7d1260690",
"0x8635476f243d70f33199f10d5eef2c52f0dcf5cd94b0e5a1cf65bc52346b9ab5c62252ad6a30e51e641717234af1930b",
"0xb70a83bb0ea82378c69be19c7d09b9d79715f51b2f0fc76590ddb0a854676d436d5df4b5a7b07841f1e4ee0a2f53af4e",
"0xaff10fca80fa5dee07581449b5f7fc0bc49f9d3692f82c142da6a3bca473f915fa2336058b3d43ee72da68b296daed8a",
"0x8d2aaea1347fb773784fbaa1ffdb1a4532c39bebbd67a60fceac187e0c53d0c5ce24ee63b3834d37853cf2d1cfeac0eb",
"0x839095132d828e9ba44834938a2d2215c005b1b3253923ed725f967ebb9048deb4a77763551eb4f21b545a6f2a5cfc9b",
"0xad689afcde4c93de9ee7fea091a3986c18b8f150f3c5b590d01b52912eda9b500c4b6a9c859f1c94ceacc2d36a30a63c",
"0xa87f003509f48721ce96f07d6275d0271507a7c5514f43a528f5ca6b8604252c374c63b8be1243c772eb9e4fad764efc",
"0xa375b3f01167fbacc31098dc314beaac4c588e82d2b25a9f54977c416397129de684b21d623b9b8f7b662a0ebf697795",
"0xb4d9b9c4bdba5ca97778a0212ebed9eddf1a401b7b86d09aef1558c6f80923780d116429b967c470b8844aa634447609",
"0x96f222d696b5f7d78464f3935aef514fd93d92e6d2144dec0ba5d20ca92f9b47fd049b7707c489d95852198076a7b3e6",
"0x850f9dc96df38be7881d20260d4f8c1de2423893fcb07bc8f909b49efd8c7bc6279ee928dfac2d6252cbc65cea89c59b",
"0xa8c191ef703f615922a3c8f5738464baa6cad1180af9363fe5856df6f0e8f4069fbbf2459ec6a2f7335a8d938feb9025",
"0xb9c8fe68a8424710080b51e43e3a077a21fa1786a0f09b47b9f4df14e60d52364d9a7e347c9baff9064721750f90cd42",
"0x99287c61ce49700183076a705f84fde1ba9256dbe99a0cddec37a26594a0922826600d577cf06d3992e7de9e894a7aca",
"0xafe50aa8421e71aa450f69d509533599abb135d44fbe00455d0509051a8cc8b019e844cf727dd8f437d05e26e015c4e2",
"0x92a3bec46bd9bb87a1094a50e726ce45787a401f021979273cfb843f38a86f6ac30bce6a967371364d5d5fdf001f5307",
"0x94ba65a0a8f9f0f068f87286451afd3e6a2f3da3d7e04443174cdb570cbf0b1db99bdad24120342caeee94fbfa0552a1",
"0x974b5dcf98ebbafb46228637a1ee398c3232d369041b7e54acae68a7433c16597c15a421477f6084574469b234979a46",
"0x829909dc9bd18bc00f9d207265e3c5fa7cef86b263bc1a8f4bb38ac149a0d359d5826bf17873eca3e26de0003f8273b5",
"0xa412f463eb1ce3dba017e26baa1f9462540dfb1b4869f457c0662944160b15bd2048f4294516b4e5f963de2a26d8e6c2",
"0xad18c1793a0dca47a007dfeed949734c052539ebeb3038f467b13002d230b3bd3fb6a5a790bf5875fa8d7578b15eef94",
"0xa00bdccdb819cb0be1c82029845c34ad2714c98e01c8daf32742b93d6a5d68b45bd9860d2a3a16354719d94ee765c279",
"0x95bf88625608534df263f10dfd0e035e2dbc32ed364fec9ea0f54284531a1c91d9f5da40c854e6d362530922872285fb",
"0xb6129ce594f600af8204ed47ac63591df553b6b6838854d132471cce5b58b69e3a7421dc18eb9fca63d701d181fca246",
"0x88e7d4a16e184f972e9d2e37175133b73f6d7332f6d4938ba1fb2be193c3c7376a057a412d2764b11c55531c57a8bca2",
"0xb06725bd8ea964bbadee23df09862e27a72b0d84d946c27b24a89ce00bd076c072dfae6359a3d456bb6f00b58da41b9a",
"0x8a230574460af57c06daf8fe299a9e20b1814d92dfc88dbe1c2f9cd5b67554cac4615828ed8f7c04ac77631669634a2f",
"0x8c9be345ded9d3bdd3ef6ebcc914b9bad60806d5e8ed8987e644d022dead01599522d32307f4252c49fe24c609e744b9",
"0x8ed42a0222f48c01165bf89c3381b13adec7b434c8a5c11ff2401ab44e79c7c5f0ccd9a364e19499c1a4875b4ea284b5",
"0x846ee59fbeee4f2b95e8ff6b062c27383f29e8b6df3f7135526ff9bf34f4aea783924758bf83d3250c991901a11170f5",
"0xa0509b13ac31034aa9528d39cb622ffc3f74fc173a6eaf3530d6f54c0cf19eea536ac27a3296b40f0e4448f5b0415bb3",
"0xb3e24d8b7dd94c5427cb5d3fea62eedf2577fda8a3ecba5519dd57f843359e004250388fc51f3c52a4bc0e9e9add66ce",
"0x90e8fbafcd68b1c71f3fc3da14a142128a28391d4ea01e211948f742e492376fbd45bdd37ba6fe382fce28e8b50982fa",
"0xab89c7b0e1e1371751719d1e672a590fa993bbe31a0a65fcabf2967cf7b5a946e06b5a11104d3e0fe84411594f31528a",
"0x88141dd38d8a246465eb474c26f7dee2287b7269c58dd644f52809bd4458cba8e92e547ea28884a2486dcc80fb156340",
"0xb323a4bb4bfde21aec718bf4718037b0ee05c93bc7ec9ff3e7aa840b8dac931329c5aad8644a5edd0cec203767865564",
"0x912c5c064bda2983c54ebe9e927ff00eddde82e27e4cada42eaacee546e4e3b87a15ae9ae8002343b20098cca3fcda9e",
"0x949dddbaede7db7c5cfdc2801d84163a0f9a7528c795e4a68ff56289c07b432941f09d3f9325eebfb58b96cbb3be5d14",
"0xa2f1c75490027cbc691ce58257ed5e5d7d33e3ae48bc0d1c76aad9e87d180750c95dee06f24b8130ed1449ff0719f709",
"0xb121ac1f532597b043a7529f5bafaee271aca174e00ddc573f121584d42f39ba407b60909fa5d553ba3f1404e5c9efac",
"0xa227294b5ce9a703215cbc150006b8bde5383ad62d493776c3608bbd700a6a9f9266974545098467c2adf0216d0511b1",
"0xa645fc5434ef686dc1e0299cdb482b0d44a805ddddeea60f679aef6c68242f27cabb4ab6bd6950629278f1cf9a3e383b",
"0xb138f732ef5470e3a24107ab5b8914bc65df996587a1133689fce0acdaaac1ba7813e8355e1497b2f7c623376ad9d93f",
"0xb1999c40ccf40cb48fa85d2d81d3b9a23007f34979befdf0a715401e42dfdd7d17a4088c4e5148fd8fb22d93cb0715b3",
"0x95b5e4d415e128fe7267051114ae0730460b5e8b83a148f50c831354fc52fbaac8930963f7b038292f37c37564544c1b",
"0x8fd63048cf632b7d25476a7f2bd0cbe5d27a27a7cfac78b399cbf67e56cbd1950893ca3b4a9dd92478482729ccc52edd",
"0x8c0d954a41db75fd3b1277c8f39d12dad2c1bd6fa5e0c495a72d955546d69fb33aba8d735fc130b1142455369698e1f8",
"0xb85a2178b54b6cefc7c052992d1bb5697cdd17165476f843bd359d22fcb0d84536a77e805c97be806ad3983b63812ede",
"0xb85484e500f55ed2158f2ac96de79664e68049f5e595c95ff7a0d38412f1fe8065a8be66b5a093698ed5897f482bb72d",
"0xa80ea24b3b288597fd10c364b1ebcb8b49c337e9dc120692fc3554748456df57e3d9e14a29a752b53bc93f1eed6b62f7",
"0xaeae8798fdf8ef637b0d44a3fc0930683f2bffe01fba18c706792febcc591b562423f67eeacf0eed791c5f970a5066fa",
"0x864df81664bd51f7681e8849080e0ef3d7598a5c6e79aeadcf3438c4db2b37a4248d858aee0e062e3ce764be2c082d73",
"0xb8eb250f34e47f0c8fb6f0c5900c8cafcde5245e500b7366612ee6f8a11ff47764bab9514bc17f60ea39c62e7c62612d",
"0xb2d7d689319bd3c5cff190c0c378ea0aced5705a0bf949bfdf0b361f85a87f3463277100a73db4aa17292ed4f2ec73cb",
"0xa95e035c3d620207291ec6a0da8e1b4a0051168a8d4778b8d12ced8fa5eaa8341d8e2c96f7bacd2573f5b38a888530a9",
"0x8ab7a2d9b38a71dc15cdda24c9d99921da0c19dda2fb0ee5b25742a4dd6cdef98b243d25ea6cbf90d4a1a6fc622265df",
"0xa3fe8df76114613005d958e2f8477fc2557c7c00274c55db5303eb1e4d0aa1d80803fd5783e583b661c22bf1b93b1de9",
"0xabb52e7720dbddf926a96a21ef94c419d99e392962ae92b7d87a250ace37ad9c1be0192032396308108ac21878862a8d",
"0xad94073521e1583c0c8d655c7a38ee3f2490a939ca1ae814cf9a961533ca4e53b8c0bd3109782bcaec1495225ee9ef21",
"0xa2a98f2a0850b736e71a50c2e7cfe4f239627dc32fca5f2ab860926ffa7cca02a1bb40218eb88c7e30a6feff7b2ed97a",
"0xb9896126df609b9293f88683d56fc1c3731711b5ef36d51c4e8f57aa510f6d01a6de0592e0353a1430926017a8a133eb",
"0xafe0114f0991ad339c4d61e2c0cc25b78e54da66eef86251d9b94a9dacfd000667cbd7c574bf7ddaa0878ce40d9c142b",
"0xab33a9954886656307b70b710d0fd2be5aff948b018d86e0d54c1eb9bda09e1a41cf694e397cbc1140dc28544564f112",
"0x8d463548631a20b46cd84a91a1d88249d11efeb0bbc8e6512299416f50dc6826e40b102791a87feb273c3934cdae42d2",
"0x8c223a1d785dc445b5239ee13181f016594b1ba46b18b34cfb32c1886737636ff5f3c1d42e1253f54c6d7d10ae108182",
"0x85a76a1170987a00ef36737e06c219dfb14c0c6439692e4566a7e2a365e235a0409dce27bb86d6bd514c0cafdb724a84",
"0x96f66a28b87f729dd6cd50a59ed76229dd103ec05615f11c879c385ad2bbafa939d2909e70aae0294b1296e128cc9dff",
"0xb1d0ec1e38b1e5a76374cea1a8098c9ac7c5c8a2df521ae4a5cf08a2d087af6150213b6207d72f15445e71dbe4e62983",
"0x978ea82ae02c3f5b036b8dd921a6bb31de22c86851a0e9ad6ac5f841ef74539ab7495b56b463158b0d3287dbbf1efd6d",
"0x8ca3f1c70424145a58af0dc12f63e6da7039026e5af0576f9281cc45c33be931024047b0a5ac6d296494d5026a6d50af",
"0xa5634400602ab9ee917ca89930e85234a6e3efaa7184cde0963c7b5b51701f3dff3422c1ed3c9d8322b9f3d4385e625d",
"0xb9648f646c294732c2826249de9e8439c205be487c123e56e763ee49107168bd9530aea41041cea748ab4ce1ed6b8294",
"0xb72a0ee4751acad142e1bb44826ce47d11145560879db81a328cb0112b60793a29179846f157ed2df789da2a295d57fc",
"0x8f90bf84e4178b25e7f68264284ee17fd281e8a84b51a5e7ee04414170b9c637ea7c7ac80f71d02b435eb4717ccb5276",
"0xa4671ba51d40ee33dcbd4b6153197bb79919c6599043de01b4db56a1622ee9a8590f1ebecdeadc8c7105a003ea74567f",
"0x808e21a11be47cff2e04fdeac8e605c95646f1f34f6566b2c5bbfb55316da922d015c338761b20fc66e03db56a397376",
"0xa1f4d3e0838f2917ad2b3759f202b80dc76f64c31d74cd2357a4ccf90c925331bf0170704c6e323a4f9f2cc37e24fb0f",
"0xa897ac6349b9d314c600bd811112743d7e3209b2259f2df5be451a6291aee3a96017b414b3f37677c776a159766a3aa5",
"0x8b813cfc9a260895787a30cec6f764afb19b33ff0c5d99377c2079547cb4e2e9a3039273c324b96de13ba89ca32720ef",
"0xa2390c3d8a20906115440d51c467a6c844ea45d21723304d3446bf66919217b4013ca32b27342779750fd498f6f77f44",
"0x83b2d8d8160003943aa3a1b33275b36f73260b76309a1825a773746006650469027e8703f0b99237ab0c1d2c7b530b41",
"0xab8e694ecd08290e5468b2678a2b26cc4e5c7488117d046bb13cb69847aa30262ffda5999aaf62e93ef6473519f89481",
"0x92d274414b27f9792dbce29aada1e73a365fa907e46f7b71cd1cf5e8680c5edeb3b26f94be6cf6847a1e0c43408bb949",
"0x9214f625d6d9e8e81d7e5048dd448538cbbf86a49138b7e8d02a9f1ba18815bcd74ae801a118cdbac127cfbb3192201f",
"0xb81a97535bfee5394c8d555d90a96d4d99e8ed94af72281a0ce289c68c867bbc944950e082c67f2bc7e02737ba995f73",
"0x96f3652f6cf5578065d7d873538e3f245ba912d7e8d5881228ed6fbad0d2bf737130b6f353a2a1ad224961321d117731",
"0x850296b95e28e9b8a2dbc7078d5a7b49ac1f18009cd19854a26b76837fa15a38d9ec8563feef30412676b0506754e5a3",
"0xb4a59fea80d8026b1a36e7c06acb8d9903430beea306b1f3c4f049a97287e552f35a512c1b0205e5a09010dd7648ae03",
"0xb689fe66eca8424246b13d637ee230b0d7df53e7d7d3d30abbbd0ba68129c4bdba7a19291a0757f87a360e3676e1d0c1",
"0x9411006414a816076fba27262b18e0972aea1fb382f702e1769b4b723300e19ffaa7c30fed6f85cb453227aa9b60e57f",
"0x96727fcbbba02678d8ab6efdecbc1520a4948d216bfe6bad5a9b7ca671e432ca32d78eac06c15a751686a8e2c8cadd90",
"0x8629d173772ec13f79f32ad6d8f44b1f0193005fa790153dbd664d82551ca61578fc469cd2e402fd73dffd0f484a0734",
"0x974e667759f8f80cd175fde904721f18462a0e41933e2190c22b71148dc8f3a9226b238c065db39dc1c16ba38cacd4a2",
"0xa923b9cab201c92772f8a5f24dcfff38e6a64f3e7bce98fb4c07c501cf417486ee351cb3a1178d22e774eefc7cca43a2",
"0xafe9ec7ab9d38ed55d9a4ba7b61e6af7d04afadc148eed00fb649d49e1a93d8c4540d5c4abda067b932e471355a529e4",
"0x863da460ec5ce9d0576ec531f61702ba57eaf143424657ccbc3f10d979938b85037d1b210745461c2d8e259fca8199b2",
"0x805d3cea10c354758028de971de4d2c8aed3fd79c8735cc2e2c9194a72efe631ea42cc0e9c7dd1b8b49c096f9a6a6fdb",
"0x8bbf7d3aa5647ddafdf04c1eface154818fb8b5629617476b1d4dc834e1ed6cd74cd4fc11a10d7610f49e40530d47698",
"0x8c82b6491d918c0a1afd611d98774fad2a76c7a0a227fbadc3286144d6d120e1cf257496a0acccdb3ca0c94727311b01",
"0xb643e6baba0a8a1ae1fcb92ade166d6890f6dc3350a9a01ae078ef9b4d97cffc1419b37dcdf509d6e61606373d1c9475",
"0x8861fe2272a789ddfb2555431acbc71f67f942fe395a2c975843030e50961372a24ccda34fd48e5f6f640c50dc065a6e",
"0x97025de3263b266180219aeb308ca71f1fed55f54ac50c87b4b8c8b1c1b96c51ffc53b75faf37b2a8627c819a1943771",
"0x983d19931b7a2116fbb3bd429b9e5def5e6b7e8750d5faabc83446e8b032f5228af0620c84dbf51c498cbcc8aba43ec2",
"0x8bba98fcc07c2c43d416a7d4d1eca067dba76230535bd92be46e3fe7b3d5743d2998b822947f3fdc0bea3b2ad9d9ba93",
"0x8422722318b72285f7d86025468dec58f9a0f301a29a09df5277c99f88cb6ed028df5c868dc1e584366415c647a47ec9",
"0xa338f8183b6939c5c1681a4b32a5bc81f2036d3bd14eb223aeb6a0e7b6c63be76573042717b68733375403a3bd6d0834",
"0x91ce651c3ecdd672c051775dff4ad3efd12d81c7510398c723fe13620f0f9f382d9c6e47e8bf9a54e8da9e1d71a7d010",
"0x83269cad7d0ed41160fec4be634b6e9c0d8830bb95b153f68f6e1e0b509a0608400c8ddebbad116927982101950cdeab",
"0x80cce1262b8cff5025c364a00786c6c08ccfa363de9a6c893161d79b420485f3e45fc47dc9625610ee94ad5fde5a672b",
"0x90afb5e96929fb0d4f908b74793f76bbcc95e2a23042cbf9bacb2e39e1708dc8dfb331832e4255e2c166aec99e3bf357",
"0xb743ff215b97288517332a9829e1f79ebb24407f696f9b157003bc9945b460e9a4dae0f5fa3941ac18f945a678157b2e",
"0xb6542332bb5d13a200de1759bf46f50d150ffd3dcd896803219c95a765f3d57ec28563fd9c1782faeb0a5684675d51bd",
"0x94b7e98d8ad0cdb1a7e0ed465f05d285087f190cf9ea9e839687a6030cead4864abcc0d44343e1670a5a1d6dcc27a2be",
"0xaa6895a135a4efb439fb09e216d64594304fd15430a2f81de89bcd10ceeadcfbbdb9c481e846a258df0c45c81b3fd02c",
"0x9826c9769c497004a35fcd31f58e9237319e642ed928ff49749458511bb946dadecacae5a2e8b5d90a5857621588de94",
"0xb0ae1b709f9f52254bfc25520ef18f2ffccb80a564e7400e90e0e348c53631f13e29196b16c53fff25c6a4df90280086",
"0x8b97eeb339ec833536f7bfa2b0bfc1720ba2d9f8ebfd5cb4173d1aef853b911a4cb6cd73bd9a6576af3c67f79692db06",
"0xa9a785d59414a40cc025d35b1aae511fde18e8360e06be1d60f1cba87bb3879396728a448ffe8a2689b5523a0313fa21",
"0xa551c402c0456b348c81fce4d2e05d4a56c37591342e80f35885fdc766cb0df5f9a14b7a8178d105ed6a1620b04a8fe8",
"0x9653da9cb83b2869dc60a2de6bbaeaa670fa6516a92ca1da09a6b36fde1f41387d13aa013b2cfb05fb0dd568d00d48c2",
"0x8b1f88f326228ab4ea19c28ffae9e93a192c778aee51538fa09a80f6ed93b67613c5e1e7dc7bbefb7dc540a094bf160c",
"0x92ba10d87689d6f13ce6863071bcb5b778fb82000d8781a64f3e67af1ec2b2d50cdfd85d5341ebc3593e764e9a74e43f",
"0x85845552d41fd0d36d42069a50cbfe61520d3b604fc0c305eacc9a1f37b9f65a57a1e833cd3ef3979db057779a4ebf93",
"0x8654fbee8a4b281fe61787f516e4212ec5c93dd6c93736097782d66acc81f05c547d8304f041c6c2cb3b3d5b277c5545",
"0x8bf521b5eca84a18afb6926e1c5c143ab64d3822cbba3b524339940eb628e1f5296fc938f27276bfb8f8ecbfbb730b5e",
"0xa20ab3d19b03c55719a4507d401003767f7fd9593c2b2d11724aa83325d6a226a687ca63f698b29849aabce8f0ee610e",
"0x8bfca091ed9b8dc24079cfed213b6eaec21b0dd9a22a77e9757e441dde14a023ee2e7a6cb913b21804df682fc420cb06",
"0x8d5bdb82757a373d8653ce5e12e6246ab606fa7ca23688d63597c964876b92a9c100cd45bf9fa4bd64556634d3fbdbcb",
"0xb3faa4919395957683785762d2bb45ce36be9c19f348d8fe7b772e920a56bd3b1a89efb552c85cf17020d630f2af6575",
"0xa9ad7dfe24c1b5aa0d79b7ff80d336f74d64b16bc3602b22e7536a6bcd6d56ef685f7d1773cd70f055e2cfdf4ead2043",
"0xaf329f026ad345ba2ba781e8db7f908d111097eb028acc1536a5f8d6bb03b26433c7a740d5290862c1e2b10451e9162d",
"0x8c1b9bed1a2371fb5340a7f8c721df731b7835dc43ca0cf9aba0d644cbc22a9e223016fa8b52bd4f68ec8ebf4684f435",
"0xb0297e64424e87bca6ea91b60be5d8cf09fd05ee5dff1b31fcdb4e966e520ad2dff7ff9d316dcf7b7225b3ca26a8f317",
"0xa4d6eb27235d0d846fda81fe5085d06f1b28b93b0ab44e34fcdb93d6936d010abf8addcf301a3fc914ef71b7992faa80",
"0xa7b5ce82076a9a3354ebf4ab32c50c96d890d90b4ad60635e7798c69f286ddf897f8941c8faf6398754eebd14e3503c2",
"0x8d3a33fdb641fcd7c22bb5f58b20f1c58267bb90517113aef86269cc9decfb0e2d921e91e31ea11904224c8ac26d851e",
"0xb56b934e822be5aa3ef7c728918f767d4b624117bcfd6f987f9e53e1c18b956bdf7a2eed8afd49169d5112f8222946eb",
"0xad6685c0a17876cee8284f62fbfec96d2971bcc55d1b6cd19848c61d2dc2655f016473277aedc6a94d08ccecd9e7f5bb",
"0xac9d9b9946f92d9167818bc2f400af335c50b55499f8642f2d95c5e90578fa4958c1181d098b08c064c14288722dcede",
"0xa9a25f1132912b4a1974cea2227935196e9913b355869d6b7eee8f6f443fe849ef54e5dc76fe18dc31603633302d06d4",
"0xb18c43914eaa3eac7e92f72f4ca5f33c5cdc959204cf848db3999babe1a4112dcc196e1c81ca14050261d3ee654ed8a1",
"0xaa57c9bd255e19930330e67eddbbda30a210f1f991471942d4e4ff9e3f51173b405769102064f756a8886ebaf8a903ad",
"0x8dbf109fb26a12bde88555d3bd287e3268dd9d6ddb93f220952ee294897a1c128bbae877f35d5d1861e04c576dc2a3d7",
"0xb276ca76d6a75fc348d8f10da0ed3fc4022d9c3d3788ac1741e861d7d3cd8ed911dbd9a4ea5d88b478d2f5c439ddc138",
"0xad3c8b4ff9e7af7fdae7bd6653d03db1d226ae62a7c2f74f6b2832c7ffaca6c8d90bbb833f4cce2d336dbcd88e4e7edb",
"0x8f6df239c7023257bda104e19b05e7671c31ef5b952344176a5dc249e7b0dadfff969eb79fcd2eb62f722a6611d26661",
"0x96c86fa69c51fea17a4b0b740b635d21d8d9f1ec94c8925924eb1621f1f5b2cd23431da9cb4e32cd70f53684ca931966",
"0x9741ad36427760715378550d1c22de3d2bc438033cc03c3200021d16f3c426f4d58606f83fe3f93ef3c88b8402c4887e",
"0x8305d3e5e2be2bab1072acf6cbb50d431bc41547feff297cabeb44ee44bde2c3c5864220e5af6c591bce6ce16b1aaf84",
"0x9374420e4f1f23af9ac3b0b5ad9de1f41f1725765d2e2f398b152e145f3f4664e2839eadf1ba2fadf141b48c92141337",
"0xa4562968152d6d24aea9fbcb0978c3c70e25e2236e08fb2b4557e5b11ab9d8cb33e1ad502e9d972ff00a4db52f8f7d35",
"0x83c93a5f9ee1698e45e3f264c8fe9eb2082e9d977cdbaee4c035205285b7451d1c4462edab69c290d4a7178232ef8d3e",
"0xa54576136787045261d6d95aa9e53e2668c8094027a12391178cdc2dfaef94fb729b3dc4dc24a3a0b69a94249d6f37b2",
"0x88b172a1e267f88f0e55763653a1f69479654b9a932bbb4ef8ee33533e27b35d8182a8009ca0e2f13dd14302c91d0d5a",
"0xb74d49c1fcea755cd747e6f05b890df9f93ceafe6a09bcd5699a1cb6bd4b32a886c875e6bc7923a37cbc6998214f23b6",
"0xb1501a459562a0c3592dbad1ead82252853e1975cb186c78e2b1ce604ecedc8deba613e903626b8064da7887de5c7e4f",
"0x95f9ba4f84db2b875de1ee1dd7840d663759a6faf20dab17e85f11aef9a403db820dbfdc41fcac8e76799f40a881b3a8",
"0x85faa3344f8d07de0d74bc7205082693fe3d1968e0c40310a48ab1773c0ff9b2f61c75eff74166dd63ce8c2a9c0aa519",
"0x98c668be65f12afcf6f45e360fa9ef6d05e6eb63ac8132c95038f6730e585e34e25aada3cb433dc028ad477a7d137358",
"0x975a911ed97d747099f609fd19a76c00f5ea005d50b96376ab75c2bef96162ea338dd0e9b8868bcb2b6f1eda525cb591",
"0x98f1b6264ebd9954b01f058026489763421a01a0889f37bd1acd6785ccf44290b46172635a0126e16bf997d1804792fd",
"0x980f1b1f5bdf3a2813aecaffd057f4fbdfcd2323fb5860262f0c4a79c525df63784c643f20eb22ab9b14ba15c7b01615",
"0x8436b25525dc8e6094322bdf807d1aa2996e64091c30a9e12173a1b357b95b1ba938aebe1fe55c2758edf8e34b5f7329",
"0x92cb8d7f898742bb4e2b6ed8e55fcac5382b99a67fc1e5ff6dc91db1e4d7c3c1285ca6e80932d9d9513ce0e21654e372",
"0x8f2b6a3807e21de3b82c754927c4359e7c700286e88955472de3c3ef91f58994ea56a10837b96576b9beff1f996833db",
"0x9568497114a28ebb94d365a73e54d296c78c8a00e400148afb9d408684c7a03111eddeba638cc0e2039f1f45c835ef4d",
"0xaad3c72b4fe19411651a684e54ad95b2650b75889ce24e5bf1af5d0b63a7b3405e10684b4247b95de6c67644c6f813b8",
"0xad70bd1662ba8de25a894ed9d369f6982c05560bf5e369c2d01968a226cf5c038eda615c38eb0fc9d0ad7bd5f5c31b8d",
"0x91c1c7f59a561c6afc0c440375573f491998d7ba0d1c5837860b2074370c0697182de098990861bc8921add91adfa84e",
"0xb5f1221b37e19ab5b0be66ce4fcf8d8edb08b31af055ae3df2bc3d3b6547da5064ab9a86856853faf0006702bccc9e37",
"0xac0c6a10ddc41f1500e8efe23a6472309ce2ea4cca644421f3a6a6c9e19460a06c25a2f66116c16eb078863a3bcdbcde",
"0x93f8204ae13e2c7b92d784dafeb28d6ceb2c1cc6fe0caab039e5a378bc87c992e3cbea64347588991a45dd91ad52308f",
"0xace84ae505573b433fbc0a0f93a86f71f48f30b334fec5fd86f0fca0578080cce605955e3f244bd2901a9ab2fb9855ae",
"0x8c47430b02a01f7efdc90446043592552d2436c663f62dd0415a111ab41124271529f40b78a583e946fc8a791bb405e2",
"0x9746e09ca817dd9257ee1ac4ba95dce1f1da66dc07172b7e7859f173c40b21f0f912f9273398a7b050c186c92f1baef7",
"0x8e8cd42957e12c38377103dfc2c3013deb627daaf6d6011073245f6bff3c4b8c27ec5aa7d455c5f00eb295398ca9bc58",
"0xa5936633ed28b07ccc8a5434babbfe7a2111b8bb2c306e6fe388ad315ea19641ea7515f358fc667f13d9fb1d1067eb25",
"0x8914bd61c2063292ddd9b64305e2a7d8883cdb91dee547a128577de553f1b611d4a5bfe17e4969cabbf38bd7a5d4fc14",
"0x85de28eb89efa5c419b126ce3287936ab9ea09eeedf974bc37ad6a7bff17547ede5afe428cbdac3ba2fd959b3d16fbcd",
"0xb622a192754e8fa73d69454e4f6f89eefc6bba3716b0082fdf74bda4847d8bd21c3e028a61c3510c2d1b25ee9c48401b",
"0xa74c9366e7a9cf8cedf66359b3b03b4b0dd2fe4c15bf4b1f728be7472a27ce479e0d92fd5cbe50363b1245c45b144ffa",
"0x8870152d25d02c8b580646372232ac065eaf7aa3890d6acf5bc9d069f98251cdfab88c2c02e11a00b7f51c8d55f70b29",
"0xa394a4676432f6a9cc8c66ba6e2b3d29881373312d41128413a0df486a793d4b9f1e6d3a7ae5e1a407a789dd1fab29ba",
"0xb8e5aa58a256172195c149fffe7513223e0412eca319e344ea06b76ff3913ba9ec25eef2555ccad2c1e35c7947ae3e47",
"0xb8d4e3185eb5ef45f3502b08acbf879dcf087f7b3cbda3214d612053954e63cdb6fb3512f84ac6e94363445bd2e8cea8",
"0x98521d27aa04a53db1f0d19783e8c78a4650e41ca8c046d075410724201be5054ac163de6e23f7871055a7a5c754313e",
"0x858b814fc3e5d2eededace3d725437b346a82caa4e14d7afca6b8abf3a852417ff731c5746cc88389a9daa4645316869",
"0xaa43f1d635a80a8d383e046433552cbb170cf4b659e660abb397d71e33225552be0939daf1ff0478607e1d6f4b84f604",
"0x8f1e55b08dd72da3daf10631f32df89fb0ff52ab9871024412cfc5ff65ff6b2afd33f03ab713a22fef5a8fa798634354",
"0xa478b0fd88abcdd3da4e63fb669f88c3fb2b7b0750385f9ed520637504ed4c5764ad5c0f0b2d843a0ad99097507a5d0e",
"0xb9b7ecccf5140d3b4660e79625eeab5bb97f95cb78c1e310d4e234911eb4952d467d7b163a991d519f311a0138f04b8b",
"0xa597c486699b203b81ad5a9ad239aaf796391f26d393241e691ebeb8ea5b102bddf56ea2a356b354f0187bc7d4b33689",
"0x8ed9a55edda0a1414bd64a6069f0ec07f20b3ea7a4dd7eefca79082bcd5f5f94ab145ab84eecb2d5029964fb59cd4eac",
"0x8ffd7c21db22cc010d3f172f924c463afa9227f0b8009d0a1be6bd3859319de6fc8c933e1b2e7158b168916d13529110",
"0x86e8e6143a552696dbb1349a212ece4408b8efd54d7fbffe35178c13b8fde9ff70411a63fe4a8be35b9fcb282922b538",
"0x9553f39a170425b4a4e346af3937bec3be30730e446fd387910fd7d64b04d4aeda0de6c35c973ea0d5e9d60397897f9d",
"0xb53251df22419f7dc65242488e2f38e0e01aa60412eaa5123e4067ac5d76f20e72d093a838f91539eacfb1c9086a46f7",
"0xb549a2984990b3a159b6be06d59c158f43b69cf8acabc035572e1d15c3255c51f8a0f3df788cdfd244e878c055f25ac9",
"0xa615712ae4d4fd3ef9723fa09988a44b677beb098fce85bf4ea39a943cc027ba2547ee5ec4143b5f00011916a5f358db",
"0x981f4afdc7ca36475fc567de39d62ad202a93350c7b9d09da59dbc1f10d53ef0f9c7095b3a2ac2c86af71938b895cfc5",
"0xa8f096db03c9e1e6675bbccb9a26bd202cbea463f9557e3de5b6e08aa15fdc2345a898656fb9077fb32fa30ea69a0e7b",
"0x91fae7166f0f4d21e7fba3f7737a7d88b38d472de99dbd61a6b26ec935bba0da282d8b8b9b2c94e7bdf2003b5d354931",
"0x8d6354c49b46d287d27c228f7935de94848a2eea7e0ba3d69e24f4569fdc400be68d829e6579b4b39f36cd44cb382dcc",
"0xa18219917297c3cfd8341e0b434780b541f19b59f8e0044b42c02b333a5f56441b84db7ae94955a06fa14a0cea39bad7",
"0xa72f04ca6876fad40e71fdc530f47483ca634710a8d7b0a26dc31bd4ab9c505860f31891e66ceb0446f2418866c800cf",
"0x949eea840f5c350414b8ee59504a3d00b1bcaac456c2e764ac6d12b0ead715f46b10a06d18815942c4c4785e0731a132",
"0x9470729bf237acfbcc5df5cb1b843e65db9e9624989a0844857ed40d7514680118acf0eb37520bfc1477232d5aa7fcdf",
"0xac92af39f920851830d1cc3bda7753ceb80c66488c8e78c047d16409771fdb267079d31480e1cc908610da8d23b30741",
"0xb3cc1b562b5aaa402a33edb28d6154d88692e07ef141e5ea03a39dac3fd2fb4de054214f96a6afc78343549fbcea6572",
"0x906908bc424c967b8cf3e982535c62f3fe3d91076f583b5e0f027b5a818a0dfda7d0e46855d4649d598a3985fb4b855a",
"0x97742b33610964be65e27ab4f91086559cec5844b1a4ccd15bec47146fe016bbeddf202584e3de33e683a0a16f9ec7ab",
"0xac9a17e15a1a280d165746f68581fa62cf4fc93d4d20d95c19de9910c4ff223e0c4d1659e4b3576d6ac0486d75531610",
"0x8eb44f5cd5f5681d2c1b0a702ec60d2ffaea1c67e995d1db91f6877d07f5215d057e22d8faa38bb30165588785da22bf",
"0xafbc3418dbcf3ed2de7f3a8ea61e545386af1864fafc769d35f41bce9ceb6084b7a5645b3c14dd275fc1fa99313a7847",
"0xa1e6d4569fa4c7e907394511063119e952efffd6133e68f6910ab98959aed3e62179561a2516a2260ef6e87c82b4291c",
"0xb90e66fac83bd5d155c25a2b0fad4d26648149f4a0a03165b50679286f9cad05241087b2eb2e3be67fec4259c8834ef8",
"0x8c37efd274ab046bae70c51b89617b98e3f516a95ecd65f26bcfef889d417f83534d2ecfacce8049b78a7f742cfa7e70",
"0x9904023b35c02512c87eb215e13bb2951d099f31de97a3f875ad980d698b5df67fc075b452f6b651ccab46e528bea1a0",
"0xb877e7cfc2fd3c423cf314112ec6b46a46387280ad83643eedd5099684fea54f6add99a6007d744af57fcf8792fe71bf",
"0x9781d4b1026ec1b492a245957b1f3cafbaae598e19a52a84df68d66c34fffb0e26e2396dd33fa6923f93ee424cb328f7",
"0x9309d974712b4f7eee4149edd215f5a3797b2e2f5a470274de67a9cc84284273af55298d2720a1d1551da2034192bc7a",
"0x8f69ecdacc5b69f51b7c86c4034535cecf71325b4ee701d1df7386558cb22dbed2f0b0ea46708fe7299edfd87ad538e8",
"0x87bbd9dbb43e5f563efe01f5078dc41f11649649959513272db71cf7ecd2fcd56505ad41662f176834c689c575c83771",
"0xb62c985584ff5e6f37e4e3df1ed689af83cfbb8e1cb84512ce9c86cd3feeefb03cc7d8cc95626ad4d4401dd8cc7cbb4b",
],
};
export const BEACON_SYNC_SUPER_MAJORITY = Math.ceil(
(BEACON_SYNC_COMMITTEE_SIZE * 2) / 3
);
// These are the rough numbers from benchmark experiments
export const DEFAULT_BATCH_SIZE = 200;
export const DEFAULT_TREE_DEGREE = 200;
export const POLLING_DELAY = 13 * 1000; //13s (slightly higher than the slot time)

4
src/client/index.ts Normal file
View File

@ -0,0 +1,4 @@
import Client from "./client.js";
import Prover from "./prover.js";
export { Client, Prover };

13
src/client/interfaces.ts Normal file
View File

@ -0,0 +1,13 @@
import { AsyncOrSync } from "ts-essentials";
import { LightClientUpdate } from "./types.js";
export interface IProver {
getSyncUpdate(
period: number,
currentPeriod: number,
cacheCount: number
): AsyncOrSync<LightClientUpdate>;
}
export interface IStore {
addUpdate(period: number, update: LightClientUpdate): AsyncOrSync<void>;
}

View File

@ -0,0 +1,52 @@
import { digest } from "@chainsafe/as-sha256";
import { IStore } from "./interfaces.js";
import { LightClientUpdate } from "./types.js";
import { LightClientUpdateSSZ, CommitteeSSZ, HashesSSZ } from "./ssz.js";
import { concatUint8Array } from "./utils.js";
export class MemoryStore implements IStore {
store: {
[period: number]: {
update: Uint8Array;
nextCommittee: Uint8Array;
nextCommitteeHash: Uint8Array;
};
} = {};
addUpdate(period: number, update: LightClientUpdate) {
this.store[period] = {
update: LightClientUpdateSSZ.serialize(update),
nextCommittee: CommitteeSSZ.serialize(update.nextSyncCommittee.pubkeys),
nextCommitteeHash: digest(
concatUint8Array(update.nextSyncCommittee.pubkeys)
),
};
}
getUpdate(period: number): Uint8Array {
if (period in this.store) return this.store[period].update;
throw new Error(`update unavailable for period ${period}`);
}
getCommittee(period: number): Uint8Array {
if (period < 1)
throw new Error("committee not unavailable for period less than 1");
const predPeriod = period - 1;
if (predPeriod in this.store) return this.store[predPeriod].nextCommittee;
throw new Error(`committee unavailable for period ${predPeriod}`);
}
getCommitteeHashes(period: number, count: number): Uint8Array {
if (period < 1)
throw new Error("committee not unavailable for period less than 1");
const predPeriod = period - 1;
const hashes = new Array(count).fill(0).map((_, i) => {
const p = predPeriod + i;
if (p in this.store) return this.store[p].nextCommitteeHash;
throw new Error(`committee unavailable for period ${p}`);
});
return HashesSSZ.serialize(hashes);
}
}

39
src/client/prover.ts Normal file
View File

@ -0,0 +1,39 @@
import * as altair from "@lodestar/types/altair";
import { IProver } from "./interfaces.js";
import { LightClientUpdate } from "./types.js";
import { handleGETRequest } from "./utils.js";
export default class Prover implements IProver {
cachedSyncUpdate: Map<number, LightClientUpdate> = new Map();
private serverUrl: string;
constructor(serverUrl: string) {
this.serverUrl = serverUrl;
}
async _getSyncUpdates(
startPeriod: 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));
}
async getSyncUpdate(
period: number,
currentPeriod: number,
cacheCount: number
): Promise<LightClientUpdate> {
const _cacheCount = Math.min(currentPeriod - period + 1, cacheCount);
if (!this.cachedSyncUpdate.has(period)) {
const vals = await this._getSyncUpdates(period, _cacheCount);
for (let i = 0; i < _cacheCount; i++) {
this.cachedSyncUpdate.set(period + i, vals[i]);
}
}
return this.cachedSyncUpdate.get(period)!;
}
}

26
src/client/ssz.ts Normal file
View File

@ -0,0 +1,26 @@
import {
ContainerType,
VectorCompositeType,
ByteVectorType,
BooleanType,
UintNumberType,
ListCompositeType,
} from '@chainsafe/ssz';
import * as altair from '@lodestar/types/altair';
import { BEACON_SYNC_COMMITTEE_SIZE } from './constants.js';
const MAX_BATCHSIZE = 10000;
export const LightClientUpdateSSZ = altair.ssz.LightClientUpdate;
export const LightClientUpdatesSSZ = new ListCompositeType(
LightClientUpdateSSZ as any,
MAX_BATCHSIZE,
);
export const CommitteeSSZ = new VectorCompositeType(
new ByteVectorType(48),
BEACON_SYNC_COMMITTEE_SIZE,
);
const HashSSZ = new ByteVectorType(32);
export const HashesSSZ = new ListCompositeType(HashSSZ, MAX_BATCHSIZE);

32
src/client/types.ts Normal file
View File

@ -0,0 +1,32 @@
import { routes } from "@lodestar/api";
import { BeaconConfig } from "@lodestar/config";
import * as altair from "@lodestar/types/altair";
export type PubKeyString = string;
export type Slot = number;
export type Bytes32 = string;
export type OptimisticUpdate = altair.LightClientOptimisticUpdate;
export type LightClientUpdate = altair.LightClientUpdate;
export type GenesisData = {
committee: PubKeyString[];
slot: Slot;
time: number;
};
export type ClientConfig = {
genesis: GenesisData;
chainConfig: BeaconConfig;
// treeDegree in case of Superlight and batchSize in case of Light and Optimistic
n?: number;
};
export type ExecutionInfo = {
blockhash: string;
blockNumber: bigint;
};
export type VerifyWithReason =
| { correct: true }
| { correct: false; reason: string };

50
src/client/utils.ts Normal file
View File

@ -0,0 +1,50 @@
import { fromHexString, toHexString } from "@chainsafe/ssz";
import bls from "@chainsafe/bls/switchable";
import { createBeaconConfig } from "@lodestar/config";
import { mainnetConfig } from "./constants.js";
import { networksChainConfig } from "@lodestar/config/networks";
import fetch from "node-fetch";
export function concatUint8Array(data: Uint8Array[]) {
const l = data.reduce((l, d) => l + d.length, 0);
let result = new Uint8Array(l);
let offset = 0;
data.forEach((d) => {
result.set(d, offset);
offset += d.length;
});
return result;
}
export function getDefaultClientConfig() {
const chainConfig = createBeaconConfig(
networksChainConfig.mainnet,
fromHexString(mainnetConfig.genesis_validator_root)
);
return {
genesis: {
committee: mainnetConfig.committee_pk,
slot: parseInt(mainnetConfig.slot),
time: parseInt(mainnetConfig.genesis_time),
},
chainConfig,
n: 1,
};
}
export async function handleGETRequest(
url: string,
isBuffer: boolean = true,
retry: number = 3
): Promise<any> {
if (retry < 0) {
throw Error(`GET request failed: ${url}`);
}
try {
const ret = await fetch(url);
return await ret.json();
} catch (e) {
console.error(`failed GET request (${url}): ${e.message}`);
return handleGETRequest(url, isBuffer, retry - 1);
}
}

View File

@ -1,13 +1,17 @@
import type { Plugin, PluginAPI } from "@lumeweb/interface-relay";
import fetch, { Request, RequestInit } from "node-fetch";
import { URL } from "url";
import NodeCache from "node-cache";
import stringify from "json-stringify-deterministic";
import { Client, Prover } from "./client/index.js";
import { MemoryStore } from "./client/memory-store.js";
const EXECUTION_RPC_URL =
"https://g.w.lavanet.xyz:443/gateway/eth/rpc-http/f195d68175eb091ec1f71d00f8952b85";
const CONSENSUS_RPC_URL = "https://www.lightclientdata.org";
const RPC_CACHE = new NodeCache({ stdTTL: 60 * 60 * 12 });
async function doFetch(url: string, request: RequestInit) {
sanitizeRequestArgs(url, request);
@ -47,38 +51,186 @@ function sanitizeRequestArgs(url: string, request: RequestInit) {
});
}
interface ConsensusRequest extends RequestInit {
path: string;
}
interface ExecutionRequest {
method: string;
params: string;
params: any[];
}
interface ConsensusCommitteeHashesRequest {
start: number;
count: number;
}
interface ConsensusCommitteePeriodRequest {
period: number | "latest";
}
interface ConsensusBlockRequest {
block: number;
}
let client: Client;
const plugin: Plugin = {
name: "eth",
async plugin(api: PluginAPI): Promise<void> {
api.registerMethod("consensus_request", {
const prover = new Prover(CONSENSUS_RPC_URL);
const store = new MemoryStore();
client = new Client(prover, store, CONSENSUS_RPC_URL);
await client.sync();
api.registerMethod("consensus_committee_hashes", {
cacheable: false,
async handler(request: ConsensusRequest): Promise<object> {
const consensusUrl = new URL(CONSENSUS_RPC_URL);
async handler(
request: ConsensusCommitteeHashesRequest
): Promise<Uint8Array> {
if (!(request?.start && typeof request.start == "number")) {
throw new Error('start required and must be a number"');
}
if (!(request?.count && typeof request.count == "number")) {
throw new Error('count required and must be a number"');
}
let dummyUrl = new URL(
`http://dummy/${request.path.replace(/^\/+/, "")}`
);
consensusUrl.pathname = dummyUrl.pathname;
consensusUrl.search = dummyUrl.search;
if (!client.isSynced) {
await client.sync();
}
return doFetch(consensusUrl.toString(), request);
let hashes;
try {
hashes = store.getCommitteeHashes(request.start, request.count);
} catch {
await client.sync();
}
if (!hashes) {
try {
hashes = store.getCommitteeHashes(request.start, request.count);
} catch (e) {
return e;
}
}
return hashes;
},
});
api.registerMethod("consensus_committee_period", {
cacheable: false,
async handler(
request: ConsensusCommitteePeriodRequest
): Promise<Uint8Array> {
if (
!(
request?.period &&
(typeof request.period == "number" || request.period === "latest")
)
) {
throw new Error('period required and must be a number or "latest"');
}
if (!client.isSynced) {
await client.sync();
}
let committee;
try {
committee = store.getCommittee(
request.period === "latest" ? client.latestPeriod : request.period
);
} catch {
await client.sync();
}
if (!committee) {
try {
committee = store.getCommittee(
request.period === "latest" ? client.latestPeriod : request.period
);
} catch (e) {
return e;
}
}
return committee;
},
});
api.registerMethod("execution_request", {
cacheable: false,
async handler(request: ExecutionRequest): Promise<object> {
return doFetch(EXECUTION_RPC_URL, {
method: "POST",
body: JSON.stringify(request),
});
const tempRequest = {
method: request.method,
...request.params,
};
const hash = api.util.crypto
.createHash(stringify(tempRequest))
.toString("hex");
if (RPC_CACHE.has(hash)) {
RPC_CACHE.ttl(hash);
return RPC_CACHE.get(hash);
}
try {
let resp = await doFetch(EXECUTION_RPC_URL, {
method: "POST",
body: JSON.stringify(request),
});
if (resp && resp.result) {
RPC_CACHE.set(hash, resp);
}
return resp;
} catch (e) {
return e;
}
},
});
api.registerMethod("consensus_optimistic_update", {
cacheable: false,
async handler(): Promise<object> {
return await doFetch(
`${CONSENSUS_RPC_URL}/eth/v1/beacon/light_client/optimistic_update`,
{
method: "GET",
}
);
},
});
api.registerMethod("consensus_block", {
cacheable: false,
async handler(request: ConsensusBlockRequest): Promise<object> {
try {
BigInt(request?.block);
} catch {
throw new Error("block is required and must be a number");
}
const block = request?.block;
if (BigInt(block) > BigInt(client.latestPeriod)) {
await client.sync();
}
if (!client.blockHashCache.has(request.block)) {
throw new Error("block not found");
}
if (client.blockCache.has(request.block)) {
client.blockCache.ttl(request.block);
return client.blockCache.get(request.block);
}
await client.getExecutionFromBlockRoot(
request.block as any,
client.blockHashCache.get(request.block)
);
return client.blockCache.get(request.block);
},
});
},