Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor indexing #2889

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@ impl MultisigIsmMetadataBuilder for MerkleRootMultisigMetadataBuilder {
checkpoint_syncer: &MultisigCheckpointSyncer,
) -> Result<Option<MultisigMetadata>> {
const CTX: &str = "When fetching MerkleRootMultisig metadata";
unwrap_or_none_result!(
highest_leaf_index,
let highest_leaf_index = unwrap_or_none_result!(
self.highest_known_leaf_index().await,
debug!("Couldn't get highest known leaf index")
);
unwrap_or_none_result!(
leaf_index,
let leaf_index = unwrap_or_none_result!(
self.get_merkle_leaf_id_by_message_id(message.id())
.await
.context(CTX)?,
Expand All @@ -51,8 +49,7 @@ impl MultisigIsmMetadataBuilder for MerkleRootMultisigMetadataBuilder {
"No merkle leaf found for message id, must have not been enqueued in the tree"
)
);
unwrap_or_none_result!(
quorum_checkpoint,
let quorum_checkpoint = unwrap_or_none_result!(
checkpoint_syncer
.fetch_checkpoint_in_range(
validators,
Expand All @@ -67,8 +64,7 @@ impl MultisigIsmMetadataBuilder for MerkleRootMultisigMetadataBuilder {
highest_leaf_index, "Couldn't get checkpoint in range"
)
);
unwrap_or_none_result!(
proof,
let proof = unwrap_or_none_result!(
self.get_proof(leaf_index, quorum_checkpoint.checkpoint.checkpoint)
.await
.context(CTX)?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ impl MultisigIsmMetadataBuilder for MessageIdMultisigMetadataBuilder {
let message_id = message.id();

const CTX: &str = "When fetching MessageIdMultisig metadata";
unwrap_or_none_result!(
leaf_index,
let leaf_index = unwrap_or_none_result!(
self.get_merkle_leaf_id_by_message_id(message_id)
.await
.context(CTX)?,
Expand All @@ -47,8 +46,7 @@ impl MultisigIsmMetadataBuilder for MessageIdMultisigMetadataBuilder {
"No merkle leaf found for message id, must have not been enqueued in the tree"
)
);
unwrap_or_none_result!(
quorum_checkpoint,
let quorum_checkpoint = unwrap_or_none_result!(
checkpoint_syncer
.fetch_checkpoint(validators, threshold as usize, leaf_index)
.await
Expand Down
5 changes: 2 additions & 3 deletions rust/agents/scraper/src/chain_scraper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,13 +382,12 @@ impl HyperlaneSequenceIndexerStore<HyperlaneMessage> for HyperlaneSqlDb {

/// Gets the block number at which the log occurred.
async fn retrieve_log_block_number(&self, sequence: u32) -> Result<Option<u64>> {
unwrap_or_none_result!(
tx_id,
let tx_id = unwrap_or_none_result!(
self.db
.retrieve_dispatched_tx_id(self.domain().id(), &self.mailbox_address, sequence)
.await?
);
unwrap_or_none_result!(block_id, self.db.retrieve_block_id(tx_id).await?);
let block_id = unwrap_or_none_result!(self.db.retrieve_block_id(tx_id).await?);
Ok(self.db.retrieve_block_number(block_id).await?)
}
}
Expand Down
202 changes: 150 additions & 52 deletions rust/chains/hyperlane-cosmos/src/interchain_gas.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
use async_trait::async_trait;
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use cosmrs::tendermint::abci::EventAttribute;
use hyperlane_core::{
unwrap_or_none_result, HyperlaneDomain, HyperlaneProvider, InterchainGasPayment, LogMeta, H256,
};
use hyperlane_core::{
ChainResult, ContractLocator, HyperlaneChain, HyperlaneContract, Indexer,
InterchainGasPaymaster, SequenceIndexer, U256,
};
use hyperlane_core::{HyperlaneDomain, HyperlaneProvider, InterchainGasPayment, LogMeta, H256};
use std::ops::RangeInclusive;

use crate::grpc::WasmGrpcProvider;
use crate::rpc::{CosmosWasmIndexer, WasmIndexer};
use crate::signers::Signer;
use crate::{ConnectionConf, CosmosProvider};
use crate::{
grpc::WasmGrpcProvider,
rpc::{CosmosWasmIndexer, ParsedEvent, WasmIndexer},
signers::Signer,
utils::{CONTRACT_ADDRESS_ATTRIBUTE_KEY, CONTRACT_ADDRESS_ATTRIBUTE_KEY_BASE64},
ConnectionConf, CosmosProvider,
};
use tracing::debug;

/// A reference to a InterchainGasPaymaster contract on some Cosmos chain
#[derive(Debug)]
Expand Down Expand Up @@ -51,6 +56,24 @@ impl CosmosInterchainGasPaymaster {
}
}

// ------------------ Indexer ------------------

const MESSAGE_ID_ATTRIBUTE_KEY: &str = "message_id";
// echo -n message_id | base64
const MESSAGE_ID_ATTRIBUTE_KEY_BASE64: &str = "bWVzc2FnZV9pZA==";
tkporter marked this conversation as resolved.
Show resolved Hide resolved

const PAYMENT_ATTRIBUTE_KEY: &str = "payment";
// echo -n payment | base64
const PAYMENT_ATTRIBUTE_KEY_BASE64: &str = "cGF5bWVudA==";

const GAS_AMOUNT_ATTRIBUTE_KEY: &str = "gas_amount";
// echo -n gas_amount | base64
const GAS_AMOUNT_ATTRIBUTE_KEY_BASE64: &str = "Z2FzX2Ftb3VudA==";

const DESTINATION_ATTRIBUTE_KEY: &str = "dest_domain";
// echo -n dest_domain | base64
const DESTINATION_ATTRIBUTE_KEY_BASE64: &str = "ZGVzdF9kb21haW4=";

/// A reference to a InterchainGasPaymasterIndexer contract on some Cosmos chain
#[derive(Debug)]
pub struct CosmosInterchainGasPaymasterIndexer {
Expand All @@ -64,56 +87,104 @@ impl CosmosInterchainGasPaymasterIndexer {
locator: ContractLocator,
event_type: String,
reorg_period: u32,
) -> Self {
let indexer: CosmosWasmIndexer =
CosmosWasmIndexer::new(conf, locator, event_type.clone(), reorg_period);
) -> ChainResult<Self> {
let indexer = CosmosWasmIndexer::new(conf, locator, event_type.clone(), reorg_period)?;

Self {
Ok(Self {
indexer: Box::new(indexer),
}
})
}

fn get_parser(
&self,
) -> fn(attrs: Vec<EventAttribute>) -> ChainResult<Option<InterchainGasPayment>> {
|attrs: Vec<EventAttribute>| -> ChainResult<Option<InterchainGasPayment>> {
let mut res = InterchainGasPayment::default();
for attr in attrs {
let key = attr.key.as_str();
let value = attr.value;
let value = value.as_str();

match key {
"message_id" => {
res.message_id = H256::from_slice(hex::decode(value)?.as_slice())
}
"bWVzc2FnZV9pZA==" => {
res.message_id = H256::from_slice(
hex::decode(String::from_utf8(STANDARD.decode(value)?)?)?.as_slice(),
)
}
"payment" => res.payment = value.parse()?,
"cGF5bWVudA==" => {
let dec_str = String::from_utf8(STANDARD.decode(value)?)?;
// U256's from_str assumes a radix of 16, so we explicitly use from_dec_str.
res.payment = U256::from_dec_str(dec_str.as_str())?;
}
"gas_amount" => res.gas_amount = value.parse()?,
"Z2FzX2Ftb3VudA==" => {
let dec_str = String::from_utf8(STANDARD.decode(value)?)?;
// U256's from_str assumes a radix of 16, so we explicitly use from_dec_str.
res.gas_amount = U256::from_dec_str(dec_str.as_str())?;
}
"dest_domain" => res.destination = value.parse()?,
"ZGVzdF9kb21haW4=" => {
res.destination = String::from_utf8(STANDARD.decode(value)?)?.parse()?
}
_ => {}
fn interchain_gas_payment_parser(
attrs: &Vec<EventAttribute>,
) -> ChainResult<Option<ParsedEvent<InterchainGasPayment>>> {
let mut contract_address: Option<String> = None;
let mut message_id: Option<H256> = None;
let mut payment: Option<U256> = None;
let mut gas_amount: Option<U256> = None;
let mut destination: Option<u32> = None;

for attr in attrs {
let key = attr.key.as_str();
let value = attr.value.as_str();

match key {
CONTRACT_ADDRESS_ATTRIBUTE_KEY => {
contract_address = Some(value.to_string());
}
CONTRACT_ADDRESS_ATTRIBUTE_KEY_BASE64 => {
contract_address = Some(String::from_utf8(BASE64.decode(value)?)?);
}

MESSAGE_ID_ATTRIBUTE_KEY => {
message_id = Some(H256::from_slice(hex::decode(value)?.as_slice()));
}
MESSAGE_ID_ATTRIBUTE_KEY_BASE64 => {
message_id = Some(H256::from_slice(
hex::decode(String::from_utf8(BASE64.decode(value)?)?)?.as_slice(),
));
}

PAYMENT_ATTRIBUTE_KEY => {
payment = Some(value.parse()?);
}
PAYMENT_ATTRIBUTE_KEY_BASE64 => {
let dec_str = String::from_utf8(BASE64.decode(value)?)?;
// U256's from_str assumes a radix of 16, so we explicitly use from_dec_str.
payment = Some(U256::from_dec_str(dec_str.as_str())?);
}
}

Ok(Some(res))
GAS_AMOUNT_ATTRIBUTE_KEY => {
gas_amount = Some(value.parse()?);
}
GAS_AMOUNT_ATTRIBUTE_KEY_BASE64 => {
let dec_str = String::from_utf8(BASE64.decode(value)?)?;
// U256's from_str assumes a radix of 16, so we explicitly use from_dec_str.
gas_amount = Some(U256::from_dec_str(dec_str.as_str())?);
}

DESTINATION_ATTRIBUTE_KEY => {
destination = Some(value.parse::<u32>()?);
}
DESTINATION_ATTRIBUTE_KEY_BASE64 => {
destination = Some(String::from_utf8(BASE64.decode(value)?)?.parse()?);
}

_ => {}
}
}

let contract_address = unwrap_or_none_result!(
contract_address,
tkporter marked this conversation as resolved.
Show resolved Hide resolved
debug!("No contract address found in event attributes")
);
let message_id = unwrap_or_none_result!(
message_id,
debug!("No message ID found in event attributes")
);

let payment =
unwrap_or_none_result!(payment, debug!("No payment found in event attributes"));

let gas_amount = unwrap_or_none_result!(
gas_amount,
debug!("No gas_amount found in event attributes")
);

let destination = unwrap_or_none_result!(
destination,
debug!("No destination found in event attributes")
);

Ok(Some(ParsedEvent::new(
contract_address,
InterchainGasPayment {
message_id,
payment,
gas_amount,
destination,
},
)))
}
}

Expand All @@ -123,8 +194,10 @@ impl Indexer<InterchainGasPayment> for CosmosInterchainGasPaymasterIndexer {
&self,
range: RangeInclusive<u32>,
) -> ChainResult<Vec<(InterchainGasPayment, LogMeta)>> {
let parser = self.get_parser();
let result = self.indexer.get_range_event_logs(range, parser).await?;
let result = self
.indexer
.get_range_event_logs(range, Self::interchain_gas_payment_parser)
.await?;
Ok(result)
}

Expand All @@ -141,3 +214,28 @@ impl SequenceIndexer<InterchainGasPayment> for CosmosInterchainGasPaymasterIndex
Ok((None, tip))
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_base64_keys() {
assert_eq!(
MESSAGE_ID_ATTRIBUTE_KEY_BASE64,
BASE64.encode(MESSAGE_ID_ATTRIBUTE_KEY)
);
assert_eq!(
PAYMENT_ATTRIBUTE_KEY_BASE64,
BASE64.encode(PAYMENT_ATTRIBUTE_KEY)
);
assert_eq!(
GAS_AMOUNT_ATTRIBUTE_KEY_BASE64,
BASE64.encode(GAS_AMOUNT_ATTRIBUTE_KEY)
);
assert_eq!(
DESTINATION_ATTRIBUTE_KEY_BASE64,
BASE64.encode(DESTINATION_ATTRIBUTE_KEY)
);
}
}
Loading
Loading