Skip to content

Commit

Permalink
chore(docs): improve rustdocs (#1710)
Browse files Browse the repository at this point in the history
  • Loading branch information
benluelo authored Apr 9, 2024
2 parents dfbba9d + d5d48a5 commit 6f837b9
Show file tree
Hide file tree
Showing 15 changed files with 214 additions and 195 deletions.
1 change: 1 addition & 0 deletions dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ rsplit
ruint
runtimeservices
rustc
rustdoc
rustfilt
rustflags
rustfmt
Expand Down
2 changes: 1 addition & 1 deletion generated/rust/protos/src/lib.rs

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

3 changes: 2 additions & 1 deletion lib/block-message/src/chain_impls/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use std::{collections::VecDeque, marker::PhantomData};

use beacon_api::client::BeaconApiClient;
use chain_utils::ethereum::{
Ethereum, EthereumChain, IBCHandlerEvents, IbcHandlerExt, ETHEREUM_REVISION_NUMBER,
Ethereum, EthereumChain, EthereumChainExt as _, IBCHandlerEvents, IbcHandlerExt,
ETHEREUM_REVISION_NUMBER,
};
use contracts::{
ibc_channel_handshake::{
Expand Down
9 changes: 9 additions & 0 deletions lib/chain-utils/src/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,29 @@ pub type EthereumSignerMiddleware =
SignerMiddleware<NonceManagerMiddleware<Provider<Ws>>, Wallet<ecdsa::SigningKey>>;

// NOTE: ClientType bound is temporary until I figure out a better way to deal with client types
/// An Ethereum-based chain. This can be any chain that is based off of and settles on Ethereum (i.e. Ethereum mainnet/ Sepolia, L2s such as Scroll).
pub trait EthereumChain:
Chain<IbcStateEncoding = EthAbi, StateProof = StorageProof, ClientType = String>
{
/// Fetch the execution height associated with the given beacon slot. For [`Ethereum`], this will simply be the execution block number, but for L2s this will fetch the settled height at the L1 block number.
fn execution_height_of_beacon_slot(&self, slot: u64) -> impl Future<Output = u64>;

/// The provider connected to this chain's [JSON-RPC](https://ethereum.org/en/developers/docs/apis/json-rpc/).
fn provider(&self) -> Arc<Provider<Ws>>;

/// The address of the [`IBCHandler`] smart contract deployed natively on this chain.
fn ibc_handler_address(&self) -> H160;
}

pub trait EthereumChainExt: EthereumChain {
/// Convenience method to construct an [`IBCHandler`] instance for this chain.
fn ibc_handler(&self) -> IBCHandler<Provider<Ws>> {
IBCHandler::new(self.ibc_handler_address(), self.provider())
}
}

impl<T: EthereumChain> EthereumChainExt for T {}

impl<C: ChainSpec, S: EthereumSignersConfig> EthereumChain for Ethereum<C, S> {
async fn execution_height_of_beacon_slot(&self, slot: u64) -> u64 {
self.beacon_api_client
Expand Down
43 changes: 15 additions & 28 deletions lib/chain-utils/src/scroll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ use std::{error::Error, num::NonZeroU64, sync::Arc};

use bip32::secp256k1::ecdsa;
use contracts::ibc_handler::IBCHandler;
use ethers::{
middleware::{NonceManagerMiddleware, SignerMiddleware},
providers::{Middleware, Provider, ProviderError, Ws, WsClientError},
signers::LocalWallet,
utils::secret_key_to_address,
};
use ethers::providers::{Middleware, Provider, ProviderError, Ws, WsClientError};
use futures::{FutureExt, TryFutureExt};
use scroll_api::ScrollClient;
use serde::{Deserialize, Serialize};
Expand All @@ -17,13 +12,14 @@ use unionlabs::{
hash::{H160, H256},
ibc::{core::client::height::Height, lightclients::scroll},
id::{ChannelId, PortId},
traits::{Chain, ClientState, FromStrExact},
traits::{Chain, ClientIdOf, ClientState, FromStrExact},
uint::U256,
};

use crate::{
ethereum::{
self, Ethereum, EthereumChain, EthereumInitError, EthereumSignerMiddleware, Readonly,
self, Ethereum, EthereumChain, EthereumInitError, EthereumSignerMiddleware,
EthereumSignersConfig, ReadWrite, Readonly,
},
private_key::PrivateKey,
union::Union,
Expand All @@ -37,7 +33,7 @@ pub const SCROLL_REVISION_NUMBER: u64 = 0;
pub struct Scroll {
pub chain_id: U256,

// The provider on scroll chain.
/// The provider on scroll chain.
pub provider: Arc<Provider<Ws>>,

pub ibc_handlers: Pool<IBCHandler<EthereumSignerMiddleware>>,
Expand All @@ -51,7 +47,7 @@ pub struct Scroll {
pub rollup_contract_address: H160,
pub rollup_finalized_state_roots_slot: U256,
pub rollup_last_finalized_batch_index_slot: U256,
pub l1_client_id: String,
pub l1_client_id: ClientIdOf<Ethereum<Mainnet>>,
pub union_grpc_url: String,
}

Expand All @@ -69,7 +65,7 @@ pub struct Config {
pub rollup_contract_address: H160,
pub rollup_finalized_state_roots_slot: U256,
pub rollup_last_finalized_batch_index_slot: U256,
pub l1_client_id: String,
pub l1_client_id: ClientIdOf<Ethereum<Mainnet>>,
pub l1: ethereum::Config<Readonly>,
pub scroll_api: String,
pub union_grpc_url: String,
Expand Down Expand Up @@ -110,23 +106,14 @@ impl Scroll {
let chain_id = provider.get_chainid().await?;
tracing::info!(?chain_id);

let ibc_handlers = config.signers.into_iter().map(|signer| {
let signing_key: ecdsa::SigningKey = signer.value();
let address = secret_key_to_address(&signing_key);

let wallet = LocalWallet::new_with_signer(signing_key, address, chain_id.as_u64());

let signer_middleware = Arc::new(SignerMiddleware::new(
NonceManagerMiddleware::new(provider.clone(), address),
wallet.clone(),
));

IBCHandler::new(config.ibc_handler_address, signer_middleware.clone())
});

Ok(Self {
chain_id: U256(chain_id),
ibc_handlers: Pool::new(ibc_handlers),
ibc_handlers: ReadWrite::new(
config.signers,
config.ibc_handler_address,
chain_id.as_u64(),
provider.clone(),
),
ibc_handler_address: config.ibc_handler_address,
provider: Arc::new(provider),
scroll_api_client: ScrollClient::new(config.scroll_api),
Expand Down Expand Up @@ -225,7 +212,7 @@ impl Chain for Scroll {
)
.await?
.client_state(protos::ibc::core::client::v1::QueryClientStateRequest {
client_id: self.l1_client_id.clone(),
client_id: self.l1_client_id.to_string(),
})
.await?
.into_inner()
Expand Down Expand Up @@ -258,7 +245,7 @@ impl Chain for Scroll {

async fn self_client_state(&self, height: Self::Height) -> Self::SelfClientState {
scroll::client_state::ClientState {
l1_client_id: self.l1_client_id.clone(),
l1_client_id: self.l1_client_id.to_string(),
chain_id: self.chain_id(),
latest_batch_index: self
.batch_index_of_beacon_slot(height.revision_height)
Expand Down
4 changes: 2 additions & 2 deletions lib/relay-message/src/chain_impls/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::{collections::VecDeque, fmt::Debug, marker::PhantomData, ops::Div, sync

use chain_utils::{
ethereum::{
Ethereum, EthereumChain, EthereumSignerMiddleware, IbcHandlerErrors, IbcHandlerExt,
ETHEREUM_REVISION_NUMBER,
Ethereum, EthereumChain, EthereumChainExt as _, EthereumSignerMiddleware, IbcHandlerErrors,
IbcHandlerExt, ETHEREUM_REVISION_NUMBER,
},
Pool,
};
Expand Down
2 changes: 1 addition & 1 deletion lib/relay-message/src/chain_impls/scroll.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{collections::VecDeque, marker::PhantomData};

use chain_utils::{
ethereum::{EthereumChain, IbcHandlerExt},
ethereum::{EthereumChain, EthereumChainExt, IbcHandlerExt},
scroll::Scroll,
};
use ethers::providers::Middleware;
Expand Down
54 changes: 54 additions & 0 deletions lib/unionlabs/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use core::fmt::Debug;

#[derive(Debug, Clone, PartialEq, thiserror::Error)]
#[error("unknown enum variant `{0}`")]
pub struct UnknownEnumVariant<T>(pub T);

/// A protobuf field was none unexpectedly.
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
#[error("missing field `{0}`")]
pub struct MissingField(pub &'static str);

/// For fields that are "fake options" from prost, for use in `TryFrom<<Self as Proto>::Proto>`.
///
/// `Self::Error` is expected to have a `MissingField(`[`MissingField`]`)` variant.
macro_rules! required {
($struct_var:ident.$field:ident) => {
$struct_var
.$field
.ok_or(<Self::Error>::MissingField(MissingField(stringify!(
$field
))))
};
}

// https://stackoverflow.com/questions/26731243/how-do-i-use-a-macro-across-module-files
pub(crate) use required;

// Expected one length, but found another.
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("invalid length: expected {expected}, found {found}")]
pub struct InvalidLength {
// TODO: Make this generic with this enum as individual types
pub expected: ExpectedLength,
pub found: usize,
}

#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)]
pub enum ExpectedLength {
#[display(fmt = "exactly {_0}")]
Exact(usize),
#[display(fmt = "less than {_0}")]
LessThan(usize),
#[display(fmt = "between ({_0}, {_1})")]
Between(usize, usize),
#[display(fmt = "greater than or equal to ({_0})")]
Gte(usize),
}

#[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[error("invalid value: expected {expected}, found {found}")]
pub struct InvalidValue<T> {
pub expected: T,
pub found: T,
}
81 changes: 46 additions & 35 deletions lib/unionlabs/src/google/protobuf/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,30 @@ use crate::{
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Any<T>(pub T);

/// Provides a way to convert a type `T` into an [`Any`], even if `T` is itself an [`Any`].
///
/// ```rust
/// # use unionlabs::google::protobuf::duration::Duration;
/// # use unionlabs::google::protobuf::any::{Any, IntoAny};
///
/// let duration = Duration::new(1, 2).expect("valid duration");
/// let _: Any<Duration> = duration.into_any();
/// let _: Any<Duration> = Any(duration).into_any();
/// ```
pub trait IntoAny {
type T: Encode<crate::encoding::Proto> + TypeUrl;
type T: Encode<Proto> + TypeUrl;
fn into_any(self) -> Any<Self::T>;
}

impl<T: TypeUrl + Encode<crate::encoding::Proto>> IntoAny for T {
impl<T: TypeUrl + Encode<Proto>> IntoAny for T {
type T = T;

fn into_any(self) -> Any<Self::T> {
Any(self)
}
}

impl<T: TypeUrl + Encode<crate::encoding::Proto>> IntoAny for Any<T> {
impl<T: TypeUrl + Encode<Proto>> IntoAny for Any<T> {
type T = T;

fn into_any(self) -> Any<Self::T> {
Expand Down Expand Up @@ -145,7 +155,7 @@ pub enum TryFromAnyError<E> {

impl<T> TryFrom<protos::google::protobuf::Any> for Any<T>
where
T: Decode<crate::encoding::Proto> + TypeUrl,
T: Decode<Proto> + TypeUrl,
{
type Error = TryFromAnyError<T::Error>;

Expand Down Expand Up @@ -179,48 +189,49 @@ impl<T: Decode<Proto> + TypeUrl> Decode<Proto> for Any<T> {

#[must_use]
pub fn mk_any<T: prost::Name + prost::Message>(t: &T) -> protos::google::protobuf::Any {
mk_any_from_bytes::<T>(t.encode_to_vec())
}

#[must_use]
pub fn mk_any_from_bytes<T: prost::Name>(bz: Vec<u8>) -> protos::google::protobuf::Any {
let bz = t.encode_to_vec();
protos::google::protobuf::Any {
type_url: T::type_url(),
value: bz,
}
}

#[test]
fn test_flatten() {
use crate::google::protobuf::{duration::Duration, timestamp::Timestamp};
#[cfg(test)]
mod tests {
use super::*;

trait Foo {
type Bar;
}
#[test]
fn test_flatten() {
use crate::google::protobuf::{duration::Duration, timestamp::Timestamp};

struct A;
struct B;
trait Foo {
type Bar;
}

impl Foo for A {
type Bar = Timestamp;
}
struct A;
struct B;

impl Foo for B {
type Bar = Any<Duration>;
}
impl Foo for A {
type Bar = Timestamp;
}

fn wrap_any_one_level<T>(bar: T::Bar) -> Any<<T::Bar as IntoAny>::T>
where
T: Foo,
T::Bar: IntoAny,
{
bar.into_any()
}
impl Foo for B {
type Bar = Any<Duration>;
}

fn wrap_any_one_level<T>(bar: T::Bar) -> Any<<T::Bar as IntoAny>::T>
where
T: Foo,
T::Bar: IntoAny,
{
bar.into_any()
}

let _: Any<Timestamp> = wrap_any_one_level::<A>(Timestamp {
seconds: crate::bounded::BoundedI64::new(1).unwrap(),
nanos: crate::bounded::BoundedI32::new(2).unwrap(),
});
let _: Any<Timestamp> = wrap_any_one_level::<A>(Timestamp {
seconds: crate::bounded::BoundedI64::new(1).unwrap(),
nanos: crate::bounded::BoundedI32::new(2).unwrap(),
});

let _: Any<Duration> = wrap_any_one_level::<B>(Any(Duration::new(3, 4).unwrap()));
let _: Any<Duration> = wrap_any_one_level::<B>(Any(Duration::new(3, 4).unwrap()));
}
}
Loading

0 comments on commit 6f837b9

Please sign in to comment.