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

feat: Use H512 as transaction hash in HyperlaneProvider and Scraper #4759

Merged
merged 2 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion rust/main/Cargo.lock

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

1 change: 0 additions & 1 deletion rust/main/agents/scraper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ tokio = { workspace = true, features = ["rt", "macros", "parking_lot"] }
tracing-futures.workspace = true
tracing.workspace = true

hex = { path = "../../utils/hex" }
hyperlane-base = { path = "../../hyperlane-base" }
hyperlane-core = { path = "../../hyperlane-core", features = ["agent"] }
migration = { path = "migration" }
Expand Down
56 changes: 20 additions & 36 deletions rust/main/agents/scraper/src/chain_scraper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ use std::{collections::HashMap, sync::Arc};

use async_trait::async_trait;
use eyre::Result;
use itertools::Itertools;
use tracing::{trace, warn};

use hyperlane_base::settings::IndexSettings;
use hyperlane_core::{
unwrap_or_none_result, BlockId, BlockInfo, Delivery, HyperlaneDomain, HyperlaneLogStore,
HyperlaneMessage, HyperlaneProvider, HyperlaneSequenceAwareIndexerStoreReader,
HyperlaneWatermarkedLogStore, Indexed, InterchainGasPayment, LogMeta, H256,
HyperlaneWatermarkedLogStore, Indexed, InterchainGasPayment, LogMeta, H256, H512,
};
use itertools::Itertools;
use tracing::{trace, warn};

