Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validator refactor #207

Draft
wants to merge 4 commits into
base: feat/sdk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ As long as there is one honest participant running a working implementation of t

##### ⚖️ [VeaScan explorer](https://veascan.io)

##### 📦 NPM Packages

- [@kleros/vea-sdk](https://www.npmjs.com/package/@kleros/vea-sdk)
- [@kleros/vea-contracts](https://www.npmjs.com/package/@kleros/vea-contracts)

##### 🗃️ Subgraph endpoints

- [Inbox for VeaScan](veascan-subgraph-inbox/README.md#deployments)
Expand All @@ -78,10 +83,10 @@ As long as there is one honest participant running a working implementation of t
| **[relayer-subgraph-inbox](/relayer-subgraph-inbox)** | Indexing of the bridge inbox for relaying purposes, in particular for the computation of the proof of inclusion of a message in a state root. |
| **[services](/services)** | Supporting services such as a graph-node container. |
| **[validator-cli](/validator-cli)** | Validator implementation in TypeScript capable of fulfilling the roles of Oracle and Challenger. |
| **[vea-sdk](/vea-sdk)** | SDK for the developers of cross-chain apps on Vea. |
| **[veascan-subgraph-inbox](/veascan-subgraph-inbox)** | Indexing of the bridge inbox for retrieval by the Veascan frontend. |
| **[veascan-subgraph-outbox](/veascan-subgraph-outbox)** | Indexing of the bridge outbox for retrieval by the Veascan frontend. |
| **[veascan-web](/veascan-web)** | Explorer of snapshot and messages crossing the bridge. |
| | |

## Toolchain:

Expand Down
3 changes: 1 addition & 2 deletions contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kleros/vea-contracts",
"version": "0.1.14",
"version": "0.2.1",
"description": "Smart contracts for Vea",
"repository": {
"type": "git",
Expand Down Expand Up @@ -75,7 +75,6 @@
"json-schema": "^0.4.0",
"mocha": "^10.2.0",
"node-fetch": "^3.3.1",
"shelljs": "^0.8.5",
"solhint": "^3.4.1",
"solidity-coverage": "^0.8.2",
"ts-node": "^10.9.1",
Expand Down
2 changes: 1 addition & 1 deletion contracts/scripts/publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ trap _finally EXIT
yarn version $1

mkdir dist
cp -pr README.md deployments src/ dist/
cp -pr README.md deployments typechain-types src/ dist/
rm -rf dist/test
jq 'del(.scripts.prepare)' package.json > dist/package.json

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"relayer-subgraph-inbox",
"validator-cli",
"relayer-cli",
"vea-sdk",
"veascan-web",
"veascan-subgraph-inbox",
"veascan-subgraph-outbox"
Expand Down
1 change: 0 additions & 1 deletion relayer-cli/src/utils/relay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { getProofAtCount, getMessageDataToRelay, getSubgraph } from "./proof";
import { getVeaOutboxArbToEth } from "./ethers";
import request from "graphql-request";
import { VeaInboxArbToEth, VeaOutboxArbToEth } from "@kleros/vea-contracts/typechain-types";
const fs = require("fs");

require("dotenv").config();

Expand Down
15 changes: 11 additions & 4 deletions validator-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,25 @@
"yarn": "3.3.1"
},
"scripts": {
"start": "npx ts-node ./src/ArbToEth/watcher.ts",
"start-chiado-devnet": "npx ts-node ./src/devnet/arbToChiado/happyPath.ts",
"start-goerli-devnet": "npx ts-node ./src/devnet/arbToGoerli/happyPath.ts"
"start": "NODE_NO_WARNINGS=1 NODE_OPTIONS=--experimental-fetch ts-node ./src/ArbToEth/index.ts",
"pm2:start": "pm2 start 'yarn start' --name watcher --cron '*/10 * * * *' --no-autorestart",
"start-chiado-devnet": "NODE_NO_WARNINGS=1 NODE_OPTIONS=--experimental-fetch ts-node ./src/devnet/arbToChiado/happyPath.ts",
"start-goerli-devnet": "NODE_NO_WARNINGS=1 NODE_OPTIONS=--experimental-fetch ts-node ./src/devnet/arbToGoerli/happyPath.ts"
},
"dependencies": {
"@arbitrum/sdk": "^3.1.2",
"@kleros/vea-contracts": "workspace:^",
"@logtail/pino": "^0.4.0",
"@typechain/ethers-v5": "^10.2.0",
"dotenv": "^16.0.3",
"pino": "^8.14.1",
"pino-pretty": "^10.0.0",
"pm2": "^5.2.2",
"typescript": "^4.9.5",
"web3": "^1.10.0",
"web3-batched-send": "^1.0.3"
},
"devDependencies": {
"ts-node": "^10.9.1",
"typescript": "^4.9.5"
}
}
7 changes: 7 additions & 0 deletions validator-cli/src/ArbToEth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import watch from "./watcher";

try {
watch();
} catch (error) {
console.log("error", error);
}
59 changes: 36 additions & 23 deletions validator-cli/src/ArbToEth/watcher.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,59 @@
import { getVeaOutboxArbToEthProvider, getVeaInboxArbToEth } from "../utils/ethers";
import { JsonRpcProvider } from "@ethersproject/providers";

require("dotenv").config();
import { arbToEthDevnet, IBridge } from "../utils/contracts";
import envVar from "../utils/envVar";
import baseLogger from "../utils/logger";

const watch = async () => {
const l1provider = new JsonRpcProvider(process.env.RPC_VEAOUTBOX);

const veaOutbox = getVeaOutboxArbToEthProvider(process.env.VEAOUTBOX_ADDRESS, process.env.PRIVATE_KEY, l1provider);
const bridge: IBridge = arbToEthDevnet;
const logger = baseLogger.child({
bridge: bridge.label,
inbox: bridge.inboxAddress,
outbox: bridge.outboxAddress,
});
logger.info("Watching for claims...");
logger.debug("Inbox RPC: %s", bridge.inboxRpc);
logger.debug("Outbox RPC: %s", bridge.outboxRpc);

const veaInbox = getVeaInboxArbToEth(process.env.VEAINBOX_ADDRESS, process.env.PRIVATE_KEY, process.env.RPC_VEAINBOX);
const privateKey = envVar("PRIVATE_KEY");
const rpcProviderOutbox = new JsonRpcProvider(bridge.outboxRpc);
const veaOutbox = getVeaOutboxArbToEthProvider(bridge.outboxAddress, privateKey, rpcProviderOutbox);
const veaInbox = getVeaInboxArbToEth(bridge.inboxAddress, privateKey, bridge.inboxRpc);

const deposit = await veaOutbox.deposit();
const epochPeriod = (await veaOutbox.epochPeriod()).toNumber();
const claimDelay = (await veaOutbox.claimDelay()).toNumber();
const challengePeriod = (await veaOutbox.challengePeriod()).toNumber();

const currentBlockNumber = await l1provider.getBlockNumber();
const challengableTimeStart = Math.floor(Date.now() / 1000) - challengePeriod;
const challengableBlockStart = currentBlockNumber - Math.ceil((challengePeriod * 2) / 12);
const currentBlockNumber = await rpcProviderOutbox.getBlockNumber();
const challengeableTimeStart = Math.floor(Date.now() / 1000) - challengePeriod;
const challengeableBlockStart = currentBlockNumber - Math.ceil((challengePeriod * 2) / 12);

const logs = await l1provider.getLogs({
address: process.env.VEAOUTBOX_ADDRESS,
const logs = await rpcProviderOutbox.getLogs({
address: bridge.outboxAddress,
topics: veaOutbox.filters.Claimed(null, null).topics,
fromBlock: challengableBlockStart,
fromBlock: challengeableBlockStart,
});
logger.info("Claim events found: %d", logs.length);

for (let i = 0; i < logs.length; i++) {
const log = logs[i];
const claimedTimestamp = (await l1provider.getBlock(log.blockNumber)).timestamp;
console.log({
for (var log of logs) {
const claimedTimestamp = (await rpcProviderOutbox.getBlock(log.blockNumber)).timestamp;
logger.info({
stateRoot: log.data,
claimer: "0x" + log.topics[1].substring(26),
timestamp: claimedTimestamp,
blocknumber: log.blockNumber,
honest: "0",
challenger: "0x0000000000000000000000000000000000000000",
});
if (claimedTimestamp < challengableTimeStart) {
if (claimedTimestamp < challengeableTimeStart) {
continue;
} else {
const claimedStateRoot = log.data;
const claimedEpoch = Math.floor((claimedTimestamp - claimDelay) / epochPeriod);
const inboxStateRoot = await veaInbox.snapshots(claimedEpoch);
if (claimedStateRoot !== inboxStateRoot) {
console.log(`Challenging claim ${claimedStateRoot} at epoch ${claimedEpoch}.`);
logger.warn(`Challenging claim ${claimedStateRoot} at epoch ${claimedEpoch}.`);
const unchallengedClaim = {
stateRoot: claimedStateRoot,
claimer: "0x" + log.topics[1].substring(26),
Expand All @@ -54,17 +64,20 @@ const watch = async () => {
};
const unchallengedClaimHash = await veaOutbox.hashClaim(unchallengedClaim);
const claimHash = await veaOutbox.claimHashes(claimedEpoch);
console.log(unchallengedClaim);
console.log(unchallengedClaimHash);
console.log(claimHash);
console.log(claimedEpoch);
logger.warn(unchallengedClaim);
logger.warn(unchallengedClaimHash);
logger.warn(claimHash);
logger.warn(claimedEpoch);
if (unchallengedClaimHash == claimHash) {
const txn = await veaOutbox.challenge(claimedEpoch, unchallengedClaim, { value: deposit });
console.log(`Challenge Txn: ${txn.hash}`);
logger.warn(`Challenge Txn: ${txn.hash}`);
}
}
}
}

// TODO: make this env var optional, skip fetch if undefined
fetch(envVar("HEARTBEAT_URL"));
};

export default watch;
Empty file added validator-cli/src/index.ts
Empty file.
31 changes: 31 additions & 0 deletions validator-cli/src/utils/contracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import VeaInboxArbToGnosisDevnet from "@kleros/vea-contracts/deployments/arbitrumGoerli/VeaInboxArbToGnosisDevnet.json";
import VeaOutboxArbToGnosisDevnet from "@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisDevnet.json";

import VeaInboxArbToEthDevnet from "@kleros/vea-contracts/deployments/arbitrumGoerli/VeaInboxArbToEthDevnet.json";
import VeaOutboxArbToEthDevnet from "@kleros/vea-contracts/deployments/goerli/VeaOutboxArbToEthDevnet.json";

import envVar from "./envVar";

export interface IBridge {
label: string;
inboxAddress: `0x${string}`;
outboxAddress: `0x${string}`;
inboxRpc: string;
outboxRpc: string;
}

export const arbToGnosisDevnet: IBridge = {
label: "Arbitrum to Chiado Devnet",
inboxAddress: VeaInboxArbToGnosisDevnet.address as `0x${string}`,
outboxAddress: VeaOutboxArbToGnosisDevnet.address as `0x${string}`,
inboxRpc: envVar("RPC_ARB_GOERLI"),
outboxRpc: envVar("RPC_CHIADO"),
};

export const arbToEthDevnet: IBridge = {
label: "Arbitrum to Goerli Devnet",
inboxAddress: VeaInboxArbToEthDevnet.address as `0x${string}`,
outboxAddress: VeaOutboxArbToEthDevnet.address as `0x${string}`,
inboxRpc: envVar("RPC_ARB_GOERLI"),
outboxRpc: envVar("RPC_GOERLI"),
};
16 changes: 16 additions & 0 deletions validator-cli/src/utils/envVar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import dotenv from "dotenv";
import logger from "./logger";

dotenv.config();

function envVar(key: string): string {
const value = process.env[key];
if (value === undefined) {
const error = new Error(`Environment variable ${key} is undefined`);
logger.error(error);
throw error;
}
return value;
}

export default envVar;
28 changes: 28 additions & 0 deletions validator-cli/src/utils/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pino from "pino";
import envVar from "./envVar";

// TODO: make this env var optional, skip fetch if undefined
const logtailToken = envVar("LOGTAIL_TOKEN");
const transport = pino.transport({
targets: [
{
target: "@logtail/pino",
options: { sourceToken: logtailToken },
level: "debug",
},
{
target: "pino-pretty",
options: {},
level: "debug",
},
],
});
const logger = pino(
{
level: envVar("LOG_LEVEL"), // TODO: set it to info if not defined
timestamp: pino.stdTimeFunctions.isoTime,
},
transport
);

export default logger;
11 changes: 11 additions & 0 deletions validator-cli/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
{
"compilerOptions": {
"target": "es2021",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "dist",
"declaration": true,
"sourceMap": true,
"noImplicitAny": false,
"resolveJsonModule": true
},
"include": [
"src"
]
Expand Down
13 changes: 13 additions & 0 deletions vea-sdk/.env.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PRIVATE_KEY=

RPC_CHIADO=https://rpc.chiadochain.net
RPC_ARB_GOERLI=https://goerli-rollup.arbitrum.io/rpc
RPC_GOERLI=

VEAINBOX_ARBGOERLI_TO_GOERLI_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
VEAINBOX_ARBGOERLI_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C
VEAOUTBOX_ARBGOERLI_TO_GOERLI_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
VEAOUTBOX_ARBGOERLI_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C

TRANSACTION_BATCHER_CONTRACT_ADDRESS_GOERLI=0xe7953da7751063d0a41ba727c32c762d3523ade8
TRANSACTION_BATCHER_CONTRACT_ADDRESS_CHIADO=0xcC0a08D4BCC5f91ee9a1587608f7a2975EA75d73
3 changes: 3 additions & 0 deletions vea-sdk/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
scripts
tsconfig.json
.env*
31 changes: 31 additions & 0 deletions vea-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Vea SDK <a href="https://www.npmjs.com/package/@kleros/vea-sdk"><img alt="npm" src="https://img.shields.io/npm/v/@kleros/vea-sdk?color=lightgrey"></a>

This package facilitates the interactions with the Vea protocol.

## Getting Started

```bash
yarn add @kleros/vea-sdk
# or
npm install @kleros/vea-sdk
```

## Example

```typescript
import { Wallet } from "@ethersproject/wallet";
import VeaSdk from "../src/index";
import envVar from "../src/utils/envVar";

// Create the Vea client
const vea = VeaSdk.ClientFactory.arbitrumGoerliToChiadoDevnet(envVar("RPC_ARB_GOERLI"), envVar("RPC_CHIADO"));

// Get the message info
const messageId = 42;
const messageInfo = await vea.getMessageInfo(messageId);

// Relay the message
const privateKey = envVar("PRIVATE_KEY");
const wallet = new Wallet(privateKey, vea.outboxProvider);
await vea.relay(messageInfo, wallet);
```
15 changes: 15 additions & 0 deletions vea-sdk/examples/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Wallet } from "@ethersproject/wallet";
import VeaSdk from "../src/index";
import envVar from "../src/utils/envVar";

// Create the Vea client
const vea = VeaSdk.ClientFactory.arbitrumGoerliToChiadoDevnet(envVar("RPC_ARB_GOERLI"), envVar("RPC_CHIADO"));

// Get the message info
const messageId = 42;
const messageInfo = await vea.getMessageInfo(messageId);

// Relay the message
const privateKey = envVar("PRIVATE_KEY");
const wallet = new Wallet(privateKey, vea.outboxProvider);
await vea.relay(messageInfo, wallet);
Loading