Skip to content

Commit

Permalink
Merge pull request #16 from lambdaclass/test-validium
Browse files Browse the repository at this point in the history
Improving validium script code and testing
  • Loading branch information
jordibonet-lambdaclass authored May 31, 2024
2 parents 23aec10 + 97d2d0c commit 23a2ab9
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 88 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/deno_testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ jobs:
- name: Set up .env
run: |
cd deno
echo "ETH_PROVIDER_URL=${{ secrets.ETH_PROVIDER_URL }}" > .env
echo "AVAIL_RPC=${{ secrets.AVAIL_RPC }}" >> .env
echo "SURI=${{ secrets.SURI }}" >> .env
echo "DA_BRIDGE_ADDRESS=${{ secrets.DA_BRIDGE_ADDRESS }}" >> .env
echo "BRIDGE_API_URL=${{ secrets.BRIDGE_API_URL }}" >> .env
echo "ETH_PROVIDER_URL=${{ secrets.ETH_PROVIDER_URL }}" >> .env
shell: bash
- name: Run tests
run: |
Expand Down
2 changes: 1 addition & 1 deletion deno/deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"tasks": {
"validium": "deno run --allow-read --allow-net --allow-env validium.ts",
"validium": "deno run --allow-read --allow-net --allow-env main.ts",
"test": "deno test --allow-net --allow-read --allow-env tests.ts"
}
}
189 changes: 189 additions & 0 deletions deno/deno.lock

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions deno/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
ApiPromise,
Keyring,
WsProvider,
} from "https://deno.land/x/[email protected]/api/mod.ts";
import { API_EXTENSIONS, API_RPC, API_TYPES } from "./api_options.ts";
import { KeyringPair } from "https://deno.land/x/[email protected]/keyring/types.ts";

export function initializeAvailApi(availRpc: string): Promise<ApiPromise> {
return ApiPromise.create({
provider: new WsProvider(availRpc),
rpc: API_RPC,
types: API_TYPES,
signedExtensions: API_EXTENSIONS,
});
}

export function createAccount(suri: string): KeyringPair {
return new Keyring({ type: "sr25519" }).addFromUri(suri);
}
3 changes: 3 additions & 0 deletions deno/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { submitDataAndVerify } from "./validium.ts";

await submitDataAndVerify();
51 changes: 29 additions & 22 deletions deno/tests.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import { ethers } from "npm:[email protected]";
import {
assert,
assertEquals,
} from "https://deno.land/[email protected]/assert/mod.ts";
import { load } from "https://deno.land/[email protected]/dotenv/mod.ts";
import { assertEquals } from "https://deno.land/[email protected]/assert/mod.ts";
import ABI from "./abi/availbridge.json" with { type: "json" };
import { ProofData, submitDataAndVerify, verifyProof } from "./validium.ts";

