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

WIP: Bankai daemon implementation #12

Open
wants to merge 73 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
e5fd1a1
Fix install script
lakewik Dec 18, 2024
0c50aaa
WIP: Initial implementation of daemon
lakewik Jan 8, 2025
99a6e30
Prepare to merge
lakewik Jan 9, 2025
950144b
Merge
lakewik Jan 9, 2025
e4cddcd
Update cargo.toml
lakewik Jan 10, 2025
77530c6
Merge branch 'main' into feat/daemon
lakewik Jan 10, 2025
83474ef
Update cargo.toml
lakewik Jan 10, 2025
01a2931
Fixes after merge
lakewik Jan 10, 2025
b8d94d2
Change names to more represent actual values
lakewik Jan 10, 2025
2a4e6f6
Start implementing batched scheduler
lakewik Jan 13, 2025
4d38984
Working merkle paths retrieval for epoch
lakewik Jan 13, 2025
81169f9
Spawn blocking thead to avoid blocking other I/O like axum requests b…
lakewik Jan 13, 2025
336c864
Add Semaphore to control how many concurrent trace generation jobs ar…
lakewik Jan 13, 2025
e5837a0
Divide main to separate modules, improve state handling
lakewik Jan 13, 2025
6ad4468
Structurize code & create DatabaseManager
lakewik Jan 15, 2025
091b1f8
feat: Add worker for transaction broadcasting, major sync committe up…
lakewik Jan 17, 2025
640bb09
feat: add committee hash insert to db
lakewik Jan 17, 2025
726c0b5
Fix state persistence
lakewik Jan 21, 2025
96d1a37
Refactor, add missing RPC endpoints, various jobs improvements
lakewik Jan 22, 2025
5c680de
Fix queries
lakewik Jan 22, 2025
4a4fbf4
Fix constants
lakewik Jan 22, 2025
f096be3
Improve batches handling
lakewik Jan 24, 2025
3e19f9b
Fix calculation of epochs ranges, add reconnection logic to beacon ch…
lakewik Jan 27, 2025
2a69717
Add ability to graceful shutdown & fix sync commite epochs counting
lakewik Jan 27, 2025
549e262
Implementation of Herodotus Transactor client
lakewik Jan 31, 2025
56c6bee
Various pipelines fixes
lakewik Feb 3, 2025
85d5475
feat: add program hash update + pausing
petscheit Feb 3, 2025
d007c2b
Merge branch 'feat/contract_refactor' into feat/daemon
petscheit Feb 3, 2025
067be10
chore: fix contract and add new config
petscheit Feb 3, 2025
10daaca
feat: restore cli functionality
petscheit Feb 3, 2025
edebc6a
chore: refactor contracts, adding ownable and upgradeable + overall c…
petscheit Feb 3, 2025
2061633
chore: update config
petscheit Feb 3, 2025
10d380b
Merge pull request #14 from petscheit/chore/reactivate-cli
lakewik Feb 3, 2025
b73060e
FIxes in retrying and changed batches file names
lakewik Feb 4, 2025
79a9f2a
fix: owner init issue
petscheit Feb 4, 2025
76e1394
Epochs calculation fixes
lakewik Feb 4, 2025
823d956
Fixes in job start and resume conditions
lakewik Feb 4, 2025
cbd1145
Add more status info to endpoint
lakewik Feb 4, 2025
7b2ad61
feat: add dashboard
petscheit Feb 4, 2025
7d3ce0f
Merge branch 'feat/daemon' into dashboard
petscheit Feb 4, 2025
f367c98
fix: merge error
petscheit Feb 4, 2025
c58531d
Small logic fixes
lakewik Feb 4, 2025
051d8cc
Merge pull request #15 from petscheit/dashboard
lakewik Feb 4, 2025
75a729d
Add root RPC path & update DB structure
lakewik Feb 5, 2025
c73f219
Add missing entrypoint file
lakewik Feb 5, 2025
e52aa8e
Fix bug related to sync committee and add more details
lakewik Feb 5, 2025
02340be
Improvements fail handling
lakewik Feb 5, 2025
1afdb19
Fix sync committee id
lakewik Feb 5, 2025
fd66ec2
Simplify db manager & add failures reason
lakewik Feb 5, 2025
85eb4e8
Increase status display count and fix errors on etry
lakewik Feb 5, 2025
ed92d54
Fix error propagation and other minor fixes
lakewik Feb 5, 2025
107ef4b
Retrying from specific point works
lakewik Feb 5, 2025
0690eba
Retryer fix
lakewik Feb 5, 2025
b8a3a3b
Fix SQL
lakewik Feb 5, 2025
2d1401e
Change max skipped slots & fix issue with sync committee
lakewik Feb 5, 2025
101dce3
Hotfix
lakewik Feb 5, 2025
0fce765
Improvements dashboard #1
lakewik Feb 6, 2025
313fa26
Hotfix
lakewik Feb 6, 2025
d013b3e
Hotfix 2
lakewik Feb 6, 2025
5b3a8af
Add txhashes to dashboard
lakewik Feb 6, 2025
0f7c5a6
Display fix
lakewik Feb 6, 2025
a87ba9c
Display fix 2
lakewik Feb 6, 2025
bc8f6d8
Fixes in committee update
lakewik Feb 6, 2025
85f206f
Add sync committee info in dashboard
lakewik Feb 7, 2025
a75dada
Enable resume
lakewik Feb 7, 2025
ed61ff1
Add periodic retry, improve display details
lakewik Feb 7, 2025
56e9571
Fix argument
lakewik Feb 7, 2025
204df11
Temporary change ASCII art
lakewik Feb 7, 2025
60f7463
chore: new title
petscheit Feb 7, 2025
f377210
Merge pull request #16 from petscheit/dashboard-title
lakewik Feb 7, 2025
de3fa52
debug 1
lakewik Feb 8, 2025
dc0624b
debug 2
lakewik Feb 8, 2025
7466b5a
Add timestamps to dashboard
lakewik Feb 8, 2025
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
838 changes: 580 additions & 258 deletions client-rs/Cargo.lock

