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

[babylon] POC implements rooch finality #2992

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
309 changes: 284 additions & 25 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 9 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ members = [
"crates/rooch-cosmwasm-vm",
"crates/testsuite",
"crates/rooch-ord",
"crates/rooch-finality",
"frameworks/bitcoin-move",
"frameworks/framework-builder",
"frameworks/framework-release",
Expand Down Expand Up @@ -144,6 +145,7 @@ rooch-event = { path = "crates/rooch-event" }
rooch-ord = { path = "crates/rooch-ord" }
rooch-cosmwasm-vm = { path = "crates/rooch-cosmwasm-vm" }
rooch-oracle = { path = "crates/rooch-oracle" }
rooch-finality = { path = "crates/rooch-finality" }

# frameworks
framework-types = { path = "frameworks/framework-types" }
Expand Down Expand Up @@ -201,8 +203,7 @@ parking_lot = "0.12.3"
pathdiff = "0.2.1"
petgraph = "0.6.5"
primitive-types = { version = "0.12.1", features = ["serde", "arbitrary"] }
prost = "0.12"
prost-types = "0.11"
prost = "0.13.3"
proptest = "1.5.0"
proptest-derive = "0.3.0"
rayon = "1.5.2"
Expand Down Expand Up @@ -231,7 +232,6 @@ tokio = { version = "1.41.1", features = ["full"] }
tokio-util = "0.7.12"
tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] }
tokio-stream = "0.1.16"
tonic = { version = "0.8", features = ["gzip"] }
tracing = "0.1.41"
tracing-appender = "0.2.2"
tracing-subscriber = { version = "0.3.19" }
Expand Down Expand Up @@ -345,6 +345,7 @@ sled = { version = "0.34.7" }
scopeguard = "1.1"
uuid = { version = "1.11.0", features = ["v4", "fast-rng"] }
protobuf = { version = "2.28", features = ["with-bytes"] }
#protobuf = { version = "3.7.1", features = ["with-bytes"] }
redb = { version = "2.1.1" }
rocksdb = { git = "https://github.com/rooch-network/rust-rocksdb.git", rev = "41d102327ba3cf9a2335d1192e8312c92bc3d6f9", features = ["lz4", "mt_static"] }
lz4 = { version = "1.28.0" }
Expand All @@ -358,6 +359,11 @@ vergen-pretty = "0.3.6"
crossbeam-channel = "0.5.13"
inferno = "0.11.21"
handlebars = "4.2.2"
tonic = { version = "0.12.3", features = ["codegen", "prost", "gzip"] }
tonic-build = { version = "0.12.3", features = ["prost"] }
protox = "0.7.1"
prost-build = "0.13.3"
prost-types = "0.13.3"

# Note: the BEGIN and END comments below are required for external tooling. Do not remove.
# BEGIN MOVE DEPENDENCIES
Expand Down
6 changes: 6 additions & 0 deletions crates/rooch-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use rooch_store::{
RoochStore, META_SEQUENCER_INFO_COLUMN_FAMILY_NAME, STATE_CHANGE_SET_COLUMN_FAMILY_NAME,
TRANSACTION_COLUMN_FAMILY_NAME, TX_SEQUENCE_INFO_MAPPING_COLUMN_FAMILY_NAME,
};
use rooch_types::finality_block::L2BlockRef;
use rooch_types::indexer::state::{
collect_revert_object_change_ids, handle_revert_object_change, IndexerObjectStateChangeSet,
IndexerObjectStatesIndexGenerator,
Expand Down Expand Up @@ -409,4 +410,9 @@ impl RoochDB {
// TODO repair the changeset sync and indexer store
Ok((issues, fixed))
}

//TODO implements this after proposer generate blocks
pub fn l2_block_ref_by_number(&self, _block_number: u64) -> Result<L2BlockRef> {
Ok(L2BlockRef::default())
}
}
47 changes: 47 additions & 0 deletions crates/rooch-finality/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[package]
name = "rooch-finality"

# Workspace inherited keys
version = { workspace = true }
authors = { workspace = true }
edition = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
publish = { workspace = true }
repository = { workspace = true }
rust-version = { workspace = true }