Deno.test("verifyBlobLeaf function should return expected result", async () => {
const env = await load();
const env = await load();

const BRIDGE_ADDRESS = env["DA_BRIDGE_ADDRESS"];
const ETH_PROVIDER_URL = env["ETH_PROVIDER_URL"];
const provider = new ethers.providers.JsonRpcProvider(ETH_PROVIDER_URL);
const contractInstance = new ethers.Contract(BRIDGE_ADDRESS, ABI, provider);
Deno.test("Load environment variables", () => {
assert(env["AVAIL_RPC"], "AVAIL_RPC should be defined");
assert(env["SURI"], "SURI should be defined");
assert(env["DA_BRIDGE_ADDRESS"], "DA_BRIDGE_ADDRESS should be defined");
assert(env["BRIDGE_API_URL"], "BRIDGE_API_URL should be defined");
assert(env["ETH_PROVIDER_URL"], "ETH_PROVIDER_URL should be defined");
});

Deno.test("verifyBlobLeaf function should return expected result", async () => {
const proof = {
blobRoot:
"0xe882a0dd840cc7b99d5f9ff05216be547c7b7d84a61d474353c4d9cb90cb2cdd",
Expand Down Expand Up @@ -42,19 +47,21 @@ Deno.test("verifyBlobLeaf function should return expected result", async () => {
"0xfbab0eb809f03a99ee5dcca7f4131b6b8a8b56eccbee8f439cd33145d2d14e1d",
};

const isVerified = await contractInstance.verifyBlobLeaf([
proof.dataRootProof,
proof.leafProof,
proof.rangeHash,
proof.dataRootIndex,
proof.blobRoot,
proof.bridgeRoot,
proof.leaf,
proof.leafIndex,
]);

console.log(`Blob validation is: ${isVerified}`);

const proofData: ProofData = {
dataRootProof: proof.dataRootProof,
leafProof: proof.leafProof,
rangeHash: proof.rangeHash,
dataRootIndex: proof.dataRootIndex,
blobRoot: proof.blobRoot,
bridgeRoot: proof.bridgeRoot,
leaf: proof.leaf,
leafIndex: proof.leafIndex,
};
const isVerified = await verifyProof(proofData);
const expectedValue = true;
assertEquals(isVerified, expectedValue);
});

Deno.test("submitDataAndVerify", async () => {
await submitDataAndVerify();
});
142 changes: 78 additions & 64 deletions deno/validium.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import {
ApiPromise,
Keyring,
WsProvider,
} from "https://deno.land/x/[email protected]/api/mod.ts";
import { API_EXTENSIONS, API_RPC, API_TYPES } from "./api_options.ts";
import { ApiPromise } from "https://deno.land/x/[email protected]/api/mod.ts";
import { ISubmittableResult } from "https://deno.land/x/[email protected]/types/types/extrinsic.ts";
import { ethers } from "npm:[email protected]";
import { load } from "https://deno.land/[email protected]/dotenv/mod.ts";
import ABI from "./abi/availbridge.json" with { type: "json" };
import { KeyringPair } from "https://deno.land/x/[email protected]/keyring/types.ts";
import { createAccount, initializeAvailApi } from "./helpers.ts";

const env = await load();

Expand All @@ -18,24 +14,16 @@ const BRIDGE_ADDRESS = env["DA_BRIDGE_ADDRESS"]; // deployed bridge address
const DATA = "a"; // data to send
const BRIDGE_API_URL = env["BRIDGE_API_URL"]; // bridge api url
const ETH_PROVIDER_URL = env["ETH_PROVIDER_URL"]; // eth provider url
const availApi = await ApiPromise.create({
provider: new WsProvider(AVAIL_RPC),
rpc: API_RPC,
types: API_TYPES,
signedExtensions: API_EXTENSIONS,
});
const account = new Keyring({ type: "sr25519" }).addFromUri(SURI);

/**
* ProofData represents a response from the api that holds proof for
* the blob verification.
*/
// deno-lint-ignore no-unused-vars
class ProofData {
export class ProofData {
// proof of inclusion for the data root
dataRootProof: Array<string> | undefined;
// proof of inclusion of leaf within blob/bridge root
leafProof: string | undefined;
leafProof: Array<string> | undefined;
// abi.encodePacked(startBlock, endBlock) of header range commitment on VectorX
rangeHash: string | undefined;
// index of the data root in the commitment tree
Expand All @@ -62,7 +50,7 @@ interface SubmitDataResult extends ISubmittableResult {
* @param account that is sending transaction
* @returns {Promise<SubmitDataResult>}
*/
function submitData(
export function submitData(
availApi: ApiPromise,
data: string,
account: KeyringPair,
Expand All @@ -88,17 +76,9 @@ function submitData(
});
}

const result: SubmitDataResult = await submitData(availApi, DATA, account);
if (result.isFinalized) {
console.log(
`DA transaction in finalized block: ${result.blockNumber}, transaction index: ${result.txIndex}`,
);
console.log(`result submitData = ${JSON.stringify(result)}`);
}

// wait until the chain head on the Ethereum network is updated with the block range
// in which the Avail DA transaction is included.
while (true) {
export async function getLastCommittedBlock(
result: SubmitDataResult,
): Promise<number> {
const getHeadRsp = await fetch(BRIDGE_API_URL + "/avl/head");
if (getHeadRsp.status != 200) {
console.log("Something went wrong fetching the head.");
Expand All @@ -107,7 +87,7 @@ while (true) {
console.log("Headers:", Array.from(getHeadRsp.headers.entries()));
const responseBody = await getHeadRsp.text();
console.log("Response Body:", responseBody);
break;
Deno.exit(0);
}
const headRsp = await getHeadRsp.json();
const blockNumber: number = Number(result.blockNumber);
Expand All @@ -117,43 +97,77 @@ while (true) {
blockNumber - lastCommittedBlock
} blocks left`,
);
if (lastCommittedBlock >= blockNumber) {
console.log("Fetching the blob proof.");
const proofResponse = await fetch(
BRIDGE_API_URL + "/eth/proof/" + result.status.asFinalized + "?index=" +
result.txIndex,
);
console.log(proofResponse.url);
if (proofResponse.status != 200) {
console.log("Something went wrong fetching the proof.");
console.log(proofResponse);
break;
}
const proof: ProofData = await proofResponse.json();
console.log("Proof fetched:");
console.log(proof);
// call the deployed contract verification function with the inclusion proof.
const provider = new ethers.providers.JsonRpcProvider(ETH_PROVIDER_URL);
const contractInstance = new ethers.Contract(BRIDGE_ADDRESS, ABI, provider);
const isVerified = await contractInstance.verifyBlobLeaf([
proof.dataRootProof,
proof.leafProof,
proof.rangeHash,
proof.dataRootIndex,
proof.blobRoot,
proof.bridgeRoot,
proof.leaf,
proof.leafIndex,
]);
console.log(`Blob validation is: ${isVerified}`);
break;
return lastCommittedBlock;
}

export async function getProof(result: SubmitDataResult): Promise<ProofData> {
console.log("Fetching the blob proof.");
const proofResponse = await fetch(
BRIDGE_API_URL + "/eth/proof/" + result.status.asFinalized + "?index=" +
result.txIndex,
);
console.log(proofResponse.url);
if (proofResponse.status != 200) {
console.log("Something went wrong fetching the proof.");
console.log(proofResponse);
Deno.exit(0);
}
const proof: ProofData = await proofResponse.json();
console.log("Proof fetched:");
console.log(proof);
return proof;
}

console.log(
"Waiting to bridge inclusion commitment. This can take a while...",
export async function verifyProof(proof: ProofData): Promise<boolean> {
// call the deployed contract verification function with the inclusion proof.
const provider = new ethers.providers.JsonRpcProvider(ETH_PROVIDER_URL);
const contractInstance = new ethers.Contract(
BRIDGE_ADDRESS,
ABI,
provider,
);
// wait for 1 minute to check again
await new Promise((f) => setTimeout(f, 60 * 1000));
const isVerified = await contractInstance.verifyBlobLeaf([
proof.dataRootProof,
proof.leafProof,
proof.rangeHash,
proof.dataRootIndex,
proof.blobRoot,
proof.bridgeRoot,
proof.leaf,
proof.leafIndex,
]);
console.log(`Blob validation is: ${isVerified}`);
return isVerified;
}

Deno.exit(0);
export async function proofAndVerify(result: SubmitDataResult) {
// wait until the chain head on the Ethereum network is updated with the block range
// in which the Avail DA transaction is included.
while (true) {
const blockNumber: number = Number(result.blockNumber);
const lastCommittedBlock: number = await getLastCommittedBlock(result);
if (lastCommittedBlock >= blockNumber) {
const proof = await getProof(result);
await verifyProof(proof);
}
console.log(
"Waiting to bridge inclusion commitment. This can take a while...",
);
// wait for 1 minute to check again
await new Promise((f) => setTimeout(f, 60 * 1000));
}
}

export async function submitDataAndVerify() {
const availApi = await initializeAvailApi(AVAIL_RPC);
const account = createAccount(SURI);
const result: SubmitDataResult = await submitData(availApi, DATA, account);
if (result.isFinalized) {
console.log(
`DA transaction in finalized block: ${result.blockNumber}, transaction index: ${result.txIndex}`,
);
console.log(`result submitData = ${JSON.stringify(result)}`);
}
await proofAndVerify(result);
Deno.exit(0);
}

0 comments on commit 23a2ab9

Please sign in to comment.