Large diffs are not rendered by default.

36 changes: 34 additions & 2 deletions client-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ name = "client-rs"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "daemon"
path = "src/daemon.rs"

[[bin]]
name = "cli"
path = "src/main.rs"

[dependencies]
alloy-primitives = "0.8.13"
ethereum_serde_utils = "0.7.0"
Expand All @@ -12,9 +20,9 @@ serde_derive = "1.0.215"
serde_json = "1.0.133"
tokio = { version = "1.0", features = ["full"] }
beacon-state-proof = { git = "https://github.com/petscheit/beacon-state-proof" }
types = { path = "../../lighthouse/consensus/types", package = "types" }
types = { git = "https://github.com/petscheit/lighthouse.git", package = "types" }
sha2 = "0.10.8"
reqwest = { version = "0.12.9", features = ["json", "multipart"] }
reqwest = { version = "0.12.9", features = ["json", "multipart", "stream"] }
rand = "0.8.5"
alloy-rpc-types-beacon = "0.7.2"
itertools = "0.13.0"
Expand All @@ -24,5 +32,29 @@ starknet = "0.12.0"
tree_hash_derive = "0.8.0"
tree_hash = "0.8.0"
dotenv = "0.15"
tokio-postgres = { version = "0.7.12", features = [
"with-uuid-1",
"with-chrono-0_4",
] }
axum = "0.7.9"
thiserror = "2.0.9"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
tokio-stream = "0.1.17"
futures = "0.3"
uuid = { version = "1.11.0", features = [
"v4",
"fast-rng",
"macro-diagnostics",
] }
postgres-types = { version = "0.2.8", features = ["derive"] }
num_cpus = "1.16.0"


starknet-crypto = "0.7.3"
glob = "0.3.2"
num-traits = "0.2.19"
tower = "0.5.2"
tower-http = { version = "0.6.2", features = ["trace", "timeout"] }
chrono = { version = "0.4.39", features = ["serde"] }
tokio-util = "0.7.13"
39 changes: 39 additions & 0 deletions client-rs/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM rust:1.72 as builder

