Skip to content

Commit

Permalink
feat(voyager): split out voyager-core
Browse files Browse the repository at this point in the history
  • Loading branch information
benluelo committed Sep 21, 2024
1 parent 28952f6 commit c522006
Show file tree
Hide file tree
Showing 31 changed files with 434 additions and 387 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ members = [
"lib/unionlabs",
"lib/zktrie-rs",
"lib/voyager-message",
"lib/voyager-core",

"lib/near/near-ibc",
"lib/near/near-light-client",
Expand Down Expand Up @@ -99,6 +100,7 @@ members = [
"lib/aptos-verifier",

"lib/reconnecting-jsonrpc-ws-client",
"lib/voyager-core",
]

[workspace.package]
Expand Down Expand Up @@ -156,6 +158,7 @@ tendermint-verifier = { path = "lib/tendermint-verifier", default-fea
token-factory-api = { path = "cosmwasm/token-factory-api", default-features = false }
ucs01-relay-api = { path = "cosmwasm/ucs01-relay-api", default-features = false }
unionlabs = { path = "lib/unionlabs", default-features = false }
voyager-core = { path = "lib/voyager-core", default-features = false }
voyager-message = { path = "lib/voyager-message", default-features = false }
zktrie = { path = "lib/zktrie-rs", default-features = false }

Expand Down
28 changes: 28 additions & 0 deletions lib/voyager-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
edition = { workspace = true }
license-file = { workspace = true }
name = "voyager-core"
repository = { workspace = true }
resolver = "2"
version = "0.1.0"

[lints]
workspace = true

[dependencies]
enumorph = { workspace = true }
hex = { workspace = true }
# jsonrpsee = { workspace = true, features = ["server", "client", "async-client", "macros", "tracing"] }
macros = { workspace = true }
serde = { workspace = true, features = ["derive"] }
# serde-utils = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
unionlabs = { workspace = true }

[dev-dependencies]
hex-literal = { workspace = true }

[features]
default = []
259 changes: 259 additions & 0 deletions lib/voyager-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
use macros::{apply, model};

/// Represents the IBC interface of a chain. Since multiple chains with
/// different consensus mechanisms can have the same execution environment, this
/// value is used to describe how the IBC state is stored on-chain and how the
/// IBC stack is to be interacted with.
#[apply(str_newtype)]
pub struct IbcInterface;

/// Well-known IBC interfaces, defined as constants for reusability and to allow
/// for pattern matching.
impl IbcInterface<'static> {
/// Native light clients in ibc-go, through the client v1 router. This
/// entrypoint uses protobuf [`Any`] wrapping to route to the correct
/// module, such as "/ibc.lightclients.tendermint.v1.ClientState" for native
/// 07-tendermint clients.
///
/// [`Any`]: https://protobuf.dev/programming-guides/proto3/#any
pub const IBC_GO_V8_NATIVE: &'static str = "ibc-go-v8/native";

/// 08-wasm light clients in ibc-go, through the client v1 router. Similar
/// to the ibc-go-v8/native entrypoint, this module also uses [`Any`]
/// wrapping for client routing, however, there is another level of
/// indirection, since the `Any` routing only routes to the wasm module. All
/// state for wasm clients is [wrapped](wasm-protos), with the internal
/// state being opaque bytes to be interpreted by the light client.
///
/// [`Any`]: https://protobuf.dev/programming-guides/proto3/#any
/// [wasm-protos]: https://github.com/cosmos/ibc-go/blob/release/v8.4.x/proto/ibc/lightclients/wasm/v1/wasm.proto
pub const IBC_GO_V8_08_WASM: &'static str = "ibc-go-v8/08-wasm";

/// Solidity light clients, run via Union's IBC solidity stack. This stack
/// is fully virtualized in the EVM, and as such can be run on any chain
/// running the EVM as part of their execution layer (ethereum, ethereum
/// L2s, berachain, etc).
pub const IBC_SOLIDITY: &'static str = "ibc-solidity";

pub const IBC_MOVE_APTOS: &'static str = "ibc-move/aptos";

// lots more to come - near, fuel - stay tuned
}

/// Newtype for client types. Clients of the same type have the same client
/// state, consensus state, and header (client update) types.
#[apply(str_newtype)]
pub struct ClientType;

/// Well-known client types, defined as constants for reusability and to allow
/// for pattern matching.
impl ClientType<'static> {
/// A client tracking CometBLS consensus.
pub const COMETBLS: &'static str = "cometbls";

/// A client tracking vanilla Tendermint (CometBFT).
pub const TENDERMINT: &'static str = "tendermint";

/// A client tracking the Ethereum beacon chain consensus, with the mainnet
/// configuration.
pub const ETHEREUM_MAINNET: &'static str = "ethereum-mainnet";

/// A client tracking the Ethereum beacon chain consensus, with the minimal
/// configuration.
pub const ETHEREUM_MINIMAL: &'static str = "ethereum-minimal";

/// A client tracking the state of the [Scroll] zkevm L2, settling on
/// Ethereum.
///
/// [Scroll]: https://github.com/scroll-tech/scroll
pub const SCROLL: &'static str = "scroll";

/// A client tracking the state of the Arbitrum optimistic L2, settling on
/// Ethereum.
///
/// [Arbitrum]: https://github.com/OffchainLabs/nitro-contracts
pub const ARBITRUM: &'static str = "arbitrum";

/// A client tracking the state of a [BeaconKit] chain.
///
/// [BeaconKit]: https://github.com/berachain/beacon-kit
pub const BEACON_KIT: &'static str = "beacon-kit";

/// A client tracking the state of a [Movement] chain.
///
/// [Movement]: https://github.com/movementlabsxyz/movement
pub const MOVEMENT: &'static str = "movement";

// lots more to come - near, linea, polygon - stay tuned
}