use crate::db::{
BasicBlock, BlockCursor, ScraperDb, StorableDelivery, StorableMessage, StorablePayment,
Expand Down Expand Up @@ -78,12 +79,10 @@ impl HyperlaneSqlDb {
&self,
log_meta: impl Iterator<Item = &LogMeta>,
) -> Result<impl Iterator<Item = TxnWithId>> {
let block_id_by_txn_hash: HashMap<H256, BlockId> = log_meta
let block_id_by_txn_hash: HashMap<H512, BlockId> = log_meta
.map(|meta| {
(
meta.transaction_id
.try_into()
.expect("256-bit transaction ids are the maximum supported at this time"),
meta.transaction_id,
BlockId::new(meta.block_hash, meta.block_number),
)
})
Expand Down Expand Up @@ -121,7 +120,7 @@ impl HyperlaneSqlDb {
txns: impl Iterator<Item = TxnWithBlockId>,
) -> Result<impl Iterator<Item = TxnWithId>> {
// mapping of txn hash to (txn_id, block_id).
let mut txns: HashMap<H256, (Option<i64>, i64)> = txns
let mut txns: HashMap<H512, (Option<i64>, i64)> = txns
.map(|TxnWithBlockId { txn_hash, block_id }| (txn_hash, (None, block_id)))
.collect();

Expand All @@ -145,9 +144,9 @@ impl HyperlaneSqlDb {
let mut txns_to_fetch = txns.iter_mut().filter(|(_, id)| id.0.is_none());

let mut txns_to_insert: Vec<StorableTxn> = Vec::with_capacity(CHUNK_SIZE);
let mut hashes_to_insert: Vec<&H256> = Vec::with_capacity(CHUNK_SIZE);
let mut hashes_to_insert: Vec<&H512> = Vec::with_capacity(CHUNK_SIZE);

for mut chunk in as_chunks::<(&H256, &mut (Option<i64>, i64))>(txns_to_fetch, CHUNK_SIZE) {
for mut chunk in as_chunks::<(&H512, &mut (Option<i64>, i64))>(txns_to_fetch, CHUNK_SIZE) {
for (hash, (_, block_id)) in chunk.iter() {
let info = match self.provider.get_txn_by_hash(hash).await {
Ok(info) => info,
Expand Down Expand Up @@ -302,21 +301,16 @@ impl HyperlaneLogStore<HyperlaneMessage> for HyperlaneSqlDb {
if messages.is_empty() {
return Ok(0);
}
let txns: HashMap<H256, TxnWithId> = self
let txns: HashMap<H512, TxnWithId> = self
.ensure_blocks_and_txns(messages.iter().map(|r| &r.1))
.await?
.map(|t| (t.hash, t))
.collect();
let storable = messages
.iter()
.filter_map(|(message, meta)| {
txns.get(
&meta
.transaction_id
.try_into()
.expect("256-bit transaction ids are the maximum supported at this time"),
)
.map(|t| (message.inner().clone(), meta, t.id))
txns.get(&meta.transaction_id)
.map(|t| (message.inner().clone(), meta, t.id))
})
.map(|(msg, meta, txn_id)| StorableMessage { msg, meta, txn_id });
let stored = self
Expand All @@ -336,21 +330,16 @@ impl HyperlaneLogStore<Delivery> for HyperlaneSqlDb {
if deliveries.is_empty() {
return Ok(0);
}
let txns: HashMap<Delivery, TxnWithId> = self
let txns: HashMap<H512, TxnWithId> = self
.ensure_blocks_and_txns(deliveries.iter().map(|r| &r.1))
.await?
.map(|t| (t.hash, t))
.collect();
let storable = deliveries
.iter()
.filter_map(|(message_id, meta)| {
txns.get(
&meta
.transaction_id
.try_into()
.expect("256-bit transaction ids are the maximum supported at this time"),
)
.map(|txn| (*message_id.inner(), meta, txn.id))
txns.get(&meta.transaction_id)
.map(|txn| (*message_id.inner(), meta, txn.id))
})
.map(|(message_id, meta, txn_id)| StorableDelivery {
message_id,
Expand Down Expand Up @@ -378,21 +367,16 @@ impl HyperlaneLogStore<InterchainGasPayment> for HyperlaneSqlDb {
if payments.is_empty() {
return Ok(0);
}
let txns: HashMap<H256, TxnWithId> = self
let txns: HashMap<H512, TxnWithId> = self
.ensure_blocks_and_txns(payments.iter().map(|r| &r.1))
.await?
.map(|t| (t.hash, t))
.collect();
let storable = payments
.iter()
.filter_map(|(payment, meta)| {
txns.get(
&meta
.transaction_id
.try_into()
.expect("256-bit transaction ids are the maximum supported at this time"),
)
.map(|txn| (payment.inner(), meta, txn.id))
txns.get(&meta.transaction_id)
.map(|txn| (payment.inner(), meta, txn.id))
})
.map(|(payment, meta, txn_id)| StorablePayment {
payment,
Expand Down Expand Up @@ -446,13 +430,13 @@ where

#[derive(Debug, Clone)]
struct TxnWithId {
hash: H256,
hash: H512,
id: i64,
}

#[derive(Debug, Clone)]
struct TxnWithBlockId {
txn_hash: H256,
txn_hash: H512,
block_id: i64,
}

Expand Down
31 changes: 1 addition & 30 deletions rust/main/agents/scraper/src/conversions.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,7 @@
use num_bigint::{BigInt, Sign};
use sea_orm::prelude::BigDecimal;

use hyperlane_core::{H256, U256};

// Creates a big-endian hex representation of the address
pub fn address_to_bytes(data: &H256) -> Vec<u8> {
if hex::is_h160(data.as_fixed_bytes()) {
// take the last 20 bytes
data.as_fixed_bytes()[12..32].into()
} else {
h256_to_bytes(data)
}
}

// Creates a big-endian hex representation of the address
pub fn bytes_to_address(data: Vec<u8>) -> eyre::Result<H256> {
if (data.len() != 20) && (data.len() != 32) {
return Err(eyre::eyre!("Invalid address length"));
}
if data.len() == 20 {
let mut prefix = vec![0; 12];
prefix.extend(data);
Ok(H256::from_slice(&prefix[..]))
} else {
Ok(H256::from_slice(&data[..]))
}
}

// Creates a big-endian hex representation of the address hash
pub fn h256_to_bytes(data: &H256) -> Vec<u8> {
data.as_fixed_bytes().as_slice().into()
}
use hyperlane_core::U256;

pub fn u256_to_decimal(v: U256) -> BigDecimal {
let mut buf = [0u8; 32];
Expand Down
3 changes: 1 addition & 2 deletions rust/main/agents/scraper/src/db/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ use sea_orm::{
};
use tracing::{debug, trace};

use hyperlane_core::{BlockInfo, H256};
use hyperlane_core::{address_to_bytes, h256_to_bytes, BlockInfo, H256};
use migration::OnConflict;

use crate::conversions::{address_to_bytes, h256_to_bytes};
use crate::date_time;
use crate::db::ScraperDb;

Expand Down
5 changes: 3 additions & 2 deletions rust/main/agents/scraper/src/db/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ use itertools::Itertools;
use sea_orm::{prelude::*, ActiveValue::*, DeriveColumn, EnumIter, Insert, QuerySelect};
use tracing::{debug, instrument, trace};

use hyperlane_core::{HyperlaneMessage, LogMeta, H256};
use hyperlane_core::{
address_to_bytes, bytes_to_address, h256_to_bytes, HyperlaneMessage, LogMeta, H256,
};
use migration::OnConflict;

use crate::conversions::{address_to_bytes, bytes_to_address, h256_to_bytes};
use crate::date_time;
use crate::db::ScraperDb;

Expand Down
4 changes: 2 additions & 2 deletions rust/main/agents/scraper/src/db/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use itertools::Itertools;
use sea_orm::{prelude::*, ActiveValue::*, Insert, QuerySelect};
use tracing::{debug, instrument, trace};

use hyperlane_core::{InterchainGasPayment, LogMeta};
use hyperlane_core::{h256_to_bytes, InterchainGasPayment, LogMeta};
use migration::OnConflict;

use crate::conversions::{h256_to_bytes, u256_to_decimal};
use crate::conversions::u256_to_decimal;
use crate::date_time;
use crate::db::ScraperDb;

Expand Down
20 changes: 9 additions & 11 deletions rust/main/agents/scraper/src/db/txn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@ use std::collections::HashMap;

use derive_more::Deref;
use eyre::{eyre, Context, Result};
use hyperlane_core::{TxnInfo, H256};
use sea_orm::{
prelude::*, sea_query::OnConflict, ActiveValue::*, DeriveColumn, EnumIter, Insert, NotSet,
QuerySelect,
};
use tracing::{debug, instrument, trace};

use hyperlane_core::{address_to_bytes, bytes_to_h512, h512_to_bytes, TxnInfo, H512};

use super::generated::transaction;
use crate::{
conversions::{address_to_bytes, h256_to_bytes, u256_to_decimal},
date_time,
db::ScraperDb,
};

use crate::{conversions::u256_to_decimal, date_time, db::ScraperDb};

#[derive(Debug, Clone, Deref)]
pub struct StorableTxn {
Expand Down Expand Up @@ -43,8 +41,8 @@ impl ScraperDb {
/// found be excluded from the hashmap.
pub async fn get_txn_ids(
&self,
hashes: impl Iterator<Item = &H256>,
) -> Result<HashMap<H256, i64>> {
hashes: impl Iterator<Item = &H512>,
) -> Result<HashMap<H512, i64>> {
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
enum QueryAs {
Id,
Expand All @@ -53,7 +51,7 @@ impl ScraperDb {

// check database to see which txns we already know and fetch their IDs
let txns = transaction::Entity::find()
.filter(transaction::Column::Hash.is_in(hashes.map(h256_to_bytes)))
.filter(transaction::Column::Hash.is_in(hashes.map(h512_to_bytes)))
.select_only()
.column_as(transaction::Column::Id, QueryAs::Id)
.column_as(transaction::Column::Hash, QueryAs::Hash)
Expand All @@ -62,7 +60,7 @@ impl ScraperDb {
.await
.context("When querying transactions")?
.into_iter()
.map(|(id, hash)| Ok((H256::from_slice(&hash), id)))
.map(|(id, hash)| Ok((bytes_to_h512(&hash), id)))
.collect::<Result<HashMap<_, _>>>()?;

trace!(?txns, "Queried transaction info for hashes");
Expand All @@ -86,7 +84,7 @@ impl ScraperDb {
max_priority_fee_per_gas: Set(txn
.max_priority_fee_per_gas
.map(u256_to_decimal)),
hash: Unchanged(h256_to_bytes(&txn.hash)),
hash: Unchanged(h512_to_bytes(&txn.hash)),
time_created: Set(date_time::now()),
gas_used: Set(u256_to_decimal(receipt.gas_used)),
gas_price: Set(txn.gas_price.map(u256_to_decimal)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use tracing::{error, warn};

use crypto::decompress_public_key;
use hyperlane_core::{
AccountAddressType, BlockInfo, ChainCommunicationError, ChainInfo, ChainResult,
ContractLocator, HyperlaneChain, HyperlaneDomain, HyperlaneProvider, HyperlaneProviderError,
TxnInfo, TxnReceiptInfo, H256, U256,
bytes_to_h512, h512_to_bytes, AccountAddressType, BlockInfo, ChainCommunicationError,
ChainInfo, ChainResult, ContractLocator, HyperlaneChain, HyperlaneDomain, HyperlaneProvider,
HyperlaneProviderError, TxnInfo, TxnReceiptInfo, H256, H512, U256,
};

use crate::grpc::{WasmGrpcProvider, WasmProvider};
Expand Down Expand Up @@ -204,10 +204,10 @@ impl CosmosProvider {
/// Extract contract address from transaction.
fn contract(tx: &Tx, tx_hash: &H256) -> ChainResult<H256> {
// We merge two error messages together so that both of them are reported
match Self::contract_address_from_msg_execute_contract(tx, tx_hash) {
match Self::contract_address_from_msg_execute_contract(tx) {
Ok(contract) => Ok(contract),
Err(msg_execute_contract_error) => {
match Self::contract_address_from_msg_recv_packet(tx, tx_hash) {
match Self::contract_address_from_msg_recv_packet(tx) {
Ok(contract) => Ok(contract),
Err(msg_recv_packet_error) => {
let errors = vec![msg_execute_contract_error, msg_recv_packet_error];
Expand All @@ -221,10 +221,7 @@ impl CosmosProvider {
}

/// Assumes that there is only one `MsgExecuteContract` message in the transaction
fn contract_address_from_msg_execute_contract(
tx: &Tx,
tx_hash: &H256,
) -> Result<H256, HyperlaneCosmosError> {
fn contract_address_from_msg_execute_contract(tx: &Tx) -> Result<H256, HyperlaneCosmosError> {
use cosmrs::proto::cosmwasm::wasm::v1::MsgExecuteContract as ProtoMsgExecuteContract;

let contract_execution_messages = tx
Expand Down Expand Up @@ -253,10 +250,7 @@ impl CosmosProvider {
Ok(contract)
}

fn contract_address_from_msg_recv_packet(
tx: &Tx,
tx_hash: &H256,
) -> Result<H256, HyperlaneCosmosError> {
fn contract_address_from_msg_recv_packet(tx: &Tx) -> Result<H256, HyperlaneCosmosError> {
let packet_data = tx
.body
.messages
Expand Down Expand Up @@ -392,15 +386,17 @@ impl HyperlaneProvider for CosmosProvider {
Ok(block_info)
}

async fn get_txn_by_hash(&self, hash: &H256) -> ChainResult<TxnInfo> {
async fn get_txn_by_hash(&self, hash: &H512) -> ChainResult<TxnInfo> {
let hash: H256 = H256::from_slice(&h512_to_bytes(hash));

let tendermint_hash = Hash::from_bytes(Algorithm::Sha256, hash.as_bytes())
.expect("transaction hash should be of correct size");

let response = self.rpc_client.get_tx_by_hash(tendermint_hash).await?;

let received_hash = H256::from_slice(response.hash.as_bytes());

if &received_hash != hash {
if received_hash != hash {
return Err(ChainCommunicationError::from_other_str(&format!(
"received incorrect transaction, expected hash: {:?}, received hash: {:?}",
hash, received_hash,
Expand All @@ -409,12 +405,12 @@ impl HyperlaneProvider for CosmosProvider {

let tx = Tx::from_bytes(&response.tx)?;

let contract = Self::contract(&tx, hash)?;
let contract = Self::contract(&tx, &hash)?;
let (sender, nonce) = self.sender_and_nonce(&tx)?;
let gas_price = self.calculate_gas_price(hash, &tx);
let gas_price = self.calculate_gas_price(&hash, &tx);

let tx_info = TxnInfo {
hash: hash.to_owned(),
hash: hash.into(),
gas_limit: U256::from(response.tx_result.gas_wanted),
max_priority_fee_per_gas: None,
max_fee_per_gas: None,
Expand Down
Loading
Loading