diff --git a/Cargo.lock b/Cargo.lock index 011d9b865a..1b60aec2e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -780,6 +780,28 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2 1.0.92", + "quote 1.0.37", + "syn 2.0.87", +] + [[package]] name = "async-task" version = "4.7.1" @@ -872,7 +894,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "hyper 1.3.1", + "hyper 1.5.1", "hyper-util", "itoa", "matchit", @@ -928,7 +950,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "hyper 1.3.1", + "hyper 1.5.1", "hyper-util", "pin-project-lite", "rustls 0.21.12", @@ -1760,9 +1782,9 @@ version = "0.1.0" source = "git+https://github.com/eigerco/celestia-node-rs.git?rev=129272e8d926b4c7badf27a26dea915323dd6489#129272e8d926b4c7badf27a26dea915323dd6489" dependencies = [ "anyhow 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "prost", - "prost-build", - "prost-types", + "prost 0.12.6", + "prost-build 0.12.6", + "prost-types 0.12.6", "serde 1.0.215", "tendermint-proto", ] @@ -5405,9 +5427,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.3.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", @@ -5448,7 +5470,7 @@ checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.3.1", + "hyper 1.5.1", "hyper-util", "log", "rustls 0.23.10", @@ -5459,6 +5481,19 @@ dependencies = [ "webpki-roots 0.26.1", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.5.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -5480,7 +5515,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.3.1", + "hyper 1.5.1", "hyper-util", "native-tls", "tokio", @@ -5490,20 +5525,19 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.0", - "hyper 1.3.1", + "hyper 1.5.1", "pin-project-lite", "socket2", "tokio", - "tower 0.4.13", "tower-service", "tracing", ] @@ -6106,7 +6140,7 @@ dependencies = [ "async-trait", "base64 0.22.1", "http-body 1.0.0", - "hyper 1.3.1", + "hyper 1.5.1", "hyper-rustls 0.27.2", "hyper-util", "jsonrpsee-core 0.23.2", @@ -6159,7 +6193,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "hyper 1.3.1", + "hyper 1.5.1", "hyper-util", "jsonrpsee-core 0.23.2", "jsonrpsee-types 0.23.2", @@ -6589,6 +6623,39 @@ dependencies = [ "value-bag", ] +[[package]] +name = "logos" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c6b6e02facda28ca5fb8dbe4b152496ba3b1bd5a4b40bb2b1b2d8ad74e0f39b" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32eb6b5f26efacd015b000bfc562186472cd9b34bdba3f6b264e2a052676d10" +dependencies = [ + "beef", + "fnv", + "lazy_static 1.5.0", + "proc-macro2 1.0.92", + "quote 1.0.37", + "regex-syntax 0.8.5", + "syn 2.0.87", +] + +[[package]] +name = "logos-derive" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5d0c5463c911ef55624739fc353238b4e310f0144be1f875dc42fec6bfd5ec" +dependencies = [ + "logos-codegen", +] + [[package]] name = "lru" version = "0.11.1" @@ -6711,6 +6778,29 @@ dependencies = [ "uuid 1.11.0", ] +[[package]] +name = "miette" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317f146e2eb7021892722af37cf1b971f0a70c8406f487e24952667616192c64" +dependencies = [ + "cfg-if", + "miette-derive", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c9b935fbe1d6cbd1dac857b54a688145e2d93f48db36010514d0f612d0ad67" +dependencies = [ + "proc-macro2 1.0.92", + "quote 1.0.37", + "syn 2.0.87", +] + [[package]] name = "migrations_internals" version = "2.2.0" @@ -9226,7 +9316,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.12.6", +] + +[[package]] +name = "prost" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" +dependencies = [ + "bytes", + "prost-derive 0.13.3", ] [[package]] @@ -9243,8 +9343,29 @@ dependencies = [ "once_cell", "petgraph 0.6.5", "prettyplease", - "prost", - "prost-types", + "prost 0.12.6", + "prost-types 0.12.6", + "regex", + "syn 2.0.87", + "tempfile", +] + +[[package]] +name = "prost-build" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" +dependencies = [ + "bytes", + "heck 0.5.0", + "itertools 0.13.0", + "log", + "multimap", + "once_cell", + "petgraph 0.6.5", + "prettyplease", + "prost 0.13.3", + "prost-types 0.13.3", "regex", "syn 2.0.87", "tempfile", @@ -9263,13 +9384,48 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "prost-derive" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" +dependencies = [ + "anyhow 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.13.0", + "proc-macro2 1.0.92", + "quote 1.0.37", + "syn 2.0.87", +] + +[[package]] +name = "prost-reflect" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7535b02f0e5efe3e1dbfcb428be152226ed0c66cad9541f2274c8ba8d4cd40" +dependencies = [ + "logos", + "miette", + "once_cell", + "prost 0.13.3", + "prost-types 0.13.3", +] + [[package]] name = "prost-types" version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost", + "prost 0.12.6", +] + +[[package]] +name = "prost-types" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" +dependencies = [ + "prost 0.13.3", ] [[package]] @@ -9300,6 +9456,33 @@ dependencies = [ "protobuf-codegen", ] +[[package]] +name = "protox" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873f359bdecdfe6e353752f97cb9ee69368df55b16363ed2216da85e03232a58" +dependencies = [ + "bytes", + "miette", + "prost 0.13.3", + "prost-reflect", + "prost-types 0.13.3", + "protox-parse", + "thiserror", +] + +[[package]] +name = "protox-parse" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3a462d115462c080ae000c29a47f0b3985737e5d3a995fcdbcaa5c782068dde" +dependencies = [ + "logos", + "miette", + "prost-types 0.13.3", + "thiserror", +] + [[package]] name = "ptr_meta" version = "0.1.4" @@ -9850,7 +10033,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "hyper 1.3.1", + "hyper 1.5.1", "hyper-rustls 0.27.2", "hyper-tls 0.6.0", "hyper-util", @@ -10339,6 +10522,32 @@ dependencies = [ "tracing", ] +[[package]] +name = "rooch-finality" +version = "0.8.2" +dependencies = [ + "anyhow 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "async-trait", + "coerce", + "function_name", + "metrics", + "moveos-eventbus", + "prometheus", + "prost 0.13.3", + "prost-build 0.13.3", + "prost-types 0.13.3", + "protox", + "rooch-db", + "rooch-event", + "rooch-types", + "serde 1.0.215", + "thiserror", + "tokio", + "tonic", + "tonic-build", + "tracing", +] + [[package]] name = "rooch-framework" version = "0.8.2" @@ -10662,6 +10871,7 @@ dependencies = [ "rooch-config", "rooch-store", "rooch-types", + "serde 1.0.215", "tracing", ] @@ -10751,7 +10961,7 @@ dependencies = [ "dashmap 6.0.1", "hex", "http 1.1.0", - "hyper 1.3.1", + "hyper 1.5.1", "jsonrpsee 0.23.2", "metrics", "move-core-types", @@ -12553,8 +12763,8 @@ dependencies = [ "futures", "num-traits 0.2.19", "once_cell", - "prost", - "prost-types", + "prost 0.12.6", + "prost-types 0.12.6", "serde 1.0.215", "serde_bytes", "serde_json", @@ -12577,8 +12787,8 @@ dependencies = [ "flex-error", "num-derive", "num-traits 0.2.19", - "prost", - "prost-types", + "prost 0.12.6", + "prost-types 0.12.6", "serde 1.0.215", "serde_bytes", "subtle-encoding", @@ -13074,6 +13284,51 @@ dependencies = [ "winnow 0.6.18", ] +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "flate2", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.5.1", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.3", + "socket2", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" +dependencies = [ + "prettyplease", + "proc-macro2 1.0.92", + "prost-build 0.13.3", + "prost-types 0.13.3", + "quote 1.0.37", + "syn 2.0.87", +] + [[package]] name = "tower" version = "0.4.13" @@ -13082,9 +13337,13 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", + "indexmap 1.9.3", "pin-project", "pin-project-lite", + "rand 0.8.5", + "slab", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", diff --git a/Cargo.toml b/Cargo.toml index ab0eb0ed43..34543073a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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", @@ -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" } @@ -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" @@ -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" } @@ -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" } @@ -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 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..cbeb6585a7 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +# BUILDDIR ?= $(CURDIR)/build +BUILD_FLAGS := --tags '$(BUILD_TAGS)' --ldflags '$(LDFLAGS)' +BUILD_ARGS := $(BUILD_ARGS) -o $(BUILDDIR) + +DOCKER ?= $(shell which docker) +GIT_ROOT := $(shell git rev-parse --show-toplevel) + +test: + cargo test + +# $(BUILDDIR)/: +# mkdir -p $(BUILDDIR)/ + +build: + cargo build + +build-docker: + $(DOCKER) build --tag baichuan3/rooch -f ./docker/DockerfilePoc \ + $(shell git rev-parse --show-toplevel) + +.PHONY: build build-docker diff --git a/crates/rooch-config/src/settings.rs b/crates/rooch-config/src/settings.rs index 247ed5881f..dd1330128e 100644 --- a/crates/rooch-config/src/settings.rs +++ b/crates/rooch-config/src/settings.rs @@ -4,6 +4,7 @@ // 15 minutes > Bitcoin block interval, Rooch block must be made in this interval // at least has Bitcoin block transaction // large interval give enough time window to submit block to DA -pub const ROOCH_BATCH_INTERVAL: u64 = 1000 * 60 * 15; +// pub const ROOCH_BATCH_INTERVAL: u64 = 1000 * 60 * 15; +pub const ROOCH_BATCH_INTERVAL: u64 = 1000*60*1; // 5 seconds, check avail block to propose interval pub const PROPOSER_CHECK_INTERVAL: u64 = 5; diff --git a/crates/rooch-db/src/lib.rs b/crates/rooch-db/src/lib.rs index 5e354f91d0..a66b2628ad 100644 --- a/crates/rooch-db/src/lib.rs +++ b/crates/rooch-db/src/lib.rs @@ -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, @@ -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 { + Ok(L2BlockRef::default()) + } } diff --git a/crates/rooch-finality/Cargo.toml b/crates/rooch-finality/Cargo.toml new file mode 100644 index 0000000000..dbf5a2189f --- /dev/null +++ b/crates/rooch-finality/Cargo.toml @@ -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"] \ No newline at end of file diff --git a/crates/rooch-finality/build.rs b/crates/rooch-finality/build.rs new file mode 100644 index 0000000000..5a0cadc422 --- /dev/null +++ b/crates/rooch-finality/build.rs @@ -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"); +} diff --git a/crates/rooch-finality/build2.rs b/crates/rooch-finality/build2.rs new file mode 100644 index 0000000000..0e8d5e66ab --- /dev/null +++ b/crates/rooch-finality/build2.rs @@ -0,0 +1,29 @@ +use std::error::Error; +use std::fs; + +static OUT_DIR: &str = "src/proto"; + +fn main() -> Result<(), Box> { + 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); + } +} diff --git a/crates/rooch-finality/src/actor/finality.rs b/crates/rooch-finality/src/actor/finality.rs new file mode 100644 index 0000000000..f90f177a35 --- /dev/null +++ b/crates/rooch-finality/src/actor/finality.rs @@ -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, + event_actor: Option>, +} + +impl FinalityActor { + pub async fn new( + rooch_db: RoochDB, + service_status: ServiceStatus, + registry: &Registry, + event_actor: Option>, + ) -> Result { + 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, + executor_actor_ref: LocalActorRef, + ) { + 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 = 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 for FinalityActor { + async fn handle(&mut self, msg: FinalityMessage, _ctx: &mut ActorContext) -> Result<()> { + self.finality(msg.block).await + } +} + +#[async_trait] +impl Handler for FinalityActor { + async fn handle(&mut self, msg: EventData, _ctx: &mut ActorContext) -> Result<()> { + if let Ok(service_status_event) = msg.data.downcast::() { + let service_status = service_status_event.status; + tracing::warn!("FinalityActor set self status to {:?}", service_status); + self.service_status = service_status; + } + + Ok(()) + } +} diff --git a/crates/rooch-finality/src/actor/mod.rs b/crates/rooch-finality/src/actor/mod.rs new file mode 100644 index 0000000000..1b3f20e19a --- /dev/null +++ b/crates/rooch-finality/src/actor/mod.rs @@ -0,0 +1,4 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +pub mod finality; diff --git a/crates/rooch-finality/src/finality/expected_clients.rs b/crates/rooch-finality/src/finality/expected_clients.rs new file mode 100644 index 0000000000..0ad2d2b0fe --- /dev/null +++ b/crates/rooch-finality/src/finality/expected_clients.rs @@ -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; + + /// Searches for a row of consecutive finalized blocks in the block range + fn query_block_range_babylon_finalized(&self, blocks: &[Block]) -> Result>; + + /// Returns the timestamp when the BTC staking is activated + fn query_btc_staking_activated_timestamp(&self) -> Result; + + /// 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; + + /// 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; + + /// Returns the latest finalized block by querying the local db + fn query_latest_finalized_block(&self) -> Result; + + /// Closes the client + fn close(&self) -> Result<()>; +} diff --git a/crates/rooch-finality/src/finality/finalizer.rs b/crates/rooch-finality/src/finality/finalizer.rs new file mode 100644 index 0000000000..a05ed6b210 --- /dev/null +++ b/crates/rooch-finality/src/finality/finalizer.rs @@ -0,0 +1,514 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::rpc_client::FinalityGadgetGrpcClient; +use anyhow::{anyhow, Result}; +use async_trait::async_trait; +use rooch_db::RoochDB; +use rooch_types::finality_block::{Block, BlockID, L1BlockRef, L2BlockRef}; +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tracing::{debug, error}; + +// defaultFinalityLookback defines the amount of L1<>L2 relations to track for finalization purposes, one per L1 block. +// +// When L1 finalizes blocks, it finalizes finalityLookback blocks behind the L1 head. +// Non-finality may take longer, but when it does finalize again, it is within this range of the L1 head. +// Thus we only need to retain the L1<>L2 derivation relation data of this many L1 blocks. +// +// In the event of older finalization signals, misconfiguration, or insufficient L1<>L2 derivation relation data, +// then we may miss the opportunity to finalize more L2 blocks. +// This does not cause any divergence, it just causes lagging finalization status. +// +// The beacon chain on mainnet has 32 slots per epoch, +// and new finalization events happen at most 4 epochs behind the head. +// And then we add 1 to make pruning easier by leaving room for a new item without pruning the 32*4. +const DEFAULT_FINALITY_LOOKBACK: u64 = 4 * 32 + 1; + +// finalityDelay is the number of L1 blocks to traverse before trying to finalize L2 blocks again. +// We do not want to do this too often, since it requires fetching a L1 block by number, so no cache data. +const FINALITY_DELAY: u64 = 64; + +// // Types and Structs +// #[derive(Clone, Debug, Default, PartialEq)] +// pub struct BlockID { +// pub number: u64, +// pub hash: String, +// } +// +// #[derive(Clone, Debug, Default, PartialEq)] +// pub struct L1BlockRef { +// pub hash: String, +// pub number: u64, +// pub time: u64, +// pub parent_hash: String, +// } +// +// #[derive(Clone, Debug, Default, PartialEq)] +// pub struct L2BlockRef { +// pub hash: H256, +// pub number: u64, +// pub time: u64, +// pub parent_hash: H256, +// } + +#[derive(Clone, Debug)] +pub struct FinalityData { + // The last L2 block that was fully derived and inserted into the L2 engine while processing this L1 block. + l2_block: L2BlockRef, + // The L1 block this stage was at when inserting the L2 block. + // When this L1 block is finalized, the L2 chain up to this block can be fully reproduced from finalized L1 data. + l1_block: BlockID, +} + +#[derive(Clone, Debug)] +pub struct Config { + pub babylon_finality_gadget_rpc: String, +} + +// Events +#[derive(Debug)] +pub enum Event { + FinalizeL1(FinalizeL1Event), + SafeDerived(SafeDerivedEvent), + DeriverIdle(DeriverIdleEvent), + Reset(ResetEvent), + TryFinalize, + ForkchoiceUpdate(ForkchoiceUpdateEvent), + CriticalError(CriticalErrorEvent), +} + +#[derive(Debug)] +pub struct FinalizeL1Event { + pub finalized_l1: L1BlockRef, +} + +#[derive(Debug)] +pub struct SafeDerivedEvent { + pub safe: L2BlockRef, + pub derived_from: L1BlockRef, +} + +#[derive(Debug)] +pub struct DeriverIdleEvent { + pub origin: L1BlockRef, +} + +#[derive(Debug)] +pub struct ResetEvent { + pub err: String, +} + +#[derive(Debug)] +pub struct ForkchoiceUpdateEvent { + pub finalized_l2_head: L2BlockRef, +} + +#[derive(Debug)] +pub struct CriticalErrorEvent { + pub err: String, +} + +// Traits +#[async_trait] +pub trait FinalizerEngine: Send + Sync { + fn finalized(&self) -> L2BlockRef; + fn set_finalized_head(&self, head: L2BlockRef); +} + +#[async_trait] +pub trait FinalizerL1Interface: Send + Sync { + // async fn l1_block_ref_by_number(&self, number: u64) -> Result>; + async fn l1_block_ref_by_number(&self, number: u64) -> Result; +} +#[async_trait] +pub trait EventEmitter: Send + Sync { + async fn emit(&self, event: Event); +} + +// Main Finalizer Implementation +pub struct Finalizer { + ctx: Arc>, + emitter: Arc, + finalized_l1: Arc>, + last_finalized_l2: Arc>, + tried_finalize_at: Arc>, + finality_data: Arc>>, + finality_lookback: u64, + l1_fetcher: Arc, + l2_fetcher: RoochDB, + babylon_finality_client: FinalityGadgetGrpcClient, +} + +impl Finalizer { + fn calc_finality_lookback(_cfg: &Config) -> u64 { + DEFAULT_FINALITY_LOOKBACK + } + + pub async fn new( + cfg: &Config, + l1_fetcher: Arc, + l2_fetcher: RoochDB, + ) -> Result { + let lookback = Self::calc_finality_lookback(cfg); + + debug!( + "creating Babylon Finality client, rpc_addr {:?}", + cfg.babylon_finality_gadget_rpc + ); + + let babylon_finality_gadget_client = + FinalityGadgetGrpcClient::new(cfg.babylon_finality_gadget_rpc.clone()) + .await + .map_err(|e| anyhow!(format!("New finalizer error: {:?}", e)))?; + + Ok(Finalizer { + ctx: Arc::new(tokio::sync::Mutex::new(())), + emitter: Arc::new(NoopEmitter::default()), + finalized_l1: Arc::new(Mutex::new(L1BlockRef::default())), + last_finalized_l2: Arc::new(Mutex::new(L2BlockRef::default())), + tried_finalize_at: Arc::new(Mutex::new(0)), + finality_data: Arc::new(Mutex::new(Vec::with_capacity(lookback as usize))), + finality_lookback: lookback, + l1_fetcher, + l2_fetcher, + babylon_finality_client: babylon_finality_gadget_client, + }) + } + + pub fn attach_emitter(&mut self, emitter: Arc) { + self.emitter = emitter; + } + + pub fn finalized_l1(&self) -> L1BlockRef { + self.finalized_l1.lock().unwrap().clone() + } + + pub async fn on_event(&mut self, event: Event) -> Result { + match event { + Event::FinalizeL1(ev) => { + self.on_l1_finalized(ev.finalized_l1).await; + Ok(true) + } + Event::SafeDerived(ev) => { + self.on_derived_safe_block(ev.safe, ev.derived_from).await; + Ok(true) + } + Event::DeriverIdle(ev) => { + self.on_derivation_idle(ev.origin).await; + Ok(true) + } + Event::Reset(_) => { + self.on_reset().await; + Ok(true) + } + Event::TryFinalize => { + self.try_finalize().await?; + Ok(true) + } + Event::ForkchoiceUpdate(ev) => { + *self.last_finalized_l2.lock().unwrap() = ev.finalized_l2_head; + Ok(true) + } + _ => Ok(false), + } + } + + // onL1Finalized applies a L1 finality signal + async fn on_l1_finalized(&self, l1_origin: L1BlockRef) { + let mut finalized_l1 = self.finalized_l1.lock().unwrap(); + let prev_finalized_l1 = finalized_l1.clone(); + + if l1_origin.number < finalized_l1.number { + error!("ignoring old L1 finalized block signal! prev_finalized_l1 {:?}, signaled_finalized_l1 {:?}", prev_finalized_l1, l1_origin); + return; + } + + if *finalized_l1 != l1_origin { + *self.tried_finalize_at.lock().unwrap() = 0; + *finalized_l1 = l1_origin; + } + + self.emitter.emit(Event::TryFinalize).await; + } + + // onDerivationIdle is called when the pipeline is exhausted of new data (i.e. no more L2 blocks to derive from). + async fn on_derivation_idle(&self, derived_from: L1BlockRef) { + let finalized_l1 = self.finalized_l1.lock().unwrap(); + if *finalized_l1 == L1BlockRef::default() { + return; + } + + let tried_finalize_at = *self.tried_finalize_at.lock().unwrap(); + if tried_finalize_at != 0 && derived_from.number <= tried_finalize_at + FINALITY_DELAY { + return; + } + + debug!("processing L1 finality information, l1_finalized {:?}, derived_from {:?}, previous {:?}", finalized_l1, derived_from, tried_finalize_at); + + *self.tried_finalize_at.lock().unwrap() = derived_from.number; + self.emitter.emit(Event::TryFinalize).await; + } + + pub async fn try_finalize(&mut self) -> Result<()> { + // Clone or copy values that need to be used across await points + let finalized_l1 = { + let guard = self.finalized_l1.lock().unwrap(); + guard.clone() + }; + let gadget_activated_timestamp = match self + .babylon_finality_client + .query_btc_staking_activated_timestamp() + .await + { + Ok(timestamp) => timestamp, + Err(e) if e.to_string().contains("BtcStakingNotActivated") => 0, + Err(e) => { + self.emitter + .emit(Event::CriticalError(CriticalErrorEvent { + err: format!( + "failed to query BTC staking activated timestamp: {}", + e.to_string() + ), + })) + .await; + return Ok(()); + } + }; + + // let mut finalized_l2 = self.last_finalized_l2.lock().unwrap().clone(); + let mut finalized_l2 = { + let guard = self.last_finalized_l2.lock().unwrap(); + guard.clone() + }; + let mut finalized_derived_from = None; + + let finality_data = self.finality_data.lock().unwrap().clone(); + for fd in finality_data.iter() { + if fd.l2_block.number > finalized_l2.number && fd.l1_block.number <= finalized_l1.number + { + if let Some(last_finalized_block) = self + .find_last_btc_finalized_l2_block( + fd.l2_block.number, + finalized_l2.number, + gadget_activated_timestamp, + ) + .await? + { + finalized_l2 = last_finalized_block; + finalized_derived_from = Some(fd.l1_block.clone()); + } + + if finalized_derived_from.is_none() || finalized_l2.number != fd.l2_block.number { + break; + } + } + } + + if let Some(derived_from) = finalized_derived_from { + let ctx = tokio::time::timeout(Duration::from_secs(10), async { + let signal_ref = self + .l1_fetcher + .l1_block_ref_by_number(finalized_l1.number) + .await + .map_err(|e| { + anyhow!(format!("l1_block_ref_by_number error: {:?}", e.to_string())) + })?; + + if signal_ref.hash != finalized_l1.hash { + let err_msg = format!( + "need to reset, we assumed {:?} is finalized, but canonical chain is {:?}", + finalized_l1, signal_ref + ); + self.emitter + .emit(Event::Reset(ResetEvent { err: err_msg })) + .await; + return Err(anyhow::anyhow!("Chain reset needed")); + } + + let derived_ref = self + .l1_fetcher + .l1_block_ref_by_number(derived_from.number) + .await?; + + if derived_ref.hash != derived_from.hash { + let err_msg = format!( + "need to reset, we are on {:?}, not on the finalizing L1 chain {:?}", + derived_from, derived_ref + ); + self.emitter + .emit(Event::Reset(ResetEvent { err: err_msg })) + .await; + return Err(anyhow::anyhow!("Chain reset needed")); + } + Ok(()) + // Ok::<(), Box>(()) + }) + .await; + + match ctx { + Ok(Ok(())) => { + self.emitter + .emit(Event::ForkchoiceUpdate(ForkchoiceUpdateEvent { + finalized_l2_head: finalized_l2, + })) + .await; + } + Ok(Err(e)) => { + return Err(anyhow::anyhow!( + "Error during finalization, error {:?}", + e.to_string() + )); + } + Err(_) => { + return Err(anyhow::anyhow!("Timeout during finalization")); + } + } + } + return Ok(()); + } + + async fn find_last_btc_finalized_l2_block( + &mut self, + fd_l2_block_number: u64, + finalized_l2_number: u64, + gadget_activated_timestamp: u64, + ) -> Result> { + let block_count = (fd_l2_block_number - finalized_l2_number) as usize; + let mut l2_blocks = HashMap::new(); + let mut query_blocks = Vec::new(); + let mut largest_non_activated_block = None; + + for i in 0..block_count { + let block_number = (i as u64) + finalized_l2_number + 1; + let l2_block = match self.l2_fetcher.l2_block_ref_by_number(block_number) { + Ok(block) => block, + Err(e) => { + self.emitter.emit(Event::CriticalError(CriticalErrorEvent { + err: format!( + "failed to check if block {} to {} is finalized on Babylon, could not fetch block {}: {}", + finalized_l2_number + 1, + fd_l2_block_number, + block_number, + e + ) + })).await; + return Ok(None); + } + }; + + l2_blocks.insert(block_number, l2_block.clone()); + + if l2_block.time < gadget_activated_timestamp { + largest_non_activated_block = Some(l2_block); + continue; + } + + query_blocks.push(Block { + block_height: l2_block.number, + block_hash: l2_block.hash.to_string(), + block_timestamp: l2_block.time, + }); + } + + if query_blocks.is_empty() { + return Ok(largest_non_activated_block); + } + + match self + .babylon_finality_client + .query_block_range_babylon_finalized(query_blocks.as_slice()) + .await + { + Ok(last_finalized_block_number) => { + if let Some(number) = last_finalized_block_number { + return Ok(l2_blocks.get(&number).cloned()); + } + } + Err(e) => { + self.emitter + .emit(Event::CriticalError(CriticalErrorEvent { + err: format!( + "failed to check if block {} to {} is finalized on Babylon: {}", + finalized_l2_number + 1, + fd_l2_block_number, + e + ), + })) + .await; + } + } + + Ok(largest_non_activated_block) + } + + async fn on_reset(&self) { + let mut finality_data = self.finality_data.lock().unwrap(); + finality_data.clear(); + *self.tried_finalize_at.lock().unwrap() = 0; + } + + async fn on_derived_safe_block(&self, l2_safe: L2BlockRef, derived_from: L1BlockRef) { + let mut finality_data = self.finality_data.lock().unwrap(); + + if finality_data.is_empty() + || finality_data.last().unwrap().l1_block.number < derived_from.number + { + if finality_data.len() as u64 >= self.finality_lookback { + finality_data.drain(0..1); + } + + finality_data.push(FinalityData { + l2_block: l2_safe.clone(), + l1_block: BlockID { + number: derived_from.number, + hash: derived_from.hash, + }, + }); + + debug!( + "extended finality-data last_l1 {:?}, last_l2 {:?}", + finality_data.last().unwrap().l1_block, + finality_data.last().unwrap().l2_block + ); + } else { + let last = finality_data.last_mut().unwrap(); + if last.l2_block != l2_safe { + last.l2_block = l2_safe; + debug!( + "updated finality-data last_l1 {:?}, last_l2 {:?}", + last.l1_block, last.l2_block + ); + } + } + } +} + +// Default implementations +#[derive(Default)] +pub struct NoopEmitter; + +#[async_trait] +impl EventEmitter for NoopEmitter { + async fn emit(&self, _event: Event) {} +} + +// #[async_trait] +// pub trait FinalizerL1Interface: Send + Sync { +// async fn l1_block_ref_by_number(&self, number: u64) -> Result>; +// } + +#[derive(Clone, Debug, Default)] +pub struct FinalizerL1Mock {} + +#[async_trait] +impl FinalizerL1Interface for FinalizerL1Mock { + // async fn l1_block_ref_by_number(&self, number: u64) -> Result> { + async fn l1_block_ref_by_number(&self, _number: u64) -> Result { + // Implement your gRPC client initialization here + let mock = L1BlockRef::default(); + + Ok(mock) + } +} diff --git a/crates/rooch-finality/src/finality/mod.rs b/crates/rooch-finality/src/finality/mod.rs new file mode 100644 index 0000000000..e50e51d738 --- /dev/null +++ b/crates/rooch-finality/src/finality/mod.rs @@ -0,0 +1,5 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +pub mod expected_clients; +pub mod finalizer; diff --git a/crates/rooch-finality/src/lib.rs b/crates/rooch-finality/src/lib.rs new file mode 100644 index 0000000000..ab5a15db41 --- /dev/null +++ b/crates/rooch-finality/src/lib.rs @@ -0,0 +1,11 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +pub mod actor; +pub mod finality; +pub mod messages; +pub mod metrics; +pub mod proto; +pub mod proxy; +pub mod rpc_client; +pub mod types; diff --git a/crates/rooch-finality/src/messages.rs b/crates/rooch-finality/src/messages.rs new file mode 100644 index 0000000000..2fd34df508 --- /dev/null +++ b/crates/rooch-finality/src/messages.rs @@ -0,0 +1,17 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Result; +use coerce::actor::message::Message; +use rooch_types::finality_block::Block; +use serde::{Deserialize, Serialize}; + +/// Finality Message +#[derive(Debug, Serialize, Deserialize)] +pub struct FinalityMessage { + pub block: Block, +} + +impl Message for FinalityMessage { + type Result = Result<()>; +} diff --git a/crates/rooch-finality/src/metrics.rs b/crates/rooch-finality/src/metrics.rs new file mode 100644 index 0000000000..4e0eb93597 --- /dev/null +++ b/crates/rooch-finality/src/metrics.rs @@ -0,0 +1,36 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use metrics::metrics_util::LATENCY_SEC_BUCKETS; +use prometheus::{register_histogram_vec_with_registry, HistogramVec, Registry}; + +#[derive(Debug)] +pub struct FinalityMetrics { + pub finality_latency_seconds: HistogramVec, + pub finality_bytes: HistogramVec, +} + +impl FinalityMetrics { + pub(crate) fn new(registry: &Registry) -> Self { + FinalityMetrics { + finality_latency_seconds: register_histogram_vec_with_registry!( + "finality_latency_seconds", + "Finality sequence latency in seconds", + &["fn_name"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + finality_bytes: register_histogram_vec_with_registry!( + "finality_bytes", + "Finality sequence size in bytes", + &["fn_name"], + prometheus::exponential_buckets(1.0, 4.0, 15) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/rooch-finality/src/proto/finalitygadget.proto b/crates/rooch-finality/src/proto/finalitygadget.proto new file mode 100644 index 0000000000..34d96e4ded --- /dev/null +++ b/crates/rooch-finality/src/proto/finalitygadget.proto @@ -0,0 +1,87 @@ +syntax = "proto3"; + +package proto; + +option go_package = "github.com/babylonlabs-io/finality-gadget/proto"; +// Add rust specific options +// option rust_package = "rooch-finality/src/proto"; + +service FinalityGadget { + // QueryIsBlockBabylonFinalized returns the finality status of a block by + // querying Babylon chain + rpc QueryIsBlockBabylonFinalized(QueryIsBlockBabylonFinalizedRequest) + returns (QueryIsBlockFinalizedResponse); + + // QueryBlockRangeBabylonFinalized returns the last finalized block height + // within a block range by querying Babylon chain + rpc QueryBlockRangeBabylonFinalized(QueryBlockRangeBabylonFinalizedRequest) + returns (QueryBlockRangeBabylonFinalizedResponse); + + // QueryBtcStakingActivatedTimestamp returns the timestamp when BTC staking + // was activated + rpc QueryBtcStakingActivatedTimestamp( + QueryBtcStakingActivatedTimestampRequest) + returns (QueryBtcStakingActivatedTimestampResponse); + + // QueryIsBlockFinalizedByHeight returns the finality status of a block at + // given height by querying the local db + rpc QueryIsBlockFinalizedByHeight(QueryIsBlockFinalizedByHeightRequest) + returns (QueryIsBlockFinalizedResponse); + + // QueryIsBlockFinalizedByHash returns the finality status of a block with + // given hash by querying the local db + rpc QueryIsBlockFinalizedByHash(QueryIsBlockFinalizedByHashRequest) + returns (QueryIsBlockFinalizedResponse); + + // QueryLatestFinalizedBlock returns the latest consecutively finalized block + // by querying the local db + rpc QueryLatestFinalizedBlock(QueryLatestFinalizedBlockRequest) + returns (QueryBlockResponse); +} + +message BlockInfo { + // block_hash is the hash of the block + string block_hash = 1; + // block_height is the height of the block + uint64 block_height = 2; + // block_timestamp is the unix timestamp of the block + uint64 block_timestamp = 3; +} + +message QueryIsBlockBabylonFinalizedRequest { BlockInfo block = 1; } + +message QueryBlockRangeBabylonFinalizedRequest { + // blocks is a list of blocks to query + repeated BlockInfo blocks = 1; +} + +message QueryBlockRangeBabylonFinalizedResponse { + // last_finalized_block_height is the height of the last finalized block + uint64 last_finalized_block_height = 1; +} + +message QueryBtcStakingActivatedTimestampRequest {} + +message QueryBtcStakingActivatedTimestampResponse { + // timestamp is the unix timestamp when BTC staking was activated + uint64 activated_timestamp = 1; +} + +message QueryIsBlockFinalizedByHeightRequest { + // block_height is the height of the block + uint64 block_height = 1; +} + +message QueryIsBlockFinalizedByHashRequest { + // block_hash is the hash of the block + string block_hash = 1; +} + +message QueryIsBlockFinalizedResponse { + // is_finalized is true if the block is finalized + bool is_finalized = 1; +} + +message QueryLatestFinalizedBlockRequest {} + +message QueryBlockResponse { BlockInfo block = 1; } \ No newline at end of file diff --git a/crates/rooch-finality/src/proto/finalitygadget_pb.rs b/crates/rooch-finality/src/proto/finalitygadget_pb.rs new file mode 100644 index 0000000000..3e701db9df --- /dev/null +++ b/crates/rooch-finality/src/proto/finalitygadget_pb.rs @@ -0,0 +1,1531 @@ +// This file is generated by rust-protobuf 3.7.1. Do not edit +// .proto file is parsed by protoc --rs_out=... +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_results)] +#![allow(unused_mut)] + +//! Generated file from `finalitygadget.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_7_1; + +// @@protoc_insertion_point(message:proto.BlockInfo) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct BlockInfo { + // message fields + /// block_hash is the hash of the block + // @@protoc_insertion_point(field:proto.BlockInfo.block_hash) + pub block_hash: ::std::string::String, + /// block_height is the height of the block + // @@protoc_insertion_point(field:proto.BlockInfo.block_height) + pub block_height: u64, + /// block_timestamp is the unix timestamp of the block + // @@protoc_insertion_point(field:proto.BlockInfo.block_timestamp) + pub block_timestamp: u64, + // special fields + // @@protoc_insertion_point(special_field:proto.BlockInfo.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a BlockInfo { + fn default() -> &'a BlockInfo { + ::default_instance() + } +} + +impl BlockInfo { + pub fn new() -> BlockInfo { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(3); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "block_hash", + |m: &BlockInfo| { &m.block_hash }, + |m: &mut BlockInfo| { &mut m.block_hash }, + )); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "block_height", + |m: &BlockInfo| { &m.block_height }, + |m: &mut BlockInfo| { &mut m.block_height }, + )); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "block_timestamp", + |m: &BlockInfo| { &m.block_timestamp }, + |m: &mut BlockInfo| { &mut m.block_timestamp }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "BlockInfo", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for BlockInfo { + const NAME: &'static str = "BlockInfo"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.block_hash = is.read_string()?; + }, + 16 => { + self.block_height = is.read_uint64()?; + }, + 24 => { + self.block_timestamp = is.read_uint64()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if !self.block_hash.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.block_hash); + } + if self.block_height != 0 { + my_size += ::protobuf::rt::uint64_size(2, self.block_height); + } + if self.block_timestamp != 0 { + my_size += ::protobuf::rt::uint64_size(3, self.block_timestamp); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if !self.block_hash.is_empty() { + os.write_string(1, &self.block_hash)?; + } + if self.block_height != 0 { + os.write_uint64(2, self.block_height)?; + } + if self.block_timestamp != 0 { + os.write_uint64(3, self.block_timestamp)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> BlockInfo { + BlockInfo::new() + } + + fn clear(&mut self) { + self.block_hash.clear(); + self.block_height = 0; + self.block_timestamp = 0; + self.special_fields.clear(); + } + + fn default_instance() -> &'static BlockInfo { + static instance: BlockInfo = BlockInfo { + block_hash: ::std::string::String::new(), + block_height: 0, + block_timestamp: 0, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for BlockInfo { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("BlockInfo").unwrap()).clone() + } +} + +impl ::std::fmt::Display for BlockInfo { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for BlockInfo { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryIsBlockBabylonFinalizedRequest) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryIsBlockBabylonFinalizedRequest { + // message fields + // @@protoc_insertion_point(field:proto.QueryIsBlockBabylonFinalizedRequest.block) + pub block: ::protobuf::MessageField, + // special fields + // @@protoc_insertion_point(special_field:proto.QueryIsBlockBabylonFinalizedRequest.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryIsBlockBabylonFinalizedRequest { + fn default() -> &'a QueryIsBlockBabylonFinalizedRequest { + ::default_instance() + } +} + +impl QueryIsBlockBabylonFinalizedRequest { + pub fn new() -> QueryIsBlockBabylonFinalizedRequest { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, BlockInfo>( + "block", + |m: &QueryIsBlockBabylonFinalizedRequest| { &m.block }, + |m: &mut QueryIsBlockBabylonFinalizedRequest| { &mut m.block }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryIsBlockBabylonFinalizedRequest", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryIsBlockBabylonFinalizedRequest { + const NAME: &'static str = "QueryIsBlockBabylonFinalizedRequest"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + ::protobuf::rt::read_singular_message_into_field(is, &mut self.block)?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if let Some(v) = self.block.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len; + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if let Some(v) = self.block.as_ref() { + ::protobuf::rt::write_message_field_with_cached_size(1, v, os)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryIsBlockBabylonFinalizedRequest { + QueryIsBlockBabylonFinalizedRequest::new() + } + + fn clear(&mut self) { + self.block.clear(); + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryIsBlockBabylonFinalizedRequest { + static instance: QueryIsBlockBabylonFinalizedRequest = QueryIsBlockBabylonFinalizedRequest { + block: ::protobuf::MessageField::none(), + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryIsBlockBabylonFinalizedRequest { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryIsBlockBabylonFinalizedRequest").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryIsBlockBabylonFinalizedRequest { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryIsBlockBabylonFinalizedRequest { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryBlockRangeBabylonFinalizedRequest) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryBlockRangeBabylonFinalizedRequest { + // message fields + /// blocks is a list of blocks to query + // @@protoc_insertion_point(field:proto.QueryBlockRangeBabylonFinalizedRequest.blocks) + pub blocks: ::std::vec::Vec, + // special fields + // @@protoc_insertion_point(special_field:proto.QueryBlockRangeBabylonFinalizedRequest.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryBlockRangeBabylonFinalizedRequest { + fn default() -> &'a QueryBlockRangeBabylonFinalizedRequest { + ::default_instance() + } +} + +impl QueryBlockRangeBabylonFinalizedRequest { + pub fn new() -> QueryBlockRangeBabylonFinalizedRequest { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>( + "blocks", + |m: &QueryBlockRangeBabylonFinalizedRequest| { &m.blocks }, + |m: &mut QueryBlockRangeBabylonFinalizedRequest| { &mut m.blocks }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryBlockRangeBabylonFinalizedRequest", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryBlockRangeBabylonFinalizedRequest { + const NAME: &'static str = "QueryBlockRangeBabylonFinalizedRequest"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.blocks.push(is.read_message()?); + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + for value in &self.blocks { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + for v in &self.blocks { + ::protobuf::rt::write_message_field_with_cached_size(1, v, os)?; + }; + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryBlockRangeBabylonFinalizedRequest { + QueryBlockRangeBabylonFinalizedRequest::new() + } + + fn clear(&mut self) { + self.blocks.clear(); + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryBlockRangeBabylonFinalizedRequest { + static instance: QueryBlockRangeBabylonFinalizedRequest = QueryBlockRangeBabylonFinalizedRequest { + blocks: ::std::vec::Vec::new(), + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryBlockRangeBabylonFinalizedRequest { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryBlockRangeBabylonFinalizedRequest").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryBlockRangeBabylonFinalizedRequest { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryBlockRangeBabylonFinalizedRequest { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryBlockRangeBabylonFinalizedResponse) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryBlockRangeBabylonFinalizedResponse { + // message fields + /// last_finalized_block_height is the height of the last finalized block + // @@protoc_insertion_point(field:proto.QueryBlockRangeBabylonFinalizedResponse.last_finalized_block_height) + pub last_finalized_block_height: u64, + // special fields + // @@protoc_insertion_point(special_field:proto.QueryBlockRangeBabylonFinalizedResponse.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryBlockRangeBabylonFinalizedResponse { + fn default() -> &'a QueryBlockRangeBabylonFinalizedResponse { + ::default_instance() + } +} + +impl QueryBlockRangeBabylonFinalizedResponse { + pub fn new() -> QueryBlockRangeBabylonFinalizedResponse { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "last_finalized_block_height", + |m: &QueryBlockRangeBabylonFinalizedResponse| { &m.last_finalized_block_height }, + |m: &mut QueryBlockRangeBabylonFinalizedResponse| { &mut m.last_finalized_block_height }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryBlockRangeBabylonFinalizedResponse", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryBlockRangeBabylonFinalizedResponse { + const NAME: &'static str = "QueryBlockRangeBabylonFinalizedResponse"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 8 => { + self.last_finalized_block_height = is.read_uint64()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if self.last_finalized_block_height != 0 { + my_size += ::protobuf::rt::uint64_size(1, self.last_finalized_block_height); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if self.last_finalized_block_height != 0 { + os.write_uint64(1, self.last_finalized_block_height)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryBlockRangeBabylonFinalizedResponse { + QueryBlockRangeBabylonFinalizedResponse::new() + } + + fn clear(&mut self) { + self.last_finalized_block_height = 0; + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryBlockRangeBabylonFinalizedResponse { + static instance: QueryBlockRangeBabylonFinalizedResponse = QueryBlockRangeBabylonFinalizedResponse { + last_finalized_block_height: 0, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryBlockRangeBabylonFinalizedResponse { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryBlockRangeBabylonFinalizedResponse").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryBlockRangeBabylonFinalizedResponse { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryBlockRangeBabylonFinalizedResponse { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryBtcStakingActivatedTimestampRequest) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryBtcStakingActivatedTimestampRequest { + // special fields + // @@protoc_insertion_point(special_field:proto.QueryBtcStakingActivatedTimestampRequest.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryBtcStakingActivatedTimestampRequest { + fn default() -> &'a QueryBtcStakingActivatedTimestampRequest { + ::default_instance() + } +} + +impl QueryBtcStakingActivatedTimestampRequest { + pub fn new() -> QueryBtcStakingActivatedTimestampRequest { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(0); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryBtcStakingActivatedTimestampRequest", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryBtcStakingActivatedTimestampRequest { + const NAME: &'static str = "QueryBtcStakingActivatedTimestampRequest"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryBtcStakingActivatedTimestampRequest { + QueryBtcStakingActivatedTimestampRequest::new() + } + + fn clear(&mut self) { + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryBtcStakingActivatedTimestampRequest { + static instance: QueryBtcStakingActivatedTimestampRequest = QueryBtcStakingActivatedTimestampRequest { + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryBtcStakingActivatedTimestampRequest { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryBtcStakingActivatedTimestampRequest").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryBtcStakingActivatedTimestampRequest { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryBtcStakingActivatedTimestampRequest { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryBtcStakingActivatedTimestampResponse) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryBtcStakingActivatedTimestampResponse { + // message fields + /// timestamp is the unix timestamp when BTC staking was activated + // @@protoc_insertion_point(field:proto.QueryBtcStakingActivatedTimestampResponse.activated_timestamp) + pub activated_timestamp: u64, + // special fields + // @@protoc_insertion_point(special_field:proto.QueryBtcStakingActivatedTimestampResponse.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryBtcStakingActivatedTimestampResponse { + fn default() -> &'a QueryBtcStakingActivatedTimestampResponse { + ::default_instance() + } +} + +impl QueryBtcStakingActivatedTimestampResponse { + pub fn new() -> QueryBtcStakingActivatedTimestampResponse { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "activated_timestamp", + |m: &QueryBtcStakingActivatedTimestampResponse| { &m.activated_timestamp }, + |m: &mut QueryBtcStakingActivatedTimestampResponse| { &mut m.activated_timestamp }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryBtcStakingActivatedTimestampResponse", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryBtcStakingActivatedTimestampResponse { + const NAME: &'static str = "QueryBtcStakingActivatedTimestampResponse"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 8 => { + self.activated_timestamp = is.read_uint64()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if self.activated_timestamp != 0 { + my_size += ::protobuf::rt::uint64_size(1, self.activated_timestamp); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if self.activated_timestamp != 0 { + os.write_uint64(1, self.activated_timestamp)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryBtcStakingActivatedTimestampResponse { + QueryBtcStakingActivatedTimestampResponse::new() + } + + fn clear(&mut self) { + self.activated_timestamp = 0; + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryBtcStakingActivatedTimestampResponse { + static instance: QueryBtcStakingActivatedTimestampResponse = QueryBtcStakingActivatedTimestampResponse { + activated_timestamp: 0, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryBtcStakingActivatedTimestampResponse { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryBtcStakingActivatedTimestampResponse").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryBtcStakingActivatedTimestampResponse { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryBtcStakingActivatedTimestampResponse { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryIsBlockFinalizedByHeightRequest) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryIsBlockFinalizedByHeightRequest { + // message fields + /// block_height is the height of the block + // @@protoc_insertion_point(field:proto.QueryIsBlockFinalizedByHeightRequest.block_height) + pub block_height: u64, + // special fields + // @@protoc_insertion_point(special_field:proto.QueryIsBlockFinalizedByHeightRequest.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryIsBlockFinalizedByHeightRequest { + fn default() -> &'a QueryIsBlockFinalizedByHeightRequest { + ::default_instance() + } +} + +impl QueryIsBlockFinalizedByHeightRequest { + pub fn new() -> QueryIsBlockFinalizedByHeightRequest { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "block_height", + |m: &QueryIsBlockFinalizedByHeightRequest| { &m.block_height }, + |m: &mut QueryIsBlockFinalizedByHeightRequest| { &mut m.block_height }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryIsBlockFinalizedByHeightRequest", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryIsBlockFinalizedByHeightRequest { + const NAME: &'static str = "QueryIsBlockFinalizedByHeightRequest"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 8 => { + self.block_height = is.read_uint64()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if self.block_height != 0 { + my_size += ::protobuf::rt::uint64_size(1, self.block_height); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if self.block_height != 0 { + os.write_uint64(1, self.block_height)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryIsBlockFinalizedByHeightRequest { + QueryIsBlockFinalizedByHeightRequest::new() + } + + fn clear(&mut self) { + self.block_height = 0; + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryIsBlockFinalizedByHeightRequest { + static instance: QueryIsBlockFinalizedByHeightRequest = QueryIsBlockFinalizedByHeightRequest { + block_height: 0, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryIsBlockFinalizedByHeightRequest { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryIsBlockFinalizedByHeightRequest").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryIsBlockFinalizedByHeightRequest { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryIsBlockFinalizedByHeightRequest { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryIsBlockFinalizedByHashRequest) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryIsBlockFinalizedByHashRequest { + // message fields + /// block_hash is the hash of the block + // @@protoc_insertion_point(field:proto.QueryIsBlockFinalizedByHashRequest.block_hash) + pub block_hash: ::std::string::String, + // special fields + // @@protoc_insertion_point(special_field:proto.QueryIsBlockFinalizedByHashRequest.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryIsBlockFinalizedByHashRequest { + fn default() -> &'a QueryIsBlockFinalizedByHashRequest { + ::default_instance() + } +} + +impl QueryIsBlockFinalizedByHashRequest { + pub fn new() -> QueryIsBlockFinalizedByHashRequest { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "block_hash", + |m: &QueryIsBlockFinalizedByHashRequest| { &m.block_hash }, + |m: &mut QueryIsBlockFinalizedByHashRequest| { &mut m.block_hash }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryIsBlockFinalizedByHashRequest", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryIsBlockFinalizedByHashRequest { + const NAME: &'static str = "QueryIsBlockFinalizedByHashRequest"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.block_hash = is.read_string()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if !self.block_hash.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.block_hash); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if !self.block_hash.is_empty() { + os.write_string(1, &self.block_hash)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryIsBlockFinalizedByHashRequest { + QueryIsBlockFinalizedByHashRequest::new() + } + + fn clear(&mut self) { + self.block_hash.clear(); + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryIsBlockFinalizedByHashRequest { + static instance: QueryIsBlockFinalizedByHashRequest = QueryIsBlockFinalizedByHashRequest { + block_hash: ::std::string::String::new(), + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryIsBlockFinalizedByHashRequest { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryIsBlockFinalizedByHashRequest").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryIsBlockFinalizedByHashRequest { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryIsBlockFinalizedByHashRequest { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryIsBlockFinalizedResponse) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryIsBlockFinalizedResponse { + // message fields + /// is_finalized is true if the block is finalized + // @@protoc_insertion_point(field:proto.QueryIsBlockFinalizedResponse.is_finalized) + pub is_finalized: bool, + // special fields + // @@protoc_insertion_point(special_field:proto.QueryIsBlockFinalizedResponse.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryIsBlockFinalizedResponse { + fn default() -> &'a QueryIsBlockFinalizedResponse { + ::default_instance() + } +} + +impl QueryIsBlockFinalizedResponse { + pub fn new() -> QueryIsBlockFinalizedResponse { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "is_finalized", + |m: &QueryIsBlockFinalizedResponse| { &m.is_finalized }, + |m: &mut QueryIsBlockFinalizedResponse| { &mut m.is_finalized }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryIsBlockFinalizedResponse", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryIsBlockFinalizedResponse { + const NAME: &'static str = "QueryIsBlockFinalizedResponse"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 8 => { + self.is_finalized = is.read_bool()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if self.is_finalized != false { + my_size += 1 + 1; + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if self.is_finalized != false { + os.write_bool(1, self.is_finalized)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryIsBlockFinalizedResponse { + QueryIsBlockFinalizedResponse::new() + } + + fn clear(&mut self) { + self.is_finalized = false; + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryIsBlockFinalizedResponse { + static instance: QueryIsBlockFinalizedResponse = QueryIsBlockFinalizedResponse { + is_finalized: false, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryIsBlockFinalizedResponse { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryIsBlockFinalizedResponse").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryIsBlockFinalizedResponse { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryIsBlockFinalizedResponse { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryLatestFinalizedBlockRequest) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryLatestFinalizedBlockRequest { + // special fields + // @@protoc_insertion_point(special_field:proto.QueryLatestFinalizedBlockRequest.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryLatestFinalizedBlockRequest { + fn default() -> &'a QueryLatestFinalizedBlockRequest { + ::default_instance() + } +} + +impl QueryLatestFinalizedBlockRequest { + pub fn new() -> QueryLatestFinalizedBlockRequest { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(0); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryLatestFinalizedBlockRequest", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryLatestFinalizedBlockRequest { + const NAME: &'static str = "QueryLatestFinalizedBlockRequest"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryLatestFinalizedBlockRequest { + QueryLatestFinalizedBlockRequest::new() + } + + fn clear(&mut self) { + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryLatestFinalizedBlockRequest { + static instance: QueryLatestFinalizedBlockRequest = QueryLatestFinalizedBlockRequest { + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryLatestFinalizedBlockRequest { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryLatestFinalizedBlockRequest").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryLatestFinalizedBlockRequest { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryLatestFinalizedBlockRequest { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:proto.QueryBlockResponse) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct QueryBlockResponse { + // message fields + // @@protoc_insertion_point(field:proto.QueryBlockResponse.block) + pub block: ::protobuf::MessageField, + // special fields + // @@protoc_insertion_point(special_field:proto.QueryBlockResponse.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a QueryBlockResponse { + fn default() -> &'a QueryBlockResponse { + ::default_instance() + } +} + +impl QueryBlockResponse { + pub fn new() -> QueryBlockResponse { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, BlockInfo>( + "block", + |m: &QueryBlockResponse| { &m.block }, + |m: &mut QueryBlockResponse| { &mut m.block }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "QueryBlockResponse", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for QueryBlockResponse { + const NAME: &'static str = "QueryBlockResponse"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + ::protobuf::rt::read_singular_message_into_field(is, &mut self.block)?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if let Some(v) = self.block.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len; + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if let Some(v) = self.block.as_ref() { + ::protobuf::rt::write_message_field_with_cached_size(1, v, os)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> QueryBlockResponse { + QueryBlockResponse::new() + } + + fn clear(&mut self) { + self.block.clear(); + self.special_fields.clear(); + } + + fn default_instance() -> &'static QueryBlockResponse { + static instance: QueryBlockResponse = QueryBlockResponse { + block: ::protobuf::MessageField::none(), + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for QueryBlockResponse { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("QueryBlockResponse").unwrap()).clone() + } +} + +impl ::std::fmt::Display for QueryBlockResponse { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryBlockResponse { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x14finalitygadget.proto\x12\x05proto\"v\n\tBlockInfo\x12\x1d\n\nblock\ + _hash\x18\x01\x20\x01(\tR\tblockHash\x12!\n\x0cblock_height\x18\x02\x20\ + \x01(\x04R\x0bblockHeight\x12'\n\x0fblock_timestamp\x18\x03\x20\x01(\x04\ + R\x0eblockTimestamp\"M\n#QueryIsBlockBabylonFinalizedRequest\x12&\n\x05b\ + lock\x18\x01\x20\x01(\x0b2\x10.proto.BlockInfoR\x05block\"R\n&QueryBlock\ + RangeBabylonFinalizedRequest\x12(\n\x06blocks\x18\x01\x20\x03(\x0b2\x10.\ + proto.BlockInfoR\x06blocks\"h\n'QueryBlockRangeBabylonFinalizedResponse\ + \x12=\n\x1blast_finalized_block_height\x18\x01\x20\x01(\x04R\x18lastFina\ + lizedBlockHeight\"*\n(QueryBtcStakingActivatedTimestampRequest\"\\\n)Que\ + ryBtcStakingActivatedTimestampResponse\x12/\n\x13activated_timestamp\x18\ + \x01\x20\x01(\x04R\x12activatedTimestamp\"I\n$QueryIsBlockFinalizedByHei\ + ghtRequest\x12!\n\x0cblock_height\x18\x01\x20\x01(\x04R\x0bblockHeight\"\ + C\n\"QueryIsBlockFinalizedByHashRequest\x12\x1d\n\nblock_hash\x18\x01\ + \x20\x01(\tR\tblockHash\"B\n\x1dQueryIsBlockFinalizedResponse\x12!\n\x0c\ + is_finalized\x18\x01\x20\x01(\x08R\x0bisFinalized\"\"\n\x20QueryLatestFi\ + nalizedBlockRequest\"<\n\x12QueryBlockResponse\x12&\n\x05block\x18\x01\ + \x20\x01(\x0b2\x10.proto.BlockInfoR\x05block2\xd3\x05\n\x0eFinalityGadge\ + t\x12p\n\x1cQueryIsBlockBabylonFinalized\x12*.proto.QueryIsBlockBabylonF\ + inalizedRequest\x1a$.proto.QueryIsBlockFinalizedResponse\x12\x80\x01\n\ + \x1fQueryBlockRangeBabylonFinalized\x12-.proto.QueryBlockRangeBabylonFin\ + alizedRequest\x1a..proto.QueryBlockRangeBabylonFinalizedResponse\x12\x86\ + \x01\n!QueryBtcStakingActivatedTimestamp\x12/.proto.QueryBtcStakingActiv\ + atedTimestampRequest\x1a0.proto.QueryBtcStakingActivatedTimestampRespons\ + e\x12r\n\x1dQueryIsBlockFinalizedByHeight\x12+.proto.QueryIsBlockFinaliz\ + edByHeightRequest\x1a$.proto.QueryIsBlockFinalizedResponse\x12n\n\x1bQue\ + ryIsBlockFinalizedByHash\x12).proto.QueryIsBlockFinalizedByHashRequest\ + \x1a$.proto.QueryIsBlockFinalizedResponse\x12_\n\x19QueryLatestFinalized\ + Block\x12'.proto.QueryLatestFinalizedBlockRequest\x1a\x19.proto.QueryBlo\ + ckResponseB1Z/github.com/babylonlabs-io/finality-gadget/protoJ\xc9\x12\n\ + \x06\x12\x04\0\0T3\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\ + \x03\x02\0\x0e\n\x08\n\x01\x08\x12\x03\x04\0F\n\t\n\x02\x08\x0b\x12\x03\ + \x04\0F\n\n\n\x02\x06\0\x12\x04\x06\0%\x01\n\n\n\x03\x06\0\x01\x12\x03\ + \x06\x08\x16\nn\n\x04\x06\0\x02\0\x12\x04\t\x02\n.\x1a`\x20QueryIsBlockB\ + abylonFinalized\x20returns\x20the\x20finality\x20status\x20of\x20a\x20bl\ + ock\x20by\n\x20querying\x20Babylon\x20chain\n\n\x0c\n\x05\x06\0\x02\0\ + \x01\x12\x03\t\x06\"\n\x0c\n\x05\x06\0\x02\0\x02\x12\x03\t#F\n\x0c\n\x05\ + \x06\0\x02\0\x03\x12\x03\n\x0f,\n\x87\x01\n\x04\x06\0\x02\x01\x12\x04\ + \x0e\x02\x0f8\x1ay\x20QueryBlockRangeBabylonFinalized\x20returns\x20the\ + \x20last\x20finalized\x20block\x20height\n\x20within\x20a\x20block\x20ra\ + nge\x20by\x20querying\x20Babylon\x20chain\n\n\x0c\n\x05\x06\0\x02\x01\ + \x01\x12\x03\x0e\x06%\n\x0c\n\x05\x06\0\x02\x01\x02\x12\x03\x0e&L\n\x0c\ + \n\x05\x06\0\x02\x01\x03\x12\x03\x0f\x0f6\ng\n\x04\x06\0\x02\x02\x12\x04\ + \x13\x02\x15:\x1aY\x20QueryBtcStakingActivatedTimestamp\x20returns\x20th\ + e\x20timestamp\x20when\x20BTC\x20staking\n\x20was\x20activated\n\n\x0c\n\ + \x05\x06\0\x02\x02\x01\x12\x03\x13\x06'\n\x0c\n\x05\x06\0\x02\x02\x02\ + \x12\x03\x14\x06.\n\x0c\n\x05\x06\0\x02\x02\x03\x12\x03\x15\x0f8\n~\n\ + \x04\x06\0\x02\x03\x12\x04\x19\x02\x1a.\x1ap\x20QueryIsBlockFinalizedByH\ + eight\x20returns\x20the\x20finality\x20status\x20of\x20a\x20block\x20at\ + \n\x20given\x20height\x20by\x20querying\x20the\x20local\x20db\n\n\x0c\n\ + \x05\x06\0\x02\x03\x01\x12\x03\x19\x06#\n\x0c\n\x05\x06\0\x02\x03\x02\ + \x12\x03\x19$H\n\x0c\n\x05\x06\0\x02\x03\x03\x12\x03\x1a\x0f,\n|\n\x04\ + \x06\0\x02\x04\x12\x04\x1e\x02\x1f.\x1an\x20QueryIsBlockFinalizedByHash\ + \x20returns\x20the\x20finality\x20status\x20of\x20a\x20block\x20with\n\ + \x20given\x20hash\x20by\x20querying\x20the\x20local\x20db\n\n\x0c\n\x05\ + \x06\0\x02\x04\x01\x12\x03\x1e\x06!\n\x0c\n\x05\x06\0\x02\x04\x02\x12\ + \x03\x1e\"D\n\x0c\n\x05\x06\0\x02\x04\x03\x12\x03\x1f\x0f,\nt\n\x04\x06\ + \0\x02\x05\x12\x04#\x02$#\x1af\x20QueryLatestFinalizedBlock\x20returns\ + \x20the\x20latest\x20consecutively\x20finalized\x20block\n\x20by\x20quer\ + ying\x20the\x20local\x20db\n\n\x0c\n\x05\x06\0\x02\x05\x01\x12\x03#\x06\ + \x1f\n\x0c\n\x05\x06\0\x02\x05\x02\x12\x03#\x20@\n\x0c\n\x05\x06\0\x02\ + \x05\x03\x12\x03$\x0f!\n\n\n\x02\x04\0\x12\x04'\0.\x01\n\n\n\x03\x04\0\ + \x01\x12\x03'\x08\x11\n2\n\x04\x04\0\x02\0\x12\x03)\x02\x18\x1a%\x20bloc\ + k_hash\x20is\x20the\x20hash\x20of\x20the\x20block\n\n\x0c\n\x05\x04\0\ + \x02\0\x05\x12\x03)\x02\x08\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03)\t\x13\n\ + \x0c\n\x05\x04\0\x02\0\x03\x12\x03)\x16\x17\n6\n\x04\x04\0\x02\x01\x12\ + \x03+\x02\x1a\x1a)\x20block_height\x20is\x20the\x20height\x20of\x20the\ + \x20block\n\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03+\x02\x08\n\x0c\n\x05\ + \x04\0\x02\x01\x01\x12\x03+\t\x15\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03+\ + \x18\x19\nA\n\x04\x04\0\x02\x02\x12\x03-\x02\x1d\x1a4\x20block_timestamp\ + \x20is\x20the\x20unix\x20timestamp\x20of\x20the\x20block\n\n\x0c\n\x05\ + \x04\0\x02\x02\x05\x12\x03-\x02\x08\n\x0c\n\x05\x04\0\x02\x02\x01\x12\ + \x03-\t\x18\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03-\x1b\x1c\n\t\n\x02\x04\ + \x01\x12\x030\0D\n\n\n\x03\x04\x01\x01\x12\x030\x08+\n\x0b\n\x04\x04\x01\ + \x02\0\x12\x030.B\n\x0c\n\x05\x04\x01\x02\0\x06\x12\x030.7\n\x0c\n\x05\ + \x04\x01\x02\0\x01\x12\x0308=\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x030@A\n\ + \n\n\x02\x04\x02\x12\x042\05\x01\n\n\n\x03\x04\x02\x01\x12\x032\x08.\n2\ + \n\x04\x04\x02\x02\0\x12\x034\x02\x20\x1a%\x20blocks\x20is\x20a\x20list\ + \x20of\x20blocks\x20to\x20query\n\n\x0c\n\x05\x04\x02\x02\0\x04\x12\x034\ + \x02\n\n\x0c\n\x05\x04\x02\x02\0\x06\x12\x034\x0b\x14\n\x0c\n\x05\x04\ + \x02\x02\0\x01\x12\x034\x15\x1b\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x034\ + \x1e\x1f\n\n\n\x02\x04\x03\x12\x047\0:\x01\n\n\n\x03\x04\x03\x01\x12\x03\ + 7\x08/\nT\n\x04\x04\x03\x02\0\x12\x039\x02)\x1aG\x20last_finalized_block\ + _height\x20is\x20the\x20height\x20of\x20the\x20last\x20finalized\x20bloc\ + k\n\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x039\x02\x08\n\x0c\n\x05\x04\x03\ + \x02\0\x01\x12\x039\t$\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x039'(\n\t\n\ + \x02\x04\x04\x12\x03<\03\n\n\n\x03\x04\x04\x01\x12\x03<\x080\n\n\n\x02\ + \x04\x05\x12\x04>\0A\x01\n\n\n\x03\x04\x05\x01\x12\x03>\x081\nM\n\x04\ + \x04\x05\x02\0\x12\x03@\x02!\x1a@\x20timestamp\x20is\x20the\x20unix\x20t\ + imestamp\x20when\x20BTC\x20staking\x20was\x20activated\n\n\x0c\n\x05\x04\ + \x05\x02\0\x05\x12\x03@\x02\x08\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03@\t\ + \x1c\n\x0c\n\x05\x04\x05\x02\0\x03\x12\x03@\x1f\x20\n\n\n\x02\x04\x06\ + \x12\x04C\0F\x01\n\n\n\x03\x04\x06\x01\x12\x03C\x08,\n6\n\x04\x04\x06\ + \x02\0\x12\x03E\x02\x1a\x1a)\x20block_height\x20is\x20the\x20height\x20o\ + f\x20the\x20block\n\n\x0c\n\x05\x04\x06\x02\0\x05\x12\x03E\x02\x08\n\x0c\ + \n\x05\x04\x06\x02\0\x01\x12\x03E\t\x15\n\x0c\n\x05\x04\x06\x02\0\x03\ + \x12\x03E\x18\x19\n\n\n\x02\x04\x07\x12\x04H\0K\x01\n\n\n\x03\x04\x07\ + \x01\x12\x03H\x08*\n2\n\x04\x04\x07\x02\0\x12\x03J\x02\x18\x1a%\x20block\ + _hash\x20is\x20the\x20hash\x20of\x20the\x20block\n\n\x0c\n\x05\x04\x07\ + \x02\0\x05\x12\x03J\x02\x08\n\x0c\n\x05\x04\x07\x02\0\x01\x12\x03J\t\x13\ + \n\x0c\n\x05\x04\x07\x02\0\x03\x12\x03J\x16\x17\n\n\n\x02\x04\x08\x12\ + \x04M\0P\x01\n\n\n\x03\x04\x08\x01\x12\x03M\x08%\n=\n\x04\x04\x08\x02\0\ + \x12\x03O\x02\x18\x1a0\x20is_finalized\x20is\x20true\x20if\x20the\x20blo\ + ck\x20is\x20finalized\n\n\x0c\n\x05\x04\x08\x02\0\x05\x12\x03O\x02\x06\n\ + \x0c\n\x05\x04\x08\x02\0\x01\x12\x03O\x07\x13\n\x0c\n\x05\x04\x08\x02\0\ + \x03\x12\x03O\x16\x17\n\t\n\x02\x04\t\x12\x03R\0+\n\n\n\x03\x04\t\x01\ + \x12\x03R\x08(\n\t\n\x02\x04\n\x12\x03T\03\n\n\n\x03\x04\n\x01\x12\x03T\ + \x08\x1a\n\x0b\n\x04\x04\n\x02\0\x12\x03T\x1d1\n\x0c\n\x05\x04\n\x02\0\ + \x06\x12\x03T\x1d&\n\x0c\n\x05\x04\n\x02\0\x01\x12\x03T',\n\x0c\n\x05\ + \x04\n\x02\0\x03\x12\x03T/0b\x06proto3\ +"; + +/// `FileDescriptorProto` object which was a source for this generated file +fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new(); + file_descriptor_proto_lazy.get(|| { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() + }) +} + +/// `FileDescriptor` object which allows dynamic access to files +pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { + static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new(); + static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new(); + file_descriptor.get(|| { + let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { + let mut deps = ::std::vec::Vec::with_capacity(0); + let mut messages = ::std::vec::Vec::with_capacity(11); + messages.push(BlockInfo::generated_message_descriptor_data()); + messages.push(QueryIsBlockBabylonFinalizedRequest::generated_message_descriptor_data()); + messages.push(QueryBlockRangeBabylonFinalizedRequest::generated_message_descriptor_data()); + messages.push(QueryBlockRangeBabylonFinalizedResponse::generated_message_descriptor_data()); + messages.push(QueryBtcStakingActivatedTimestampRequest::generated_message_descriptor_data()); + messages.push(QueryBtcStakingActivatedTimestampResponse::generated_message_descriptor_data()); + messages.push(QueryIsBlockFinalizedByHeightRequest::generated_message_descriptor_data()); + messages.push(QueryIsBlockFinalizedByHashRequest::generated_message_descriptor_data()); + messages.push(QueryIsBlockFinalizedResponse::generated_message_descriptor_data()); + messages.push(QueryLatestFinalizedBlockRequest::generated_message_descriptor_data()); + messages.push(QueryBlockResponse::generated_message_descriptor_data()); + let mut enums = ::std::vec::Vec::with_capacity(0); + ::protobuf::reflect::GeneratedFileDescriptor::new_generated( + file_descriptor_proto(), + deps, + messages, + enums, + ) + }); + ::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor) + }) +} + +include!("finaltitygadget_grpc.rs"); +// @@protoc_insertion_point(module) \ No newline at end of file diff --git a/crates/rooch-finality/src/proto/mod.rs b/crates/rooch-finality/src/proto/mod.rs new file mode 100644 index 0000000000..983edfd0b5 --- /dev/null +++ b/crates/rooch-finality/src/proto/mod.rs @@ -0,0 +1,11 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +// This file is @generated by prost-build. +pub mod proto { + include!("proto.rs"); +} + +// pub mod proto; + +// include!(concat!(env!("OUT_DIR"), "/mod.rs")); diff --git a/crates/rooch-finality/src/proto/proto.rs b/crates/rooch-finality/src/proto/proto.rs new file mode 100644 index 0000000000..16fcc1d342 --- /dev/null +++ b/crates/rooch-finality/src/proto/proto.rs @@ -0,0 +1,453 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockInfo { + /// block_hash is the hash of the block + #[prost(string, tag = "1")] + pub block_hash: ::prost::alloc::string::String, + /// block_height is the height of the block + #[prost(uint64, tag = "2")] + pub block_height: u64, + /// block_timestamp is the unix timestamp of the block + #[prost(uint64, tag = "3")] + pub block_timestamp: u64, +} +impl ::prost::Name for BlockInfo { + const NAME: &'static str = "BlockInfo"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.BlockInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.BlockInfo".into() + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryIsBlockBabylonFinalizedRequest { + #[prost(message, optional, tag = "1")] + pub block: ::core::option::Option, +} +impl ::prost::Name for QueryIsBlockBabylonFinalizedRequest { + const NAME: &'static str = "QueryIsBlockBabylonFinalizedRequest"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryIsBlockBabylonFinalizedRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryIsBlockBabylonFinalizedRequest".into() + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryBlockRangeBabylonFinalizedRequest { + /// blocks is a list of blocks to query + #[prost(message, repeated, tag = "1")] + pub blocks: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for QueryBlockRangeBabylonFinalizedRequest { + const NAME: &'static str = "QueryBlockRangeBabylonFinalizedRequest"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryBlockRangeBabylonFinalizedRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryBlockRangeBabylonFinalizedRequest".into() + } +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryBlockRangeBabylonFinalizedResponse { + /// last_finalized_block_height is the height of the last finalized block + #[prost(uint64, tag = "1")] + pub last_finalized_block_height: u64, +} +impl ::prost::Name for QueryBlockRangeBabylonFinalizedResponse { + const NAME: &'static str = "QueryBlockRangeBabylonFinalizedResponse"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryBlockRangeBabylonFinalizedResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryBlockRangeBabylonFinalizedResponse".into() + } +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryBtcStakingActivatedTimestampRequest {} +impl ::prost::Name for QueryBtcStakingActivatedTimestampRequest { + const NAME: &'static str = "QueryBtcStakingActivatedTimestampRequest"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryBtcStakingActivatedTimestampRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryBtcStakingActivatedTimestampRequest".into() + } +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryBtcStakingActivatedTimestampResponse { + /// timestamp is the unix timestamp when BTC staking was activated + #[prost(uint64, tag = "1")] + pub activated_timestamp: u64, +} +impl ::prost::Name for QueryBtcStakingActivatedTimestampResponse { + const NAME: &'static str = "QueryBtcStakingActivatedTimestampResponse"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryBtcStakingActivatedTimestampResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryBtcStakingActivatedTimestampResponse".into() + } +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryIsBlockFinalizedByHeightRequest { + /// block_height is the height of the block + #[prost(uint64, tag = "1")] + pub block_height: u64, +} +impl ::prost::Name for QueryIsBlockFinalizedByHeightRequest { + const NAME: &'static str = "QueryIsBlockFinalizedByHeightRequest"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryIsBlockFinalizedByHeightRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryIsBlockFinalizedByHeightRequest".into() + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryIsBlockFinalizedByHashRequest { + /// block_hash is the hash of the block + #[prost(string, tag = "1")] + pub block_hash: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryIsBlockFinalizedByHashRequest { + const NAME: &'static str = "QueryIsBlockFinalizedByHashRequest"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryIsBlockFinalizedByHashRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryIsBlockFinalizedByHashRequest".into() + } +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryIsBlockFinalizedResponse { + /// is_finalized is true if the block is finalized + #[prost(bool, tag = "1")] + pub is_finalized: bool, +} +impl ::prost::Name for QueryIsBlockFinalizedResponse { + const NAME: &'static str = "QueryIsBlockFinalizedResponse"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryIsBlockFinalizedResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryIsBlockFinalizedResponse".into() + } +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryLatestFinalizedBlockRequest {} +impl ::prost::Name for QueryLatestFinalizedBlockRequest { + const NAME: &'static str = "QueryLatestFinalizedBlockRequest"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryLatestFinalizedBlockRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryLatestFinalizedBlockRequest".into() + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryBlockResponse { + #[prost(message, optional, tag = "1")] + pub block: ::core::option::Option, +} +impl ::prost::Name for QueryBlockResponse { + const NAME: &'static str = "QueryBlockResponse"; + const PACKAGE: &'static str = "proto"; + fn full_name() -> ::prost::alloc::string::String { + "proto.QueryBlockResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/proto.QueryBlockResponse".into() + } +} +/// Generated client implementations. +pub mod finality_gadget_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct FinalityGadgetClient { + inner: tonic::client::Grpc, + } + impl FinalityGadgetClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl FinalityGadgetClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> FinalityGadgetClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + FinalityGadgetClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// QueryIsBlockBabylonFinalized returns the finality status of a block by + /// querying Babylon chain + pub async fn query_is_block_babylon_finalized( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.FinalityGadget/QueryIsBlockBabylonFinalized", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "proto.FinalityGadget", + "QueryIsBlockBabylonFinalized", + ), + ); + self.inner.unary(req, path, codec).await + } + /// QueryBlockRangeBabylonFinalized returns the last finalized block height + /// within a block range by querying Babylon chain + pub async fn query_block_range_babylon_finalized( + &mut self, + request: impl tonic::IntoRequest< + super::QueryBlockRangeBabylonFinalizedRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.FinalityGadget/QueryBlockRangeBabylonFinalized", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "proto.FinalityGadget", + "QueryBlockRangeBabylonFinalized", + ), + ); + self.inner.unary(req, path, codec).await + } + /// QueryBtcStakingActivatedTimestamp returns the timestamp when BTC staking + /// was activated + pub async fn query_btc_staking_activated_timestamp( + &mut self, + request: impl tonic::IntoRequest< + super::QueryBtcStakingActivatedTimestampRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.FinalityGadget/QueryBtcStakingActivatedTimestamp", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "proto.FinalityGadget", + "QueryBtcStakingActivatedTimestamp", + ), + ); + self.inner.unary(req, path, codec).await + } + /// QueryIsBlockFinalizedByHeight returns the finality status of a block at + /// given height by querying the local db + pub async fn query_is_block_finalized_by_height( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.FinalityGadget/QueryIsBlockFinalizedByHeight", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "proto.FinalityGadget", + "QueryIsBlockFinalizedByHeight", + ), + ); + self.inner.unary(req, path, codec).await + } + /// QueryIsBlockFinalizedByHash returns the finality status of a block with + /// given hash by querying the local db + pub async fn query_is_block_finalized_by_hash( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.FinalityGadget/QueryIsBlockFinalizedByHash", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "proto.FinalityGadget", + "QueryIsBlockFinalizedByHash", + ), + ); + self.inner.unary(req, path, codec).await + } + /// QueryLatestFinalizedBlock returns the latest consecutively finalized block + /// by querying the local db + pub async fn query_latest_finalized_block( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.FinalityGadget/QueryLatestFinalizedBlock", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("proto.FinalityGadget", "QueryLatestFinalizedBlock"), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/crates/rooch-finality/src/proxy/mod.rs b/crates/rooch-finality/src/proxy/mod.rs new file mode 100644 index 0000000000..521ad1427d --- /dev/null +++ b/crates/rooch-finality/src/proxy/mod.rs @@ -0,0 +1,23 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::actor::finality::FinalityActor; +use crate::messages::FinalityMessage; +use anyhow::Result; +use coerce::actor::ActorRef; +use rooch_types::finality_block::Block; + +#[derive(Clone)] +pub struct FinalityProxy { + pub actor: ActorRef, +} + +impl FinalityProxy { + pub fn new(actor: ActorRef) -> Self { + Self { actor } + } + + pub async fn finality(&self, block: Block) -> Result<()> { + self.actor.send(FinalityMessage { block }).await? + } +} diff --git a/crates/rooch-finality/src/rpc_client.rs b/crates/rooch-finality/src/rpc_client.rs new file mode 100644 index 0000000000..a7689299d2 --- /dev/null +++ b/crates/rooch-finality/src/rpc_client.rs @@ -0,0 +1,146 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use tonic::{transport::Channel, Request}; + +use crate::proto::proto::finality_gadget_client::FinalityGadgetClient; +use crate::proto::proto::{ + BlockInfo, QueryBlockRangeBabylonFinalizedRequest, QueryBtcStakingActivatedTimestampRequest, + QueryIsBlockBabylonFinalizedRequest, QueryIsBlockFinalizedByHashRequest, + QueryIsBlockFinalizedByHeightRequest, QueryLatestFinalizedBlockRequest, +}; +use anyhow::{anyhow, Result}; +use rooch_types::finality_block::Block; + +pub struct FinalityGadgetGrpcClient { + client: FinalityGadgetClient, +} + +impl FinalityGadgetGrpcClient { + pub async fn new(remote_addr: String) -> Result { + let channel = Channel::from_shared(remote_addr)? + .connect() + .await + .map_err(|e| anyhow!(format!("new error: {:?}", e)))?; + + let client = FinalityGadgetClient::new(channel); + + Ok(Self { client }) + } + + pub async fn query_is_block_babylon_finalized(&mut self, block: &Block) -> Result { + let req = Request::new(QueryIsBlockBabylonFinalizedRequest { + block: Some(BlockInfo { + block_hash: block.block_hash.clone(), + block_height: block.block_height, + block_timestamp: block.block_timestamp, + }), + }); + + let response = self + .client + .query_is_block_babylon_finalized(req) + .await + .map_err(|e| anyhow!(format!("query_is_block_babylon_finalized error: {:?}", e)))?; + Ok(response.into_inner().is_finalized) + } + + pub async fn query_block_range_babylon_finalized( + &mut self, + blocks: &[Block], + ) -> Result> { + let block_infos: Vec = blocks + .iter() + .map(|block| BlockInfo { + block_hash: block.block_hash.clone(), + block_height: block.block_height, + block_timestamp: block.block_timestamp, + }) + .collect(); + + let req = Request::new(QueryBlockRangeBabylonFinalizedRequest { + blocks: block_infos, + }); + + let response = self + .client + .query_block_range_babylon_finalized(req) + .await + .map_err(|e| { + anyhow!(format!( + "query_block_range_babylon_finalized error: {:?}", + e + )) + })?; + let height = response.into_inner().last_finalized_block_height; + + if height == 0 { + Ok(None) + } else { + Ok(Some(height)) + } + } + + pub async fn query_btc_staking_activated_timestamp(&mut self) -> Result { + let req = Request::new(QueryBtcStakingActivatedTimestampRequest {}); + + let response = self + .client + .query_btc_staking_activated_timestamp(req) + .await + .map_err(|e| { + anyhow!(format!( + "query_btc_staking_activated_timestamp error: {:?}", + e + )) + })?; + Ok(response.into_inner().activated_timestamp) + } + + pub async fn query_is_block_finalized_by_height(&mut self, height: u64) -> Result { + let req = Request::new(QueryIsBlockFinalizedByHeightRequest { + block_height: height, + }); + + let response = self + .client + .query_is_block_finalized_by_height(req) + .await + .map_err(|e| anyhow!(format!("query_is_block_finalized_by_height error: {:?}", e)))?; + Ok(response.into_inner().is_finalized) + } + + pub async fn query_is_block_finalized_by_hash(&mut self, hash: String) -> Result { + let req = Request::new(QueryIsBlockFinalizedByHashRequest { block_hash: hash }); + + let response = self + .client + .query_is_block_finalized_by_hash(req) + .await + .map_err(|e| anyhow!(format!("query_is_block_finalized_by_hash error: {:?}", e)))?; + Ok(response.into_inner().is_finalized) + } + + pub async fn query_latest_finalized_block(&mut self) -> Result { + let req = Request::new(QueryLatestFinalizedBlockRequest {}); + + let response = self + .client + .query_latest_finalized_block(req) + .await + .map_err(|e| anyhow!(format!("query_latest_finalized_block error: {:?}", e)))?; + let block = response.into_inner().block.unwrap(); + + Ok(Block { + block_hash: block.block_hash, + block_height: block.block_height, + block_timestamp: block.block_timestamp, + }) + } +} + +impl Drop for FinalityGadgetGrpcClient { + fn drop(&mut self) { + // Channel cleanup is handled automatically by tonic + } +} diff --git a/crates/rooch-finality/src/types/errors.rs b/crates/rooch-finality/src/types/errors.rs new file mode 100644 index 0000000000..3f64d125b4 --- /dev/null +++ b/crates/rooch-finality/src/types/errors.rs @@ -0,0 +1,17 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("block not found")] + BlockNotFound, + + #[error("no FP has voting power for the consumer chain")] + NoFpHasVotingPower, + + #[error("BTC staking is not activated for the consumer chain")] + BtcStakingNotActivated, + + #[error("BTC staking activated timestamp not found")] + ActivatedTimestampNotFound, +} diff --git a/crates/rooch-finality/src/types/mod.rs b/crates/rooch-finality/src/types/mod.rs new file mode 100644 index 0000000000..b7ba5e7ffd --- /dev/null +++ b/crates/rooch-finality/src/types/mod.rs @@ -0,0 +1,5 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +pub mod errors; +pub mod transaction; diff --git a/crates/rooch-finality/src/types/transaction.rs b/crates/rooch-finality/src/types/transaction.rs new file mode 100644 index 0000000000..bf2aafe0f0 --- /dev/null +++ b/crates/rooch-finality/src/types/transaction.rs @@ -0,0 +1,30 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct TransactionInfo { + #[serde(rename = "txHash")] + pub tx_hash: String, + #[serde(rename = "blockHash")] + pub block_hash: String, + pub status: FinalityStatus, + #[serde(rename = "blockTimestamp")] + pub block_timestamp: u64, + #[serde(rename = "blockHeight")] + pub block_height: u64, + #[serde(rename = "babylonFinalized")] + pub babylon_finalized: bool, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum FinalityStatus { + Pending, + Unsafe, + #[serde(rename = "btc finalized")] + BitcoinFinalized, + Safe, + Finalized, +} diff --git a/crates/rooch-open-rpc-spec/schemas/openrpc.json b/crates/rooch-open-rpc-spec/schemas/openrpc.json index 3b3fca4ce8..781dbc6a09 100644 --- a/crates/rooch-open-rpc-spec/schemas/openrpc.json +++ b/crates/rooch-open-rpc-spec/schemas/openrpc.json @@ -249,6 +249,42 @@ } } }, + { + "name": "rooch_getBlocksByNumber", + "params": [ + { + "name": "block_type", + "schema": { + "$ref": "#/components/schemas/rooch_types::block::BlockType" + } + }, + { + "name": "cursor", + "schema": { + "$ref": "#/components/schemas/u128" + } + }, + { + "name": "limit", + "schema": { + "$ref": "#/components/schemas/u64" + } + }, + { + "name": "descending_order", + "schema": { + "type": "boolean" + } + } + ], + "result": { + "name": "BlockPageView", + "required": true, + "schema": { + "$ref": "#/components/schemas/PageView_for_BlockView_and_u128" + } + } + }, { "name": "rooch_getChainID", "params": [], @@ -1062,6 +1098,40 @@ } } }, + "BlockView": { + "type": "object", + "required": [ + "block_hash", + "block_number", + "time" + ], + "properties": { + "block_hash": { + "description": "How many transactions in the block The hash of the block, made by DA", + "allOf": [ + { + "$ref": "#/components/schemas/primitive_types::H256" + } + ] + }, + "block_number": { + "description": "The index if the block", + "allOf": [ + { + "$ref": "#/components/schemas/u128" + } + ] + }, + "time": { + "description": "The previous tx accumulator root of the block The tx accumulator root after the last transaction append to the accumulator The last transaction's state root the block generate timestamp", + "allOf": [ + { + "$ref": "#/components/schemas/u64" + } + ] + } + } + }, "DAInfoView": { "type": "object", "properties": { @@ -2594,6 +2664,35 @@ } } }, + "PageView_for_BlockView_and_u128": { + "description": "`next_cursor` points to the last item in the page; Reading with `next_cursor` will start from the next item after `next_cursor` if `next_cursor` is `Some`, otherwise it will start from the first item.", + "type": "object", + "required": [ + "data", + "has_next_page" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BlockView" + } + }, + "has_next_page": { + "type": "boolean" + }, + "next_cursor": { + "anyOf": [ + { + "$ref": "#/components/schemas/u128" + }, + { + "type": "null" + } + ] + } + } + }, "PageView_for_EventView_and_u64": { "description": "`next_cursor` points to the last item in the page; Reading with `next_cursor` will start from the next item after `next_cursor` if `next_cursor` is `Some`, otherwise it will start from the first item.", "type": "object", @@ -3014,6 +3113,13 @@ "enum": [ "date-import-mode" ] + }, + { + "description": "The service is in finality mode.", + "type": "string", + "enum": [ + "finality-mode" + ] } ] }, @@ -3731,6 +3837,9 @@ "rooch_types::bitcoin::ord::InscriptionID": { "type": "string" }, + "rooch_types::block::BlockType": { + "type": "string" + }, "rooch_types::repair::RepairIndexerType": { "type": "string" }, diff --git a/crates/rooch-proposer/Cargo.toml b/crates/rooch-proposer/Cargo.toml index 09db9c3144..aaa35c582b 100644 --- a/crates/rooch-proposer/Cargo.toml +++ b/crates/rooch-proposer/Cargo.toml @@ -25,3 +25,4 @@ metrics = { workspace = true } rooch-config = { workspace = true } rooch-types = { workspace = true } rooch-store = { workspace = true } +serde = { version = "1.0.197", features = ["derive"] } diff --git a/crates/rooch-proposer/src/actor/messages.rs b/crates/rooch-proposer/src/actor/messages.rs deleted file mode 100644 index d28ad9c31f..0000000000 --- a/crates/rooch-proposer/src/actor/messages.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use coerce::actor::{message::Message, scheduler::timer::TimerTick}; - -#[derive(Clone)] -pub struct ProposeBlock {} - -impl Message for ProposeBlock { - type Result = (); -} - -impl TimerTick for ProposeBlock {} diff --git a/crates/rooch-proposer/src/actor/mod.rs b/crates/rooch-proposer/src/actor/mod.rs index 5561bd0964..e8ae81edd7 100644 --- a/crates/rooch-proposer/src/actor/mod.rs +++ b/crates/rooch-proposer/src/actor/mod.rs @@ -1,5 +1,4 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -pub mod messages; pub mod proposer; diff --git a/crates/rooch-proposer/src/actor/proposer.rs b/crates/rooch-proposer/src/actor/proposer.rs index a8a26d41df..41a6e7ae8f 100644 --- a/crates/rooch-proposer/src/actor/proposer.rs +++ b/crates/rooch-proposer/src/actor/proposer.rs @@ -1,9 +1,10 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -use super::messages::ProposeBlock; +use crate::messages::{GetBlocksMessage, GetLastestBlockNumberMessage, ProposeBlock}; use crate::metrics::ProposerMetrics; use crate::scc::StateCommitmentChain; +use anyhow::Result; use async_trait::async_trait; use coerce::actor::{context::ActorContext, message::Handler, Actor}; use moveos_store::MoveOSStore; @@ -11,6 +12,7 @@ use prometheus::Registry; use rooch_config::proposer_config::ProposerConfig; use rooch_store::proposer_store::ProposerStore; use rooch_store::RoochStore; +use rooch_types::block::Block; use rooch_types::crypto::RoochKeyPair; use std::sync::Arc; @@ -99,3 +101,26 @@ impl Handler for ProposerActor { } } } + +#[async_trait] +impl Handler for ProposerActor { + async fn handle( + &mut self, + msg: GetBlocksMessage, + _ctx: &mut ActorContext, + ) -> Result>> { + let GetBlocksMessage { block_numbers } = msg; + self.scc.get_blocks(block_numbers) + } +} + +#[async_trait] +impl Handler for ProposerActor { + async fn handle( + &mut self, + _msg: GetLastestBlockNumberMessage, + _ctx: &mut ActorContext, + ) -> Result { + Ok(self.scc.lastest_proposed_block_number()) + } +} diff --git a/crates/rooch-proposer/src/lib.rs b/crates/rooch-proposer/src/lib.rs index a4146b4686..1fe458b0fd 100644 --- a/crates/rooch-proposer/src/lib.rs +++ b/crates/rooch-proposer/src/lib.rs @@ -2,5 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 pub mod actor; +pub mod messages; pub mod metrics; +pub mod proxy; pub mod scc; diff --git a/crates/rooch-proposer/src/messages.rs b/crates/rooch-proposer/src/messages.rs new file mode 100644 index 0000000000..db80f0c545 --- /dev/null +++ b/crates/rooch-proposer/src/messages.rs @@ -0,0 +1,32 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Result; +use coerce::actor::{message::Message, scheduler::timer::TimerTick}; +use rooch_types::block::Block; +use serde::{Deserialize, Serialize}; + +#[derive(Clone)] +pub struct ProposeBlock {} + +impl Message for ProposeBlock { + type Result = (); +} + +impl TimerTick for ProposeBlock {} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GetBlocksMessage { + pub block_numbers: Vec, +} + +impl Message for GetBlocksMessage { + type Result = Result>>; +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GetLastestBlockNumberMessage {} + +impl Message for GetLastestBlockNumberMessage { + type Result = Result; +} diff --git a/crates/rooch-proposer/src/proxy/mod.rs b/crates/rooch-proposer/src/proxy/mod.rs new file mode 100644 index 0000000000..d93711c14a --- /dev/null +++ b/crates/rooch-proposer/src/proxy/mod.rs @@ -0,0 +1,27 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::actor::proposer::ProposerActor; +use crate::messages::{GetBlocksMessage, GetLastestBlockNumberMessage}; +use anyhow::Result; +use coerce::actor::ActorRef; +use rooch_types::block::Block; + +#[derive(Clone)] +pub struct ProposerProxy { + pub actor: ActorRef, +} + +impl ProposerProxy { + pub fn new(actor: ActorRef) -> Self { + Self { actor } + } + + pub async fn get_blocks(&self, block_numbers: Vec) -> Result>> { + self.actor.send(GetBlocksMessage { block_numbers }).await? + } + + pub async fn latest_block_number(&self) -> Result { + self.actor.send(GetLastestBlockNumberMessage {}).await? + } +} diff --git a/crates/rooch-proposer/src/scc/mod.rs b/crates/rooch-proposer/src/scc/mod.rs index a7732e89ad..8ac3a3e397 100644 --- a/crates/rooch-proposer/src/scc/mod.rs +++ b/crates/rooch-proposer/src/scc/mod.rs @@ -76,12 +76,46 @@ impl StateCommitmentChain { prev_tx_accumulator_root, tx_accumulator_root, tx_state_root, + 0, )) } None => Err(anyhow::anyhow!("No block has been proposed")), } } + // TODO fill Block fields when necessary + // Skip check when multi get blocks, distinguish with get block by signle + pub fn get_blocks(&self, block_number: Vec) -> anyhow::Result>> { + let block_da_submit_states = self.rooch_store.try_get_block_states(block_number)?; + block_da_submit_states + .into_iter() + .map( + |block_da_submit_state_opt| match block_da_submit_state_opt { + Some(block_da_submit_state) => { + if !block_da_submit_state.done { + return Err(anyhow::anyhow!( + "block: {} is not done but proposed. database is inconsistent", + block_da_submit_state.block_range.block_number, + )); + } + let block_range = block_da_submit_state.block_range; + let batch_size = block_range.tx_order_end - block_range.tx_order_start + 1; + Ok(Some(Block::new( + block_range.block_number, + batch_size, + block_da_submit_state.batch_hash, + H256::zero(), + H256::zero(), + H256::zero(), + 0, + ))) + } + None => Ok(None), + }, + ) + .collect::, _>>() + } + // get_roots returns the tx accumulator root & state root of the transaction with the given tx_order fn get_roots(&self, tx_order: u64) -> anyhow::Result<(H256, H256)> { let mut ledger_tx = get_ledger_tx(self.rooch_store.clone(), tx_order)?; @@ -138,6 +172,8 @@ impl StateCommitmentChain { prev_tx_accumulator_root, tx_accumulator_root, tx_state_root, + // TODO generate block timestamp + 0, ); self.last_proposed_block_number = Some(block_number); self.last_proposed_block_accumulator_root = tx_accumulator_root; @@ -173,6 +209,10 @@ impl StateCommitmentChain { } } } + + pub fn lastest_proposed_block_number(&self) -> u128 { + self.last_proposed_block_number.unwrap_or(0) + } } fn get_ledger_tx(rooch_store: RoochStore, tx_order: u64) -> anyhow::Result { diff --git a/crates/rooch-rpc-api/src/api/rooch_api.rs b/crates/rooch-rpc-api/src/api/rooch_api.rs index b90617b03b..a67945c87e 100644 --- a/crates/rooch-rpc-api/src/api/rooch_api.rs +++ b/crates/rooch-rpc-api/src/api/rooch_api.rs @@ -3,13 +3,14 @@ use crate::jsonrpc_types::account_view::BalanceInfoView; use crate::jsonrpc_types::address::UnitedAddressView; +use crate::jsonrpc_types::block_view::BlockTypeView; use crate::jsonrpc_types::event_view::{EventFilterView, IndexerEventIDView}; use crate::jsonrpc_types::repair_view::{RepairIndexerParamsView, RepairIndexerTypeView}; use crate::jsonrpc_types::transaction_view::{TransactionFilterView, TransactionWithInfoView}; use crate::jsonrpc_types::{ - AccessPathView, AnnotatedFunctionResultView, BalanceInfoPageView, BytesView, EventOptions, - EventPageView, ExecuteTransactionResponseView, FieldKeyView, FunctionCallView, H256View, - IndexerEventPageView, IndexerObjectStatePageView, IndexerStateIDView, ModuleABIView, + AccessPathView, AnnotatedFunctionResultView, BalanceInfoPageView, BlockPageView, BytesView, + EventOptions, EventPageView, ExecuteTransactionResponseView, FieldKeyView, FunctionCallView, + H256View, IndexerEventPageView, IndexerObjectStatePageView, IndexerStateIDView, ModuleABIView, ObjectIDVecView, ObjectIDView, ObjectStateFilterView, ObjectStateView, QueryOptions, RoochAddressView, StateChangeSetPageView, StateOptions, StatePageView, StrView, StructTagView, SyncStateFilterView, TransactionWithInfoPageView, TxOptions, @@ -214,4 +215,13 @@ pub trait RoochAPI { /// Get the chain and service status #[method(name = "status")] async fn status(&self) -> RpcResult; + + #[method(name = "getBlocksByNumber")] + async fn get_blocks_by_number( + &self, + block_type: Option, + cursor: Option>, + limit: Option>, + descending_order: Option, + ) -> RpcResult; } diff --git a/crates/rooch-rpc-api/src/jsonrpc_types/block_view.rs b/crates/rooch-rpc-api/src/jsonrpc_types/block_view.rs new file mode 100644 index 0000000000..27985b09eb --- /dev/null +++ b/crates/rooch-rpc-api/src/jsonrpc_types/block_view.rs @@ -0,0 +1,51 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::jsonrpc_types::{H256View, StrView}; +use rooch_types::block::{Block, BlockType}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct BlockView { + /// The index if the block + pub block_number: StrView, + /// How many transactions in the block + // pub batch_size: StrView, + /// The hash of the block, made by DA + pub block_hash: H256View, + /// The previous tx accumulator root of the block + // pub prev_tx_accumulator_root: H256View, + /// The tx accumulator root after the last transaction append to the accumulator + // pub tx_accumulator_root: H256View, + /// The last transaction's state root + // pub state_root: H256View, + /// the block generate timestamp + pub time: StrView, +} + +impl From for BlockView { + fn from(block: Block) -> Self { + Self { + block_number: block.block_number.into(), + block_hash: block.block_hash.into(), + time: block.time.into(), + } + } +} + +pub type BlockTypeView = StrView; + +impl std::fmt::Display for BlockTypeView { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl FromStr for BlockTypeView { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + Ok(StrView(BlockType::from_str(s)?)) + } +} diff --git a/crates/rooch-rpc-api/src/jsonrpc_types/mod.rs b/crates/rooch-rpc-api/src/jsonrpc_types/mod.rs index d6811d5386..154ca814b0 100644 --- a/crates/rooch-rpc-api/src/jsonrpc_types/mod.rs +++ b/crates/rooch-rpc-api/src/jsonrpc_types/mod.rs @@ -24,6 +24,7 @@ pub mod json_to_table_display; pub mod transaction_view; pub mod address; +pub mod block_view; pub mod btc; pub mod repair_view; diff --git a/crates/rooch-rpc-api/src/jsonrpc_types/rooch_types.rs b/crates/rooch-rpc-api/src/jsonrpc_types/rooch_types.rs index e9303460c2..8fdda1d744 100644 --- a/crates/rooch-rpc-api/src/jsonrpc_types/rooch_types.rs +++ b/crates/rooch-rpc-api/src/jsonrpc_types/rooch_types.rs @@ -4,6 +4,7 @@ use super::event_view::IndexerEventIDView; use super::{HumanReadableDisplay, IndexerStateIDView, StateChangeSetWithTxOrderView}; use crate::jsonrpc_types::account_view::BalanceInfoView; +use crate::jsonrpc_types::block_view::BlockView; use crate::jsonrpc_types::btc::ord::InscriptionStateView; use crate::jsonrpc_types::btc::utxo::UTXOStateView; use crate::jsonrpc_types::event_view::{EventView, IndexerEventView}; @@ -31,6 +32,8 @@ pub type UTXOPageView = PageView; pub type InscriptionPageView = PageView; pub type StateChangeSetPageView = PageView>; +pub type BlockPageView = PageView>; + /// `next_cursor` points to the last item in the page; /// Reading with `next_cursor` will start from the next item after `next_cursor` if /// `next_cursor` is `Some`, otherwise it will start from the first item. diff --git a/crates/rooch-rpc-server/src/lib.rs b/crates/rooch-rpc-server/src/lib.rs index 758ee00a47..e70ee7f6c9 100644 --- a/crates/rooch-rpc-server/src/lib.rs +++ b/crates/rooch-rpc-server/src/lib.rs @@ -35,8 +35,9 @@ use rooch_indexer::actor::reader_indexer::IndexerReaderActor; use rooch_indexer::proxy::IndexerProxy; use rooch_pipeline_processor::actor::processor::PipelineProcessorActor; use rooch_pipeline_processor::proxy::PipelineProcessorProxy; -use rooch_proposer::actor::messages::ProposeBlock; use rooch_proposer::actor::proposer::ProposerActor; +use rooch_proposer::messages::ProposeBlock; +use rooch_proposer::proxy::ProposerProxy; use rooch_relayer::actor::messages::RelayTick; use rooch_relayer::actor::relayer::RelayerActor; use rooch_rpc_api::api::RoochRpcModule; @@ -328,6 +329,7 @@ pub async fn run_start_server(opt: RoochOpt, server_opt: ServerOpt) -> Result Result, + cursor: Option>, + limit: Option>, + descending_order: Option, + ) -> RpcResult { + // TODO filter by blcok type + let latest_block_number = self.rpc_service.latest_block_number().await?; + + let limit_of = min( + limit + .map(Into::into) + .unwrap_or(DEFAULT_RESULT_LIMIT_USIZE as u64), + MAX_RESULT_LIMIT_USIZE as u64, + ); + + let descending_order = descending_order.unwrap_or(true); + let cursor = cursor.map(|v| v.0); + + let block_numbers = if descending_order { + let start = cursor.unwrap_or(latest_block_number + 1); + let end = if start >= (limit_of as u128) { + start - (limit_of as u128) + } else { + 0 + }; + + (end..start).rev().collect::>() + } else { + let start = cursor.unwrap_or(0); + let start_plus = + start + .checked_add((limit_of + 1) as u128) + .ok_or(RpcError::UnexpectedError( + "cursor value is overflow".to_string(), + ))?; + let end = min(start_plus, latest_block_number + 1); + + (start..end).collect::>() + }; + + let blocks = self.rpc_service.get_blocks(block_numbers.clone()).await?; + + let mut data = blocks + .into_iter() + .map(|v| v.map(BlockView::from)) + .flatten() + .collect::>(); + + let has_next_page = (data.len() as u64) > limit_of; + data.truncate(limit_of as usize); + + let next_cursor = data.last().map_or(cursor, |v| Some(v.block_number.0)); + Ok(BlockPageView { + data, + next_cursor: next_cursor.map(StrView), + has_next_page, + }) + } } impl RoochRpcModule for RoochServer { diff --git a/crates/rooch-rpc-server/src/service/rpc_service.rs b/crates/rooch-rpc-server/src/service/rpc_service.rs index 74d3511552..df16987540 100644 --- a/crates/rooch-rpc-server/src/service/rpc_service.rs +++ b/crates/rooch-rpc-server/src/service/rpc_service.rs @@ -22,6 +22,7 @@ use rooch_executor::actor::messages::DryRunTransactionResult; use rooch_executor::proxy::ExecutorProxy; use rooch_indexer::proxy::IndexerProxy; use rooch_pipeline_processor::proxy::PipelineProcessorProxy; +use rooch_proposer::proxy::ProposerProxy; use rooch_rpc_api::jsonrpc_types::{ BitcoinStatus, DisplayFieldsView, IndexerObjectStateView, ObjectMetaView, RoochStatus, Status, }; @@ -29,6 +30,7 @@ use rooch_sequencer::proxy::SequencerProxy; use rooch_types::address::{BitcoinAddress, RoochAddress}; use rooch_types::bitcoin::pending_block::PendingBlockModule; use rooch_types::bitcoin::BitcoinModule; +use rooch_types::block::Block; use rooch_types::framework::address_mapping::RoochToBitcoinAddressMapping; use rooch_types::indexer::event::{ AnnotatedIndexerEvent, EventFilter, IndexerEvent, IndexerEventID, @@ -54,6 +56,7 @@ pub struct RpcService { bitcoin_network: u8, pub(crate) executor: ExecutorProxy, pub(crate) sequencer: SequencerProxy, + pub(crate) proposer: ProposerProxy, pub(crate) indexer: IndexerProxy, pub(crate) pipeline_processor: PipelineProcessorProxy, pub(crate) bitcoin_client: Option, @@ -66,6 +69,7 @@ impl RpcService { bitcoin_network: u8, executor: ExecutorProxy, sequencer: SequencerProxy, + proposer: ProposerProxy, indexer: IndexerProxy, pipeline_processor: PipelineProcessorProxy, bitcoin_client: Option, @@ -76,6 +80,7 @@ impl RpcService { bitcoin_network, executor, sequencer, + proposer, indexer, pipeline_processor, bitcoin_client, @@ -827,4 +832,14 @@ impl RpcService { bitcoin_status, }) } + + pub async fn get_blocks(&self, block_numbers: Vec) -> Result>> { + let resp = self.proposer.get_blocks(block_numbers).await?; + Ok(resp) + } + + pub async fn latest_block_number(&self) -> Result { + let resp = self.proposer.latest_block_number().await?; + Ok(resp) + } } diff --git a/crates/rooch-store/src/da_store/mod.rs b/crates/rooch-store/src/da_store/mod.rs index 9dd78a4183..e7b0a69817 100644 --- a/crates/rooch-store/src/da_store/mod.rs +++ b/crates/rooch-store/src/da_store/mod.rs @@ -79,6 +79,10 @@ pub trait DAMetaStore { fn get_block_state(&self, block_number: u128) -> anyhow::Result; // get block state by block_number, return None if not exist fn try_get_block_state(&self, block_number: u128) -> anyhow::Result>; + fn try_get_block_states( + &self, + block_numbers: Vec, + ) -> anyhow::Result>>; } #[derive(Clone)] @@ -555,4 +559,11 @@ impl DAMetaStore for DAMetaDBStore { fn try_get_block_state(&self, block_number: u128) -> anyhow::Result> { self.get_block_state_opt(block_number) } + + fn try_get_block_states( + &self, + block_numbers: Vec, + ) -> anyhow::Result>> { + self.block_submit_state_store.multiple_get(block_numbers) + } } diff --git a/crates/rooch-store/src/lib.rs b/crates/rooch-store/src/lib.rs index 4157ea618a..ccb493052d 100644 --- a/crates/rooch-store/src/lib.rs +++ b/crates/rooch-store/src/lib.rs @@ -393,6 +393,13 @@ impl DAMetaStore for RoochStore { fn try_get_block_state(&self, block_number: u128) -> Result> { self.get_da_meta_store().try_get_block_state(block_number) } + + fn try_get_block_states( + &self, + block_numbers: Vec, + ) -> Result>> { + self.get_da_meta_store().try_get_block_states(block_numbers) + } } impl ProposerStore for RoochStore { diff --git a/crates/rooch-types/src/block.rs b/crates/rooch-types/src/block.rs index a3e75a3ced..1e434f3697 100644 --- a/crates/rooch-types/src/block.rs +++ b/crates/rooch-types/src/block.rs @@ -1,8 +1,12 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 +use anyhow::format_err; use moveos_types::h256::H256; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use std::fmt::Display; +use std::str::FromStr; /// The block in Rooch is constructed by the proposer, representing a batch of transactions #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] @@ -11,32 +15,64 @@ pub struct Block { pub block_number: u128, /// How many transactions in the block pub batch_size: u64, - /// The hash of the batch, made by DA - pub batch_hash: H256, + /// The hash of the block, made by DA + pub block_hash: H256, /// The previous tx accumulator root of the block pub prev_tx_accumulator_root: H256, /// The tx accumulator root after the last transaction append to the accumulator pub tx_accumulator_root: H256, /// The last transaction's state root pub state_root: H256, + /// the block generate timestamp + pub time: u64, } impl Block { pub fn new( block_number: u128, batch_size: u64, - batch_hash: H256, + block_hash: H256, prev_tx_accumulator_root: H256, tx_accumulator_root: H256, state_root: H256, + time: u64, ) -> Self { Self { block_number, batch_size, - batch_hash, + block_hash, prev_tx_accumulator_root, tx_accumulator_root, state_root, + time, + } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum BlockType { + All, + Finalized, +} + +impl Display for BlockType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BlockType::All => write!(f, "all"), + BlockType::Finalized => write!(f, "finalized"), + } + } +} + +impl FromStr for BlockType { + type Err = anyhow::Error; + + fn from_str(s: &str) -> anyhow::Result { + match s.to_lowercase().as_str() { + "all" => Ok(BlockType::All), + "finalized" => Ok(BlockType::Finalized), + s => Err(format_err!("Invalid block type str: {}", s)), } } } diff --git a/crates/rooch-types/src/finality_block.rs b/crates/rooch-types/src/finality_block.rs new file mode 100644 index 0000000000..16f3f70402 --- /dev/null +++ b/crates/rooch-types/src/finality_block.rs @@ -0,0 +1,50 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use moveos_types::h256::H256; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Block { + #[serde(rename = "block_hash")] + pub block_hash: String, + #[serde(rename = "block_height")] + pub block_height: u64, + #[serde(rename = "block_timestamp")] + pub block_timestamp: u64, +} + +// Types and Structs +#[derive(Clone, Debug, Default, PartialEq)] +pub struct BlockID { + pub number: u64, + pub hash: String, +} + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct L1BlockRef { + pub hash: String, + pub number: u64, + pub time: u64, + pub parent_hash: String, +} + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct L2BlockRef { + pub hash: H256, + pub number: u64, + pub time: u64, + pub parent_hash: H256, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ChainSyncStatus { + #[serde(rename = "latest_block")] + pub latest_block_height: u64, + #[serde(rename = "latest_btc_finalized_block")] + pub latest_btc_finalized_block_height: u64, + #[serde(rename = "earliest_btc_finalized_block")] + pub earliest_btc_finalized_block_height: u64, + #[serde(rename = "latest_eth_finalized_block")] + pub latest_eth_finalized_block_height: u64, +} diff --git a/crates/rooch-types/src/lib.rs b/crates/rooch-types/src/lib.rs index 6612bd4aeb..38a09a09a4 100644 --- a/crates/rooch-types/src/lib.rs +++ b/crates/rooch-types/src/lib.rs @@ -29,4 +29,5 @@ pub mod test_utils; pub mod to_bech32; pub mod transaction; +pub mod finality_block; pub mod service_type; diff --git a/crates/rooch-types/src/service_status.rs b/crates/rooch-types/src/service_status.rs index 2fc5a08aeb..f7ded63352 100644 --- a/crates/rooch-types/src/service_status.rs +++ b/crates/rooch-types/src/service_status.rs @@ -18,6 +18,8 @@ pub enum ServiceStatus { ReadOnlyMode, /// The service is in date import mode. DateImportMode, + /// The service is in finality mode. + FinalityMode, } impl ServiceStatus { @@ -36,4 +38,7 @@ impl ServiceStatus { pub fn is_date_import_mode(&self) -> bool { matches!(self, ServiceStatus::DateImportMode) } + pub fn is_finality_mode(&self) -> bool { + matches!(self, ServiceStatus::FinalityMode) + } } diff --git a/docker/DockerfilePoc b/docker/DockerfilePoc new file mode 100644 index 0000000000..f1ef854045 --- /dev/null +++ b/docker/DockerfilePoc @@ -0,0 +1,105 @@ +#FROM ubuntu:jammy AS builder +FROM ubuntu:jammy AS builder + +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + libc6-dev \ + git \ + libssl-dev \ + wget \ + pkg-config \ + libclang-dev clang \ + llvm \ + lld \ + libsnappy-dev \ + g++ \ + cmake \ + make \ + libprotobuf-dev \ + protobuf-compiler \ + build-essential \ + libreadline-dev; \ + rm -rf /var/lib/apt/lists/* + +# Install SQLite 3.46.1 with multi-threading enabled +RUN set -eux; \ + wget https://www.sqlite.org/2024/sqlite-autoconf-3460100.tar.gz; \ + tar xvf sqlite-autoconf-3460100.tar.gz; \ + cd sqlite-autoconf-3460100; \ + CFLAGS="-DSQLITE_THREADSAFE=2" ./configure --prefix=/usr/local; \ + make; \ + make install; \ + cd ..; \ + rm -rf sqlite-autoconf-3460100 sqlite-autoconf-3460100.tar.gz; \ + ldconfig + +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:/usr/local/bin:$PATH \ + RUSTUP_VERSION=1.26.0 \ + RUSTUP_SHA256=0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db \ + RUST_ARCH=x86_64-unknown-linux-gnu + +RUN set -eux; \ + url="https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/${RUST_ARCH}/rustup-init"; \ + wget "$url"; \ + echo "${RUSTUP_SHA256} *rustup-init" | sha256sum -c -; \ + chmod +x rustup-init + +RUN set -eux; \ + wget "http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.23_amd64.deb"; \ + DEBIAN_FRONTEND=noninteractive dpkg -i libssl1.1_1.1.1f-1ubuntu2.23_amd64.deb; + +ENV RUST_VERSION=1.78.0 + +RUN set -eux; \ + ./rustup-init -y --no-modify-path --default-toolchain $RUST_VERSION; \ + rm rustup-init; \ + chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \ + rustup --version; \ + cargo --version; \ + rustc --version; + +WORKDIR /rooch +COPY ./ . +RUN #cargo build --release +RUN cargo build + +FROM ubuntu:jammy +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + wget \ + libssl-dev \ + build-essential \ + libreadline-dev; \ + rm -rf /var/lib/apt/lists/* + +# Install SQLite 3.46.1 with multi-threading enabled +RUN set -eux; \ + wget https://www.sqlite.org/2024/sqlite-autoconf-3460100.tar.gz; \ + tar xvf sqlite-autoconf-3460100.tar.gz; \ + cd sqlite-autoconf-3460100; \ + CFLAGS="-DSQLITE_THREADSAFE=2" ./configure --prefix=/usr/local; \ + make; \ + make install; \ + cd ..; \ + rm -rf sqlite-autoconf-3460100 sqlite-autoconf-3460100.tar.gz; \ + ldconfig + +RUN set -eux; \ + wget "http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.23_amd64.deb"; \ + DEBIAN_FRONTEND=noninteractive dpkg -i libssl1.1_1.1.1f-1ubuntu2.23_amd64.deb; + +#ENV RELEASE_PATH="/rooch/target/release" +ENV RELEASE_PATH="/rooch/target/debug" +COPY --from=builder $RELEASE_PATH/rooch \ + /rooch/ + + +ENTRYPOINT [ "/rooch/rooch" ] +CMD [ "server", "start" ] \ No newline at end of file