mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-08 03:43:56 -05:00
* use 9 blobs for Pectra * add linting to script * turn prague on by default * remove non-prague configuration * testing not-yet-prague is the reason for failure * using pectra from genesis * reset to 9 for testing * lowering blobs per tick * add missing 9s and update blobscan * spotless * expect 9 blobs in one tx * Update coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfig.kt Co-authored-by: Julien Marchand <julien-marchand@users.noreply.github.com> Signed-off-by: The Dark Jester <thedarkjester@users.noreply.github.com> * refactor testdata folders and use 9 blob agg * refactor function for ease of reading * move arguments up * rename function * format parameters * validate at least 1 blob exists * more spotless * simplify blob hash computation --------- Signed-off-by: The Dark Jester <thedarkjester@users.noreply.github.com> Co-authored-by: Julien Marchand <julien-marchand@users.noreply.github.com>
404 lines
13 KiB
TypeScript
404 lines
13 KiB
TypeScript
import { AbiCoder, BytesLike, Transaction, Wallet, ethers } from "ethers";
|
|
import { commitmentsToVersionedHashes } from "@ethereumjs/util";
|
|
import * as kzg from "c-kzg";
|
|
import submissionDataJson1 from "./blocks-1-46.json";
|
|
import submissionDataJson2 from "./blocks-47-81.json";
|
|
import submissionDataJson3 from "./blocks-82-114.json";
|
|
import submissionDataJson4 from "./blocks-115-155.json";
|
|
import submissionDataJson5 from "./blocks-156-175.json";
|
|
import submissionDataJson6 from "./blocks-176-206.json";
|
|
import submissionDataJson7 from "./blocks-207-228.json";
|
|
import submissionDataJson8 from "./blocks-229-265.json";
|
|
import submissionDataJson9 from "./blocks-266-305.json";
|
|
import aggregateProof1to305 from "./aggregatedProof-1-305.json";
|
|
import { DataHexString } from "ethers/lib.commonjs/utils/data";
|
|
|
|
const dataItems = [
|
|
submissionDataJson1,
|
|
submissionDataJson2,
|
|
submissionDataJson3,
|
|
submissionDataJson4,
|
|
submissionDataJson5,
|
|
submissionDataJson6,
|
|
submissionDataJson7,
|
|
submissionDataJson8,
|
|
submissionDataJson9,
|
|
];
|
|
|
|
export function generateKeccak256(types: string[], values: unknown[], packed?: boolean) {
|
|
return ethers.keccak256(encodeData(types, values, packed));
|
|
}
|
|
|
|
export const encodeData = (types: string[], values: unknown[], packed?: boolean) => {
|
|
if (packed) {
|
|
return ethers.solidityPacked(types, values);
|
|
}
|
|
return AbiCoder.defaultAbiCoder().encode(types, values);
|
|
};
|
|
|
|
export type SubmissionData = {
|
|
parentStateRootHash: string;
|
|
dataParentHash: string;
|
|
finalStateRootHash: string;
|
|
firstBlockInData: bigint;
|
|
finalBlockInData: bigint;
|
|
snarkHash: string;
|
|
};
|
|
|
|
export type BlobSubmissionData = {
|
|
submissionData: SubmissionData;
|
|
parentSubmissionData: ParentSubmissionData;
|
|
dataEvaluationClaim: bigint;
|
|
kzgCommitment: BytesLike;
|
|
kzgProof: BytesLike;
|
|
};
|
|
|
|
export type ParentSubmissionData = {
|
|
finalStateRootHash: string;
|
|
firstBlockInData: bigint;
|
|
finalBlockInData: bigint;
|
|
shnarf: string;
|
|
dataParentHash: string;
|
|
};
|
|
|
|
export function generateSubmissionDataFromJSON(
|
|
startingBlockNumber: number,
|
|
endingBlockNumber: number,
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
parsedJSONData: any,
|
|
): { submissionData: SubmissionData; blob: Uint8Array } {
|
|
const returnData = {
|
|
parentStateRootHash: parsedJSONData.parentStateRootHash,
|
|
dataParentHash: parsedJSONData.parentDataHash,
|
|
finalStateRootHash: parsedJSONData.finalStateRootHash,
|
|
firstBlockInData: BigInt(startingBlockNumber),
|
|
finalBlockInData: BigInt(endingBlockNumber),
|
|
snarkHash: parsedJSONData.snarkHash,
|
|
};
|
|
|
|
return {
|
|
submissionData: returnData,
|
|
blob: ethers.decodeBase64(parsedJSONData.compressedData),
|
|
};
|
|
}
|
|
|
|
export function generateParentSubmissionData(finalStateRootHash: string, parentDataHash: string): ParentSubmissionData {
|
|
return {
|
|
finalStateRootHash: finalStateRootHash,
|
|
firstBlockInData: BigInt(0),
|
|
finalBlockInData: BigInt(0),
|
|
shnarf: "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f",
|
|
dataParentHash: parentDataHash,
|
|
};
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
export function generateParentSubmissionDataFromJson(parsedJSONData: any): ParentSubmissionData {
|
|
return {
|
|
finalStateRootHash: parsedJSONData.finalStateRootHash,
|
|
firstBlockInData: BigInt(parsedJSONData.conflationOrder.startingBlockNumber),
|
|
finalBlockInData: BigInt(parsedJSONData.conflationOrder.upperBoundaries.slice(-1)[0]),
|
|
shnarf: parsedJSONData.expectedShnarf,
|
|
dataParentHash: parsedJSONData.parentDataHash,
|
|
};
|
|
}
|
|
|
|
export function generateSubmissionCallDataFromJSON(
|
|
startingBlockNumber: number,
|
|
endingBlockNumber: number,
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
parsedJSONData: any,
|
|
): { submissionData: SubmissionData } {
|
|
const returnData = {
|
|
parentStateRootHash: parsedJSONData.parentStateRootHash,
|
|
dataParentHash: parsedJSONData.parentDataHash,
|
|
finalStateRootHash: parsedJSONData.finalStateRootHash,
|
|
firstBlockInData: BigInt(startingBlockNumber),
|
|
finalBlockInData: BigInt(endingBlockNumber),
|
|
snarkHash: parsedJSONData.snarkHash,
|
|
compressedData: ethers.hexlify(ethers.decodeBase64(parsedJSONData.compressedData)),
|
|
};
|
|
|
|
return {
|
|
submissionData: returnData,
|
|
};
|
|
}
|
|
|
|
function getPadded(data: Uint8Array): Uint8Array {
|
|
const pdata = new Uint8Array(131072).fill(0);
|
|
pdata.set(data);
|
|
return pdata;
|
|
}
|
|
|
|
function requireEnv(name: string): string {
|
|
const envVariable = process.env[name];
|
|
if (!envVariable) {
|
|
throw new Error(`Missing ${name} environment variable`);
|
|
}
|
|
|
|
return envVariable;
|
|
}
|
|
|
|
function kzgCommitmentsToVersionedHashes(commitments: Uint8Array[]): string[] {
|
|
const versionedHashes = commitmentsToVersionedHashes(commitments);
|
|
return versionedHashes.map((versionedHash) => ethers.hexlify(versionedHash));
|
|
}
|
|
|
|
async function main() {
|
|
const rpcUrl = requireEnv("RPC_URL");
|
|
const privateKey = requireEnv("PRIVATE_KEY");
|
|
const destinationAddress = requireEnv("DESTINATION_ADDRESS");
|
|
|
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
const wallet = new Wallet(privateKey, provider);
|
|
|
|
kzg.loadTrustedSetup(`${__dirname}/trusted_setup.txt`);
|
|
|
|
const parentSubmissionData1 = generateParentSubmissionData(
|
|
"0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd",
|
|
ethers.ZeroHash,
|
|
);
|
|
|
|
const kzgProofsArray: Uint8Array[] = [];
|
|
const commitmentsArray: Uint8Array[] = [];
|
|
const versionedHashesArray: string[] = [];
|
|
const blobsArray: Uint8Array[] = [];
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const kzgProofsContractArray: any[] = [];
|
|
// const parentSubmissionData: ParentSubmissionData[] = [];
|
|
|
|
const blobSubmissionData: BlobSubmissionData[] = [];
|
|
|
|
let previousSubmissionData = generateParentSubmissionData(
|
|
"0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd",
|
|
ethers.ZeroHash,
|
|
);
|
|
|
|
const finalSubmissionData = generateParentSubmissionDataFromJson(submissionDataJson6);
|
|
|
|
for (let i = 0; i < dataItems.length; i++) {
|
|
const { submissionData, blob } = generateSubmissionDataFromJSON(
|
|
dataItems[i].conflationOrder.startingBlockNumber,
|
|
dataItems[i].conflationOrder.upperBoundaries.slice(-1)[0],
|
|
dataItems[i],
|
|
);
|
|
const fullblob = getPadded(blob);
|
|
const commitment = kzg.blobToKzgCommitment(fullblob);
|
|
const kzgProof = kzg.computeBlobKzgProof(fullblob, commitment);
|
|
|
|
blobsArray.push(fullblob);
|
|
versionedHashesArray.push(kzgCommitmentsToVersionedHashes([commitment])[0]);
|
|
commitmentsArray.push(commitment);
|
|
kzgProofsArray.push(kzgProof);
|
|
kzgProofsContractArray.push(dataItems[i].kzgProofContract);
|
|
|
|
blobSubmissionData.push({
|
|
submissionData: submissionData,
|
|
parentSubmissionData: previousSubmissionData,
|
|
dataEvaluationClaim: BigInt(dataItems[i].expectedY),
|
|
kzgCommitment: commitment,
|
|
kzgProof: dataItems[i].kzgProofContract,
|
|
});
|
|
|
|
previousSubmissionData = generateParentSubmissionDataFromJson(dataItems[i]);
|
|
}
|
|
|
|
const encodedCall = encodeCall(blobSubmissionData);
|
|
|
|
await submitBlob(provider, wallet, encodedCall, destinationAddress, versionedHashesArray, blobsArray);
|
|
|
|
await sendMessage();
|
|
|
|
await sendProof(aggregateProof1to305, parentSubmissionData1, finalSubmissionData);
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
function mapToTuple(blobSubmissionDataItems: BlobSubmissionData[]): any {
|
|
return blobSubmissionDataItems.map((blobSubmissionData) => [
|
|
blobSubmissionData.dataEvaluationClaim,
|
|
blobSubmissionData.kzgCommitment,
|
|
blobSubmissionData.kzgProof,
|
|
blobSubmissionData.submissionData.finalStateRootHash,
|
|
blobSubmissionData.submissionData.snarkHash,
|
|
]);
|
|
}
|
|
|
|
function encodeCall(submissionData: BlobSubmissionData[]): DataHexString {
|
|
//submitBlobs((uint256,bytes,bytes,bytes32,bytes32)[],bytes32,bytes32)": "99467a35"
|
|
|
|
const encodedCall = ethers.concat([
|
|
"0x99467a35",
|
|
ethers.AbiCoder.defaultAbiCoder().encode(
|
|
["tuple(uint256,bytes,bytes,bytes32,bytes32)[]", "bytes32", "bytes32"],
|
|
[
|
|
mapToTuple(submissionData),
|
|
submissionData[0].parentSubmissionData.shnarf,
|
|
dataItems[dataItems.length - 1].expectedShnarf,
|
|
],
|
|
),
|
|
]);
|
|
|
|
return encodedCall;
|
|
}
|
|
|
|
async function sendMessage() {
|
|
console.log("sending the message");
|
|
|
|
const rpcUrl = requireEnv("RPC_URL");
|
|
const privateKey = requireEnv("PRIVATE_KEY");
|
|
const destinationAddress = requireEnv("DESTINATION_ADDRESS");
|
|
|
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
const wallet = new Wallet(privateKey, provider);
|
|
|
|
const encodedCall = ethers.concat([
|
|
"0x9f3ce55a",
|
|
ethers.AbiCoder.defaultAbiCoder().encode(
|
|
["address", "uint256", "bytes"],
|
|
["0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", "50000000000000000", "0x"],
|
|
),
|
|
]);
|
|
|
|
const { maxFeePerGas, maxPriorityFeePerGas } = await provider.getFeeData();
|
|
const nonce = await provider.getTransactionCount(wallet.address);
|
|
|
|
const transaction = Transaction.from({
|
|
data: encodedCall,
|
|
maxPriorityFeePerGas: maxPriorityFeePerGas!,
|
|
maxFeePerGas: maxFeePerGas!,
|
|
to: destinationAddress,
|
|
chainId: 31648428,
|
|
nonce,
|
|
value: 1050000000000000000n,
|
|
gasLimit: 5_000_000,
|
|
});
|
|
|
|
const tx = await wallet.sendTransaction(transaction);
|
|
const receipt = await tx.wait();
|
|
console.log({ transaction: tx, receipt });
|
|
}
|
|
|
|
async function submitBlob(
|
|
provider: ethers.JsonRpcProvider,
|
|
wallet: Wallet,
|
|
encodedCall: string,
|
|
destinationAddress: string,
|
|
versionedHashes: string[],
|
|
fullblobs: Uint8Array[],
|
|
) {
|
|
const { maxFeePerGas, maxPriorityFeePerGas } = await provider.getFeeData();
|
|
const nonce = await provider.getTransactionCount(wallet.address);
|
|
|
|
console.log(encodedCall);
|
|
|
|
const transaction = Transaction.from({
|
|
data: encodedCall,
|
|
maxPriorityFeePerGas: maxPriorityFeePerGas!,
|
|
maxFeePerGas: maxFeePerGas!,
|
|
to: destinationAddress,
|
|
chainId: 31648428,
|
|
type: 3,
|
|
nonce,
|
|
value: 0,
|
|
kzg,
|
|
blobs: fullblobs,
|
|
gasLimit: 5_000_000,
|
|
blobVersionedHashes: versionedHashes,
|
|
maxFeePerBlobGas: maxFeePerGas!,
|
|
});
|
|
|
|
const tx = await wallet.sendTransaction(transaction);
|
|
const receipt = await tx.wait();
|
|
|
|
console.log(versionedHashes);
|
|
console.log("BlobTX Hash: ", tx.hash);
|
|
console.log(`BlobTX receipt: ${JSON.stringify(receipt, null, 2)}`);
|
|
}
|
|
|
|
async function sendProof(
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
proofFile: any,
|
|
submissionData: ParentSubmissionData,
|
|
finalSubmissionData: ParentSubmissionData,
|
|
) {
|
|
console.log("proof");
|
|
|
|
const rpcUrl = requireEnv("RPC_URL");
|
|
const privateKey = requireEnv("PRIVATE_KEY");
|
|
const destinationAddress = requireEnv("DESTINATION_ADDRESS");
|
|
|
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
const wallet = new Wallet(privateKey, provider);
|
|
|
|
const finalSubmission = dataItems[dataItems.length - 1];
|
|
|
|
const proofData = [
|
|
proofFile.aggregatedProof,
|
|
0,
|
|
[
|
|
proofFile.parentStateRootHash,
|
|
finalSubmissionData.finalBlockInData,
|
|
[
|
|
finalSubmission.prevShnarf,
|
|
finalSubmission.snarkHash,
|
|
finalSubmission.finalStateRootHash,
|
|
finalSubmission.expectedX,
|
|
finalSubmission.expectedY,
|
|
],
|
|
proofFile.parentAggregationLastBlockTimestamp,
|
|
proofFile.finalTimestamp,
|
|
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
proofFile.l1RollingHash,
|
|
0, // last finalized message number
|
|
proofFile.l1RollingHashMessageNumber,
|
|
proofFile.l2MerkleTreesDepth,
|
|
proofFile.l2MerkleRoots,
|
|
proofFile.l2MessagingBlocksOffsets,
|
|
],
|
|
];
|
|
|
|
console.log(proofData);
|
|
//finalizeBlocks(bytes,uint256,(bytes32,uint256,(bytes32,bytes32,bytes32,bytes32,bytes32),uint256,uint256,bytes32,bytes32,uint256,uint256,uint256,bytes32[],bytes))": "5603c65f"
|
|
//finalizeBlocks(bytes,uint256,(bytes32,uint256,(bytes32,bytes32,bytes32,bytes32,bytes32),uint256,uint256,bytes32,bytes32,uint256,uint256,uint256,bytes32[],bytes))": "5603c65f"
|
|
const encodedCall = ethers.concat([
|
|
"0x5603c65f",
|
|
ethers.AbiCoder.defaultAbiCoder().encode(
|
|
[
|
|
"bytes",
|
|
"uint256",
|
|
"tuple(bytes32,uint256,tuple(bytes32,bytes32,bytes32,bytes32,bytes32),uint256,uint256,bytes32,bytes32,uint256,uint256,uint256,bytes32[],bytes)",
|
|
],
|
|
proofData,
|
|
),
|
|
]);
|
|
|
|
console.log(submissionData.shnarf);
|
|
console.log(finalSubmission.expectedShnarf);
|
|
console.log(BigInt(finalSubmission.conflationOrder.upperBoundaries.slice(-1)[0]));
|
|
|
|
const { maxFeePerGas, maxPriorityFeePerGas } = await provider.getFeeData();
|
|
const nonce = await provider.getTransactionCount(wallet.address);
|
|
|
|
const transaction = Transaction.from({
|
|
data: encodedCall,
|
|
maxPriorityFeePerGas: maxPriorityFeePerGas!,
|
|
maxFeePerGas: maxFeePerGas!,
|
|
to: destinationAddress,
|
|
chainId: 31648428,
|
|
nonce,
|
|
value: 0,
|
|
gasLimit: 5_000_000,
|
|
});
|
|
|
|
const tx = await wallet.sendTransaction(transaction);
|
|
const receipt = await tx.wait();
|
|
console.log({ transaction: tx, receipt });
|
|
}
|
|
|
|
main()
|
|
.then(() => process.exit(0))
|
|
.catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|