Skip to content

Commit

Permalink
Sealevel balance metrics (#3025)
Browse files Browse the repository at this point in the history
Publishes sealevel balance as a relayer metric

**Drive-by Changes**
- Creates `HyperlaneSealevelError`, a `hyperlane-sealevel` specific type
to avoid including sealevel errors in `hyperlane-core`'s
`ChainCommunicationError`. It's pretty empty now, but we have a starting
point now. This follows the approach used in `hyperlane-cosmos` too.
- Includes an rpc provider instance in `SealevelProvider`, and uses it
to add `get_balance` on `SealevelProvider`.

**Testing**
None, as sealevel e2e is currently disabled
  • Loading branch information
daniel-savu authored Dec 5, 2023
1 parent 77aa58c commit 98bb228
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 58 deletions.
23 changes: 23 additions & 0 deletions rust/chains/hyperlane-sealevel/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use hyperlane_core::ChainCommunicationError;
use solana_client::client_error::ClientError;
use solana_sdk::pubkey::ParsePubkeyError;

/// Errors from the crates specific to the hyperlane-sealevel
/// implementation.
/// This error can then be converted into the broader error type
/// in hyperlane-core using the `From` trait impl
#[derive(Debug, thiserror::Error)]
pub enum HyperlaneSealevelError {
/// ParsePubkeyError error
#[error("{0}")]
ParsePubkeyError(#[from] ParsePubkeyError),
/// ClientError error
#[error("{0}")]
ClientError(#[from] ClientError),
}

impl From<HyperlaneSealevelError> for ChainCommunicationError {
fn from(value: HyperlaneSealevelError) -> Self {
ChainCommunicationError::from_other(value)
}
}
11 changes: 5 additions & 6 deletions rust/chains/hyperlane-sealevel/src/interchain_gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct SealevelInterchainGasPaymaster {
data_pda_pubkey: Pubkey,
domain: HyperlaneDomain,
igp_account: H256,
provider: SealevelProvider,
}

impl SealevelInterchainGasPaymaster {
Expand All @@ -43,12 +44,9 @@ impl SealevelInterchainGasPaymaster {
conf: &ConnectionConf,
igp_account_locator: &ContractLocator<'_>,
) -> ChainResult<Self> {
let rpc_client = RpcClientWithDebug::new_with_commitment(
conf.url.to_string(),
CommitmentConfig::processed(),
);
let provider = SealevelProvider::new(igp_account_locator.domain.clone(), conf);
let program_id =
Self::determine_igp_program_id(&rpc_client, &igp_account_locator.address).await?;
Self::determine_igp_program_id(provider.rpc(), &igp_account_locator.address).await?;
let (data_pda_pubkey, _) =
Pubkey::find_program_address(igp_program_data_pda_seeds!(), &program_id);

Expand All @@ -57,6 +55,7 @@ impl SealevelInterchainGasPaymaster {
data_pda_pubkey,
domain: igp_account_locator.domain.clone(),
igp_account: igp_account_locator.address,
provider,
})
}

Expand Down Expand Up @@ -91,7 +90,7 @@ impl HyperlaneChain for SealevelInterchainGasPaymaster {
}

fn provider(&self) -> Box<dyn HyperlaneProvider> {
Box::new(SealevelProvider::new(self.domain.clone()))
self.provider.provider()
}
}

Expand Down
20 changes: 11 additions & 9 deletions rust/chains/hyperlane-sealevel/src/interchain_security_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,31 @@ use hyperlane_core::{
use hyperlane_sealevel_interchain_security_module_interface::InterchainSecurityModuleInstruction;
use serializable_account_meta::SimulationReturnData;

use crate::{utils::simulate_instruction, ConnectionConf, RpcClientWithDebug};
use crate::{utils::simulate_instruction, ConnectionConf, RpcClientWithDebug, SealevelProvider};

/// A reference to an InterchainSecurityModule contract on some Sealevel chain
#[derive(Debug)]
pub struct SealevelInterchainSecurityModule {
rpc_client: RpcClientWithDebug,
payer: Option<Keypair>,
program_id: Pubkey,
domain: HyperlaneDomain,
provider: SealevelProvider,
}

impl SealevelInterchainSecurityModule {
/// Create a new sealevel InterchainSecurityModule
pub fn new(conf: &ConnectionConf, locator: ContractLocator, payer: Option<Keypair>) -> Self {
let rpc_client = RpcClientWithDebug::new(conf.url.to_string());
let provider = SealevelProvider::new(locator.domain.clone(), conf);
let program_id = Pubkey::from(<[u8; 32]>::from(locator.address));
Self {
rpc_client,
payer,
program_id,
domain: locator.domain.clone(),
provider,
}
}

fn rpc(&self) -> &RpcClientWithDebug {
self.provider.rpc()
}
}

impl HyperlaneContract for SealevelInterchainSecurityModule {
Expand All @@ -43,11 +45,11 @@ impl HyperlaneContract for SealevelInterchainSecurityModule {

impl HyperlaneChain for SealevelInterchainSecurityModule {
fn domain(&self) -> &HyperlaneDomain {
&self.domain
self.provider.domain()
}

fn provider(&self) -> Box<dyn hyperlane_core::HyperlaneProvider> {
Box::new(crate::SealevelProvider::new(self.domain.clone()))
self.provider.provider()
}
}

Expand All @@ -63,7 +65,7 @@ impl InterchainSecurityModule for SealevelInterchainSecurityModule {
);

let module = simulate_instruction::<SimulationReturnData<u32>>(
&self.rpc_client,
self.rpc(),
self.payer
.as_ref()
.ok_or_else(|| ChainCommunicationError::SignerUnavailable)?,
Expand Down
1 change: 1 addition & 0 deletions rust/chains/hyperlane-sealevel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub use solana_sdk::signer::keypair::Keypair;
pub use trait_builder::*;
pub use validator_announce::*;

mod error;
mod interchain_gas;
mod interchain_security_module;
mod mailbox;
Expand Down
48 changes: 24 additions & 24 deletions rust/chains/hyperlane-sealevel/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ pub struct SealevelMailbox {
pub(crate) program_id: Pubkey,
inbox: (Pubkey, u8),
pub(crate) outbox: (Pubkey, u8),
pub(crate) rpc_client: RpcClient,
pub(crate) domain: HyperlaneDomain,
pub(crate) provider: SealevelProvider,
payer: Option<Keypair>,
}

Expand All @@ -81,10 +80,7 @@ impl SealevelMailbox {
locator: ContractLocator,
payer: Option<Keypair>,
) -> ChainResult<Self> {
// Set the `processed` commitment at rpc level
let rpc_client =
RpcClient::new_with_commitment(conf.url.to_string(), CommitmentConfig::processed());

let provider = SealevelProvider::new(locator.domain.clone(), conf);
let program_id = Pubkey::from(<[u8; 32]>::from(locator.address));
let domain = locator.domain.id();
let inbox = Pubkey::find_program_address(mailbox_inbox_pda_seeds!(), &program_id);
Expand All @@ -99,8 +95,7 @@ impl SealevelMailbox {
program_id,
inbox,
outbox,
rpc_client,
domain: locator.domain.clone(),
provider,
payer,
})
}
Expand All @@ -112,6 +107,10 @@ impl SealevelMailbox {
self.outbox
}

pub fn rpc(&self) -> &RpcClientWithDebug {
self.provider.rpc()
}

/// Simulates an instruction, and attempts to deserialize it into a T.
/// If no return data at all was returned, returns Ok(None).
/// If some return data was returned but deserialization was unsuccesful,
Expand All @@ -121,7 +120,7 @@ impl SealevelMailbox {
instruction: Instruction,
) -> ChainResult<Option<T>> {
simulate_instruction(
&self.rpc_client,
&self.rpc(),
self.payer
.as_ref()
.ok_or_else(|| ChainCommunicationError::SignerUnavailable)?,
Expand All @@ -136,7 +135,7 @@ impl SealevelMailbox {
instruction: Instruction,
) -> ChainResult<Vec<AccountMeta>> {
get_account_metas(
&self.rpc_client,
&self.rpc(),
self.payer
.as_ref()
.ok_or_else(|| ChainCommunicationError::SignerUnavailable)?,
Expand Down Expand Up @@ -263,11 +262,11 @@ impl HyperlaneContract for SealevelMailbox {

impl HyperlaneChain for SealevelMailbox {
fn domain(&self) -> &HyperlaneDomain {
&self.domain
&self.provider.domain()
}

fn provider(&self) -> Box<dyn HyperlaneProvider> {
Box::new(SealevelProvider::new(self.domain.clone()))
self.provider.provider()
}
}

Expand Down Expand Up @@ -295,7 +294,7 @@ impl Mailbox for SealevelMailbox {
);

let account = self
.rpc_client
.rpc()
.get_account_with_commitment(
&processed_message_account_key,
CommitmentConfig::finalized(),
Expand All @@ -309,7 +308,7 @@ impl Mailbox for SealevelMailbox {
#[instrument(err, ret, skip(self))]
async fn default_ism(&self) -> ChainResult<H256> {
let inbox_account = self
.rpc_client
.rpc()
.get_account(&self.inbox.0)
.await
.map_err(ChainCommunicationError::from_other)?;
Expand Down Expand Up @@ -436,7 +435,7 @@ impl Mailbox for SealevelMailbox {
};
instructions.push(inbox_instruction);
let (recent_blockhash, _) = self
.rpc_client
.rpc()
.get_latest_blockhash_with_commitment(commitment)
.await
.map_err(ChainCommunicationError::from_other)?;
Expand All @@ -451,15 +450,15 @@ impl Mailbox for SealevelMailbox {
tracing::info!(?txn, "Created sealevel transaction to process message");

let signature = self
.rpc_client
.rpc()
.send_and_confirm_transaction(&txn)
.await
.map_err(ChainCommunicationError::from_other)?;

tracing::info!(?txn, ?signature, "Sealevel transaction sent");

let executed = self
.rpc_client
.rpc()
.confirm_transaction_with_commitment(&signature, commitment)
.await
.map_err(|err| warn!("Failed to confirm inbox process transaction: {}", err))
Expand Down Expand Up @@ -498,26 +497,27 @@ impl Mailbox for SealevelMailbox {
/// Struct that retrieves event data for a Sealevel Mailbox contract
#[derive(Debug)]
pub struct SealevelMailboxIndexer {
rpc_client: RpcClientWithDebug,
mailbox: SealevelMailbox,
program_id: Pubkey,
}

impl SealevelMailboxIndexer {
pub fn new(conf: &ConnectionConf, locator: ContractLocator) -> ChainResult<Self> {
let program_id = Pubkey::from(<[u8; 32]>::from(locator.address));
let rpc_client = RpcClientWithDebug::new(conf.url.to_string());
let mailbox = SealevelMailbox::new(conf, locator, None)?;
Ok(Self {
program_id,
rpc_client,
mailbox,
})
}

fn rpc(&self) -> &RpcClientWithDebug {
&self.mailbox.rpc()
}

async fn get_finalized_block_number(&self) -> ChainResult<u32> {
let height = self
.rpc_client
.rpc()
.get_block_height()
.await
.map_err(ChainCommunicationError::from_other)?
Expand Down Expand Up @@ -560,7 +560,7 @@ impl SealevelMailboxIndexer {
with_context: Some(false),
};
let accounts = self
.rpc_client
.rpc()
.get_program_accounts_with_config(&self.mailbox.program_id, config)
.await
.map_err(ChainCommunicationError::from_other)?;
Expand Down Expand Up @@ -595,7 +595,7 @@ impl SealevelMailboxIndexer {

// Now that we have the valid message storage PDA pubkey, we can get the full account data.
let account = self
.rpc_client
.rpc()
.get_account_with_commitment(
&valid_message_storage_pda_pubkey,
CommitmentConfig::finalized(),
Expand Down Expand Up @@ -660,7 +660,7 @@ impl Indexer<HyperlaneMessage> for SealevelMailboxIndexer {
}

async fn get_finalized_block_number(&self) -> ChainResult<u32> {
get_finalized_block_number(&self.rpc_client).await
get_finalized_block_number(&self.rpc()).await
}
}

Expand Down
6 changes: 3 additions & 3 deletions rust/chains/hyperlane-sealevel/src/merkle_tree_hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use async_trait::async_trait;
use derive_new::new;
use hyperlane_core::{
accumulator::incremental::IncrementalMerkle, ChainCommunicationError, ChainResult, Checkpoint,
Indexer, LogMeta, MerkleTreeHook, MerkleTreeInsertion, SequenceIndexer,
HyperlaneChain, Indexer, LogMeta, MerkleTreeHook, MerkleTreeInsertion, SequenceIndexer,
};
use hyperlane_sealevel_mailbox::accounts::OutboxAccount;
use solana_sdk::commitment_config::CommitmentConfig;
Expand All @@ -22,7 +22,7 @@ impl MerkleTreeHook for SealevelMailbox {
);

let outbox_account = self
.rpc_client
.rpc()
.get_account_with_commitment(&self.outbox.0, CommitmentConfig::finalized())
.await
.map_err(ChainCommunicationError::from_other)?
Expand Down Expand Up @@ -58,7 +58,7 @@ impl MerkleTreeHook for SealevelMailbox {
})?;
let checkpoint = Checkpoint {
merkle_tree_hook_address: self.program_id.to_bytes().into(),
mailbox_domain: self.domain.id(),
mailbox_domain: self.domain().id(),
root,
index,
};
Expand Down
16 changes: 10 additions & 6 deletions rust/chains/hyperlane-sealevel/src/multisig_ism.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,29 @@ use multisig_ism::interface::{
/// A reference to a MultisigIsm contract on some Sealevel chain
#[derive(Debug)]
pub struct SealevelMultisigIsm {
rpc_client: RpcClientWithDebug,
payer: Option<Keypair>,
program_id: Pubkey,
domain: HyperlaneDomain,
provider: SealevelProvider,
}

impl SealevelMultisigIsm {
/// Create a new Sealevel MultisigIsm.
pub fn new(conf: &ConnectionConf, locator: ContractLocator, payer: Option<Keypair>) -> Self {
let rpc_client = RpcClientWithDebug::new(conf.url.to_string());
let provider = SealevelProvider::new(locator.domain.clone(), conf);
let program_id = Pubkey::from(<[u8; 32]>::from(locator.address));

Self {
rpc_client,
payer,
program_id,
domain: locator.domain.clone(),
provider,
}
}

fn rpc(&self) -> &RpcClientWithDebug {
self.provider.rpc()
}
}

impl HyperlaneContract for SealevelMultisigIsm {
Expand All @@ -57,7 +61,7 @@ impl HyperlaneChain for SealevelMultisigIsm {
}

fn provider(&self) -> Box<dyn HyperlaneProvider> {
Box::new(SealevelProvider::new(self.domain.clone()))
self.provider.provider()
}
}

Expand All @@ -84,7 +88,7 @@ impl MultisigIsm for SealevelMultisigIsm {

let validators_and_threshold =
simulate_instruction::<SimulationReturnData<ValidatorsAndThreshold>>(
&self.rpc_client,
self.rpc(),
self.payer
.as_ref()
.ok_or_else(|| ChainCommunicationError::SignerUnavailable)?,
Expand Down Expand Up @@ -132,7 +136,7 @@ impl SealevelMultisigIsm {
);

get_account_metas(
&self.rpc_client,
self.rpc(),
self.payer
.as_ref()
.ok_or_else(|| ChainCommunicationError::SignerUnavailable)?,
Expand Down
Loading

0 comments on commit 98bb228

Please sign in to comment.