[dependencies]
anyhow = { workspace = true }
async-trait = { workspace = true }
coerce = { workspace = true }
serde = { workspace = true }
tokio = { features = ["full"], workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
prometheus = { workspace = true }
function_name = { workspace = true }
tonic = { workspace = true, features = ["codegen", "prost"] }
prost = { workspace = true }
#prost-types = { workspace = true }
#protobuf = { workspace = true }

moveos-eventbus = { workspace = true }
metrics = { workspace = true }

rooch-types = { workspace = true }
rooch-db = { workspace = true }
rooch-event = { workspace = true }

[build-dependencies]
prost-build = { workspace = true }
prost-types = { workspace = true }
protox = "0.7.1"
tonic-build = { workspace = true, features = [ "prost" ]}

#[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
#tonic = { workspace = true, features = [ "transport" ] }
#tonic-build = { workspace = true, features = [ "transport" ] }

#[features]
#tonic = ["dep:tonic", "dep:tonic-build"]
57 changes: 57 additions & 0 deletions crates/rooch-finality/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

//! A build script generating rust types from protobuf definitions.

use prost_types::FileDescriptorSet;

static OUT_DIR: &str = "src/proto";
const PROTO_FILES: &[&str] = &["src/proto/finalitygadget.proto"];

const INCLUDES: &[&str] = &["src/proto"];

fn main() {
let fds = protox_compile();
// #[cfg(not(feature = "tonic"))]
// prost_build(fds);
// #[cfg(feature = "tonic")]
tonic_build(fds)
}

fn protox_compile() -> FileDescriptorSet {
protox::compile(PROTO_FILES, INCLUDES).expect("protox failed to build")
}

#[allow(dead_code)]
// #[cfg(not(feature = "tonic"))]
fn prost_build(fds: FileDescriptorSet) {
let mut config = prost_build::Config::new();

config
// .include_file("mod.rs")
.enable_type_names()
.out_dir(OUT_DIR)
// .bytes([".tendermint_celestia_mods.abci"])
.compile_fds(fds)
.expect("prost failed");
}

// #[cfg(feature = "tonic")]
fn tonic_build(fds: FileDescriptorSet) {
let mut prost_config = prost_build::Config::new();
prost_config.enable_type_names();

let tonic_config = tonic_build::configure()
// .include_file("mod.rs")
.build_client(true)
.build_server(false)
.out_dir(OUT_DIR)
// .client_mod_attribute(".", "#[cfg(not(target_arch=\"wasm32\"))]")
// .use_arc_self(true)
.compile_well_known_types(true)
.skip_protoc_run();

tonic_config
.compile_fds_with_config(prost_config, fds)
.expect("should be able to compile protobuf using tonic");
}
29 changes: 29 additions & 0 deletions crates/rooch-finality/build2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::error::Error;
use std::fs;

static OUT_DIR: &str = "src/proto";

fn main() -> Result<(), Box<dyn Error>> {
let protos = ["src/proto/finalitygadget.proto"];

fs::create_dir_all(OUT_DIR).unwrap();
tonic_build::configure()
// .include_file("mod.rs")
.build_server(false)
.build_client(true)
.out_dir(OUT_DIR)
// .file_descriptor_set_path("finalitygadget.rs") // Optional: save file descriptor
// .file_descriptor_set_path("src/proto/finalitygadget.rs") // Optional: save file descriptor
.compile_protos(&protos, &["src/proto"])?;
// .compile_protos(&protos, &[""])?;

rerun(&protos);

Ok(())
}

fn rerun(proto_files: &[&str]) {
for proto_file in proto_files {
println!("cargo:rerun-if-changed={}", proto_file);
}
}
146 changes: 146 additions & 0 deletions crates/rooch-finality/src/actor/finality.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use std::sync::Arc;
use std::time::SystemTime;

use crate::finality::finalizer::{Config, Finalizer, FinalizerL1Mock};
use crate::messages::FinalityMessage;
use crate::metrics::FinalityMetrics;
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use coerce::actor::{context::ActorContext, message::Handler, Actor, LocalActorRef};
use function_name::named;
use moveos_eventbus::bus::EventData;
use prometheus::Registry;
use rooch_db::RoochDB;
use rooch_event::actor::{EventActor, EventActorSubscribeMessage};
use rooch_event::event::ServiceStatusEvent;
use rooch_types::finality_block::Block;
use rooch_types::service_status::ServiceStatus;
use tracing::info;

pub struct FinalityActor {
// rooch_store: RoochStore,
finalizer: Finalizer,
rooch_db: RoochDB,
service_status: ServiceStatus,
metrics: Arc<FinalityMetrics>,
event_actor: Option<LocalActorRef<EventActor>>,
}

impl FinalityActor {
pub async fn new(
rooch_db: RoochDB,
service_status: ServiceStatus,
registry: &Registry,
event_actor: Option<LocalActorRef<EventActor>>,
) -> Result<Self, anyhow::Error> {
let babylon_finality_gadget_rpc_str = "";
let config = Config {
babylon_finality_gadget_rpc: babylon_finality_gadget_rpc_str.to_string(),
};
//TODO implements finalize L1 service
let finalizer_L1_Mock = Arc::new(FinalizerL1Mock::default());
let finalizer = Finalizer::new(&config, finalizer_L1_Mock, rooch_db.clone())
.await
.map_err(|e| anyhow!(format!("New finality actor error: {:?}", e)))?;

Ok(Self {
finalizer,
rooch_db,
service_status,
metrics: Arc::new(FinalityMetrics::new(registry)),
event_actor,
})
}

pub async fn subscribe_event(
&self,
event_actor_ref: LocalActorRef<EventActor>,
executor_actor_ref: LocalActorRef<FinalityActor>,
) {
let service_status_event = ServiceStatusEvent::default();
let actor_subscribe_message = EventActorSubscribeMessage::new(
service_status_event,
"finality".to_string(),
Box::new(executor_actor_ref),
);
let _ = event_actor_ref.send(actor_subscribe_message).await;
}

#[named]
pub async fn finality(&mut self, block: Block) -> Result<()> {
let fn_name = function_name!();
let _timer = self
.metrics
.finality_latency_seconds
.with_label_values(&[fn_name])
.start_timer();

// match self.service_status {
// ServiceStatus::ReadOnlyMode => {
// return Err(anyhow::anyhow!("The service is in read-only mode"));
// }
// ServiceStatus::DateImportMode => {
// if !tx_data.is_l1_block() && !tx_data.is_l1_tx() {
// return Err(anyhow::anyhow!(
// "The service is in date import mode, only allow l1 block and l1 tx"
// ));
// }
// }
// ServiceStatus::Maintenance => {
// // Only the sequencer can send transactions in maintenance mode
// if let Some(sender) = tx_data.sender() {
// if sender != self.sequencer_key.public().rooch_address()? {
// return Err(anyhow::anyhow!("The service is in maintenance mode"));
// }
// } else {
// return Err(anyhow::anyhow!("The service is in maintenance mode"));
// }
// }
// _ => {}
// }

let now = SystemTime::now();
let _tx_timestamp = now.duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as u64;

self.finalizer.try_finalize().await?;
info!(
"rooch finality finalize block_hash: {} block_number: {:?}",
block.block_hash, block.block_height
);

Ok(())
}
}

#[async_trait]
impl Actor for FinalityActor {
async fn started(&mut self, ctx: &mut ActorContext) {
let local_actor_ref: LocalActorRef<Self> = ctx.actor_ref();
if let Some(event_actor) = self.event_actor.clone() {
let _ = self.subscribe_event(event_actor, local_actor_ref).await;
}
}
}

#[async_trait]
impl Handler<FinalityMessage> for FinalityActor {
async fn handle(&mut self, msg: FinalityMessage, _ctx: &mut ActorContext) -> Result<()> {
self.finality(msg.block).await
}
}

#[async_trait]
impl Handler<EventData> for FinalityActor {
async fn handle(&mut self, msg: EventData, _ctx: &mut ActorContext) -> Result<()> {
if let Ok(service_status_event) = msg.data.downcast::<ServiceStatusEvent>() {
let service_status = service_status_event.status;
tracing::warn!("FinalityActor set self status to {:?}", service_status);
self.service_status = service_status;
}

Ok(())
}
}
4 changes: 4 additions & 0 deletions crates/rooch-finality/src/actor/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

pub mod finality;
31 changes: 31 additions & 0 deletions crates/rooch-finality/src/finality/expected_clients.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use rooch_types::finality_block::Block;
// This should be updated to match the gRPC interface of the Babylon finality gadget client
// https://github.com/babylonlabs-io/finality-gadget

/// Trait defining the interface for the Babylon finality gadget client
pub trait FinalityGadgetClient {
/// Checks if the given L2 block is finalized by the Babylon finality gadget
fn query_is_block_babylon_finalized(&self, block: &Block) -> Result<bool>;

/// Searches for a row of consecutive finalized blocks in the block range
fn query_block_range_babylon_finalized(&self, blocks: &[Block]) -> Result<Option<u64>>;

/// Returns the timestamp when the BTC staking is activated
fn query_btc_staking_activated_timestamp(&self) -> Result<u64>;

/// Returns the btc finalization status of a block at given height by querying the local db
fn query_is_block_finalized_by_height(&self, height: u64) -> Result<bool>;

/// Returns the btc finalization status of a block at given hash by querying the local db
fn query_is_block_finalized_by_hash(&self, hash: String) -> Result<bool>;

/// Returns the latest finalized block by querying the local db
fn query_latest_finalized_block(&self) -> Result<Block>;

/// Closes the client
fn close(&self) -> Result<()>;
}
Loading
Loading