/// Identifier used to uniquely identify a chain, as provided by the chain itself.
///
/// # Examples
///
/// | chain id | chain |
/// | --------------- | ------------------------ |
/// | 1 | ethereum mainnet |
/// | 11155111 | ethereum sepolia testnet |
/// | union-testnet-8 | union testnet |
/// | stargaze-1 | stargaze mainnet |
#[apply(str_newtype)]
pub struct ChainId;

/// The type of a light client on a chain, along with the IBC interface it's on
/// (and any associated metadata).
///
/// # Examples
///
/// - 08-wasm client on union, tracking ethereum mainnet: `(ibc-go-v8/08-wasm, ethereum_mainnet,
/// {"checksum": "0x..."})`
/// - 07-tendermint client on stargaze, tracking osmosis: `(ibc-go-v8/native, tendermint)`
/// - 08-wasm client on babylon, tracking union: `(ibc-go-v8/08-wasm, cometbls, {"checksum":
/// "0x..."}))`
/// - cometbls client on scroll, tracking union: `(ibc-solidity, cometbls)`
#[model]
pub struct ClientInfo {
pub client_type: ClientType<'static>,
pub ibc_interface: IbcInterface<'static>,
/// Additional metadata about this client.
///
/// This is currently only used for threading the checksum for ibc-go 08-wasm clients, and can
/// likely be removed when support for that IBC interface is dropped.
#[serde(default)]
pub metadata: Value,
}

#[model]
pub struct ClientStateMeta {
/// The counterparty height this client has been updated to. A consensus
/// state will exist at this height.
pub height: Height,

/// The chain id of the counterparty chain this client tracks.
pub chain_id: ChainId<'static>,
}

#[model]
pub struct ConsensusStateMeta {
/// The timestamp of the counterparty at the height represented by this
/// consensus state.
pub timestamp_nanos: u64,
}

#[model]
pub struct IbcGo08WasmClientMetadata {
pub checksum: H256,
}

macro_rules! str_newtype {
(
$(#[doc = $doc:literal])+
$vis:vis struct $Struct:ident;
) => {
$(#[doc = $doc])+
#[derive(macros::Debug, Clone, PartialEq, Eq, Hash, ::serde::Serialize, ::serde::Deserialize)]
// I tested this and apparently it's not required (newtype is automatically transparent?) but
// keeping it here for clarity
#[serde(transparent)]
#[debug("{}({:?})", stringify!($Struct), self.0)]
$vis struct $Struct<'a>(#[doc(hidden)] ::std::borrow::Cow<'a, str>);

impl<'a> ::core::fmt::Display for $Struct<'a> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Display::fmt(&self.0, f)
}
}

#[allow(unused)]
impl<'a> $Struct<'a> {
/// Construct a new [`
#[doc = stringify!($Struct)]
/// `].
///
/// This will capture the lifetime of the passed in value:
/// ```
#[doc = concat!(
"let _: ",
stringify!($Struct),
"<'static> = ",
stringify!($Struct),
"::new(\"static string\");"
)]
/// let owned_string: String = "owned string".into();
///
/// // not static
#[doc = concat!(
"let _: ",
stringify!($Struct),
"<'_> = ",
stringify!($Struct),
"::new(&owned_string);"
)]
#[doc = concat!(
"let _: ",
stringify!($Struct),
"<'static> = ",
stringify!($Struct),
"::new(owned_string);"
)]
pub fn new(s: impl Into<::std::borrow::Cow<'a, str>>) -> Self {
Self(s.into())
}

