Skip to content

Commit

Permalink
feat(voyager): introduce berachain consensus plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
hussein-aitlahcen committed Dec 17, 2024
1 parent ee2633c commit 8878d9b
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 293 deletions.
59 changes: 58 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@ members = [
"voyager/modules/client/movement",
"voyager/modules/client/tendermint",

"voyager/modules/consensus/berachain",
"voyager/modules/consensus/cometbls",
"voyager/modules/consensus/ethereum",
"voyager/modules/consensus/movement",
"voyager/modules/consensus/tendermint",

"voyager/plugins/client-update/berachain",
"voyager/plugins/client-update/cometbls",
"voyager/plugins/client-update/ethereum",
"voyager/plugins/client-update/movement",
Expand Down Expand Up @@ -252,6 +254,8 @@ voyager-core = { path = "lib/voyager-core", default-features = false }
voyager-message = { path = "lib/voyager-message", default-features = false }
voyager-vm = { path = "lib/voyager-vm", default-features = false }

voyager-consensus-module-tendermint = { path = "voyager/modules/consensus/tendermint", default-features = false }

# external dependencies
milagro_bls = { git = "https://github.com/Snowfork/milagro_bls", rev = "bc2b5b5e8d48b7e2e1bfaa56dc2d93e13cb32095", default-features = false }

Expand Down
15 changes: 7 additions & 8 deletions lib/berachain-light-client-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ name = "berachain-light-client-types"
version = "0.1.0"

[dependencies]
alloy = { workspace = true, features = ["sol-types"], optional = true }
beacon-api-types = { workspace = true }
ethereum-light-client-types = { workspace = true }
protos = { workspace = true, optional = true, features = ["union+ibc+lightclients+berachain+v1"] }
serde = { workspace = true, optional = true, features = ["derive"] }
tendermint-light-client-types = { workspace = true }
thiserror = { workspace = true }
unionlabs = { workspace = true }
alloy = { workspace = true, features = ["sol-types"], optional = true }
beacon-api-types = { workspace = true }
ethereum-light-client-types = { workspace = true }
protos = { workspace = true, optional = true, features = ["union+ibc+lightclients+berachain+v1"] }
serde = { workspace = true, optional = true, features = ["derive"] }
thiserror = { workspace = true }
unionlabs = { workspace = true }

[features]
default = []
Expand Down
2 changes: 1 addition & 1 deletion lib/chain-utils/src/cosmos_sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use unionlabs::{
};

use crate::{
cosmos_sdk::cosmos_sdk_error::{CosmosSdkError, SdkError},
cosmos_sdk::cosmos_sdk_error::CosmosSdkError,
keyring::{ConcurrentKeyring, SignerBalance},
};

Expand Down
29 changes: 29 additions & 0 deletions voyager/modules/consensus/berachain/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
edition = "2021"
name = "voyager-consensus-module-berachain"
version = "0.1.0"

[dependencies]
alloy = { workspace = true, features = ["rpc", "rpc-types", "transports", "transport-http", "transport-ws", "reqwest", "provider-ws"] }
beacon-api-types = { workspace = true, features = ["serde", "ssz"] }
cometbft-rpc = { workspace = true }
dashmap = { workspace = true }
enumorph = { workspace = true }
futures = { workspace = true }
ics23 = { workspace = true }
jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] }
macros = { workspace = true }
num-bigint = { workspace = true }
prost = { workspace = true }
protos = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tendermint-light-client-types = { workspace = true, features = ["proto", "serde"] }
berachain-light-client-types = { workspace = true, features = ["proto", "serde"] }
thiserror = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
unionlabs = { workspace = true }
voyager-message = { workspace = true }
voyager-vm = { workspace = true }
186 changes: 186 additions & 0 deletions voyager/modules/consensus/berachain/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
use std::fmt::Debug;