WORKDIR /usr/src/app

COPY Cargo.toml Cargo.lock ./

COPY src ./src

RUN cargo build --release --bin daemon

FROM debian:bullseye

RUN apt-get update && apt-get install -y \
libpq-dev \
postgresql \
&& rm -rf /var/lib/apt/lists/*

RUN mkdir -p /usr/src/app/batches

WORKDIR /usr/src/app

COPY --from=builder /usr/src/app/target/release/daemon /usr/src/app/

RUN mkdir -p /var/lib/postgresql/data && chown -R postgres:postgres /var/lib/postgresql

COPY scripts/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

EXPOSE 5432

USER postgres

RUN /usr/lib/postgresql/14/bin/initdb -D /var/lib/postgresql/data

USER root

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

CMD ["/usr/src/app/daemon"]
43 changes: 43 additions & 0 deletions client-rs/db_structure.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
CREATE TABLE jobs (
job_uuid UUID PRIMARY KEY,
job_status TEXT NOT NULL,
atlantic_proof_generate_batch_id TEXT NULL,
atlantic_proof_wrapper_batch_id TEXT NULL,
slot BIGINT NOT NULL, -- Slot associated with the job
batch_range_begin_epoch BIGINT NULL,
batch_range_end_epoch BIGINT NULL,
type TEXT NOT NULL,
tx_hash TEXT NULL,
failed_at_step TEXT NULL,
retries_count BIGINT NULL,
last_failure_time TIMESTAMP NULL,
updated_at TIMESTAMP DEFAULT NOW (),
created_at TIMESTAMP DEFAULT NOW ()
);

CREATE TABLE epoch_merkle_paths (
epoch_id BIGINT NOT NULL,
path_index BIGINT NOT NULL,
merkle_path TEXT NOT NULL,
PRIMARY KEY (epoch_id, path_index) -- Ensures uniqueness of the combination
);

CREATE TABLE verified_epoch (
epoch_id UUID PRIMARY KEY,
header_root TEXT NOT NULL, -- Header root hash of the Beacon chain header
state_root TEXT NOT NULL, -- State root hash of the Beacon chain state
n_signers INTEGER NOT NULL, -- Number of epoch signers
execution_hash TEXT NOT NULL, -- Execution layer blockhash
execution_height BIGINT NOT NULL -- Execution layer height
);

CREATE TABLE verified_sync_committee (
sync_committee_id UUID PRIMARY KEY, -- Unique identifier for sync committee (slot number/0x2000)
sync_committee_hash TEXT NOT NULL -- Sync committee hash that we are creating inside bankai
);

CREATE TABLE daemon_state (
latest_known_beacon_slot BIGINT NOT NULL,
latest_known_beacon_block BYTEA NOT NULL,
updated_at TIMESTAMP DEFAULT NOW ()
);
31 changes: 31 additions & 0 deletions client-rs/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
services:
postgres:
image: postgres:14
container_name: postgres
environment:
POSTGRESQL_USER: ${POSTGRES_USER:-postgres}
POSTGRESQL_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
POSTGRESQL_DB_NAME: ${POSTGRES_DB:-bankai}
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- ${POSTGRES_PORT:-5432}:${POSTGRES_PORT:-5432}

daemon:
build:
context: .
dockerfile: Dockerfile
container_name: bankai-daemon
depends_on:
- postgres
env_file:
- .env.sepolia
#environment:
# POSTGRESQL_USER
volumes:
- ./batches:/usr/src/app/batches
ports:
- "3000:3000"

volumes:
pgdata:
15 changes: 15 additions & 0 deletions client-rs/scripts/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -e

su postgres -c "/usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/data -l logfile start"

sleep 5

su postgres -c "psql -c \"CREATE USER postgres WITH SUPERUSER PASSWORD 'postgres';\"" || true
su postgres -c "psql -c \"CREATE DATABASE bankai_sepolia;\"" || true

# We need to do migration here, create initial DB structure form DB file

echo "PostgreSQL is running. Starting the daemon..."

exec "$@"
6 changes: 6 additions & 0 deletions client-rs/scripts/wait-for-postgres.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

while ! nc -z localhost 5434; do sleep 1; done
echo "Postgres ready"
sleep 1
exit 0
96 changes: 96 additions & 0 deletions client-rs/src/bankai_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use crate::constants;
use crate::{
contract_init::ContractInitializationData,
epoch_update::EpochUpdate,
state::Error,
sync_committee::SyncCommitteeUpdate,
utils::{
atlantic_client::AtlanticClient, rpc::BeaconRpcClient, starknet_client::StarknetClient,
transactor_client::TransactorClient,
},
BankaiConfig,
};
use dotenv::from_filename;
use std::env;
use tracing::info;

#[derive(Debug)]
pub struct BankaiClient {
pub client: BeaconRpcClient,
pub starknet_client: StarknetClient,
pub config: BankaiConfig,
pub atlantic_client: AtlanticClient,
pub transactor_client: TransactorClient,
}

impl BankaiClient {
pub async fn new() -> Self {
from_filename(".env.sepolia").ok();
let config = BankaiConfig::default();
Self {
client: BeaconRpcClient::new(env::var("BEACON_RPC_URL").unwrap()),
starknet_client: StarknetClient::new(
env::var("STARKNET_RPC_URL").unwrap().as_str(),
env::var("STARKNET_ADDRESS").unwrap().as_str(),
env::var("STARKNET_PRIVATE_KEY").unwrap().as_str(),
)
.await
.unwrap(),
atlantic_client: AtlanticClient::new(
config.atlantic_endpoint.clone(),
env::var("ATLANTIC_API_KEY").unwrap(),
),
transactor_client: TransactorClient::new(
config.transactor_endpoint.clone(),
env::var("TRANSACTOR_API_KEY").unwrap(),
),
config,
}
}

pub async fn get_sync_committee_update(
&self,
mut slot: u64,
) -> Result<SyncCommitteeUpdate, Error> {
let mut attempts = 0;

// Before we start generating the proof, we ensure the slot was not missed
let _header = loop {
match self.client.get_header(slot).await {
Ok(header) => break header,
Err(Error::EmptySlotDetected(_)) => {
attempts += 1;
if attempts >= constants::MAX_SKIPPED_SLOTS_RETRY_ATTEMPTS {
return Err(Error::EmptySlotDetected(slot));
}
slot += 1;
info!(
"Empty slot detected! Attempt {}/{}. Fetching slot: {}",
attempts,
constants::MAX_SKIPPED_SLOTS_RETRY_ATTEMPTS,
slot
);
}
Err(e) => return Err(e), // Propagate other errors immediately
}
};

let proof: SyncCommitteeUpdate = SyncCommitteeUpdate::new(&self.client, slot).await?;

Ok(proof)
}

pub async fn get_epoch_proof(&self, slot: u64) -> Result<EpochUpdate, Error> {
let epoch_proof = EpochUpdate::new(&self.client, slot).await?;
Ok(epoch_proof)
}

pub async fn get_contract_initialization_data(
&self,
slot: u64,
config: &BankaiConfig,
) -> Result<ContractInitializationData, Error> {
let contract_init = ContractInitializationData::new(&self.client, slot, config).await?;
Ok(contract_init)
}
}
24 changes: 20 additions & 4 deletions client-rs/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use crate::constants::{
MAX_CONCURRENT_PIE_GENERATIONS, MAX_CONCURRENT_RPC_DATA_FETCH_JOBS, STARKNET_SEPOLIA,
};
use starknet::core::types::Felt;
use std::sync::Arc;
use tokio::sync::Semaphore;

#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct BankaiConfig {
pub contract_class_hash: Felt,
pub contract_address: Felt,
Expand All @@ -12,17 +17,21 @@ pub struct BankaiConfig {
pub epoch_batch_circuit_path: String,
pub committee_circuit_path: String,
pub atlantic_endpoint: String,
pub transactor_endpoint: String,
pub pie_generation_semaphore: Arc<Semaphore>,
pub epoch_data_fetching_semaphore: Arc<Semaphore>,
pub proof_settlement_chain_id: Felt,
}

impl Default for BankaiConfig {
fn default() -> Self {
Self {
contract_class_hash: Felt::from_hex(
"0x02b5b08b233132464c437cf15509338e65ae7acc20419a37a9449a1d8e927f46",
"0x00034b6d1cd9858aeabcee33ef5ec5cd04be155d79ca2bbf9036700cb6c7c287",
)
.unwrap(),
contract_address: Felt::from_hex(
"0x440b622a97fab3f31a35e7e710a8a508f6693d61d74171b5c2304f5e37ccde8",
"0x1b7b70023bc2429d4453ce75d75f3e8b01b0730ca83068a82b4d17aa88a25e3",
)
.unwrap(),
committee_update_program_hash: Felt::from_hex(
Expand All @@ -34,7 +43,7 @@ impl Default for BankaiConfig {
)
.unwrap(),
epoch_batch_program_hash: Felt::from_hex(
"0x19bc492f1036c889939a5174e8f77ffbe89676c8d5f1adef0a825d2a6cc2a2f",
"0x5f4dad2d8549e91c25694875eb02fc2910eeead0e1a13d3061464a3eaa4bd8d",
)
.unwrap(),
contract_path: "../contract/target/release/bankai_BankaiContract.contract_class.json"
Expand All @@ -43,6 +52,13 @@ impl Default for BankaiConfig {
epoch_batch_circuit_path: "../cairo/build/epoch_batch.json".to_string(),
committee_circuit_path: "../cairo/build/committee_update.json".to_string(),
atlantic_endpoint: "https://atlantic.api.herodotus.cloud".to_string(),
transactor_endpoint: "https://staging.api.herodotus.cloud".to_string(),
// Set how many concurrent pie generation (trace generation) tasks are allowed
pie_generation_semaphore: Arc::new(Semaphore::new(MAX_CONCURRENT_PIE_GENERATIONS)), // 3 at once
epoch_data_fetching_semaphore: Arc::new(Semaphore::new(
MAX_CONCURRENT_RPC_DATA_FETCH_JOBS,
)), // 2 at once
proof_settlement_chain_id: Felt::from_hex(STARKNET_SEPOLIA).unwrap(),
}
}
}
17 changes: 17 additions & 0 deletions client-rs/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pub const SLOTS_PER_EPOCH: u64 = 32; // For mainnet
pub const SLOTS_PER_SYNC_COMMITTEE: u64 = 8192; // For mainnet
pub const TARGET_BATCH_SIZE: u64 = 32; // Defines how many epochs in one batch
pub const EPOCHS_PER_SYNC_COMMITTEE: u64 = 256; // For mainnet
pub const MAX_CONCURRENT_JOBS_IN_PROGRESS: u64 = 16; // Define the limit of how many jobs can be in state "in progress" concurrently
pub const MAX_CONCURRENT_PIE_GENERATIONS: usize = 1; // Define how many concurrent trace (pie file) generation jobs are allowed to not exhaust resources
pub const MAX_CONCURRENT_RPC_DATA_FETCH_JOBS: usize = 1; // Define how many data fetching jobs can be performed concurrently to not overload RPC
pub const STARKNET_SEPOLIA: &str = "0x534e5f5345504f4c4941";
pub const STARKNET_MAINNET: &str = "0x534e5f4d41494e";
pub const USE_TRANSACTOR: bool = false;
pub const MAX_JOB_RETRIES_COUNT: u64 = 10;
pub const BEACON_CHAIN_LISTENER_ENABLED: bool = true;
pub const JOBS_RETRY_ENABLED: bool = true;
pub const JOBS_RESUME_ENABLED: bool = true;
pub const RETRY_DELAY_MS: u64 = 300_0000;
pub const MAX_SKIPPED_SLOTS_RETRY_ATTEMPTS: u64 = 5; // How many skipped slots in row can be on Beacon Chain before we throw error
pub const JOBS_RETRY_CHECK_INTERVAL: u64 = 600; // In seconds
Loading