refactor: move to new sdks
This commit is contained in:
parent
e62eadd436
commit
78d192f53f
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"preset": [
|
||||
"@lumeweb/presetter-kernel-module-preset"
|
||||
],
|
||||
"config": {
|
||||
"official": true,
|
||||
"browser": true
|
||||
}
|
||||
}
|
50
build.js
50
build.js
|
@ -1,50 +0,0 @@
|
|||
import esbuild from "esbuild";
|
||||
import { readFile } from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
await esbuild.build({
|
||||
entryPoints: ["src/index.ts"],
|
||||
outfile: "dist/index.js",
|
||||
format: "iife",
|
||||
bundle: true,
|
||||
legalComments: "external",
|
||||
define: {
|
||||
global: "self",
|
||||
"import.meta": "true",
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
name: "base64",
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /\?base64$/ }, (args) => {
|
||||
return {
|
||||
path: args.path,
|
||||
pluginData: {
|
||||
isAbsolute: path.isAbsolute(args.path),
|
||||
resolveDir: args.resolveDir,
|
||||
},
|
||||
namespace: "base64-loader",
|
||||
};
|
||||
});
|
||||
build.onLoad(
|
||||
{ filter: /\?base64$/, namespace: "base64-loader" },
|
||||
async (args) => {
|
||||
const fullPath = args.pluginData.isAbsolute
|
||||
? args.path
|
||||
: path.join(args.pluginData.resolveDir, args.path);
|
||||
return {
|
||||
contents: Buffer.from(
|
||||
await readFile(fullPath.replace(/\?base64$/, ""))
|
||||
).toString("base64"),
|
||||
loader: "text",
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
external: ["fs"],
|
||||
inject: ["./polyfill.js"],
|
||||
});
|
||||
|
||||
export {};
|
51
package.json
51
package.json
|
@ -3,15 +3,27 @@
|
|||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_id": "@lumeweb/kernel-eth@0.1.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "gitea@git.lumeweb.com:LumeWeb/kernel-eth.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build-script": "tsc --project tsconfig.build.json && mv dist-build/build.js dist-build/build.mjs",
|
||||
"compile": "npm run build-script && rimraf node_modules/@lumeweb/dht-rpc-client/node_modules node_modules/@lumeweb/kernel-dht-client/node_modules/libkmodule && node build.js",
|
||||
"build": "npm run compile && node ./dist-build/build.mjs dev"
|
||||
"prepare": "presetter bootstrap",
|
||||
"build": "shx touch nop.js;run build",
|
||||
"semantic-release": "semantic-release"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lumeweb/presetter-kernel-module-preset": "^0.1.0-develop.30",
|
||||
"@rollup/plugin-alias": "^5.0.0",
|
||||
"patch-package": "^7.0.0",
|
||||
"rollup-plugin-ignore-import": "^1.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chainsafe/as-sha256": "0.4.1",
|
||||
"@chainsafe/bls": "git+https://git.lumeweb.com/LumeWeb/chainsafe-bls.git",
|
||||
"@chainsafe/blst": "^0.2.8",
|
||||
"@chainsafe/bls": "^7.1.1",
|
||||
"@chainsafe/blst": "0.2.9",
|
||||
"@chainsafe/ssz": "0.11.1",
|
||||
"@ethereumjs/block": "^4.2.1",
|
||||
"@ethereumjs/blockchain": "^6.2.1",
|
||||
|
@ -25,40 +37,17 @@
|
|||
"@lodestar/light-client": "^1.7.2",
|
||||
"@lodestar/params": "^1.8.0",
|
||||
"@lodestar/types": "^1.7.2",
|
||||
"@lumeweb/kernel-rpc-client": "git+https://git.lumeweb.com/LumeWeb/kernel-rpc-client.git",
|
||||
"@lumeweb/kernel-rpc-client": "^0.0.2-develop.1",
|
||||
"@lumeweb/libkernel": "^0.1.0-develop.14",
|
||||
"@lumeweb/libweb": "^0.2.0-develop.21",
|
||||
"decimal.js": "^10.4.3",
|
||||
"ethers": "^6.3.0",
|
||||
"json-rpc-2.0": "^1.5.1",
|
||||
"libkmodule": "^0.2.53",
|
||||
"lodash": "^4.17.21",
|
||||
"path-browserify": "^1.0.1",
|
||||
"rlp": "^3.0.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"web3-core": "^1.9.0",
|
||||
"web3-core-method": "^1.9.0",
|
||||
"web3-eth": "^1.9.0",
|
||||
"yaml": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lumeweb/interface-relay": "git+https://git.lumeweb.com/LumeWeb/interface-relay.git",
|
||||
"@scure/bip39": "^1.2.0",
|
||||
"@skynetlabs/skynet-nodejs": "^2.9.0",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/read": "^0.0.29",
|
||||
"buffer": "^6.0.3",
|
||||
"cli-progress": "^3.12.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"esbuild": "^0.17.17",
|
||||
"esbuild-plugin-wasm": "^1.0.0",
|
||||
"prettier": "^2.8.7",
|
||||
"process": "^0.11.10",
|
||||
"read": "^2.1.0",
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"browser": {
|
||||
"crypto": "crypto-browserify",
|
||||
"stream": "stream-browserify",
|
||||
"path": "path-browserify"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
diff --git a/node_modules/@chainsafe/bls/lib/herumi/index.js b/node_modules/@chainsafe/bls/lib/herumi/index.js
|
||||
index 4ed8fdd..f979984 100644
|
||||
--- a/node_modules/@chainsafe/bls/lib/herumi/index.js
|
||||
+++ b/node_modules/@chainsafe/bls/lib/herumi/index.js
|
||||
@@ -1,16 +1,20 @@
|
||||
-import { SecretKey } from "./secretKey.js";
|
||||
-import { PublicKey } from "./publicKey.js";
|
||||
-import { Signature } from "./signature.js";
|
||||
-import { init, destroy } from "./context.js";
|
||||
-import { functionalInterfaceFactory } from "../functional.js";
|
||||
-await init();
|
||||
-export * from "../constants.js";
|
||||
-export { SecretKey, PublicKey, Signature, init, destroy };
|
||||
-export const bls = {
|
||||
- implementation: "herumi",
|
||||
- SecretKey,
|
||||
- PublicKey,
|
||||
- Signature,
|
||||
- ...functionalInterfaceFactory({ SecretKey, PublicKey, Signature }),
|
||||
-};
|
||||
-export default bls;
|
||||
+import { SecretKey } from './secretKey.js'
|
||||
+import { PublicKey } from './publicKey.js'
|
||||
+import { Signature } from './signature.js'
|
||||
+import { init, destroy } from './context.js'
|
||||
+import { functionalInterfaceFactory } from '../functional.js'
|
||||
+
|
||||
+export * from '../constants.js'
|
||||
+export { SecretKey, PublicKey, Signature, init, destroy }
|
||||
+
|
||||
+export const bls = async () => {
|
||||
+ await init()
|
||||
+ return {
|
||||
+ implementation: 'herumi',
|
||||
+ SecretKey,
|
||||
+ PublicKey,
|
||||
+ Signature,
|
||||
+ ...functionalInterfaceFactory({ SecretKey, PublicKey, Signature }),
|
||||
+ }
|
||||
+}
|
||||
+export default bls
|
||||
diff --git a/node_modules/@chainsafe/bls/lib/index.d.ts b/node_modules/@chainsafe/bls/lib/index.d.ts
|
||||
index 35a9432..097a938 100644
|
||||
--- a/node_modules/@chainsafe/bls/lib/index.d.ts
|
||||
+++ b/node_modules/@chainsafe/bls/lib/index.d.ts
|
||||
@@ -1,3 +1,3 @@
|
||||
import type { IBls } from "./types.js";
|
||||
-declare let bls: IBls;
|
||||
+export declare const bls: () => Promise<IBls>;
|
||||
export default bls;
|
||||
diff --git a/node_modules/@chainsafe/bls/lib/index.js b/node_modules/@chainsafe/bls/lib/index.js
|
||||
index c2a5bdf..9572018 100644
|
||||
--- a/node_modules/@chainsafe/bls/lib/index.js
|
||||
+++ b/node_modules/@chainsafe/bls/lib/index.js
|
||||
@@ -1,11 +1,14 @@
|
||||
import { getImplementation } from "./getImplementation.js";
|
||||
// Thanks https://github.com/iliakan/detect-node/blob/master/index.esm.js
|
||||
const isNode = Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) === "[object process]";
|
||||
-let bls;
|
||||
-try {
|
||||
- bls = await getImplementation(isNode ? "blst-native" : "herumi");
|
||||
-}
|
||||
-catch (e) {
|
||||
- bls = await getImplementation("herumi");
|
||||
-}
|
||||
+export const bls = async () => {
|
||||
+ let bls;
|
||||
+ try {
|
||||
+ bls = await getImplementation(isNode ? "blst-native" : "herumi");
|
||||
+ }
|
||||
+ catch (e) {
|
||||
+ bls = await getImplementation("herumi");
|
||||
+ }
|
||||
+ return bls;
|
||||
+};
|
||||
export default bls;
|
|
@ -1,5 +0,0 @@
|
|||
import * as process from "process";
|
||||
import { Buffer } from "buffer";
|
||||
|
||||
self.process = process;
|
||||
self.Buffer = Buffer;
|
|
@ -1,218 +0,0 @@
|
|||
// This is the standard build script for a kernel module.
|
||||
|
||||
import * as fs from "fs";
|
||||
import read from "read";
|
||||
import * as bip39 from "@scure/bip39";
|
||||
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
||||
//@ts-ignore
|
||||
import { SkynetClient } from "@skynetlabs/skynet-nodejs";
|
||||
|
||||
// Helper variables to make it easier to return empty values alongside errors.
|
||||
const nu8 = new Uint8Array(0);
|
||||
const nkp = {
|
||||
publicKey: nu8,
|
||||
secretKey: nu8,
|
||||
};
|
||||
|
||||
// readFile is a wrapper for fs.readFileSync that handles the try-catch for the
|
||||
// caller.
|
||||
function readFile(fileName: string): [string, string | null] {
|
||||
try {
|
||||
let data = fs.readFileSync(fileName, "utf8");
|
||||
return [data, null];
|
||||
} catch (err) {
|
||||
return ["", "unable to read file: " + JSON.stringify(err)];
|
||||
}
|
||||
}
|
||||
|
||||
// readFileBinary is a wrapper for fs.readFileSync that handles the try-catch
|
||||
// for the caller.
|
||||
function readFileBinary(fileName: string): [Uint8Array, string | null] {
|
||||
try {
|
||||
let data = fs.readFileSync(fileName, null);
|
||||
return [data, null];
|
||||
} catch (err) {
|
||||
return [nu8, "unable to read file: " + JSON.stringify(err)];
|
||||
}
|
||||
}
|
||||
|
||||
// writeFile is a wrapper for fs.writeFileSync which handles the try-catch in a
|
||||
// non-exception way.
|
||||
function writeFile(fileName: string, fileData: string): string | null {
|
||||
try {
|
||||
fs.writeFileSync(fileName, fileData);
|
||||
return null;
|
||||
} catch (err) {
|
||||
return "unable to write file: " + JSON.stringify(err);
|
||||
}
|
||||
}
|
||||
|
||||
// handlePass handles all portions of the script that occur after the password
|
||||
// has been requested. If no password needs to be requested, handlePass will be
|
||||
// called with a null input. We need to structure the code this way because the
|
||||
// password reader is async and we can only access the password when using a
|
||||
// callback.
|
||||
function handlePass(password: string) {
|
||||
try {
|
||||
// If we are running prod and the seed file does not exist, we
|
||||
// need to confirm the password and also warn the user to use a
|
||||
// secure password.
|
||||
if (!fs.existsSync(seedFile) && process.argv[2] === "prod") {
|
||||
// The file does not exist, we need to confirm the
|
||||
// password.
|
||||
console.log();
|
||||
console.log(
|
||||
"No production entry found for module. Creating new production module..."
|
||||
);
|
||||
console.log(
|
||||
"If someone can guess the password, they can push arbitrary changes to your module."
|
||||
);
|
||||
console.log("Please use a secure password.");
|
||||
console.log();
|
||||
read(
|
||||
{ prompt: "Confirm Password: ", silent: true },
|
||||
function (err: any, confirmPassword: string) {
|
||||
if (err) {
|
||||
console.error("unable to fetch password:", err);
|
||||
process.exit(1);
|
||||
}
|
||||
if (password !== confirmPassword) {
|
||||
console.error("passwords do not match");
|
||||
process.exit(1);
|
||||
}
|
||||
handlePassConfirm(moduleSalt, password);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// If the seed file does exist, or if we are using dev,
|
||||
// there's no need to confirm the password but we do
|
||||
// need to pass the logic off to the handlePassConfirm
|
||||
// callback.
|
||||
handlePassConfirm(moduleSalt, password);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Unable to read seedFile:", err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// handlePassConfirm handles the full script after the confirmation password
|
||||
// has been provided. If not confirmation password is needed, this function
|
||||
// will be called anyway using the unconfirmed password as input.
|
||||
function handlePassConfirm(seed: string, password: string) {
|
||||
// Create the seedFile if it does not exist. For dev we just save the
|
||||
// seed to disk outright, because this is a dev build and therefore not
|
||||
// security sensitive. Also the dev seed does not get pushed to the
|
||||
// github repo.
|
||||
//
|
||||
// For prod, we use the seed to create a new seed (called the shield)
|
||||
// which allows us to verify that the developer has provided the right
|
||||
// password when deploying the module. The shield does get pushed to
|
||||
// the github repo so that the production module is the same on all
|
||||
// devices.
|
||||
if (!fs.existsSync(seedFile) && process.argv[2] !== "prod") {
|
||||
// Generate the seed phrase and write it to the file.
|
||||
let seedPhrase = bip39.generateMnemonic(wordlist);
|
||||
let errWF = writeFile(seedFile, seedPhrase);
|
||||
if (errWF !== null) {
|
||||
console.error("unable to write file:", errWF);
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (!fs.existsSync(seedFile) && process.argv[2] === "prod") {
|
||||
// Generate the seed phrase.
|
||||
let seedPhrase = bip39.generateMnemonic(wordlist);
|
||||
// Write the registry link to the file.
|
||||
}
|
||||
|
||||
// Load or verify the seed. If this is prod, the password is used to
|
||||
// create and verify the seed. If this is dev, we just load the seed
|
||||
// with no password.
|
||||
let seedPhrase: string;
|
||||
let registryLink: string;
|
||||
if (process.argv[2] === "prod") {
|
||||
// Generate the seed phrase from the password.
|
||||
seedPhrase = bip39.generateMnemonic(wordlist);
|
||||
} else {
|
||||
let [sp, errRF] = readFile(seedFile);
|
||||
if (errRF !== null) {
|
||||
console.error("unable to read seed phrase for dev command from disk");
|
||||
process.exit(1);
|
||||
}
|
||||
seedPhrase = sp;
|
||||
}
|
||||
|
||||
let metadata = {
|
||||
Filename: "index.js",
|
||||
};
|
||||
const client = new SkynetClient("https://web3portal.com");
|
||||
client
|
||||
.uploadFile("dist/index.js")
|
||||
.then((result: any) => {
|
||||
console.log("Immutable Link for module:", result);
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.error("unable to upload file", err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
// Add a newline for readability.
|
||||
console.log();
|
||||
|
||||
// Check for a 'dev' or 'prod' input to the script.
|
||||
if (process.argv.length !== 3) {
|
||||
console.error("need to provide either 'dev' or 'prod' as an input");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Create the build folder if it does not exist.
|
||||
if (!fs.existsSync("build")) {
|
||||
fs.mkdirSync("build");
|
||||
}
|
||||
|
||||
// Determine the seed file.
|
||||
let seedFile: string;
|
||||
if (process.argv[2] === "prod") {
|
||||
seedFile = "module-skylink";
|
||||
} else if (process.argv[2] === "dev") {
|
||||
seedFile = "build/dev-seed";
|
||||
} else {
|
||||
console.error("need to provide either 'dev' or 'prod' as an input");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// If doing a prod deployment, check whether the salt file exists. If it does
|
||||
// not, create it.
|
||||
let moduleSalt: string;
|
||||
if (!fs.existsSync(".module-salt")) {
|
||||
moduleSalt = bip39.generateMnemonic(wordlist);
|
||||
let errWF = writeFile(".module-salt", moduleSalt);
|
||||
if (errWF !== null) {
|
||||
console.error("unable to write module salt file:", errWF);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
let [ms, errRF] = readFile(".module-salt");
|
||||
if (errRF !== null) {
|
||||
console.error("unable to read moduleSalt");
|
||||
process.exit(1);
|
||||
}
|
||||
ms = ms.replace(/\n$/, "");
|
||||
moduleSalt = ms;
|
||||
}
|
||||
|
||||
// Need to get a password if this is a prod build.
|
||||
if (process.argv[2] === "prod") {
|
||||
read(
|
||||
{ prompt: "Password: ", silent: true },
|
||||
function (err: any, password: string) {
|
||||
if (err) {
|
||||
console.error("unable to fetch password:", err);
|
||||
process.exit(1);
|
||||
}
|
||||
handlePass(password);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
handlePass("");
|
||||
}
|
|
@ -23,7 +23,8 @@ import {
|
|||
import { assertValidSignedHeader } from "@lodestar/light-client/validation";
|
||||
import { SyncCommitteeFast } from "@lodestar/light-client";
|
||||
import bls, { init } from "@chainsafe/bls/switchable";
|
||||
import { PublicKey } from "@chainsafe/bls/types.js";
|
||||
// @ts-ignore
|
||||
import type { PublicKey } from "@chainsafe/bls/lib/types.js";
|
||||
import { fromHexString } from "@chainsafe/ssz";
|
||||
import * as capella from "@lodestar/types/capella";
|
||||
import * as phase0 from "@lodestar/types/phase0";
|
||||
|
@ -42,7 +43,7 @@ export default class Client {
|
|||
latestBlockHash?: string;
|
||||
private config: ClientConfig = getDefaultClientConfig();
|
||||
private genesisCommittee: Uint8Array[] = this.config.genesis.committee.map(
|
||||
(pk) => fromHexString(pk)
|
||||
(pk) => fromHexString(pk),
|
||||
);
|
||||
private genesisPeriod = computeSyncPeriodAtSlot(this.config.genesis.slot);
|
||||
private genesisTime = this.config.genesis.time;
|
||||
|
@ -76,11 +77,11 @@ export default class Client {
|
|||
const provider = new VerifyingProvider(
|
||||
this.rpcCallback,
|
||||
blockNumber,
|
||||
blockhash
|
||||
blockhash,
|
||||
);
|
||||
this.subscribe((ei) => {
|
||||
console.log(
|
||||
`Recieved a new blockheader: ${ei.blockNumber} ${ei.blockhash}`
|
||||
`Recieved a new blockheader: ${ei.blockNumber} ${ei.blockhash}`,
|
||||
);
|
||||
provider.update(ei.blockhash, ei.blockNumber);
|
||||
});
|
||||
|
@ -94,7 +95,7 @@ export default class Client {
|
|||
|
||||
public getCurrentPeriod(): number {
|
||||
return computeSyncPeriodAtSlot(
|
||||
getCurrentSlot(this.config.chainConfig, this.genesisTime)
|
||||
getCurrentSlot(this.config.chainConfig, this.genesisTime),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -115,12 +116,12 @@ export default class Client {
|
|||
|
||||
async optimisticUpdateVerify(
|
||||
committee: Uint8Array[],
|
||||
update: OptimisticUpdate
|
||||
update: OptimisticUpdate,
|
||||
): Promise<VerifyWithReason> {
|
||||
try {
|
||||
const { attestedHeader: header, syncAggregate } = update;
|
||||
const headerBlockRoot = phase0.ssz.BeaconBlockHeader.hashTreeRoot(
|
||||
header.beacon
|
||||
header.beacon,
|
||||
);
|
||||
const committeeFast = this.deserializeSyncCommittee(committee);
|
||||
try {
|
||||
|
@ -129,7 +130,7 @@ export default class Client {
|
|||
committeeFast,
|
||||
syncAggregate,
|
||||
headerBlockRoot,
|
||||
header.beacon.slot
|
||||
header.beacon.slot,
|
||||
);
|
||||
} catch (e) {
|
||||
return { correct: false, reason: "invalid signatures" };
|
||||
|
@ -154,27 +155,27 @@ export default class Client {
|
|||
|
||||
private isValidLightClientHeader(
|
||||
config: ChainForkConfig,
|
||||
header: allForks.LightClientHeader
|
||||
header: allForks.LightClientHeader,
|
||||
): boolean {
|
||||
return isValidMerkleBranch(
|
||||
config
|
||||
.getExecutionForkTypes(header.beacon.slot)
|
||||
.ExecutionPayloadHeader.hashTreeRoot(
|
||||
(header as capella.LightClientHeader).execution
|
||||
(header as capella.LightClientHeader).execution,
|
||||
),
|
||||
(header as capella.LightClientHeader).executionBranch,
|
||||
EXECUTION_PAYLOAD_DEPTH,
|
||||
EXECUTION_PAYLOAD_INDEX,
|
||||
header.beacon.bodyRoot
|
||||
header.beacon.bodyRoot,
|
||||
);
|
||||
}
|
||||
|
||||
public async getNextValidExecutionInfo(
|
||||
retry: number = 10
|
||||
retry: number = 10,
|
||||
): Promise<ExecutionInfo> {
|
||||
if (retry === 0)
|
||||
throw new Error(
|
||||
"no valid execution payload found in the given retry limit"
|
||||
"no valid execution payload found in the given retry limit",
|
||||
);
|
||||
const ei = await this.getLatestExecution();
|
||||
if (ei) return ei;
|
||||
|
@ -201,7 +202,7 @@ export default class Client {
|
|||
let startPeriod = this.genesisPeriod;
|
||||
|
||||
let lastCommitteeHash: Uint8Array = this.getCommitteeHash(
|
||||
this.genesisCommittee
|
||||
this.genesisCommittee,
|
||||
);
|
||||
|
||||
for (let period = startPeriod + 1; period <= currentPeriod; period++) {
|
||||
|
@ -209,11 +210,11 @@ export default class Client {
|
|||
lastCommitteeHash = await this.prover.getCommitteeHash(
|
||||
period,
|
||||
currentPeriod,
|
||||
DEFAULT_BATCH_SIZE
|
||||
DEFAULT_BATCH_SIZE,
|
||||
);
|
||||
} catch (e: any) {
|
||||
throw new Error(
|
||||
`failed to fetch committee hash for prover at period(${period}): ${e.meessage}`
|
||||
`failed to fetch committee hash for prover at period(${period}): ${e.meessage}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +226,7 @@ export default class Client {
|
|||
let startPeriod = this.latestPeriod;
|
||||
|
||||
let lastCommitteeHash: Uint8Array = this.getCommitteeHash(
|
||||
this.latestCommittee as Uint8Array[]
|
||||
this.latestCommittee as Uint8Array[],
|
||||
);
|
||||
|
||||
for (let period = startPeriod + 1; period <= currentPeriod; period++) {
|
||||
|
@ -233,11 +234,11 @@ export default class Client {
|
|||
lastCommitteeHash = await this.prover.getCommitteeHash(
|
||||
period,
|
||||
currentPeriod,
|
||||
DEFAULT_BATCH_SIZE
|
||||
DEFAULT_BATCH_SIZE,
|
||||
);
|
||||
} catch (e: any) {
|
||||
throw new Error(
|
||||
`failed to fetch committee hash for prover at period(${period}): ${e.meessage}`
|
||||
`failed to fetch committee hash for prover at period(${period}): ${e.meessage}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +247,7 @@ export default class Client {
|
|||
|
||||
async getCommittee(
|
||||
period: number,
|
||||
expectedCommitteeHash: Uint8Array | null
|
||||
expectedCommitteeHash: Uint8Array | null,
|
||||
): Promise<Uint8Array[]> {
|
||||
if (period === this.genesisPeriod) return this.genesisCommittee;
|
||||
if (!expectedCommitteeHash)
|
||||
|
@ -260,19 +261,19 @@ export default class Client {
|
|||
|
||||
private async getLatestExecution(): Promise<ExecutionInfo | null> {
|
||||
const updateJSON = await this.prover.callback(
|
||||
"consensus_optimistic_update"
|
||||
"consensus_optimistic_update",
|
||||
);
|
||||
const update = this.optimisticUpdateFromJSON(updateJSON);
|
||||
const verify = await this.optimisticUpdateVerify(
|
||||
this.latestCommittee as Uint8Array[],
|
||||
update
|
||||
update,
|
||||
);
|
||||
if (!verify.correct) {
|
||||
console.error(`Invalid Optimistic Update: ${verify.reason}`);
|
||||
return null;
|
||||
}
|
||||
console.log(
|
||||
`Optimistic update verified for slot ${updateJSON.attested_header.beacon.slot}`
|
||||
`Optimistic update verified for slot ${updateJSON.attested_header.beacon.slot}`,
|
||||
);
|
||||
return {
|
||||
blockhash: updateJSON.attested_header.execution.block_hash,
|
||||
|
@ -281,7 +282,7 @@ export default class Client {
|
|||
}
|
||||
|
||||
private deserializeSyncCommittee(
|
||||
syncCommittee: Uint8Array[]
|
||||
syncCommittee: Uint8Array[],
|
||||
): SyncCommitteeFast {
|
||||
const pubkeys = this.deserializePubkeys(syncCommittee);
|
||||
return {
|
||||
|
|
|
@ -522,7 +522,7 @@ export const mainnetConfig = {
|
|||
};
|
||||
|
||||
export const BEACON_SYNC_SUPER_MAJORITY = Math.ceil(
|
||||
(BEACON_SYNC_COMMITTEE_SIZE * 2) / 3
|
||||
(BEACON_SYNC_COMMITTEE_SIZE * 2) / 3,
|
||||
);
|
||||
|
||||
// These are the rough numbers from benchmark experiments
|
||||
|
|
|
@ -8,7 +8,7 @@ export interface IProver {
|
|||
getCommitteeHash(
|
||||
period: number,
|
||||
currentPeriod: number,
|
||||
count: number
|
||||
count: number,
|
||||
): Promise<Uint8Array>;
|
||||
|
||||
getSyncUpdate(period: number): Promise<LightClientUpdate>;
|
||||
|
|
|
@ -24,7 +24,7 @@ export default class Prover implements IProver {
|
|||
async getSyncUpdate(period: number): Promise<LightClientUpdate> {
|
||||
const res = await this.callback("consensus_committee_period", { period });
|
||||
return LightClientUpdateSSZ.deserialize(
|
||||
Uint8Array.from(Object.values(res))
|
||||
Uint8Array.from(Object.values(res)),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ export default class Prover implements IProver {
|
|||
async getCommitteeHash(
|
||||
period: number,
|
||||
currentPeriod: number,
|
||||
cacheCount: number
|
||||
cacheCount: number,
|
||||
): Promise<Uint8Array> {
|
||||
const _count = Math.min(currentPeriod - period + 1, cacheCount);
|
||||
if (!this.cachedHashes.has(period)) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
export const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
|
||||
export const ZERO_ADDR = "0x0000000000000000000000000000000000000000";
|
||||
// TODO: set the correct gas limit!
|
||||
export const GAS_LIMIT = '0x1c9c380';
|
||||
export const GAS_LIMIT = "0x1c9c380";
|
||||
export const REQUEST_BATCH_SIZE = 10;
|
||||
export const MAX_SOCKET = 10;
|
||||
export const EMPTY_ACCOUNT_EXTCODEHASH =
|
||||
'0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470';
|
||||
"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
|
||||
export const MAX_BLOCK_HISTORY = BigInt(256);
|
||||
export const MAX_BLOCK_FUTURE = BigInt(3);
|
||||
export const DEFAULT_BLOCK_PARAMETER = 'latest';
|
||||
export const DEFAULT_BLOCK_PARAMETER = "latest";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { JSONRPCErrorCode, JSONRPCErrorException } from 'json-rpc-2.0';
|
||||
import { JSONRPCErrorCode, JSONRPCErrorException } from "json-rpc-2.0";
|
||||
|
||||
export class InternalError extends JSONRPCErrorException {
|
||||
constructor(message: string) {
|
||||
|
|
|
@ -35,7 +35,10 @@ import {
|
|||
MAX_BLOCK_FUTURE,
|
||||
DEFAULT_BLOCK_PARAMETER,
|
||||
} from "./constants.js";
|
||||
import { headerDataFromWeb3Response, blockDataFromWeb3Response } from "./utils";
|
||||
import {
|
||||
headerDataFromWeb3Response,
|
||||
blockDataFromWeb3Response,
|
||||
} from "./utils.js";
|
||||
|
||||
import { keccak256 } from "ethers";
|
||||
import { InternalError, InvalidParamsError } from "./errors.js";
|
||||
|
@ -68,14 +71,14 @@ export class VerifyingProvider {
|
|||
eth_estimateGas: this.estimateGas,
|
||||
eth_sendRawTransaction: this.sendRawTransaction,
|
||||
eth_getTransactionReceipt: this.getTransactionReceipt,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
constructor(
|
||||
rpcCallback: Function,
|
||||
blockNumber: bigint | number,
|
||||
blockHash: Bytes32,
|
||||
chain: bigint | Chain = Chain.Mainnet
|
||||
chain: bigint | Chain = Chain.Mainnet,
|
||||
) {
|
||||
this.rpc = new RPC(rpcCallback);
|
||||
this.common = new Common({
|
||||
|
@ -93,7 +96,7 @@ export class VerifyingProvider {
|
|||
this.blockHashes[blockNumberHex] !== blockHash
|
||||
) {
|
||||
console.log(
|
||||
"Overriding an existing verified blockhash. Possibly the chain had a reorg"
|
||||
"Overriding an existing verified blockhash. Possibly the chain had a reorg",
|
||||
);
|
||||
}
|
||||
const latestBlockNumber = this.latestBlockNumber;
|
||||
|
@ -119,7 +122,7 @@ export class VerifyingProvider {
|
|||
|
||||
private async getBalance(
|
||||
addressHex: AddressHex,
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||
) {
|
||||
const header = await this.getBlockHeader(blockOpt);
|
||||
const address = Address.fromString(addressHex);
|
||||
|
@ -134,7 +137,7 @@ export class VerifyingProvider {
|
|||
address,
|
||||
[],
|
||||
header.stateRoot,
|
||||
proof
|
||||
proof,
|
||||
);
|
||||
if (!isAccountCorrect) {
|
||||
throw new InternalError("Invalid account proof provided by the RPC");
|
||||
|
@ -153,7 +156,7 @@ export class VerifyingProvider {
|
|||
|
||||
private async getCode(
|
||||
addressHex: AddressHex,
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||
): Promise<HexString> {
|
||||
const header = await this.getBlockHeader(blockOpt);
|
||||
const res = await this.rpc.requestBatch([
|
||||
|
@ -177,7 +180,7 @@ export class VerifyingProvider {
|
|||
address,
|
||||
[],
|
||||
header.stateRoot,
|
||||
accountProof
|
||||
accountProof,
|
||||
);
|
||||
if (!isAccountCorrect) {
|
||||
throw new InternalError(`invalid account proof provided by the RPC`);
|
||||
|
@ -185,11 +188,11 @@ export class VerifyingProvider {
|
|||
|
||||
const isCodeCorrect = await this.verifyCodeHash(
|
||||
code,
|
||||
accountProof.codeHash
|
||||
accountProof.codeHash,
|
||||
);
|
||||
if (!isCodeCorrect) {
|
||||
throw new InternalError(
|
||||
`code provided by the RPC doesn't match the account's codeHash`
|
||||
`code provided by the RPC doesn't match the account's codeHash`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -198,7 +201,7 @@ export class VerifyingProvider {
|
|||
|
||||
private async getTransactionCount(
|
||||
addressHex: AddressHex,
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||
): Promise<HexString> {
|
||||
const header = await this.getBlockHeader(blockOpt);
|
||||
const address = Address.fromString(addressHex);
|
||||
|
@ -214,7 +217,7 @@ export class VerifyingProvider {
|
|||
address,
|
||||
[],
|
||||
header.stateRoot,
|
||||
proof
|
||||
proof,
|
||||
);
|
||||
if (!isAccountCorrect) {
|
||||
throw new InternalError(`invalid account proof provided by the RPC`);
|
||||
|
@ -225,7 +228,7 @@ export class VerifyingProvider {
|
|||
|
||||
private async call(
|
||||
transaction: RPCTx,
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||
) {
|
||||
try {
|
||||
this.validateTx(transaction);
|
||||
|
@ -265,7 +268,7 @@ export class VerifyingProvider {
|
|||
|
||||
private async estimateGas(
|
||||
transaction: RPCTx,
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER
|
||||
blockOpt: BlockOpt = DEFAULT_BLOCK_PARAMETER,
|
||||
) {
|
||||
try {
|
||||
this.validateTx(transaction);
|
||||
|
@ -284,7 +287,7 @@ export class VerifyingProvider {
|
|||
? 2
|
||||
: transaction.accessList
|
||||
? 1
|
||||
: 0
|
||||
: 0,
|
||||
);
|
||||
if (txType == BigInt(2)) {
|
||||
transaction.maxFeePerGas =
|
||||
|
@ -350,7 +353,7 @@ export class VerifyingProvider {
|
|||
}
|
||||
|
||||
private async getTransactionReceipt(
|
||||
txHash: Bytes32
|
||||
txHash: Bytes32,
|
||||
): Promise<JSONRPCReceipt | null> {
|
||||
const { result: receipt, success } = await this.rpc.request({
|
||||
method: "eth_getTransactionReceipt",
|
||||
|
@ -362,7 +365,7 @@ export class VerifyingProvider {
|
|||
const header = await this.getBlockHeader(receipt.blockNumber);
|
||||
const block = await this.getBlock(header);
|
||||
const index = block.transactions.findIndex(
|
||||
(tx) => bufferToHex(tx.hash()) === txHash.toLowerCase()
|
||||
(tx) => bufferToHex(tx.hash()) === txHash.toLowerCase(),
|
||||
);
|
||||
if (index === -1) {
|
||||
throw new InternalError("the recipt provided by the RPC is invalid");
|
||||
|
@ -453,7 +456,7 @@ export class VerifyingProvider {
|
|||
}
|
||||
const responses = _.chunk(
|
||||
rawResponse.map((r: any) => r.result),
|
||||
2
|
||||
2,
|
||||
) as [AccountResponse, CodeResponse][];
|
||||
|
||||
for (let i = 0; i < accessList.length; i++) {
|
||||
|
@ -471,7 +474,7 @@ export class VerifyingProvider {
|
|||
address,
|
||||
storageKeys,
|
||||
header.stateRoot,
|
||||
accountProof
|
||||
accountProof,
|
||||
);
|
||||
if (!isAccountCorrect) {
|
||||
throw new InternalError(`invalid account proof provided by the RPC`);
|
||||
|
@ -480,7 +483,7 @@ export class VerifyingProvider {
|
|||
const isCodeCorrect = await this.verifyCodeHash(code, codeHash);
|
||||
if (!isCodeCorrect) {
|
||||
throw new InternalError(
|
||||
`code provided by the RPC doesn't match the account's codeHash`
|
||||
`code provided by the RPC doesn't match the account's codeHash`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -496,7 +499,7 @@ export class VerifyingProvider {
|
|||
await vm.stateManager.putContractStorage(
|
||||
address,
|
||||
setLengthLeft(toBuffer(storageAccess.key), 32),
|
||||
setLengthLeft(toBuffer(storageAccess.value), 32)
|
||||
setLengthLeft(toBuffer(storageAccess.value), 32),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -527,7 +530,7 @@ export class VerifyingProvider {
|
|||
throw new InvalidParamsError("specified block is too far in future");
|
||||
} else if (blockNumber + MAX_BLOCK_HISTORY < this.latestBlockNumber) {
|
||||
throw new InvalidParamsError(
|
||||
`specified block cannot older that ${MAX_BLOCK_HISTORY}`
|
||||
`specified block cannot older that ${MAX_BLOCK_HISTORY}`,
|
||||
);
|
||||
}
|
||||
return blockNumber;
|
||||
|
@ -566,7 +569,7 @@ export class VerifyingProvider {
|
|||
|
||||
if (!header.hash().equals(toBuffer(blockHash))) {
|
||||
throw new InternalError(
|
||||
`blockhash doesn't match the blockInfo provided by the RPC`
|
||||
`blockhash doesn't match the blockInfo provided by the RPC`,
|
||||
);
|
||||
}
|
||||
this.blockHeaders[blockHash] = header;
|
||||
|
@ -578,14 +581,14 @@ export class VerifyingProvider {
|
|||
address: Address,
|
||||
storageKeys: Bytes32[],
|
||||
stateRoot: Buffer,
|
||||
proof: GetProof
|
||||
proof: GetProof,
|
||||
): Promise<boolean> {
|
||||
const trie = new Trie();
|
||||
const key = keccak256(address.toString());
|
||||
const expectedAccountRLP = await trie.verifyProof(
|
||||
stateRoot,
|
||||
toBuffer(key),
|
||||
proof.accountProof.map((a) => toBuffer(a))
|
||||
proof.accountProof.map((a) => toBuffer(a)),
|
||||
);
|
||||
const account = Account.fromAccountData({
|
||||
nonce: BigInt(proof.nonce),
|
||||
|
@ -607,12 +610,12 @@ export class VerifyingProvider {
|
|||
for (let i = 0; i < storageKeys.length; i++) {
|
||||
const sp = proof.storageProof[i];
|
||||
const key = keccak256(
|
||||
bufferToHex(setLengthLeft(toBuffer(storageKeys[i]), 32))
|
||||
bufferToHex(setLengthLeft(toBuffer(storageKeys[i]), 32)),
|
||||
);
|
||||
const expectedStorageRLP = await trie.verifyProof(
|
||||
toBuffer(proof.storageHash),
|
||||
toBuffer(key),
|
||||
sp.proof.map((a) => toBuffer(a))
|
||||
sp.proof.map((a) => toBuffer(a)),
|
||||
);
|
||||
const isStorageValid =
|
||||
(!expectedStorageRLP && sp.value === "0x0") ||
|
||||
|
@ -647,7 +650,7 @@ export class VerifyingProvider {
|
|||
BigInt(tx.maxPriorityFeePerGas) > BigInt(tx.maxFeePerGas)
|
||||
) {
|
||||
throw new Error(
|
||||
`maxPriorityFeePerGas (${tx.maxPriorityFeePerGas.toString()}) is bigger than maxFeePerGas (${tx.maxFeePerGas.toString()})`
|
||||
`maxPriorityFeePerGas (${tx.maxPriorityFeePerGas.toString()}) is bigger than maxFeePerGas (${tx.maxFeePerGas.toString()})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -667,13 +670,13 @@ export class VerifyingProvider {
|
|||
|
||||
if (!block.header.hash().equals(header.hash())) {
|
||||
throw new InternalError(
|
||||
`BN(${header.number}): blockhash doest match the blockData provided by the RPC`
|
||||
`BN(${header.number}): blockhash doest match the blockData provided by the RPC`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!(await block.validateTransactionsTrie())) {
|
||||
throw new InternalError(
|
||||
`transactionTree doesn't match the transactions provided by the RPC`
|
||||
`transactionTree doesn't match the transactions provided by the RPC`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -696,7 +699,7 @@ export class VerifyingProvider {
|
|||
this.blockHashes[parentBlockNumberHex] !== parentBlockHash
|
||||
) {
|
||||
console.log(
|
||||
"Overriding an existing verified blockhash. Possibly the chain had a reorg"
|
||||
"Overriding an existing verified blockhash. Possibly the chain had a reorg",
|
||||
);
|
||||
}
|
||||
this.blockHashes[parentBlockNumberHex] = parentBlockHash;
|
||||
|
|
|
@ -25,7 +25,7 @@ export class RPC {
|
|||
}
|
||||
|
||||
async requestBatch(requests: RPCRequest[]) {
|
||||
const res = [];
|
||||
const res: RPCResponse[] = [];
|
||||
for (const request of requests) {
|
||||
const r = await this._retryRequest(request);
|
||||
res.push(r);
|
||||
|
@ -35,7 +35,7 @@ export class RPC {
|
|||
|
||||
private async _retryRequest(
|
||||
_request: RPCRequest,
|
||||
retry = 5
|
||||
retry = 5,
|
||||
): Promise<RPCResponse> {
|
||||
const request = {
|
||||
..._request,
|
||||
|
@ -52,8 +52,8 @@ export class RPC {
|
|||
`RPC batch request failed after maximum retries: ${JSON.stringify(
|
||||
request,
|
||||
null,
|
||||
2
|
||||
)} ${JSON.stringify(res, null, 2)}`
|
||||
2,
|
||||
)} ${JSON.stringify(res, null, 2)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export function headerDataFromWeb3Response(blockInfo: any): HeaderData {
|
|||
}
|
||||
|
||||
export function txDataFromWeb3Response(
|
||||
txInfo: any
|
||||
txInfo: any,
|
||||
): TxData | AccessListEIP2930TxData | FeeMarketEIP1559TxData {
|
||||
return {
|
||||
...txInfo,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { InvalidParamsError } from './errors';
|
||||
import { InvalidParamsError } from "./errors.js";
|
||||
|
||||
// Most of the validations are taken from:
|
||||
// https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/client/lib/rpc/validation.ts
|
||||
|
@ -30,13 +30,13 @@ export const validators = {
|
|||
* @param index index of parameter
|
||||
*/
|
||||
hex(params: any[], index: number) {
|
||||
if (typeof params[index] !== 'string') {
|
||||
if (typeof params[index] !== "string") {
|
||||
throw new InvalidParamsError(
|
||||
`invalid argument ${index}: argument must be a hex string`,
|
||||
);
|
||||
}
|
||||
|
||||
if (params[index].substr(0, 2) !== '0x') {
|
||||
if (params[index].substr(0, 2) !== "0x") {
|
||||
throw new InvalidParamsError(
|
||||
`invalid argument ${index}: hex string without 0x prefix`,
|
||||
);
|
||||
|
@ -67,14 +67,14 @@ export const validators = {
|
|||
blockOption(params: any[], index: number) {
|
||||
const blockOption = params[index];
|
||||
|
||||
if (typeof blockOption !== 'string') {
|
||||
if (typeof blockOption !== "string") {
|
||||
throw new InvalidParamsError(
|
||||
`invalid argument ${index}: argument must be a string`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if (['latest', 'earliest', 'pending'].includes(blockOption)) {
|
||||
if (["latest", "earliest", "pending"].includes(blockOption)) {
|
||||
return;
|
||||
}
|
||||
return this.hex([blockOption], 0);
|
||||
|
@ -91,7 +91,7 @@ export const validators = {
|
|||
* @param index index of parameter
|
||||
*/
|
||||
bool(params: any[], index: number) {
|
||||
if (typeof params[index] !== 'boolean') {
|
||||
if (typeof params[index] !== "boolean") {
|
||||
throw new InvalidParamsError(
|
||||
`invalid argument ${index}: argument is not boolean`,
|
||||
);
|
||||
|
@ -118,7 +118,7 @@ export const validators = {
|
|||
transaction(params: any[], index: number) {
|
||||
const tx = params[index];
|
||||
|
||||
if (typeof tx !== 'object') {
|
||||
if (typeof tx !== "object") {
|
||||
throw new InvalidParamsError(
|
||||
`invalid argument ${index}: argument must be an object`,
|
||||
);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
ByteVectorType,
|
||||
ContainerType,
|
||||
ListCompositeType,
|
||||
VectorCompositeType,
|
||||
} from "@chainsafe/ssz";
|
||||
|
@ -8,15 +9,88 @@ import { BEACON_SYNC_COMMITTEE_SIZE } from "./constants.js";
|
|||
|
||||
const MAX_BATCHSIZE = 10000;
|
||||
|
||||
export const LightClientUpdateSSZ = capella.ssz.LightClientUpdate;
|
||||
export const LightClientUpdateSSZ = capella.ssz
|
||||
.LightClientUpdate as unknown as ContainerType<{
|
||||
attestedHeader: ContainerType<{
|
||||
beacon: ContainerType<{
|
||||
slot: import("@chainsafe/ssz").UintNumberType;
|
||||
proposerIndex: import("@chainsafe/ssz").UintNumberType;
|
||||
parentRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
stateRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
bodyRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
}>;
|
||||
execution: ContainerType<{
|
||||
withdrawalsRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
transactionsRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
blockHash: import("@chainsafe/ssz").ByteVectorType;
|
||||
parentHash: import("@chainsafe/ssz").ByteVectorType;
|
||||
feeRecipient: import("@chainsafe/ssz").ByteVectorType;
|
||||
stateRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
receiptsRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
logsBloom: import("@chainsafe/ssz").ByteVectorType;
|
||||
prevRandao: import("@chainsafe/ssz").ByteVectorType;
|
||||
blockNumber: import("@chainsafe/ssz").UintNumberType;
|
||||
gasLimit: import("@chainsafe/ssz").UintNumberType;
|
||||
gasUsed: import("@chainsafe/ssz").UintNumberType;
|
||||
timestamp: import("@chainsafe/ssz").UintNumberType;
|
||||
extraData: import("@chainsafe/ssz").ByteListType;
|
||||
baseFeePerGas: import("@chainsafe/ssz").UintBigintType;
|
||||
}>;
|
||||
executionBranch: VectorCompositeType<
|
||||
import("@chainsafe/ssz").ByteVectorType
|
||||
>;
|
||||
}>;
|
||||
nextSyncCommittee: ContainerType<{
|
||||
pubkeys: VectorCompositeType<import("@chainsafe/ssz").ByteVectorType>;
|
||||
aggregatePubkey: import("@chainsafe/ssz").ByteVectorType;
|
||||
}>;
|
||||
nextSyncCommitteeBranch: VectorCompositeType<
|
||||
import("@chainsafe/ssz").ByteVectorType
|
||||
>;
|
||||
finalizedHeader: ContainerType<{
|
||||
beacon: ContainerType<{
|
||||
slot: import("@chainsafe/ssz").UintNumberType;
|
||||
proposerIndex: import("@chainsafe/ssz").UintNumberType;
|
||||
parentRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
stateRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
bodyRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
}>;
|
||||
execution: ContainerType<{
|
||||
withdrawalsRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
transactionsRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
blockHash: import("@chainsafe/ssz").ByteVectorType;
|
||||
parentHash: import("@chainsafe/ssz").ByteVectorType;
|
||||
feeRecipient: import("@chainsafe/ssz").ByteVectorType;
|
||||
stateRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
receiptsRoot: import("@chainsafe/ssz").ByteVectorType;
|
||||
logsBloom: import("@chainsafe/ssz").ByteVectorType;
|
||||
prevRandao: import("@chainsafe/ssz").ByteVectorType;
|
||||
blockNumber: import("@chainsafe/ssz").UintNumberType;
|
||||
gasLimit: import("@chainsafe/ssz").UintNumberType;
|
||||
gasUsed: import("@chainsafe/ssz").UintNumberType;
|
||||
timestamp: import("@chainsafe/ssz").UintNumberType;
|
||||
extraData: import("@chainsafe/ssz").ByteListType;
|
||||
baseFeePerGas: import("@chainsafe/ssz").UintBigintType;
|
||||
}>;
|
||||
executionBranch: VectorCompositeType<
|
||||
import("@chainsafe/ssz").ByteVectorType
|
||||
>;
|
||||
}>;
|
||||
finalityBranch: VectorCompositeType<import("@chainsafe/ssz").ByteVectorType>;
|
||||
syncAggregate: ContainerType<{
|
||||
syncCommitteeBits: import("@chainsafe/ssz").BitVectorType;
|
||||
syncCommitteeSignature: import("@chainsafe/ssz").ByteVectorType;
|
||||
}>;
|
||||
signatureSlot: import("@chainsafe/ssz").UintNumberType;
|
||||
}>;
|
||||
export const LightClientUpdatesSSZ = new ListCompositeType(
|
||||
LightClientUpdateSSZ as any,
|
||||
MAX_BATCHSIZE
|
||||
MAX_BATCHSIZE,
|
||||
);
|
||||
|
||||
export const CommitteeSSZ = new VectorCompositeType(
|
||||
new ByteVectorType(48),
|
||||
BEACON_SYNC_COMMITTEE_SIZE
|
||||
BEACON_SYNC_COMMITTEE_SIZE,
|
||||
);
|
||||
|
||||
const HashSSZ = new ByteVectorType(32);
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
import Decimal from "decimal.js";
|
||||
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 _ from "lodash";
|
||||
|
||||
export function logFloor(x: number, base: number = 2) {
|
||||
return Decimal.log(x, base).floor().toNumber();
|
||||
}
|
||||
|
||||
export function concatUint8Array(data: Uint8Array[]) {
|
||||
const l = data.reduce((l, d) => l + d.length, 0);
|
||||
let result = new Uint8Array(l);
|
||||
|
@ -32,7 +25,7 @@ export function isCommitteeSame(a: Uint8Array[], b: Uint8Array[]): boolean {
|
|||
}
|
||||
|
||||
export function generateRandomSyncCommittee(): Uint8Array[] {
|
||||
let res = [];
|
||||
let res: Uint8Array[] = [];
|
||||
// TODO: change 512 to constant
|
||||
for (let i = 0; i < 512; i++) {
|
||||
res.push(bls.SecretKey.fromKeygen().toPublicKey().toBytes());
|
||||
|
@ -79,26 +72,10 @@ export async function wait(ms: number) {
|
|||
});
|
||||
}
|
||||
|
||||
/*
|
||||
export function deepTypecast<T>(
|
||||
obj: any,
|
||||
checker: (val: any) => boolean,
|
||||
caster: (val: T) => any
|
||||
): any {
|
||||
return _.forEach(obj, (val: any, key: any, obj: any) => {
|
||||
obj[key] = checker(val)
|
||||
? caster(val)
|
||||
: _.isObject(val)
|
||||
? deepTypecast(val, checker, caster)
|
||||
: val;
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
export function getDefaultClientConfig() {
|
||||
const chainConfig = createBeaconConfig(
|
||||
networksChainConfig.mainnet,
|
||||
fromHexString(mainnetConfig.genesis_validator_root)
|
||||
fromHexString(mainnetConfig.genesis_validator_root),
|
||||
);
|
||||
return {
|
||||
genesis: {
|
||||
|
|
12
src/index.ts
12
src/index.ts
|
@ -1,4 +1,8 @@
|
|||
import { ActiveQuery, addHandler, handleMessage } from "libkmodule";
|
||||
import {
|
||||
ActiveQuery,
|
||||
addHandler,
|
||||
handleMessage,
|
||||
} from "@lumeweb/libkernel/module";
|
||||
import { createClient, RpcNetwork } from "@lumeweb/kernel-rpc-client";
|
||||
import Client from "./client/client.js";
|
||||
import { Prover } from "./client/index.js";
|
||||
|
@ -13,7 +17,7 @@ let moduleReady: Promise<void> = new Promise((resolve) => {
|
|||
let client: Client;
|
||||
let rpc: RpcNetwork;
|
||||
|
||||
addHandler("presentSeed", handlePresentSeed);
|
||||
addHandler("presentKey", handlePresentKey);
|
||||
addHandler("ready", handleReady);
|
||||
|
||||
[
|
||||
|
@ -50,7 +54,7 @@ addHandler("ready", handleReady);
|
|||
});
|
||||
});
|
||||
|
||||
async function handlePresentSeed() {
|
||||
async function handlePresentKey() {
|
||||
await setup();
|
||||
moduleReadyResolve();
|
||||
}
|
||||
|
@ -60,7 +64,7 @@ async function handleRpcMethod(aq: ActiveQuery) {
|
|||
return client.provider.rpcMethod(
|
||||
aq.callerInput?.method,
|
||||
// @ts-ignore
|
||||
aq.callerInput?.params as any[]
|
||||
aq.callerInput?.params as any[],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist-build",
|
||||
"strict": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src-build"],
|
||||
"exclude": ["node_modules", "**/__tests__/*"]
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"declaration": true,
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./build",
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "**/__tests__/*"]
|
||||
}
|
Loading…
Reference in New Issue