/// Convert this [`
#[doc = concat!(stringify!($Struct))]
/// `] into an owned version of itself.
///
/// This will allocate if the contained value is not already on the heap even if `'a == 'static`.
pub fn into_owned(self) -> $Struct<'static> {
use std::borrow::Cow;

$Struct(match self.0 {
Cow::Borrowed(x) => Cow::Owned(x.to_owned()),
Cow::Owned(x) => Cow::Owned(x),
})
}

/// Extracts a string slice containing the entire contained value.
pub fn as_str(&self) -> &str {
self.0.as_ref()
}


/// Borrow this [`
#[doc = stringify!($Struct)]
/// `], returning a new owned value pointing to the same data.
///
/// ```
#[doc = concat!("let t = ", stringify!($Struct), "::new_static(\"static\");")]
///
/// takes_ownership(t.borrow());
/// takes_ownership(t);
///
#[doc = concat!("fn takes_ownership<'a>(c: ", stringify!($Struct), "<'a>) {}")]
/// ```
pub fn borrow<'b>(&'a self) -> $Struct<'b>
where
'a: 'b,
{
use std::borrow::Cow;

match self.0 {
Cow::Borrowed(s) => Self(Cow::Borrowed(s)),
Cow::Owned(ref s) => Self(Cow::Borrowed(s.as_str())),
}
}
}

/// `const`-friendly version of [`Self::new`].
#[allow(unused)]
impl $Struct<'static> {
pub const fn new_static(ibc_interface: &'static str) -> Self {
Self(::std::borrow::Cow::Borrowed(ibc_interface))
}
}
};
}
use serde_json::Value;
pub(crate) use str_newtype;
use unionlabs::{hash::H256, ibc::core::client::height::Height};
1 change: 1 addition & 0 deletions lib/voyager-message/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["json"] }
typenum = { workspace = true }
unionlabs = { workspace = true, features = ["ethabi"] }
voyager-core.workspace = true

[dev-dependencies]
hex-literal = { workspace = true }
Expand Down
9 changes: 5 additions & 4 deletions lib/voyager-message/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ use unionlabs::{
};

#[cfg(doc)]
use crate::data::ClientInfo;
use crate::core::ClientInfo;
use crate::{
callback::AggregateFetchBlockRange,
core::{ChainId, IbcInterface},
data::{IbcMessage, LatestHeight, MsgCreateClientData, WithChainId},
error_object_to_queue_error, json_rpc_error_to_queue_error,
module::{
ChainModuleClient, ClientModuleClient, ConsensusModuleClient, QueueInteractionsClient,
},
rpc::json_rpc_error_to_rpc_error,
top_level_identifiable_enum, ChainId, Context, IbcInterface, PluginMessage, VoyagerMessage,
FATAL_JSONRPC_ERROR_CODE,
top_level_identifiable_enum, Context, PluginMessage, VoyagerMessage, FATAL_JSONRPC_ERROR_CODE,
};

#[apply(top_level_identifiable_enum)]
Expand Down Expand Up @@ -238,7 +238,8 @@ pub struct WaitForTimestamp {
pub timestamp: i64,
}

/// Wait for the client `.client_id` on `.chain_id` to trust a height >= `.height`.
/// Wait for the client `.client_id` on `.chain_id` to trust a height >=
/// `.height`.
#[model]
pub struct WaitForTrustedHeight {
pub chain_id: ChainId<'static>,
Expand Down
6 changes: 4 additions & 2 deletions lib/voyager-message/src/callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ use unionlabs::{
id::ClientId,
traits::Member,
};
use voyager_core::ClientInfo;

use crate::{
call::FetchBlockRange,
data::{ClientInfo, Data, LatestHeight, OrderedHeaders, OrderedMsgUpdateClients},
core::ChainId,
data::{Data, LatestHeight, OrderedHeaders, OrderedMsgUpdateClients},
error_object_to_queue_error, json_rpc_error_to_queue_error,
module::{ClientModuleClient, QueueInteractionsClient},
top_level_identifiable_enum, ChainId, Context, PluginMessage, VoyagerMessage,
top_level_identifiable_enum, Context, PluginMessage, VoyagerMessage,
};

#[apply(top_level_identifiable_enum)]
Expand Down
Loading

0 comments on commit c522006

Please sign in to comment.