From 14e4719f00be336cd7b7b74a342d212fe6a2c0a4 Mon Sep 17 00:00:00 2001 From: Danil Nemirovsky Date: Fri, 25 Oct 2024 13:51:44 +0100 Subject: [PATCH] feat: Use H512 as transaction hash in HyperlaneProvider and Scraper (#4759) ### Description Use H512 as transaction hash in HyperlaneProvider and Scraper. ### Related issues - Contributes https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/4272 ### Backward compatibility Yes ### Testing Manual run of Scraper for Ethereum and Neutron --------- Co-authored-by: Danil Nemirovsky <4614623+ameten@users.noreply.github.com> --- rust/main/Cargo.lock | 1 - rust/main/agents/scraper/Cargo.toml | 1 - .../agents/scraper/src/chain_scraper/mod.rs | 56 +++---- rust/main/agents/scraper/src/conversions.rs | 31 +--- rust/main/agents/scraper/src/db/block.rs | 3 +- rust/main/agents/scraper/src/db/message.rs | 5 +- rust/main/agents/scraper/src/db/payment.rs | 4 +- rust/main/agents/scraper/src/db/txn.rs | 20 ++- .../src/providers/cosmos/provider.rs | 32 ++-- .../src/rpc_clients/provider.rs | 4 +- .../chains/hyperlane-fuel/src/provider.rs | 12 +- .../chains/hyperlane-sealevel/src/provider.rs | 4 +- .../hyperlane-core/src/traits/provider.rs | 6 +- .../main/hyperlane-core/src/traits/signing.rs | 3 +- .../hyperlane-core/src/types/chain_data.rs | 4 +- .../hyperlane-core/src/types/conversions.rs | 138 ++++++++++++++++++ rust/main/hyperlane-core/src/types/mod.rs | 2 + rust/main/utils/hex/src/lib.rs | 38 ----- 18 files changed, 208 insertions(+), 156 deletions(-) create mode 100644 rust/main/hyperlane-core/src/types/conversions.rs diff --git a/rust/main/Cargo.lock b/rust/main/Cargo.lock index 87d2c813e9..27b11dcab1 100644 --- a/rust/main/Cargo.lock +++ b/rust/main/Cargo.lock @@ -7670,7 +7670,6 @@ dependencies = [ "ethers", "eyre", "futures", - "hex 0.1.0", "hyperlane-base", "hyperlane-core", "hyperlane-test", diff --git a/rust/main/agents/scraper/Cargo.toml b/rust/main/agents/scraper/Cargo.toml index 7bad1ec7eb..0b9e429b9b 100644 --- a/rust/main/agents/scraper/Cargo.toml +++ b/rust/main/agents/scraper/Cargo.toml @@ -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" } diff --git a/rust/main/agents/scraper/src/chain_scraper/mod.rs b/rust/main/agents/scraper/src/chain_scraper/mod.rs index c23df70a16..0be5b2ef13 100644 --- a/rust/main/agents/scraper/src/chain_scraper/mod.rs +++ b/rust/main/agents/scraper/src/chain_scraper/mod.rs @@ -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, @@ -78,12 +79,10 @@ impl HyperlaneSqlDb { &self, log_meta: impl Iterator, ) -> Result> { - let block_id_by_txn_hash: HashMap = log_meta + let block_id_by_txn_hash: HashMap = 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), ) }) @@ -121,7 +120,7 @@ impl HyperlaneSqlDb { txns: impl Iterator, ) -> Result> { // mapping of txn hash to (txn_id, block_id). - let mut txns: HashMap, i64)> = txns + let mut txns: HashMap, i64)> = txns .map(|TxnWithBlockId { txn_hash, block_id }| (txn_hash, (None, block_id))) .collect(); @@ -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 = 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))>(txns_to_fetch, CHUNK_SIZE) { + for mut chunk in as_chunks::<(&H512, &mut (Option, 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, @@ -302,7 +301,7 @@ impl HyperlaneLogStore for HyperlaneSqlDb { if messages.is_empty() { return Ok(0); } - let txns: HashMap = self + let txns: HashMap = self .ensure_blocks_and_txns(messages.iter().map(|r| &r.1)) .await? .map(|t| (t.hash, t)) @@ -310,13 +309,8 @@ impl HyperlaneLogStore for HyperlaneSqlDb { 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 @@ -336,7 +330,7 @@ impl HyperlaneLogStore for HyperlaneSqlDb { if deliveries.is_empty() { return Ok(0); } - let txns: HashMap = self + let txns: HashMap = self .ensure_blocks_and_txns(deliveries.iter().map(|r| &r.1)) .await? .map(|t| (t.hash, t)) @@ -344,13 +338,8 @@ impl HyperlaneLogStore for HyperlaneSqlDb { 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, @@ -378,7 +367,7 @@ impl HyperlaneLogStore for HyperlaneSqlDb { if payments.is_empty() { return Ok(0); } - let txns: HashMap = self + let txns: HashMap = self .ensure_blocks_and_txns(payments.iter().map(|r| &r.1)) .await? .map(|t| (t.hash, t)) @@ -386,13 +375,8 @@ impl HyperlaneLogStore for HyperlaneSqlDb { 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, @@ -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, } diff --git a/rust/main/agents/scraper/src/conversions.rs b/rust/main/agents/scraper/src/conversions.rs index 84a64a8577..9252d5cd44 100644 --- a/rust/main/agents/scraper/src/conversions.rs +++ b/rust/main/agents/scraper/src/conversions.rs @@ -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 { - 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) -> eyre::Result { - 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 { - data.as_fixed_bytes().as_slice().into() -} +use hyperlane_core::U256; pub fn u256_to_decimal(v: U256) -> BigDecimal { let mut buf = [0u8; 32]; diff --git a/rust/main/agents/scraper/src/db/block.rs b/rust/main/agents/scraper/src/db/block.rs index 1af05cd8c4..45ff0bf7c8 100644 --- a/rust/main/agents/scraper/src/db/block.rs +++ b/rust/main/agents/scraper/src/db/block.rs @@ -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; diff --git a/rust/main/agents/scraper/src/db/message.rs b/rust/main/agents/scraper/src/db/message.rs index f8b99fec50..423c24058a 100644 --- a/rust/main/agents/scraper/src/db/message.rs +++ b/rust/main/agents/scraper/src/db/message.rs @@ -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; diff --git a/rust/main/agents/scraper/src/db/payment.rs b/rust/main/agents/scraper/src/db/payment.rs index 250f4f3c6f..498128c34b 100644 --- a/rust/main/agents/scraper/src/db/payment.rs +++ b/rust/main/agents/scraper/src/db/payment.rs @@ -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; diff --git a/rust/main/agents/scraper/src/db/txn.rs b/rust/main/agents/scraper/src/db/txn.rs index ff0e70f2b5..d5cec03dc7 100644 --- a/rust/main/agents/scraper/src/db/txn.rs +++ b/rust/main/agents/scraper/src/db/txn.rs @@ -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 { @@ -43,8 +41,8 @@ impl ScraperDb { /// found be excluded from the hashmap. pub async fn get_txn_ids( &self, - hashes: impl Iterator, - ) -> Result> { + hashes: impl Iterator, + ) -> Result> { #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] enum QueryAs { Id, @@ -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) @@ -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::>>()?; trace!(?txns, "Queried transaction info for hashes"); @@ -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)), diff --git a/rust/main/chains/hyperlane-cosmos/src/providers/cosmos/provider.rs b/rust/main/chains/hyperlane-cosmos/src/providers/cosmos/provider.rs index ef0c153458..e718df6102 100644 --- a/rust/main/chains/hyperlane-cosmos/src/providers/cosmos/provider.rs +++ b/rust/main/chains/hyperlane-cosmos/src/providers/cosmos/provider.rs @@ -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}; @@ -204,10 +204,10 @@ impl CosmosProvider { /// Extract contract address from transaction. fn contract(tx: &Tx, tx_hash: &H256) -> ChainResult { // 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]; @@ -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 { + fn contract_address_from_msg_execute_contract(tx: &Tx) -> Result { use cosmrs::proto::cosmwasm::wasm::v1::MsgExecuteContract as ProtoMsgExecuteContract; let contract_execution_messages = tx @@ -253,10 +250,7 @@ impl CosmosProvider { Ok(contract) } - fn contract_address_from_msg_recv_packet( - tx: &Tx, - tx_hash: &H256, - ) -> Result { + fn contract_address_from_msg_recv_packet(tx: &Tx) -> Result { let packet_data = tx .body .messages @@ -392,7 +386,9 @@ impl HyperlaneProvider for CosmosProvider { Ok(block_info) } - async fn get_txn_by_hash(&self, hash: &H256) -> ChainResult { + async fn get_txn_by_hash(&self, hash: &H512) -> ChainResult { + 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"); @@ -400,7 +396,7 @@ impl HyperlaneProvider for CosmosProvider { 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, @@ -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, diff --git a/rust/main/chains/hyperlane-ethereum/src/rpc_clients/provider.rs b/rust/main/chains/hyperlane-ethereum/src/rpc_clients/provider.rs index c8ef3d78ce..d89cf9f43f 100644 --- a/rust/main/chains/hyperlane-ethereum/src/rpc_clients/provider.rs +++ b/rust/main/chains/hyperlane-ethereum/src/rpc_clients/provider.rs @@ -7,7 +7,7 @@ use async_trait::async_trait; use derive_new::new; use ethers::prelude::Middleware; use ethers_core::{abi::Address, types::BlockNumber}; -use hyperlane_core::{ethers_core_types, ChainInfo, HyperlaneCustomErrorWrapper, U256}; +use hyperlane_core::{ethers_core_types, ChainInfo, HyperlaneCustomErrorWrapper, H512, U256}; use tokio::time::sleep; use tracing::instrument; @@ -84,7 +84,7 @@ where #[instrument(err, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue - async fn get_txn_by_hash(&self, hash: &H256) -> ChainResult { + async fn get_txn_by_hash(&self, hash: &H512) -> ChainResult { let txn = get_with_retry_on_none( hash, |h| self.provider.get_transaction(*h), diff --git a/rust/main/chains/hyperlane-fuel/src/provider.rs b/rust/main/chains/hyperlane-fuel/src/provider.rs index a72f8a6c5f..cdd32650e1 100644 --- a/rust/main/chains/hyperlane-fuel/src/provider.rs +++ b/rust/main/chains/hyperlane-fuel/src/provider.rs @@ -17,9 +17,9 @@ use fuels::{ }; use futures::future::join_all; use hyperlane_core::{ - BlockInfo, ChainCommunicationError, ChainInfo, ChainResult, HyperlaneChain, HyperlaneDomain, - HyperlaneMessage, HyperlaneProvider, HyperlaneProviderError, Indexed, LogMeta, TxnInfo, H256, - H512, U256, + h512_to_bytes, BlockInfo, ChainCommunicationError, ChainInfo, ChainResult, HyperlaneChain, + HyperlaneDomain, HyperlaneMessage, HyperlaneProvider, HyperlaneProviderError, Indexed, LogMeta, + TxnInfo, H256, H512, U256, }; use crate::{make_client, make_provider, prelude::FuelIntoH256, ConnectionConf}; @@ -314,7 +314,9 @@ impl HyperlaneProvider for FuelProvider { /// Used by scraper #[allow(clippy::clone_on_copy)] // TODO: `rustc` 1.80.1 clippy issue #[allow(clippy::match_like_matches_macro)] // TODO: `rustc` 1.80.1 clippy issue - async fn get_txn_by_hash(&self, hash: &H256) -> ChainResult { + async fn get_txn_by_hash(&self, hash: &H512) -> ChainResult { + let hash = H256::from_slice(&h512_to_bytes(hash)); + let transaction_res = self .provider .get_transaction_by_id(&hash.0.into()) @@ -370,7 +372,7 @@ impl HyperlaneProvider for FuelProvider { }; Ok(TxnInfo { - hash: hash.clone(), + hash: hash.into(), gas_limit: gas_limit.into(), max_priority_fee_per_gas: None, max_fee_per_gas: None, diff --git a/rust/main/chains/hyperlane-sealevel/src/provider.rs b/rust/main/chains/hyperlane-sealevel/src/provider.rs index aaf32ac593..932a7191ea 100644 --- a/rust/main/chains/hyperlane-sealevel/src/provider.rs +++ b/rust/main/chains/hyperlane-sealevel/src/provider.rs @@ -3,7 +3,7 @@ use std::{str::FromStr, sync::Arc}; use async_trait::async_trait; use hyperlane_core::{ BlockInfo, ChainInfo, ChainResult, HyperlaneChain, HyperlaneDomain, HyperlaneProvider, - HyperlaneProviderError, TxnInfo, H256, U256, + HyperlaneProviderError, TxnInfo, H256, H512, U256, }; use solana_sdk::bs58; use solana_sdk::pubkey::Pubkey; @@ -68,7 +68,7 @@ impl HyperlaneProvider for SealevelProvider { Ok(block_info) } - async fn get_txn_by_hash(&self, _hash: &H256) -> ChainResult { + async fn get_txn_by_hash(&self, _hash: &H512) -> ChainResult { todo!() // FIXME } diff --git a/rust/main/hyperlane-core/src/traits/provider.rs b/rust/main/hyperlane-core/src/traits/provider.rs index 47070bc2ab..63b4d01dd9 100644 --- a/rust/main/hyperlane-core/src/traits/provider.rs +++ b/rust/main/hyperlane-core/src/traits/provider.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use auto_impl::auto_impl; use thiserror::Error; -use crate::{BlockInfo, ChainInfo, ChainResult, HyperlaneChain, TxnInfo, H256, U256}; +use crate::{BlockInfo, ChainInfo, ChainResult, HyperlaneChain, TxnInfo, H256, H512, U256}; /// Interface for a provider. Allows abstraction over different provider types /// for different chains. @@ -20,7 +20,7 @@ pub trait HyperlaneProvider: HyperlaneChain + Send + Sync + Debug { async fn get_block_by_height(&self, height: u64) -> ChainResult; /// Get txn info for a given txn hash - async fn get_txn_by_hash(&self, hash: &H256) -> ChainResult; + async fn get_txn_by_hash(&self, hash: &H512) -> ChainResult; /// Returns whether a contract exists at the provided address async fn is_contract(&self, address: &H256) -> ChainResult; @@ -40,7 +40,7 @@ pub enum HyperlaneProviderError { NoGasUsed, /// Could not find a transaction by hash #[error("Could not find transaction from provider with hash {0:?}")] - CouldNotFindTransactionByHash(H256), + CouldNotFindTransactionByHash(H512), /// Could not find a block by height #[error("Could not find block from provider with height {0:?}")] CouldNotFindBlockByHeight(u64), diff --git a/rust/main/hyperlane-core/src/traits/signing.rs b/rust/main/hyperlane-core/src/traits/signing.rs index 34e5676c42..5859d3c25b 100644 --- a/rust/main/hyperlane-core/src/traits/signing.rs +++ b/rust/main/hyperlane-core/src/traits/signing.rs @@ -1,10 +1,11 @@ +use std::fmt::{Debug, Formatter}; + use async_trait::async_trait; use auto_impl::auto_impl; use serde::{ ser::{SerializeStruct, Serializer}, Deserialize, Serialize, }; -use std::fmt::{Debug, Formatter}; use crate::utils::bytes_to_hex; use crate::{Signature, H160, H256}; diff --git a/rust/main/hyperlane-core/src/types/chain_data.rs b/rust/main/hyperlane-core/src/types/chain_data.rs index 5f5ecb2e3b..219f6989da 100644 --- a/rust/main/hyperlane-core/src/types/chain_data.rs +++ b/rust/main/hyperlane-core/src/types/chain_data.rs @@ -1,6 +1,6 @@ use derive_new::new; -use crate::{H256, U256}; +use crate::{H256, H512, U256}; /// Info about a given block in the chain. #[derive(Debug, Clone, Default)] @@ -27,7 +27,7 @@ pub struct ChainInfo { #[derive(Debug, Clone)] pub struct TxnInfo { /// Hash of this transaction - pub hash: H256, + pub hash: H512, /// Amount of gas which was allocated for running the transaction pub gas_limit: U256, /// Represents the maximum tx fee that will go to the miner as part of the diff --git a/rust/main/hyperlane-core/src/types/conversions.rs b/rust/main/hyperlane-core/src/types/conversions.rs new file mode 100644 index 0000000000..5336e0e2bf --- /dev/null +++ b/rust/main/hyperlane-core/src/types/conversions.rs @@ -0,0 +1,138 @@ +use uint::unroll; + +use crate::{H256, H512}; + +/// Creates a big-endian hex representation of the address +pub fn address_to_bytes(data: &H256) -> Vec { + if 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) -> eyre::Result { + 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 { + data.as_fixed_bytes().as_slice().into() +} + +/// Creates a big-endian hex representation of the address hash +pub fn h512_to_bytes(data: &H512) -> Vec { + if is_h256(data.as_fixed_bytes()) { + // take the last 32 bytes + data.as_fixed_bytes()[32..64].into() + } else { + data.as_fixed_bytes().as_slice().into() + } +} + +/// Convert bytes into H512 with padding +pub fn bytes_to_h512(data: &[u8]) -> H512 { + assert!(data.len() <= 64); + + if data.len() == 64 { + return H512::from_slice(data); + } + + let mut buf = [0; 64]; + buf[64 - data.len()..64].copy_from_slice(data); + + H512::from_slice(&buf) +} + +/// Checks if a byte slice fits within 160 bits. Assumes a big-endian encoding; +/// ignores leading zeros. Current implementation only supports up to a 32 byte +/// array but this could easily be extended if needed. +pub const fn is_h160(data: &[u8; S]) -> bool { + assert!(S <= 32); + if S <= 20 { + true + } else { + let mut z = data[0]; + unroll! { + for i in 0..11 { + if S >= i + 22 { + z |= data[i + 1] + } + } + } + + z == 0 + } +} + +/// Checks if a byte slice fits within 32 bytes. Assumes a big-endian encoding; +/// ignores leading zeros. Current implementation only supports up to a 64 byte long +/// array but this could easily be extended if needed. +pub const fn is_h256(data: &[u8; S]) -> bool { + assert!(S <= 64); + if S <= 32 { + true + } else { + unroll! { + for i in 0..32 { + if data[i] != 0 { + return false; + } + } + } + + true + } +} + +#[cfg(test)] +mod test { + #[test] + fn is_h160() { + let v: [u8; 32] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xd1, + 0xc9, 0x44, 0x69, 0x70, 0x08, 0x33, 0x71, 0x7f, 0xa8, 0xa3, 0x01, 0x72, 0x78, 0xbc, + 0x1c, 0xa8, 0x03, 0x1c, + ]; + assert!(super::is_h160(&v)); + + let v: [u8; 32] = [ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xd1, + 0xc9, 0x44, 0x69, 0x70, 0x08, 0x33, 0x71, 0x7f, 0xa8, 0xa3, 0x01, 0x72, 0x78, 0xbc, + 0x1c, 0xa8, 0x03, 0x1c, + ]; + assert!(!super::is_h160(&v)); + } + + #[test] + fn is_h256() { + let v: [u8; 64] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xfa, 0xd1, + 0xc9, 0x44, 0x69, 0x70, 0x08, 0x33, 0x71, 0x7f, 0xa8, 0xa3, 0x01, 0x72, 0x78, 0xbc, + 0x1c, 0xa8, 0x03, 0x1c, 0x04, 0x1d, 0x05, 0x1e, + ]; + assert!(super::is_h256(&v)); + + let v: [u8; 64] = [ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xfa, 0xd1, + 0xc9, 0x44, 0x69, 0x70, 0x08, 0x33, 0x71, 0x7f, 0xa8, 0xa3, 0x01, 0x72, 0x78, 0xbc, + 0x1c, 0xa8, 0x03, 0x1c, 0x04, 0x1d, 0x05, 0x1e, + ]; + assert!(!super::is_h256(&v)); + } +} diff --git a/rust/main/hyperlane-core/src/types/mod.rs b/rust/main/hyperlane-core/src/types/mod.rs index a8973a72b3..84df52d18e 100644 --- a/rust/main/hyperlane-core/src/types/mod.rs +++ b/rust/main/hyperlane-core/src/types/mod.rs @@ -12,6 +12,7 @@ pub use announcement::*; pub use block_id::BlockId; pub use chain_data::*; pub use checkpoint::*; +pub use conversions::*; pub use indexing::*; pub use log_metadata::*; pub use merkle_tree::*; @@ -27,6 +28,7 @@ mod announcement; mod block_id; mod chain_data; mod checkpoint; +mod conversions; mod indexing; mod log_metadata; mod merkle_tree; diff --git a/rust/main/utils/hex/src/lib.rs b/rust/main/utils/hex/src/lib.rs index 46b4d2894f..719a0b7866 100644 --- a/rust/main/utils/hex/src/lib.rs +++ b/rust/main/utils/hex/src/lib.rs @@ -29,27 +29,6 @@ const FROM_HEX_CHARS: [u8; 256] = [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ]; -/// Checks if a byte slice fits within 160 bits. Assumes a big-endian encoding; -/// ignores leading zeros. Current implementation only supports up to a 32 byte -/// array but this could easily be extended if needed. -pub const fn is_h160(data: &[u8; S]) -> bool { - assert!(S <= 32); - if S <= 20 { - true - } else { - let mut z = data[0]; - unroll! { - for i in 0..11 { - if S >= i + 22 { - z |= data[i + 1] - } - } - } - - z == 0 - } -} - /// This formats a 160bit byte slice as a lowercase hex string without any /// prefixing (will include leading zeros). pub fn format_h160_raw(data: &[u8; 20]) -> String { @@ -150,23 +129,6 @@ impl Error for InvalidHexCharacter {} mod test { use crate::FROM_HEX_CHARS; - #[test] - fn is_h160() { - let v: [u8; 32] = [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xd1, - 0xc9, 0x44, 0x69, 0x70, 0x08, 0x33, 0x71, 0x7f, 0xa8, 0xa3, 0x01, 0x72, 0x78, 0xbc, - 0x1c, 0xa8, 0x03, 0x1c, - ]; - assert!(super::is_h160(&v)); - - let v: [u8; 32] = [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xd1, - 0xc9, 0x44, 0x69, 0x70, 0x08, 0x33, 0x71, 0x7f, 0xa8, 0xa3, 0x01, 0x72, 0x78, 0xbc, - 0x1c, 0xa8, 0x03, 0x1c, - ]; - assert!(!super::is_h160(&v)); - } - #[test] fn format_h160() { let v: [u8; 20] = [