use alloy::{
providers::{Provider, ProviderBuilder, RootProvider},
transports::BoxTransport,
};
use beacon_api_types::{ExecutionPayloadHeaderSsz, Mainnet};
use berachain_light_client_types::{ClientState, ConsensusState};
use jsonrpsee::{
core::{async_trait, RpcResult},
Extensions,
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tracing::instrument;
use unionlabs::{
berachain::LATEST_EXECUTION_PAYLOAD_HEADER_PREFIX,
encoding::{DecodeAs, Ssz},
hash::H160,
ibc::core::client::height::Height,
};
use voyager_message::{
core::{ChainId, ConsensusType},
into_value,
module::{ConsensusModuleInfo, ConsensusModuleServer},
ConsensusModule, ExtensionsExt, VoyagerClient,
};
use voyager_vm::BoxDynError;

#[tokio::main(flavor = "multi_thread")]
async fn main() {
Module::run().await
}

#[derive(Debug, Clone)]
pub struct Module {
pub l1_client_id: u32,
pub l1_chain_id: ChainId,
pub l2_chain_id: ChainId,
pub ibc_handler_address: H160,
pub eth_provider: RootProvider<BoxTransport>,
pub tm_client: cometbft_rpc::Client,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub l1_client_id: u32,
pub l1_chain_id: ChainId,
pub ibc_handler_address: H160,
pub eth_rpc_api: String,
pub comet_ws_url: String,
}

impl ConsensusModule for Module {
type Config = Config;

async fn new(config: Self::Config, info: ConsensusModuleInfo) -> Result<Self, BoxDynError> {
let tm_client = cometbft_rpc::Client::new(config.comet_ws_url).await?;

let eth_provider = ProviderBuilder::new()
.on_builtin(&config.eth_rpc_api)
.await?;

let l2_chain_id = ChainId::new(eth_provider.get_chain_id().await?.to_string());

info.ensure_chain_id(l2_chain_id.as_str())?;
info.ensure_consensus_type(ConsensusType::BEACON_KIT)?;

Ok(Self {
l1_client_id: config.l1_client_id,
l1_chain_id: config.l1_chain_id,
l2_chain_id,
ibc_handler_address: config.ibc_handler_address,
eth_provider,
tm_client,
})
}
}

#[async_trait]
impl ConsensusModuleServer for Module {
/// Query the latest finalized height of this chain.
#[instrument(skip_all, fields(chain_id = %self.l2_chain_id))]
async fn query_latest_height(&self, ext: &Extensions, finalized: bool) -> RpcResult<Height> {
let voy_client = ext.try_get::<VoyagerClient>()?;
if finalized {
let l1_height = voy_client
.query_latest_height(self.l1_chain_id.clone(), finalized)
.await?;

let raw_execution_header = self
.tm_client
.abci_query(
"store/beacon/key",
[LATEST_EXECUTION_PAYLOAD_HEADER_PREFIX],
// proof for height H must be queried at H-1
Some((l1_height.height() as i64 - 1).try_into().unwrap()),
false,
)
.await
.unwrap();

let execution_header = ExecutionPayloadHeaderSsz::<Mainnet>::decode_as::<Ssz>(
raw_execution_header
.response
.value
.expect("big trouble")
.as_ref(),
)
.unwrap();

Ok(Height::new(execution_header.block_number))
} else {
Ok(Height::new(
self.eth_provider
.get_block_number()
.await
.expect("big trouble"),
))
}
}

/// Query the latest finalized timestamp of this chain.
#[instrument(skip_all, fields(chain_id = %self.l2_chain_id))]
async fn query_latest_timestamp(&self, ext: &Extensions, finalized: bool) -> RpcResult<i64> {
let latest_height = self.query_latest_height(ext, finalized).await?;
let latest_block = self
.eth_provider
.get_block_by_number(
latest_height.height().into(),
alloy::rpc::types::BlockTransactionsKind::Hashes,
)
.await
.expect("big trouble")
.expect("big trouble");
let latest_timestamp: i64 = latest_block
.header
.timestamp
.try_into()
.expect("big trouble");
// Normalize to nanos in order to be compliant with cosmos
Ok(latest_timestamp * 1_000_000_000)
}

#[instrument(skip_all, fields(chain_id = %self.l2_chain_id))]
async fn self_client_state(&self, _: &Extensions, height: Height) -> RpcResult<Value> {
Ok(into_value(ClientState {
l1_client_id: self.l1_client_id,
chain_id: self
.l2_chain_id
.as_str()
.parse()
.expect("self.chain_id is a valid u256"),
latest_height: height.height(),
ibc_contract_address: self.ibc_handler_address,
}))
}

/// The consensus state on this chain at the specified `Height`.
#[instrument(skip_all, fields(chain_id = %self.l2_chain_id))]
async fn self_consensus_state(&self, _: &Extensions, height: Height) -> RpcResult<Value> {
let block = self
.eth_provider
.get_block_by_number(
height.height().into(),
alloy::rpc::types::BlockTransactionsKind::Hashes,
)
.await
.expect("big trouble")
.expect("big trouble");
Ok(into_value(&ConsensusState {
// Normalize to nanos in order to be compliant with cosmos
timestamp: block.header.timestamp * 1_000_000_000,
state_root: block.header.state_root.into(),
storage_root: self
.eth_provider
.get_proof(self.ibc_handler_address.into(), vec![])
.block_id(height.height().into())
.await
.unwrap()
.storage_hash
.0
.into(),
}))
}
}
16 changes: 8 additions & 8 deletions voyager/modules/consensus/ethereum/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,8 @@ impl ConsensusModuleServer for Module {
// TODO: Use a better timestamp type here
#[instrument(skip_all, fields(chain_id = %self.chain_id, finalized))]
async fn query_latest_timestamp(&self, _: &Extensions, finalized: bool) -> RpcResult<i64> {
if finalized {
Ok(self
.beacon_api_client
let latest_timestamp: i64 = if finalized {
self.beacon_api_client
.finality_update()
.await
.map_err(|err| ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>))?
Expand All @@ -175,10 +174,9 @@ impl ConsensusModuleServer for Module {
.execution
.timestamp
.try_into()
.unwrap())
.unwrap()
} else {
Ok(self
.provider
self.provider
.get_block(
BlockNumberOrTag::Latest.into(),
BlockTransactionsKind::Hashes,
Expand All @@ -189,8 +187,10 @@ impl ConsensusModuleServer for Module {
.header
.timestamp
.try_into()
.unwrap())
}
.unwrap()
};
// Normalize to nanos in order to be compliant with cosmos
Ok(latest_timestamp * 1_000_000_000)
}

#[instrument(skip_all, fields(chain_id = %self.chain_id, %height))]
Expand Down
Loading

0 comments on commit 8878d9b

Please sign in to comment.