From 559a9ea23f9756cd686826ce5da2412c11ede32e Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Sat, 14 Dec 2024 11:10:03 +0200 Subject: [PATCH 01/26] feat(ampd): starknet gmp implementation --- Cargo.toml | 31 +- ampd/Cargo.toml | 18 +- ampd/src/handlers/config.rs | 21 + ampd/src/handlers/mod.rs | 2 + ampd/src/handlers/starknet_verify_msg.rs | 508 ++++++++ .../handlers/starknet_verify_verifier_set.rs | 161 +++ ampd/src/lib.rs | 18 + ampd/src/starknet/json_rpc.rs | 1054 +++++++++++++++++ ampd/src/starknet/mod.rs | 2 + ampd/src/starknet/verifier.rs | 346 ++++++ packages/axelar-wasm-std/Cargo.toml | 14 +- packages/axelar-wasm-std/src/utils.rs | 19 + packages/starknet-types/Cargo.toml | 28 + packages/starknet-types/src/error.rs | 7 + packages/starknet-types/src/events.rs | 51 + .../src/events/contract_call.rs | 267 +++++ .../src/events/signers_rotated.rs | 366 ++++++ packages/starknet-types/src/lib.rs | 3 + packages/starknet-types/src/types.rs | 3 + .../starknet-types/src/types/array_span.rs | 187 +++ .../starknet-types/src/types/byte_array.rs | 444 +++++++ .../src/types/starknet_message.rs | 260 ++++ 22 files changed, 3792 insertions(+), 18 deletions(-) create mode 100644 ampd/src/handlers/starknet_verify_msg.rs create mode 100644 ampd/src/handlers/starknet_verify_verifier_set.rs create mode 100644 ampd/src/starknet/json_rpc.rs create mode 100644 ampd/src/starknet/mod.rs create mode 100644 ampd/src/starknet/verifier.rs create mode 100644 packages/starknet-types/Cargo.toml create mode 100644 packages/starknet-types/src/error.rs create mode 100644 packages/starknet-types/src/events.rs create mode 100644 packages/starknet-types/src/events/contract_call.rs create mode 100644 packages/starknet-types/src/events/signers_rotated.rs create mode 100644 packages/starknet-types/src/lib.rs create mode 100644 packages/starknet-types/src/types.rs create mode 100644 packages/starknet-types/src/types/array_span.rs create mode 100644 packages/starknet-types/src/types/byte_array.rs create mode 100644 packages/starknet-types/src/types/starknet_message.rs diff --git a/Cargo.toml b/Cargo.toml index ff9bd4504..1066e5de2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [workspace] members = [ - "ampd", - "contracts/*", - "external-gateways/*", - "integration-tests", - "packages/*" + "ampd", + "contracts/*", + "external-gateways/*", + "integration-tests", + "packages/*", ] resolver = "2" @@ -13,8 +13,12 @@ rust-version = "1.78.0" # be sure there is an optimizer release supporting this edition = "2021" [workspace.dependencies] -alloy-primitives = { version = "0.7.6", default-features = false, features = ["std"] } -alloy-sol-types = { version = "0.7.6", default-features = false, features = ["std"] } +alloy-primitives = { version = "0.7.6", default-features = false, features = [ + "std", +] } +alloy-sol-types = { version = "0.7.6", default-features = false, features = [ + "std", +] } anyhow = "1.0.89" assert_ok = "1.0" axelar-wasm-std = { version = "^1.0.0", path = "packages/axelar-wasm-std" } @@ -31,7 +35,9 @@ cw-storage-plus = { version = "1.2.0", features = ["iterator", "macro"] } cw2 = "1.1.0" ed25519-dalek = { version = "2.1.1", default-features = false } error-stack = { version = "0.4.0", features = ["eyre"] } -ethers-contract = { version = "2.0.14", default-features = false, features = ["abigen"] } +ethers-contract = { version = "2.0.14", default-features = false, features = [ + "abigen", +] } ethers-core = "2.0.14" events = { version = "^1.0.0", path = "packages/events" } events-derive = { version = "^1.0.0", path = "packages/events-derive" } @@ -69,6 +75,10 @@ stellar-xdr = { version = "21.2.0" } strum = { version = "0.25", default-features = false, features = ["derive"] } sui-gateway = { version = "^1.0.0", path = "packages/sui-gateway" } sui-types = { version = "^1.0.0", path = "packages/sui-types" } +starknet-types-core = { version = "0.1.7" } +starknet-types = { version = "^1.0.0", path = "packages/starknet-types" } +starknet-core = "0.12.0" +starknet-providers = "0.12.0" syn = "2.0.68" thiserror = "1.0.61" tofn = { version = "1.1" } @@ -77,6 +87,11 @@ tokio-stream = "0.1.11" tokio-util = "0.7.11" voting-verifier = { version = "^1.1.0", path = "contracts/voting-verifier" } axelar-core-std = { version = "^1.0.0", path = "packages/axelar-core-std" } +# Async +futures-concurrency = "7.4" +futures-util = "0.3" +futures = "0.3" +async-trait = "0" [workspace.lints.clippy] arithmetic_side_effects = "deny" diff --git a/ampd/Cargo.toml b/ampd/Cargo.toml index 289bd83d3..ff770aac6 100644 --- a/ampd/Cargo.toml +++ b/ampd/Cargo.toml @@ -25,7 +25,7 @@ error-stack = { workspace = true } ethers-contract = { workspace = true } ethers-core = { workspace = true } ethers-providers = { version = "2.0.13", default-features = false, features = [ - "rustls", + "rustls", ] } events = { workspace = true } events-derive = { workspace = true } @@ -40,7 +40,9 @@ move-core-types = { git = "https://github.com/mystenlabs/sui", tag = "testnet-v1 multisig = { workspace = true, features = ["library"] } multiversx-sdk = "0.6.1" num-traits = { workspace = true } -openssl = { version = "0.10.35", features = ["vendored"] } # Needed to make arm compilation work by forcing vendoring +openssl = { version = "0.10.35", features = [ + "vendored", +] } # Needed to make arm compilation work by forcing vendoring prost = "0.11.9" prost-types = "0.11.9" report = { workspace = true } @@ -63,7 +65,7 @@ sui-types = { git = "https://github.com/mystenlabs/sui", tag = "testnet-v1.39.1" # The fix for the issue is at https://github.com/axelarnetwork/tendermint-rs/commit/e97033e20e660a7e707ea86db174ec047bbba50d. tendermint = { git = "https://github.com/axelarnetwork/tendermint-rs.git", branch = "v0.33.x" } tendermint-rpc = { git = "https://github.com/axelarnetwork/tendermint-rs.git", branch = "v0.33.x", features = [ - "http-client", + "http-client", ] } thiserror = { workspace = true } tokio = { workspace = true, features = ["signal"] } @@ -73,13 +75,21 @@ toml = "0.5.9" tonic = "0.9.2" tracing = { version = "0.1.37", features = ["valuable", "log"] } tracing-core = { version = "0.1.30", features = ["valuable"] } -tracing-subscriber = { version = "0.3.16", features = ["json", "valuable", "env-filter"] } +tracing-subscriber = { version = "0.3.16", features = [ + "json", + "valuable", + "env-filter", +] } typed-builder = "0.18.2" url = "2.3.1" valuable = { version = "0.1.0", features = ["derive"] } valuable-serde = { version = "0.1.0", features = ["std"] } voting-verifier = { workspace = true } +starknet-core = { workspace = true } +starknet-providers = { workspace = true } +starknet-types = { workspace = true } + [dev-dependencies] ed25519-dalek = { workspace = true, features = ["rand_core"] } elliptic-curve = "0.13.5" diff --git a/ampd/src/handlers/config.rs b/ampd/src/handlers/config.rs index c7bb9da9b..36018ac9a 100644 --- a/ampd/src/handlers/config.rs +++ b/ampd/src/handlers/config.rs @@ -63,6 +63,26 @@ pub enum Config { cosmwasm_contract: TMAddress, rpc_url: Url, }, + StarknetMsgVerifier { + cosmwasm_contract: TMAddress, + rpc_url: Url, + }, +} + +fn validate_starknet_msg_verifier_config<'de, D>(configs: &[Config]) -> Result<(), D::Error> +where + D: Deserializer<'de>, +{ + match configs + .iter() + .filter(|config| matches!(config, Config::StarknetMsgVerifier { .. })) + .count() + { + count if count > 1 => Err(de::Error::custom( + "only one Starknet msg verifier config is allowed", + )), + _ => Ok(()), + } } fn validate_evm_verifier_set_verifier_configs<'de, D>(configs: &[Config]) -> Result<(), D::Error> @@ -133,6 +153,7 @@ where { let configs: Vec = Deserialize::deserialize(deserializer)?; + validate_starknet_msg_verifier_config::(&configs)?; validate_evm_msg_verifier_configs::(&configs)?; validate_evm_verifier_set_verifier_configs::(&configs)?; diff --git a/ampd/src/handlers/mod.rs b/ampd/src/handlers/mod.rs index 1f8868164..ce724a7e5 100644 --- a/ampd/src/handlers/mod.rs +++ b/ampd/src/handlers/mod.rs @@ -5,6 +5,8 @@ pub mod evm_verify_verifier_set; pub mod multisig; pub mod mvx_verify_msg; pub mod mvx_verify_verifier_set; +pub mod starknet_verify_msg; +pub mod starknet_verify_verifier_set; pub(crate) mod stellar_verify_msg; pub(crate) mod stellar_verify_verifier_set; pub mod sui_verify_msg; diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs new file mode 100644 index 000000000..eaa098a25 --- /dev/null +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -0,0 +1,508 @@ +use std::collections::HashMap; +use std::convert::TryInto; + +use async_trait::async_trait; +use axelar_wasm_std::msg_id::FieldElementAndEventIndex; +use axelar_wasm_std::voting::{PollId, Vote}; +use cosmrs::cosmwasm::MsgExecuteContract; +use cosmrs::tx::Msg; +use cosmrs::Any; +use error_stack::{FutureExt, ResultExt}; +use events::Error::EventTypeMismatch; +use events_derive::try_from; +use futures::future::try_join_all; +use itertools::Itertools; +use router_api::ChainName; +use serde::Deserialize; +use starknet_core::types::Felt; +use starknet_types::events::contract_call::ContractCallEvent; +use tokio::sync::watch::Receiver; +use tracing::info; +use voting_verifier::msg::ExecuteMsg; + +use crate::event_processor::EventHandler; +use crate::handlers::errors::Error; +use crate::handlers::errors::Error::DeserializeEvent; +use crate::starknet::json_rpc::StarknetClient; +use crate::starknet::verifier::verify_msg; +use crate::types::{Hash, TMAddress}; + +type Result = error_stack::Result; + +#[derive(Deserialize, Debug)] +pub struct Message { + pub message_id: FieldElementAndEventIndex, + pub destination_address: String, + pub destination_chain: ChainName, + pub source_address: Felt, + pub payload_hash: Hash, +} + +#[derive(Deserialize, Debug)] +#[try_from("wasm-messages_poll_started")] +struct PollStartedEvent { + #[serde(rename = "_contract_address")] + contract_address: TMAddress, + poll_id: PollId, + source_gateway_address: String, + expires_at: u64, + messages: Vec, + participants: Vec, +} + +pub struct Handler +where + C: StarknetClient, +{ + verifier: TMAddress, + voting_verifier: TMAddress, + rpc_client: C, + latest_block_height: Receiver, +} + +impl Handler +where + C: StarknetClient + Send + Sync, +{ + pub fn new( + verifier: TMAddress, + voting_verifier: TMAddress, + rpc_client: C, + latest_block_height: Receiver, + ) -> Self { + Self { + verifier, + voting_verifier, + rpc_client, + latest_block_height, + } + } + + fn vote_msg(&self, poll_id: PollId, votes: Vec) -> MsgExecuteContract { + MsgExecuteContract { + sender: self.verifier.as_ref().clone(), + contract: self.voting_verifier.as_ref().clone(), + msg: serde_json::to_vec(&ExecuteMsg::Vote { poll_id, votes }) + .expect("vote msg should serialize"), + funds: vec![], + } + } +} + +#[async_trait] +impl EventHandler for Handler +where + V: StarknetClient + Send + Sync, +{ + type Err = Error; + + async fn handle(&self, event: &events::Event) -> Result> { + let PollStartedEvent { + poll_id, + source_gateway_address, + messages, + participants, + expires_at, + contract_address, + .. + } = match event.try_into() as error_stack::Result<_, _> { + Err(report) if matches!(report.current_context(), EventTypeMismatch(_)) => { + return Ok(vec![]); + } + event => event.change_context(DeserializeEvent)?, + }; + + if self.voting_verifier != contract_address { + return Ok(vec![]); + } + + if !participants.contains(&self.verifier) { + return Ok(vec![]); + } + + let latest_block_height = *self.latest_block_height.borrow(); + if latest_block_height >= expires_at { + info!(poll_id = poll_id.to_string(), "skipping expired poll"); + return Ok(vec![]); + } + + let unique_msgs = messages + .iter() + .unique_by(|msg| &msg.message_id.tx_hash) + .collect::>(); + + // key is the tx_hash of the tx holding the event + let events: HashMap = try_join_all( + unique_msgs + .iter() + .map(|msg| self.rpc_client.get_event_by_hash(msg.message_id.tx_hash)), + ) + .change_context(Error::TxReceipts) + .await? + .into_iter() + .flatten() + .collect(); + + let mut votes = vec![]; + for msg in unique_msgs { + if !events.contains_key(&msg.message_id.tx_hash) { + votes.push(Vote::NotFound); + continue; + } + votes.push(verify_msg( + events.get(&msg.message_id.tx_hash).unwrap(), // safe to unwrap, because of previous check + msg, + &source_gateway_address, + )); + } + + Ok(vec![self + .vote_msg(poll_id, votes) + .into_any() + .expect("vote msg should serialize")]) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use base64::engine::general_purpose::STANDARD; + use base64::Engine; + use ethers_core::types::H256; + use events::Event; + use mockall::predicate::eq; + use tendermint::abci; + use tokio::sync::watch; + use tokio::test as async_test; + use voting_verifier::events::{PollMetadata, PollStarted, TxEventConfirmation}; + + use super::*; + use crate::starknet::json_rpc::MockStarknetClient; + use crate::PREFIX; + + #[async_test] + async fn should_correctly_validate_messages() { + // Setup the context + let voting_verifier = TMAddress::random(PREFIX); + let verifier = TMAddress::random(PREFIX); + let expiration = 100u64; + let (_, rx) = watch::channel(expiration - 1); + + // Prepare the rpc client, which fetches the event and the vote broadcaster + let mut rpc_client = MockStarknetClient::new(); + rpc_client.expect_get_event_by_hash().returning(|_| { + Ok(Some(( + Felt::from_str( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", + ) + .unwrap(), + ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address"), + destination_chain: "ethereum".parse().unwrap(), + source_address: Felt::ONE, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]), + }, + ))) + }); + + let event: Event = get_event( + get_poll_started_event_with_two_msgs(participants(5, Some(verifier.clone())), 100_u64), + &voting_verifier, + ); + + let handler = super::Handler::new(verifier, voting_verifier, rpc_client, rx); + let result = handler.handle(&event).await.unwrap(); + + assert_eq!(result.len(), 1); + assert!(MsgExecuteContract::from_any(result.first().unwrap()).is_ok()); + } + + #[async_test] + async fn should_skip_duplicate_messages() { + // Setup the context + let voting_verifier = TMAddress::random(PREFIX); + let verifier = TMAddress::random(PREFIX); + let expiration = 100u64; + let (_, rx) = watch::channel(expiration - 1); + + // Prepare the rpc client, which fetches the event and the vote broadcaster + let mut rpc_client = MockStarknetClient::new(); + rpc_client + .expect_get_event_by_hash() + .once() + .with(eq(Felt::from_str( + "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", + ) + .unwrap())) + .returning(|_| { + Ok(Some(( + Felt::from_str( + "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", + ) + .unwrap(), + ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address"), + destination_chain: "ethereum".parse().unwrap(), + source_address: Felt::ONE, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, + 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, + 234, 200, + ]), + }, + ))) + }); + + let event: Event = get_event( + get_poll_started_event_with_duplicate_msgs( + participants(5, Some(verifier.clone())), + 100, + ), + &voting_verifier, + ); + + let handler = super::Handler::new(verifier, voting_verifier, rpc_client, rx); + let result = handler.handle(&event).await.unwrap(); + + assert_eq!(result.len(), 1); + assert!(MsgExecuteContract::from_any(result.first().unwrap()).is_ok()); + } + + #[async_test] + async fn should_skip_wrong_verifier_address() { + // Setup the context + let voting_verifier = TMAddress::random(PREFIX); + let verifier = TMAddress::random(PREFIX); + let expiration = 100u64; + let (_, rx) = watch::channel(expiration - 1); + + // Prepare the rpc client, which fetches the event and the vote broadcaster + let mut rpc_client = MockStarknetClient::new(); + rpc_client.expect_get_event_by_hash().times(0); + + let event: Event = get_event( + get_poll_started_event_with_duplicate_msgs( + participants(5, Some(verifier.clone())), + 100, + ), + &TMAddress::random(PREFIX), // some other random address + ); + + let handler = super::Handler::new(verifier, voting_verifier, rpc_client, rx); + + let result = handler.handle(&event).await.unwrap(); + assert_eq!(result, vec![]); + } + + #[async_test] + async fn should_skip_non_participating_verifier() { + // Setup the context + let voting_verifier = TMAddress::random(PREFIX); + let verifier = TMAddress::random(PREFIX); + let expiration = 100u64; + let (_, rx) = watch::channel(expiration - 1); + + // Prepare the rpc client, which fetches the event and the vote broadcaster + let mut rpc_client = MockStarknetClient::new(); + rpc_client.expect_get_event_by_hash().times(0); + + let event: Event = get_event( + // woker is not in participat set + get_poll_started_event_with_duplicate_msgs(participants(5, None), 100), + &voting_verifier, + ); + + let handler = super::Handler::new(verifier, voting_verifier, rpc_client, rx); + + let result = handler.handle(&event).await.unwrap(); + assert_eq!(result, vec![]); + } + + #[async_test] + async fn should_skip_expired_poll_event() { + // Setup the context + let voting_verifier = TMAddress::random(PREFIX); + let verifier = TMAddress::random(PREFIX); + let expiration = 100u64; + let (_, rx) = watch::channel(expiration); // expired! + + // Prepare the rpc client, which fetches the event and the vote broadcaster + let mut rpc_client = MockStarknetClient::new(); + rpc_client.expect_get_event_by_hash().times(0); + + let event: Event = get_event( + get_poll_started_event_with_duplicate_msgs( + participants(5, Some(verifier.clone())), + 100, + ), + &voting_verifier, + ); + + let handler = super::Handler::new(verifier, voting_verifier, rpc_client, rx); + + let result = handler.handle(&event).await.unwrap(); + assert_eq!(result, vec![]); + } + + fn participants(n: u8, verifier: Option) -> Vec { + (0..n) + .map(|_| TMAddress::random(PREFIX)) + .chain(verifier) + .collect() + } + + fn get_event(event: impl Into, contract_address: &TMAddress) -> Event { + let mut event: cosmwasm_std::Event = event.into(); + + event.ty = format!("wasm-{}", event.ty); + event = event.add_attribute("_contract_address", contract_address.to_string()); + + abci::Event::new( + event.ty, + event + .attributes + .into_iter() + .map(|cosmwasm_std::Attribute { key, value }| { + (STANDARD.encode(key), STANDARD.encode(value)) + }), + ) + .try_into() + .unwrap() + } + + fn get_poll_started_event_with_two_msgs( + participants: Vec, + expires_at: u64, + ) -> PollStarted { + PollStarted::Messages { + metadata: PollMetadata { + poll_id: "100".parse().unwrap(), + source_chain: "starknet".parse().unwrap(), + source_gateway_address: "source-gw-addr".parse().unwrap(), + confirmation_height: 15, + expires_at, + participants: participants + .into_iter() + .map(|addr| cosmwasm_std::Addr::unchecked(addr.to_string())) + .collect(), + }, + messages: vec![ + TxEventConfirmation { + tx_id: "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e" + .parse() + .unwrap(), + message_id: + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0" + .parse() + .unwrap(), + event_index: 0, + source_address: + "0x0000000000000000000000000000000000000000000000000000000000000001" + .parse() + .unwrap(), + destination_chain: "ethereum".parse().unwrap(), + destination_address: "destination-address".parse().unwrap(), + payload_hash: H256::from_slice(&[ + // keccak256("hello") + 28, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, + 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]) + .into(), + }, + TxEventConfirmation { + tx_id: "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f" + .parse() + .unwrap(), + message_id: + "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f-1" + .parse() + .unwrap(), + event_index: 1, + source_address: + "0x0000000000000000000000000000000000000000000000000000000000000001" + .parse() + .unwrap(), + destination_chain: "ethereum".parse().unwrap(), + destination_address: "destination-address".parse().unwrap(), + payload_hash: H256::from_slice(&[ + // keccak256("hello") + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]) + .into(), + }, + ], + } + } + + fn get_poll_started_event_with_duplicate_msgs( + participants: Vec, + expires_at: u64, + ) -> PollStarted { + PollStarted::Messages { + metadata: PollMetadata { + poll_id: "100".parse().unwrap(), + source_chain: "starknet".parse().unwrap(), + source_gateway_address: "source-gw-addr".parse().unwrap(), + confirmation_height: 15, + expires_at, + participants: participants + .into_iter() + .map(|addr| cosmwasm_std::Addr::unchecked(addr.to_string())) + .collect(), + }, + messages: vec![ + TxEventConfirmation { + tx_id: "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f" + .parse() + .unwrap(), + message_id: + "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f-1" + .parse() + .unwrap(), + event_index: 1, + source_address: + "0x0000000000000000000000000000000000000000000000000000000000000001" + .parse() + .unwrap(), + destination_chain: "ethereum".parse().unwrap(), + destination_address: "destination-address".parse().unwrap(), + payload_hash: H256::from_slice(&[ + // keccak256("hello") + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]) + .into(), + }, + TxEventConfirmation { + tx_id: "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f" + .parse() + .unwrap(), + message_id: + "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f-1" + .parse() + .unwrap(), + event_index: 1, + source_address: + "0x0000000000000000000000000000000000000000000000000000000000000001" + .parse() + .unwrap(), + destination_chain: "ethereum".parse().unwrap(), + destination_address: "destination-address".parse().unwrap(), + payload_hash: H256::from_slice(&[ + // keccak256("hello") + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]) + .into(), + }, + ], + } + } +} diff --git a/ampd/src/handlers/starknet_verify_verifier_set.rs b/ampd/src/handlers/starknet_verify_verifier_set.rs new file mode 100644 index 000000000..7623e8fc5 --- /dev/null +++ b/ampd/src/handlers/starknet_verify_verifier_set.rs @@ -0,0 +1,161 @@ +//! Module responsible for handling verification of verifier set changes. +//! It processes events related to verifier set, verifies them against the Starknet chain, +//! and manages the voting process for confirming these changes. + +use std::convert::TryInto; + +use async_trait::async_trait; +use axelar_wasm_std::msg_id::HexTxHashAndEventIndex; +use axelar_wasm_std::voting::{PollId, Vote}; +use cosmrs::cosmwasm::MsgExecuteContract; +use cosmrs::tx::Msg; +use cosmrs::Any; +use error_stack::ResultExt; +use events::Error::EventTypeMismatch; +use events::Event; +use events_derive::try_from; +use multisig::verifier_set::VerifierSet; +use serde::Deserialize; +use starknet_core::types::Felt; +use tokio::sync::watch::Receiver; +use tracing::{info, info_span}; +use valuable::Valuable; +use voting_verifier::msg::ExecuteMsg; + +use crate::event_processor::EventHandler; +use crate::handlers::errors::Error; +use crate::starknet::json_rpc::StarknetClient; +use crate::starknet::verifier::verify_verifier_set; +use crate::types::TMAddress; + +#[derive(Deserialize, Debug)] +pub struct VerifierSetConfirmation { + pub message_id: HexTxHashAndEventIndex, // FIXME: in the future replace by FieldElementAndEventIndex + pub verifier_set: VerifierSet, +} + +#[derive(Deserialize, Debug)] +#[try_from("wasm-verifier_set_poll_started")] +struct PollStartedEvent { + poll_id: PollId, + source_gateway_address: String, + verifier_set: VerifierSetConfirmation, + participants: Vec, + expires_at: u64, +} + +pub struct Handler +where + C: StarknetClient + Send + Sync, +{ + verifier: TMAddress, + voting_verifier_contract: TMAddress, + rpc_client: C, + latest_block_height: Receiver, +} + +impl Handler +where + C: StarknetClient + Send + Sync, +{ + /// Handler for verifying verifier set updates from Starknet + /// + /// # Type Parameters + /// * `C` - A Starknet client type that implements the [`StarknetClient`] trait + #[allow(dead_code)] + pub fn new( + verifier: TMAddress, + voting_verifier_contract: TMAddress, + rpc_client: C, + latest_block_height: Receiver, + ) -> Self { + Self { + verifier, + voting_verifier_contract, + rpc_client, + latest_block_height, + } + } + + fn vote_msg(&self, poll_id: PollId, vote: Vote) -> MsgExecuteContract { + MsgExecuteContract { + sender: self.verifier.as_ref().clone(), + contract: self.voting_verifier_contract.as_ref().clone(), + msg: serde_json::to_vec(&ExecuteMsg::Vote { + poll_id, + votes: vec![vote], + }) + .expect("vote msg should serialize"), + funds: vec![], + } + } +} + +#[async_trait] +impl EventHandler for Handler +where + C: StarknetClient + Send + Sync + 'static, +{ + type Err = Error; + + async fn handle(&self, event: &Event) -> error_stack::Result, Self::Err> { + if !event.is_from_contract(self.voting_verifier_contract.as_ref()) { + return Ok(vec![]); + } + + let PollStartedEvent { + poll_id, + source_gateway_address, + verifier_set, + expires_at, + participants, + } = match event.try_into() as error_stack::Result<_, _> { + Err(report) if matches!(report.current_context(), EventTypeMismatch(_)) => { + return Ok(vec![]) + } + event => event.change_context(Error::DeserializeEvent)?, + }; + + if !participants.contains(&self.verifier) { + return Ok(vec![]); + } + + if *self.latest_block_height.borrow() >= expires_at { + info!(poll_id = poll_id.to_string(), "skipping expired poll"); + return Ok(vec![]); + } + + let transaction_response = self + .rpc_client + .get_event_by_hash_signers_rotated(Felt::from_bytes_be( + &verifier_set.message_id.tx_hash, + )) + .await + .unwrap(); + + let vote = info_span!( + "verify a new verifier set", + poll_id = poll_id.to_string(), + message_id = verifier_set.message_id.to_string(), + ) + .in_scope(|| { + info!("ready to verify verifier set in poll",); + + let vote = transaction_response.map_or(Vote::NotFound, |tx_receipt| { + verify_verifier_set(&tx_receipt.1, &verifier_set, &source_gateway_address) + }); + + info!( + vote = vote.as_value(), + "ready to vote for a new verifier set in poll" + ); + + vote + }); + + Ok(vec![self + .vote_msg(poll_id, vote) + .into_any() + .expect("vote msg should serialize")]) + } +} diff --git a/ampd/src/lib.rs b/ampd/src/lib.rs index 75d258504..6415439a9 100644 --- a/ampd/src/lib.rs +++ b/ampd/src/lib.rs @@ -14,6 +14,7 @@ use evm::json_rpc::EthereumClient; use multiversx_sdk::gateway::GatewayProxy; use queue::queued_broadcaster::QueuedBroadcaster; use router_api::ChainName; +use starknet_providers::jsonrpc::HttpTransport; use thiserror::Error; use tofnd::grpc::{Multisig, MultisigClient}; use tokio::signal::unix::{signal, SignalKind}; @@ -40,6 +41,7 @@ mod health_check; mod json_rpc; mod mvx; mod queue; +pub(crate) mod starknet; mod stellar; mod sui; mod tm_client; @@ -388,6 +390,22 @@ where ), event_processor_config.clone(), ), + handlers::config::Config::StarknetMsgVerifier { + cosmwasm_contract, + rpc_url, + } => self.create_handler_task( + "starknet-msg-verifier", + handlers::starknet_verify_msg::Handler::new( + verifier.clone(), + cosmwasm_contract, + starknet::json_rpc::Client::new_with_transport(HttpTransport::new( + &rpc_url, + )) + .unwrap(), + self.block_height_monitor.latest_block_height(), + ), + event_processor_config.clone(), + ), }; self.event_processor = self.event_processor.add_task(task); } diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs new file mode 100644 index 000000000..2a728dcdd --- /dev/null +++ b/ampd/src/starknet/json_rpc.rs @@ -0,0 +1,1054 @@ +//! Verification implementation of Starknet JSON RPC client's verification of +//! transaction existence + +use async_trait::async_trait; +use error_stack::Report; +use mockall::automock; +use starknet_core::types::{ExecutionResult, Felt, FromStrError, TransactionReceipt}; +use starknet_providers::jsonrpc::JsonRpcTransport; +use starknet_providers::{JsonRpcClient, Provider, ProviderError}; +use starknet_types::events::contract_call::ContractCallEvent; +use starknet_types::events::signers_rotated::SignersRotatedEvent; +use thiserror::Error; + +type Result = error_stack::Result; + +#[derive(Debug, Error)] +pub enum StarknetClientError { + #[error(transparent)] + UrlParseError(#[from] url::ParseError), + #[error(transparent)] + JsonDeserializeError(#[from] serde_json::Error), + #[error("Failed to fetch tx receipt: {0}")] + FetchingReceipt(#[from] ProviderError), + #[error("Failed to create field element from string: {0}")] + FeltFromString(#[from] FromStrError), + #[error("Tx not successful")] + UnsuccessfulTx, +} + +/// Implementor of verification method(s) for given network using JSON RPC +/// client. +pub struct Client +where + T: JsonRpcTransport + Send + Sync + 'static, +{ + client: JsonRpcClient, +} + +impl Client +where + T: JsonRpcTransport + Send + Sync + 'static, +{ + /// Constructor. + /// Expects URL of any JSON RPC entry point of Starknet, which you can find + /// as constants in the `networks.rs` module + pub fn new_with_transport(transport: T) -> Result { + Ok(Client { + client: JsonRpcClient::new(transport), + }) + } +} + +/// A trait for fetching a ContractCall event, by a given tx_hash +/// and parsing parsing it into +/// `crate::starknet::events::contract_call::ContractCallEvent` +#[automock] +#[async_trait] +pub trait StarknetClient { + /// Attempts to fetch a ContractCall event, by a given `tx_hash`. + /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. + async fn get_event_by_hash(&self, tx_hash: Felt) -> Result>; + + /// Attempts to fetch a SignersRotated event, by a given `tx_hash`. + /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. + async fn get_event_by_hash_signers_rotated( + &self, + tx_hash: Felt, + ) -> Result>; +} + +#[async_trait] +impl StarknetClient for Client +where + T: JsonRpcTransport + Send + Sync + 'static, +{ + async fn get_event_by_hash(&self, tx_hash: Felt) -> Result> { + // TODO: Check ACCEPTED ON L1 times and decide if we should use it + // + // Finality status is always at least ACCEPTED_ON_L2 and this is what we're + // looking for, because ACCEPTED_ON_L1 (Ethereum) will take a very long time. + // + // Check https://github.com/eigerco/giza-axelar-starknet/issues/90 + let receipt_with_block_info = self + .client + .get_transaction_receipt(tx_hash) + .await + .map_err(StarknetClientError::FetchingReceipt)?; + + if *receipt_with_block_info.receipt.execution_result() != ExecutionResult::Succeeded { + return Err(Report::new(StarknetClientError::UnsuccessfulTx)); + } + + let event: Option<(Felt, ContractCallEvent)> = match receipt_with_block_info.receipt { + TransactionReceipt::Invoke(tx) => { + // NOTE: There should be only one ContractCall event per gateway tx + tx.events + .iter() + .filter_map(|e| { + // NOTE: Here we ignore the error, because the event might + // not be ContractCall and that by itself is not erroneous behavior + if let Ok(cce) = ContractCallEvent::try_from(e.clone()) { + Some((tx.transaction_hash, cce)) + } else { + None + } + }) + .next() + } + TransactionReceipt::L1Handler(_) => None, + TransactionReceipt::Declare(_) => None, + TransactionReceipt::Deploy(_) => None, + TransactionReceipt::DeployAccount(_) => None, + }; + + Ok(event) + } + + /// Fetches a transaction receipt by hash and extracts a SignersRotatedEvent if present + /// + /// # Arguments + /// + /// * `tx_hash` - The hash of the transaction to fetch + /// + /// # Returns + /// + /// * `Ok(Some((tx_hash, SignersRotatedEvent)))` - If the transaction exists and contains a valid SignersRotatedEvent + /// * `Ok(None)` - If the transaction exists but contains no SignersRotatedEvent + /// * `Err(StarknetClientError)` - If there was an error fetching the receipt or the transaction failed + /// + /// # Errors + /// + /// Returns a `StarknetClientError` if: + /// * Failed to fetch the transaction receipt from the node + /// * The transaction execution was not successful + async fn get_event_by_hash_signers_rotated( + &self, + tx_hash: Felt, + ) -> Result> { + let receipt_with_block_info = self + .client + .get_transaction_receipt(tx_hash) + .await + .map_err(StarknetClientError::FetchingReceipt)?; + + if *receipt_with_block_info.receipt.execution_result() != ExecutionResult::Succeeded { + return Err(Report::new(StarknetClientError::UnsuccessfulTx)); + } + + let event: Option<(Felt, SignersRotatedEvent)> = match receipt_with_block_info.receipt { + TransactionReceipt::Invoke(tx) => tx + .events + .iter() + .filter_map(|e| { + if let Ok(sre) = SignersRotatedEvent::try_from(e.clone()) { + Some((tx.transaction_hash, sre)) + } else { + None + } + }) + .next(), + TransactionReceipt::L1Handler(_) => None, + TransactionReceipt::Declare(_) => None, + TransactionReceipt::Deploy(_) => None, + TransactionReceipt::DeployAccount(_) => None, + }; + + Ok(event) + } +} + +#[cfg(test)] +mod test { + + use std::str::FromStr; + + use axum::async_trait; + use ethers_core::types::H256; + use serde::de::DeserializeOwned; + use serde::Serialize; + use starknet_core::types::Felt; + use starknet_providers::jsonrpc::{ + HttpTransportError, JsonRpcMethod, JsonRpcResponse, JsonRpcTransport, + }; + use starknet_providers::{ProviderError, ProviderRequestData}; + use starknet_types::events::contract_call::ContractCallEvent; + use starknet_types::events::signers_rotated::SignersRotatedEvent; + + use super::{Client, StarknetClient, StarknetClientError}; + + #[tokio::test] + async fn invalid_signers_rotated_event_tx_fetch() { + let mock_client = + Client::new_with_transport(InvalidSignersRotatedEventMockTransport).unwrap(); + let contract_call_event = mock_client + .get_event_by_hash_signers_rotated(Felt::ONE) + .await; + + assert!(contract_call_event.unwrap().is_none()); + } + + #[tokio::test] + async fn deploy_account_tx_fetch() { + let mock_client = Client::new_with_transport(DeployAccountMockTransport).unwrap(); + let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + + assert!(contract_call_event.unwrap().is_none()); + } + + #[tokio::test] + async fn deploy_tx_fetch() { + let mock_client = Client::new_with_transport(DeployMockTransport).unwrap(); + let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + + assert!(contract_call_event.unwrap().is_none()); + } + + #[tokio::test] + async fn l1_handler_tx_fetch() { + let mock_client = Client::new_with_transport(L1HandlerMockTransport).unwrap(); + let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + + assert!(contract_call_event.unwrap().is_none()); + } + + #[tokio::test] + async fn declare_tx_fetch() { + let mock_client = Client::new_with_transport(DeclareMockTransport).unwrap(); + let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + + assert!(contract_call_event.unwrap().is_none()); + } + + #[tokio::test] + async fn invalid_contract_call_event_tx_fetch() { + let mock_client = + Client::new_with_transport(InvalidContractCallEventMockTransport).unwrap(); + let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + + assert!(contract_call_event.unwrap().is_none()); + } + + #[tokio::test] + async fn no_events_tx_fetch() { + let mock_client = Client::new_with_transport(NoEventsMockTransport).unwrap(); + let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + + assert!(contract_call_event.unwrap().is_none()); + } + + #[tokio::test] + async fn reverted_tx_fetch() { + let mock_client = Client::new_with_transport(RevertedMockTransport).unwrap(); + let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + + assert!(contract_call_event + .unwrap_err() + .contains::()); + } + + #[tokio::test] + async fn failing_tx_fetch() { + let mock_client = Client::new_with_transport(FailingMockTransport).unwrap(); + let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + + assert!(contract_call_event.is_err()); + } + + #[tokio::test] + async fn successful_signers_rotated_tx_fetch() { + let mock_client = Client::new_with_transport(ValidMockTransportSignersRotated).unwrap(); + let signers_rotated_event: (Felt, SignersRotatedEvent) = mock_client + .get_event_by_hash_signers_rotated(Felt::ONE) + .await + .unwrap() // unwrap the result + .unwrap(); // unwrap the option + + assert_eq!( + signers_rotated_event.0, + Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") + .unwrap() + ); + + let actual: SignersRotatedEvent = signers_rotated_event.1; + let expected: SignersRotatedEvent = SignersRotatedEvent { + from_address: "0x2".to_string(), + epoch: 1, + signers_hash: [ + 226, 62, 119, 4, 210, 79, 100, 110, 94, 54, 44, 97, 64, 122, 105, 210, 212, 32, 63, + 225, 67, 54, 50, 83, 200, 154, 39, 162, 106, 108, 184, 31, + ], + signers: starknet_types::events::signers_rotated::WeightedSigners { + signers: vec![starknet_types::events::signers_rotated::Signer { + signer: "0x3ec7d572a0fe479768ac46355651f22a982b99cc".to_string(), + weight: 1, + }], + threshold: 1, + nonce: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 47, 228, 157, + ], + }, + }; + + assert_eq!(actual, expected); + } + + #[tokio::test] + async fn successful_call_contract_tx_fetch() { + let mock_client = Client::new_with_transport(ValidMockTransportCallContract).unwrap(); + let contract_call_event = mock_client + .get_event_by_hash(Felt::ONE) + .await + .unwrap() // unwrap the result + .unwrap(); // unwrap the option + + assert_eq!( + contract_call_event.0, + Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") + .unwrap() + ); + assert_eq!( + contract_call_event.1, + ContractCallEvent { + from_contract_addr: + "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), + destination_address: String::from("hello"), + destination_chain: String::from("destination_chain"), + source_address: Felt::from_str( + "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca" + ) + .unwrap(), + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, + 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200 + ]) + } + ); + } + + struct FailingMockTransport; + + #[async_trait] + impl JsonRpcTransport for FailingMockTransport { + type Error = ProviderError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + Err(ProviderError::RateLimited) + } + } + + struct L1HandlerMockTransport; + + #[async_trait] + impl JsonRpcTransport for L1HandlerMockTransport { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"L1_HANDLER\", + \"transaction_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"message_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct DeployAccountMockTransport; + + #[async_trait] + impl JsonRpcTransport for DeployAccountMockTransport { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"DEPLOY_ACCOUNT\", + \"transaction_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"contract_address\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct DeployMockTransport; + + #[async_trait] + impl JsonRpcTransport for DeployMockTransport { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"DEPLOY\", + \"transaction_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"contract_address\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct DeclareMockTransport; + + #[async_trait] + impl JsonRpcTransport for DeclareMockTransport { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"DECLARE\", + \"transaction_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct NoEventsMockTransport; + + #[async_trait] + impl JsonRpcTransport for NoEventsMockTransport { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"INVOKE\", + \"transaction_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct RevertedMockTransport; + + #[async_trait] + impl JsonRpcTransport for RevertedMockTransport { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"INVOKE\", + \"transaction_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"REVERTED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct InvalidSignersRotatedEventMockTransport; + + #[async_trait] + impl JsonRpcTransport for InvalidSignersRotatedEventMockTransport { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + // garbage "data" + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"INVOKE\", + \"transaction_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [ + { + \"from_address\": \"0x000000000000000000000000000000000000000000000000000000000000002\", + \"keys\": [ + \"0x01815547484542c49542242a23bc0a1b762af99232f38c0417050825aea8fc93\", + \"0x0268929df65ee595bb8592323f981351efdc467d564effc6d2e54d2e666e43ca\", + \"0x01\", + \"0xd4203fe143363253c89a27a26a6cb81f\", + \"0xe23e7704d24f646e5e362c61407a69d2\" + ], + \"data\": [ + \"0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca\", + \"0x0000000000000000000000000000000000000000000000000000000000000000\", + \"0x00000000000000000000000000000000000000000000000000000068656c6c6f\", + \"0x0000000000000000000000000000000000000000000000000000000000000001\", + \"0x0000000000000000000000000000000056d9517b9c948127319a09a7a36deac8\", + \"0x000000000000000000000000000000001c8aff950685c2ed4bc3174f3472287b\", + \"0x0000000000000000000000000000000000000000000000000000000000000005\", + \"0x0000000000000000000000000000000000000000000000000000000000000068\", + \"0x0000000000000000000000000000000000000000000000000000000000000065\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006f\" + ] + } + ], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct InvalidContractCallEventMockTransport; + + #[async_trait] + impl JsonRpcTransport for InvalidContractCallEventMockTransport { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + // 1 byte for the pending_word, instead of 5 + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"INVOKE\", + \"transaction_hash\": \"0x000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [ + { + \"from_address\": \"0x000000000000000000000000000000000000000000000000000000000000002\", + \"keys\": [ + \"0x01815547484542c49542242a23bc0a1b762af99232f38c0417050825aea8fc93\", + \"0x0268929df65ee595bb8592323f981351efdc467d564effc6d2e54d2e666e43ca\", + \"0x01\", + \"0xd4203fe143363253c89a27a26a6cb81f\", + \"0xe23e7704d24f646e5e362c61407a69d2\" + ], + \"data\": [ + \"0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca\", + \"0x0000000000000000000000000000000000000000000000000000000000000000\", + \"0x00000000000000000000000000000000000000000000000000000068656c6c6f\", + \"0x0000000000000000000000000000000000000000000000000000000000000001\", + \"0x0000000000000000000000000000000056d9517b9c948127319a09a7a36deac8\", + \"0x000000000000000000000000000000001c8aff950685c2ed4bc3174f3472287b\", + \"0x0000000000000000000000000000000000000000000000000000000000000005\", + \"0x0000000000000000000000000000000000000000000000000000000000000068\", + \"0x0000000000000000000000000000000000000000000000000000000000000065\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006f\" + ] + } + ], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct ValidMockTransportSignersRotated; + + #[async_trait] + impl JsonRpcTransport for ValidMockTransportSignersRotated { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"INVOKE\", + \"transaction_hash\": \"0x0000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [ + { + \"from_address\": \"0x0000000000000000000000000000000000000000000000000000000000000002\", + \"keys\": [ + \"0x01815547484542c49542242a23bc0a1b762af99232f38c0417050825aea8fc93\", + \"0x0268929df65ee595bb8592323f981351efdc467d564effc6d2e54d2e666e43ca\", + \"0x01\", + \"0xd4203fe143363253c89a27a26a6cb81f\", + \"0xe23e7704d24f646e5e362c61407a69d2\" + ], + \"data\": [ + \"0x01\", + \"0x3ec7d572a0fe479768ac46355651f22a982b99cc\", + \"0x01\", + \"0x01\", + \"0x2fe49d\", + \"0x00\" + ] + } + ], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } + + struct ValidMockTransportCallContract; + + #[async_trait] + impl JsonRpcTransport for ValidMockTransportCallContract { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"INVOKE\", + \"transaction_hash\": \"0x0000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [ + { + \"from_address\": \"0x0000000000000000000000000000000000000000000000000000000000000002\", + \"keys\": [ + \"0x034d074b86d78f064ec0a29639fcfab989c7a3ea6343653633624b2df9ec08f6\", + \"0x00000000000000000000000000000064657374696e6174696f6e5f636861696e\" + ], + \"data\": [ + \"0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca\", + \"0x0000000000000000000000000000000000000000000000000000000000000000\", + \"0x00000000000000000000000000000000000000000000000000000068656c6c6f\", + \"0x0000000000000000000000000000000000000000000000000000000000000005\", + \"0x0000000000000000000000000000000056d9517b9c948127319a09a7a36deac8\", + \"0x000000000000000000000000000000001c8aff950685c2ed4bc3174f3472287b\", + \"0x0000000000000000000000000000000000000000000000000000000000000005\", + \"0x0000000000000000000000000000000000000000000000000000000000000068\", + \"0x0000000000000000000000000000000000000000000000000000000000000065\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006f\" + ] + } + ], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } +} diff --git a/ampd/src/starknet/mod.rs b/ampd/src/starknet/mod.rs new file mode 100644 index 000000000..f5a7d0a3f --- /dev/null +++ b/ampd/src/starknet/mod.rs @@ -0,0 +1,2 @@ +pub mod json_rpc; +pub mod verifier; diff --git a/ampd/src/starknet/verifier.rs b/ampd/src/starknet/verifier.rs new file mode 100644 index 000000000..4460c4bdc --- /dev/null +++ b/ampd/src/starknet/verifier.rs @@ -0,0 +1,346 @@ +use axelar_wasm_std::voting::Vote; +use cosmwasm_std::HexBinary; +use starknet_types::events::contract_call::ContractCallEvent; +use starknet_types::events::signers_rotated::SignersRotatedEvent; + +use crate::handlers::starknet_verify_msg::Message; +use crate::handlers::starknet_verify_verifier_set::VerifierSetConfirmation; + +/// Attempts to fetch the tx provided in `axl_msg.tx_id`. +/// If successful, extracts and parses the ContractCall event +/// and compares it to the message from the relayer (via PollStarted event). +/// Also checks if the source_gateway_address with which +/// the voting verifier has been instantiated is the same address from +/// which the ContractCall event is coming. +pub fn verify_msg( + starknet_event: &ContractCallEvent, + msg: &Message, + source_gateway_address: &str, +) -> Vote { + if *starknet_event == *msg && starknet_event.from_contract_addr == source_gateway_address { + Vote::SucceededOnChain + } else { + Vote::NotFound + } +} + +impl PartialEq for ContractCallEvent { + fn eq(&self, axl_msg: &Message) -> bool { + axl_msg.source_address == self.source_address + && axl_msg.destination_chain == self.destination_chain + && axl_msg.destination_address == self.destination_address + && axl_msg.payload_hash == self.payload_hash + } +} + +pub fn verify_verifier_set( + event: &SignersRotatedEvent, + confirmation: &VerifierSetConfirmation, + source_gateway_address: &str, +) -> Vote { + if event.signers.nonce != [0_u8; 32] + && event == confirmation + && event.from_address == source_gateway_address + { + Vote::SucceededOnChain + } else { + Vote::NotFound + } +} + +impl PartialEq for SignersRotatedEvent { + fn eq(&self, confirmation: &VerifierSetConfirmation) -> bool { + let expected = &confirmation.verifier_set; + + // Convert and sort expected signers + let mut expected_signers = expected + .signers + .values() + .map(|signer| { + if let multisig::key::PublicKey::Ecdsa(pubkey) = &signer.pub_key { + (pubkey.clone(), signer.weight.u128()) + } else { + // Skip non-ECDSA keys + (HexBinary::from_hex("").unwrap(), 0) + } + }) + .collect::>(); + expected_signers.sort(); + + // Convert and sort actual signers from the event + let mut actual_signers = self + .signers + .signers + .iter() + .map(|signer| (HexBinary::from_hex(&signer.signer).unwrap(), signer.weight)) + .collect::>(); + actual_signers.sort(); + + // Compare signers, threshold, and created_at timestamp + actual_signers == expected_signers + && self.signers.threshold == expected.threshold.u128() + && self.epoch == expected.created_at + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + use std::str::FromStr; + + use axelar_wasm_std::msg_id::{FieldElementAndEventIndex, HexTxHashAndEventIndex}; + use axelar_wasm_std::voting::Vote; + use cosmwasm_std::{Addr, HexBinary, Uint128}; + use ethers_core::types::H256; + use multisig::msg::Signer; + use multisig::verifier_set::VerifierSet; + use router_api::ChainName; + use starknet_core::types::Felt; + use starknet_types::events::contract_call::ContractCallEvent; + use starknet_types::events::signers_rotated::{ + Signer as StarknetSigner, SignersRotatedEvent, WeightedSigners, + }; + + use super::verify_msg; + use crate::handlers::starknet_verify_msg::Message; + use crate::handlers::starknet_verify_verifier_set::VerifierSetConfirmation; + use crate::starknet::verifier::verify_verifier_set; + + // "hello" as payload + // "hello" as destination address + // "some_contract_address" as source address + // "destination_chain" as destination_chain + fn mock_valid_event() -> ContractCallEvent { + ContractCallEvent { + from_contract_addr: String::from( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", + ), + destination_address: String::from("destination_address"), + destination_chain: String::from("ethereum"), + source_address: Felt::from_str( + "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca", + ) + .unwrap(), + payload_hash: H256::from_slice(&[ + 28, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, 217, + 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]), + } + } + + fn mock_valid_message() -> Message { + Message { + message_id: FieldElementAndEventIndex { + tx_hash: Felt::from_str( + "0x0000000000000000000000000000000000000000000000000000000000000001", + ) + .unwrap(), + event_index: 0, + }, + destination_address: String::from("destination_address"), + destination_chain: ChainName::from_str("ethereum").unwrap(), + source_address: Felt::from_str( + "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca", + ) + .unwrap(), + payload_hash: H256::from_slice(&[ + 28, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, 217, + 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]), + } + } + + #[test] + fn shoud_fail_different_source_gw() { + assert_eq!( + verify_msg( + &mock_valid_event(), + &mock_valid_message(), + &String::from("different"), + ), + Vote::NotFound + ) + } + + #[test] + fn shoud_fail_different_event_fields() { + let msg = mock_valid_message(); + let source_gw_address = + String::from("0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e"); + + let mut event = mock_valid_event(); + event.destination_address = String::from("different"); + assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); + + let mut event = { mock_valid_event() }; + event.destination_chain = String::from("different"); + assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); + + let mut event = { mock_valid_event() }; + event.source_address = Felt::THREE; + assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); + + let mut event = { mock_valid_event() }; + event.payload_hash = H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, 217, 81, + 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, + 1, // last byte is different + ]); + assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); + } + + #[test] + fn shoud_fail_different_msg_fields() { + let event = mock_valid_event(); + let source_gw_address = + String::from("0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e"); + + let mut msg = mock_valid_message(); + msg.destination_address = String::from("different"); + assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); + + let mut msg = { mock_valid_message() }; + msg.destination_chain = ChainName::from_str("avalanche").unwrap(); + assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); + + let mut msg = { mock_valid_message() }; + msg.source_address = Felt::THREE; + assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); + + let mut msg = { mock_valid_message() }; + msg.payload_hash = H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, 217, 81, + 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, + 1, // last byte is different + ]); + assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); + } + + #[test] + fn shoud_verify_event() { + assert_eq!( + verify_msg( + &mock_valid_event(), + &mock_valid_message(), + &String::from("0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e"), + ), + Vote::SucceededOnChain + ) + } + + /// Verifier set - signers rotated + + fn mock_valid_confirmation_signers_rotated() -> VerifierSetConfirmation { + VerifierSetConfirmation { + verifier_set: mock_valid_verifier_set_signers_rotated(), + message_id: HexTxHashAndEventIndex { + tx_hash: [0_u8; 32], + event_index: 0, + }, + } + } + + fn mock_valid_verifier_set_signers_rotated() -> VerifierSet { + let signers = vec![Signer { + address: Addr::unchecked("axelarvaloper1x86a8prx97ekkqej2x636utrdu23y8wupp9gk5"), + weight: Uint128::from(10u128), + pub_key: multisig::key::PublicKey::Ecdsa( + HexBinary::from_hex( + "03d123ce370b163acd576be0e32e436bb7e63262769881d35fa3573943bf6c6f81", + ) + .unwrap(), + ), + }]; + + let mut btree_signers = BTreeMap::new(); + for signer in signers { + btree_signers.insert(signer.address.clone().to_string(), signer); + } + + VerifierSet { + signers: btree_signers, + threshold: Uint128::one(), + created_at: 1, + } + } + + fn mock_valid_event_signers_rotated() -> SignersRotatedEvent { + SignersRotatedEvent { + // should be the same as the source gw address + from_address: String::from( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", + ), + epoch: 1, + signers_hash: [8_u8; 32], + signers: WeightedSigners { + signers: vec![StarknetSigner { + signer: String::from( + "03d123ce370b163acd576be0e32e436bb7e63262769881d35fa3573943bf6c6f81", + ), + weight: Uint128::from(10u128).into(), + }], + threshold: Uint128::one().into(), + nonce: [7_u8; 32], + }, + } + } + + fn mock_second_valid_event_signers_rotated() -> SignersRotatedEvent { + SignersRotatedEvent { + from_address: String::from( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", + ), + epoch: 1, + signers_hash: [8_u8; 32], + signers: WeightedSigners { + signers: vec![StarknetSigner { + signer: String::from( + "028584592624e742ba154c02df4c0b06e4e8a957ba081083ea9fe5309492aa6c7b", + ), + weight: Uint128::from(10u128).into(), + }], + threshold: Uint128::one().into(), + nonce: [7_u8; 32], + }, + } + } + + #[test] + fn should_verify_verifier_set() { + let source_gw_address = + String::from("0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e"); + let confirmation = mock_valid_confirmation_signers_rotated(); + let event = mock_valid_event_signers_rotated(); + + assert_eq!( + verify_verifier_set(&event, &confirmation, &source_gw_address), + Vote::SucceededOnChain + ); + } + + #[test] + fn should_not_verify_verifier_set_if_nonce_zero() { + let mut event = mock_valid_event_signers_rotated(); + event.signers.nonce = [0_u8; 32]; + let gateway_address = + String::from("0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e"); + let confirmation = mock_valid_confirmation_signers_rotated(); + + assert_eq!( + verify_verifier_set(&event, &confirmation, &gateway_address), + Vote::NotFound + ); + } + #[test] + fn shoud_not_verify_verifier_set_if_signers_mismatch() { + let source_gw_address = + String::from("0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e"); + let event = mock_second_valid_event_signers_rotated(); + let confirmation = mock_valid_confirmation_signers_rotated(); + + assert_eq!( + verify_verifier_set(&event, &confirmation, &source_gw_address), + Vote::NotFound + ); + } +} diff --git a/packages/axelar-wasm-std/Cargo.toml b/packages/axelar-wasm-std/Cargo.toml index a0dee342d..39763faf5 100644 --- a/packages/axelar-wasm-std/Cargo.toml +++ b/packages/axelar-wasm-std/Cargo.toml @@ -5,10 +5,7 @@ rust-version = { workspace = true } edition = { workspace = true } description = "Axelar cosmwasm standard library crate" -exclude = [ - "contract.wasm", - "hash.txt" -] +exclude = ["contract.wasm", "hash.txt"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] @@ -41,7 +38,10 @@ into-inner-derive = { workspace = true } itertools = { workspace = true } lazy_static = "1.4.0" num-traits = { workspace = true } -regex = { version = "1.10.0", default-features = false, features = ["perf", "std"] } +regex = { version = "1.10.0", default-features = false, features = [ + "perf", + "std", +] } report = { workspace = true } schemars = "0.8.10" semver = { workspace = true } @@ -50,17 +50,19 @@ serde_json = "1.0.89" serde_with = { version = "3.11.0", features = ["macros"] } sha3 = { workspace = true } stellar-xdr = { workspace = true } +starknet-types-core = { workspace = true } strum = { workspace = true } sui-types = { workspace = true } thiserror = { workspace = true } valuable = { version = "0.1.0", features = ["derive"] } +crypto-bigint = { version = "0.5.5", features = ["rand_core"] } [dev-dependencies] assert_ok = { workspace = true } cw-multi-test = "0.15.1" goldie = { workspace = true } -hex = { version = "0.4.3", default-features = false } rand = { workspace = true } +hex = { version = "0.4.3", default-features = false } [lints] workspace = true diff --git a/packages/axelar-wasm-std/src/utils.rs b/packages/axelar-wasm-std/src/utils.rs index e45c0695a..292deb920 100644 --- a/packages/axelar-wasm-std/src/utils.rs +++ b/packages/axelar-wasm-std/src/utils.rs @@ -1,3 +1,6 @@ +use crypto_bigint::U256; +use starknet_types_core::felt::Felt; + pub trait TryMapExt { type Monad; fn try_map(self, func: impl FnMut(T) -> Result) -> Result, E>; @@ -19,6 +22,22 @@ impl TryMapExt for Vec { } } +/// since the `Felt` type doesn't error on overflow, we have to implement that check +pub fn does_felt_overflow_from_slice(felt_hex_slice: &[u8]) -> bool { + if felt_hex_slice.len() > 32 { + return true; + } + let felt_max_hex_str = format!("{:064x}", Felt::MAX); + U256::from_be_slice(felt_hex_slice) > U256::from_be_hex(&felt_max_hex_str) +} + +/// since the `Felt` type doesn't error on overflow, we have to implement that check +pub fn does_felt_overflow_from_str(felt_hex_str: &str) -> bool { + let felt_hex_str = felt_hex_str.trim_start_matches("0x"); + let felt_max_hex_str = format!("{:064x}", Felt::MAX); + U256::from_be_hex(felt_hex_str) > U256::from_be_hex(&felt_max_hex_str) +} + #[cfg(test)] mod test { use super::*; diff --git a/packages/starknet-types/Cargo.toml b/packages/starknet-types/Cargo.toml new file mode 100644 index 000000000..839eeac05 --- /dev/null +++ b/packages/starknet-types/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "starknet-types" +version = "1.0.0" +rust-version.workspace = true +edition.workspace = true + +[dependencies] +axelar-wasm-std = { workspace = true, features = ["derive"] } +cosmwasm-std = { workspace = true } +router-api = { workspace = true } +ethers-core = { workspace = true } +starknet-core = { workspace = true } +starknet-types-core = { workspace = true } +error-stack = { workspace = true } +thiserror = { workspace = true } +itertools = { workspace = true } +hex = { workspace = true } +tokio = { version = "1", features = [ + "rt", + "signal", + "rt-multi-thread", + "macros", +] } +rand = { workspace = true } +futures = { workspace = true } + +[lints] +workspace = true diff --git a/packages/starknet-types/src/error.rs b/packages/starknet-types/src/error.rs new file mode 100644 index 000000000..a8e5bc2b8 --- /dev/null +++ b/packages/starknet-types/src/error.rs @@ -0,0 +1,7 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("invalid starknet address")] + InvalidAddress, +} diff --git a/packages/starknet-types/src/events.rs b/packages/starknet-types/src/events.rs new file mode 100644 index 000000000..cd1c4fa77 --- /dev/null +++ b/packages/starknet-types/src/events.rs @@ -0,0 +1,51 @@ +use std::sync::OnceLock; + +use starknet_core::types::Felt; +use starknet_core::utils::starknet_keccak; + +pub mod contract_call; +pub mod signers_rotated; +// Since a keccak hash over a string is a deterministic operation, +// we can use `OnceLock` to eliminate useless hash calculations. +static CALL_CONTRACT_FELT: OnceLock = OnceLock::new(); + +/// All Axelar event types supported by starknet +#[derive(Debug)] +pub enum EventType { + ContractCall, +} + +impl EventType { + fn parse(event_type_felt: Felt) -> Option { + let contract_call_type = + CALL_CONTRACT_FELT.get_or_init(|| starknet_keccak("ContractCall".as_bytes())); + + if event_type_felt == *contract_call_type { + Some(EventType::ContractCall) + } else { + None + } + } +} + +#[cfg(test)] +mod event_type_tests { + use starknet_core::utils::starknet_keccak; + + use super::EventType; + + #[test] + fn parse_contract_call() { + let contract_call_felt = starknet_keccak("ContractCall".as_bytes()); + assert!(matches!( + EventType::parse(contract_call_felt), + Some(EventType::ContractCall) + )); + } + + #[test] + fn parse_unknown_event() { + let contract_call_felt = starknet_keccak("UnknownEvent".as_bytes()); + assert!(EventType::parse(contract_call_felt).is_none()); + } +} diff --git a/packages/starknet-types/src/events/contract_call.rs b/packages/starknet-types/src/events/contract_call.rs new file mode 100644 index 000000000..cb243a8a5 --- /dev/null +++ b/packages/starknet-types/src/events/contract_call.rs @@ -0,0 +1,267 @@ +use ethers_core::types::H256; +use starknet_core::types::Felt; +use starknet_core::utils::{parse_cairo_short_string, ParseCairoShortStringError}; +use thiserror::Error; + +use crate::events::EventType; +use crate::types::byte_array::{ByteArray, ByteArrayError}; + +/// This is the event emitted by the gateway cairo contract on Starknet, +/// when the call_contract method is called from a third party. +#[derive(Debug, PartialEq, Clone)] +pub struct ContractCallEvent { + pub from_contract_addr: String, + pub destination_address: String, + pub destination_chain: String, + pub source_address: Felt, + pub payload_hash: H256, +} + +/// An error, representing failure to convert/parse a starknet event +/// to some specific event. +#[derive(Error, Debug)] +pub enum ContractCallError { + #[error("Invalid ContractCall event: {0}")] + InvalidEvent(String), + #[error("Cairo short string parse error: {0}")] + Cairo(#[from] ParseCairoShortStringError), + #[error("Failed felt conversion: {0}")] + TryFromConversion(String), + #[error("Event data/keys array index is out of bounds")] + OutOfBound, + #[error("ByteArray type error: {0}")] + ByteArray(#[from] ByteArrayError), +} + +impl TryFrom for ContractCallEvent { + type Error = ContractCallError; + + fn try_from(starknet_event: starknet_core::types::Event) -> Result { + if starknet_event.keys.len() != 2 { + return Err(ContractCallError::InvalidEvent( + "ContractCall should have exactly 2 event keys - event_type and destination_chain" + .to_owned(), + )); + } + + // first key is always the event type + let event_type_felt = starknet_event.keys[0]; + if !matches!( + EventType::parse(event_type_felt), + Some(EventType::ContractCall) + ) { + return Err(ContractCallError::InvalidEvent( + "not a ContractCall event".to_owned(), + )); + } + + // `event.from_address` is the contract address, which emitted the event + let from_contract_addr = format!( + "0x{}", + hex::encode(starknet_event.from_address.to_bytes_be()) + ); + + // destination_chain is the second key in the event keys list (the first key + // defined from the event) + // + // This field, should not exceed 252 bits (a felt's length) + let destination_chain = parse_cairo_short_string(&starknet_event.keys[1])?; + + // source_address represents the original caller of the `call_contract` gateway + // method. It is the first field in data, by the order defined in the + // event. + // + // TODO: Not sure if `064x` is the correct formatting. Maybe we should calculate + // the pedersen hash of the felt as described here, to get the actual address, + // although I'm not sure that we can do it as described here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/contract-address/ + let source_address = starknet_event.data[0]; + + // destination_contract_address (ByteArray) is composed of FieldElements + // from the second element to elemet X. + let destination_address_chunks_count_felt = starknet_event.data[1]; + let da_chunks_count: usize = u8::try_from(destination_address_chunks_count_felt) + .map_err(|err| ContractCallError::TryFromConversion(err.to_string()))? + .into(); + + // It's + 3, because we need to offset the 0th element, pending_word and + // pending_word_count, in addition to all chunks (da_chunks_count_usize) + let da_elements_start_index: usize = 1; + let da_elements_end_index: usize = da_chunks_count.wrapping_add(3); + let destination_address_byte_array: ByteArray = ByteArray::try_from( + starknet_event + .data + .get(da_elements_start_index..=da_elements_end_index) + .ok_or(ContractCallError::OutOfBound)? + .to_vec(), + )?; + let destination_address = destination_address_byte_array.try_to_string()?; + + // payload_hash is a keccak256, which is a combination of two felts (chunks) + // - first felt contains the 128 least significat bits (LSB) + // - second felt contains the 128 most significat bits (MSG) + let ph_chunk1_index: usize = da_elements_end_index.wrapping_add(1); + let ph_chunk2_index: usize = ph_chunk1_index.wrapping_add(1); + let mut payload_hash = [0; 32]; + let lsb: [u8; 32] = starknet_event + .data + .get(ph_chunk1_index) + .ok_or(ContractCallError::InvalidEvent( + "payload_hash chunk 1 out of range".to_owned(), + ))? + .to_bytes_be(); + let msb: [u8; 32] = starknet_event + .data + .get(ph_chunk2_index) + .ok_or(ContractCallError::InvalidEvent( + "payload_hash chunk 2 out of range".to_owned(), + ))? + .to_bytes_be(); + + // most significat bits, go before least significant bits for u256 construction + // check - https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_in_u256_values + payload_hash[..16].copy_from_slice(&msb[16..]); + payload_hash[16..].copy_from_slice(&lsb[16..]); + + Ok(ContractCallEvent { + from_contract_addr, + destination_address, + destination_chain, + source_address, + payload_hash: H256::from_slice(&payload_hash), + }) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use ethers_core::types::H256; + use starknet_core::types::{Felt, FromStrError}; + use starknet_core::utils::starknet_keccak; + + use super::ContractCallEvent; + use crate::events::contract_call::ContractCallError; + use crate::types::byte_array::ByteArrayError; + + #[test] + fn destination_address_chunks_offset_out_of_range() { + let mut starknet_event = get_dummy_event(); + // longer chunk, which offsets the destination_address byte array out of range + starknet_event.data[1] = + Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); + + let event = ContractCallEvent::try_from(starknet_event).unwrap_err(); + assert!(matches!( + event, + ContractCallError::ByteArray(ByteArrayError::ParsingFelt(_)) + )); + } + + #[test] + fn destination_address_chunks_count_too_long() { + let mut starknet_event = get_dummy_event(); + // too long for u32 + starknet_event.data[1] = Felt::MAX; + + let event = ContractCallEvent::try_from(starknet_event).unwrap_err(); + assert!(matches!(event, ContractCallError::TryFromConversion(_))); + } + + #[test] + fn invalid_dest_chain() { + let mut starknet_event = get_dummy_event(); + // too long for Cairo long string too long + starknet_event.keys[1] = Felt::MAX; + + let event = ContractCallEvent::try_from(starknet_event).unwrap_err(); + assert!(matches!(event, ContractCallError::Cairo(_))); + } + + #[test] + fn more_than_2_keys() { + // the payload is the word "hello" + let mut starknet_event = get_dummy_event(); + starknet_event + .keys + .push(starknet_keccak("additional_element".as_bytes())); + + let event = ContractCallEvent::try_from(starknet_event).unwrap_err(); + assert!(matches!(event, ContractCallError::InvalidEvent(_))); + } + + #[test] + fn wrong_event_type() { + // the payload is the word "hello" + let mut starknet_event = get_dummy_event(); + starknet_event.keys[0] = starknet_keccak("NOTContractCall".as_bytes()); + + let event = ContractCallEvent::try_from(starknet_event).unwrap_err(); + assert!(matches!(event, ContractCallError::InvalidEvent(_))); + } + + #[test] + fn valid_call_contract_event() { + // the payload is the word "hello" + let starknet_event = get_dummy_event(); + let event = ContractCallEvent::try_from(starknet_event).unwrap(); + + assert_eq!( + event, + ContractCallEvent { + from_contract_addr: String::from( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e" + ), + destination_address: String::from("hello"), + destination_chain: String::from("destination_chain"), + source_address: Felt::from_str( + "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca" + ) + .unwrap(), + payload_hash: H256::from_slice(&[ + 28, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, + 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200 + ]) + } + ); + } + + fn get_dummy_event() -> starknet_core::types::Event { + // "hello" as payload + // "hello" as destination address + // "some_contract_address" as source address + // "destination_chain" as destination_chain + let event_data: Result, FromStrError> = vec![ + "0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca", // the caller addr + "0x0000000000000000000000000000000000000000000000000000000000000000", // 0 data + "0x00000000000000000000000000000000000000000000000000000068656c6c6f", // "hello" + "0x0000000000000000000000000000000000000000000000000000000000000005", // 5 bytes + "0x0000000000000000000000000000000056d9517b9c948127319a09a7a36deac8", // keccak256(hello) + "0x000000000000000000000000000000001c8aff950685c2ed4bc3174f3472287b", + "0x0000000000000000000000000000000000000000000000000000000000000005", // 5 bytes + "0x0000000000000000000000000000000000000000000000000000000000000068", // h + "0x0000000000000000000000000000000000000000000000000000000000000065", // e + "0x000000000000000000000000000000000000000000000000000000000000006c", // l + "0x000000000000000000000000000000000000000000000000000000000000006c", // l + "0x000000000000000000000000000000000000000000000000000000000000006f", // o + ] + .into_iter() + .map(Felt::from_str) + .collect(); + starknet_core::types::Event { + // I think it's a pedersen hash in actuallity, but for the tests I think it's ok + from_address: starknet_keccak("some_contract_address".as_bytes()), + keys: vec![ + starknet_keccak("ContractCall".as_bytes()), + // destination chain + Felt::from_str( + "0x00000000000000000000000000000064657374696e6174696f6e5f636861696e", + ) + .unwrap(), + ], + data: event_data.unwrap(), + } + } +} diff --git a/packages/starknet-types/src/events/signers_rotated.rs b/packages/starknet-types/src/events/signers_rotated.rs new file mode 100644 index 000000000..194fc0969 --- /dev/null +++ b/packages/starknet-types/src/events/signers_rotated.rs @@ -0,0 +1,366 @@ +use starknet_core::types::{Event, Felt}; +use thiserror::Error; + +/// An error, representing failure to convert/parse a starknet event +/// to a SignersRotated event. +#[derive(Error, Debug)] +pub enum SignersRotatedErrors { + /// Error returned when a required signers hash is missing from a + /// transaction. + #[error("missing signers hash for transaction")] + MissingSignersHash, + + /// Error returned when payload data cannot be parsed correctly. + #[error("failed to parse payload data, error: {0}")] + FailedToParsePayloadData(String), + + /// Error returned when the payload data is missing. + #[error("missing payload data for transaction")] + MissingPayloadData, + + /// Error returned when the epoch number in a transaction is invalid or + /// unexpected. + #[error("incorrect epoch for transaction")] + IncorrectEpoch, + + /// Error returned when the threshold in a transaction is invalid or + /// unexpected. + #[error("incorrect threshold for transaction")] + IncorrectThreshold, + + /// Error returned when the nonce in a transaction is missing. + #[error("missing nonce for transaction")] + MissingNonce, + + /// Error returned when the keys in a transaction are missing. + #[error("missing keys for transaction")] + MissingKeys, +} + +/// Represents a weighted signer +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Signer { + /// The address of the signer + pub signer: String, + /// The weight (voting power) of this signer + pub weight: u128, +} + +/// Represents a set of signers +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct WeightedSigners { + pub signers: Vec, + pub threshold: u128, + pub nonce: [u8; 32], +} + +/// Represents a Starknet SignersRotated event +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SignersRotatedEvent { + /// The address of the sender + pub from_address: String, + /// The epoch number when this rotation occurred + pub epoch: u64, + /// The hash of the new signers + pub signers_hash: [u8; 32], + /// The new set of weighted signers with their voting power + pub signers: WeightedSigners, +} + +impl TryFrom for SignersRotatedEvent { + type Error = SignersRotatedErrors; + + /// Attempts to convert a Starknet event to a SignersRotated event + /// + /// # Arguments + /// + /// * `event` - The Starknet event to convert + /// + /// # Returns + /// + /// * `Ok(SignersRotated)` - Successfully converted event containing: + /// * `epoch` - The epoch number when rotation occurred + /// * `signers_hash` - Hash of the new signers (32 bytes) + /// * `signers` - New set of weighted signers with: + /// * List of signers with their addresses and weights + /// * Threshold for required voting power + /// * Nonce value (32 bytes) + /// + /// # Errors + /// + /// Returns a `SignersRotatedErrors` if: + /// * Event data or keys are empty + /// * Failed to parse epoch number + /// * Missing or invalid signers hash + /// * Failed to parse signers array length + /// * Failed to parse signer addresses or weights + /// * Missing or invalid threshold + /// * Missing or invalid nonce + fn try_from(event: Event) -> Result { + if event.data.is_empty() { + return Err(SignersRotatedErrors::MissingPayloadData); + } + if event.keys.is_empty() { + return Err(SignersRotatedErrors::MissingKeys); + } + + let from_address = event.from_address.to_hex_string(); + + // it starts at 2 because 0 is the selector and 1 is the from_address + let epoch_index = 2; + // INFO: there might be better way to convert to u64 + let epoch = event + .keys + .get(epoch_index) + .ok_or(SignersRotatedErrors::IncorrectEpoch)? + .to_string() + .parse::() + .map_err(|_| SignersRotatedErrors::IncorrectEpoch)?; + + // Construct signers hash + let mut signers_hash = [0_u8; 32]; + let lsb = event + .keys + .get(epoch_index + 1) + .map(Felt::to_bytes_be) + .ok_or(SignersRotatedErrors::MissingSignersHash)?; + let msb = event + .keys + .get(epoch_index + 2) + .map(Felt::to_bytes_be) + .ok_or(SignersRotatedErrors::MissingSignersHash)?; + signers_hash[..16].copy_from_slice(&msb[16..]); + signers_hash[16..].copy_from_slice(&lsb[16..]); + + // Parse signers array from event data + let mut buff_signers = vec![]; + + let signers_index = 0; + let signers_len = event.data[signers_index] + .to_string() + .parse::() + .map_err(|_| { + SignersRotatedErrors::FailedToParsePayloadData( + "failed to parse signers length".to_string(), + ) + })?; + let signers_end_index = signers_index.saturating_add(signers_len.saturating_mul(2)); + + // Parse signers and weights + for i in 0..signers_len { + let signer_index = signers_index + .saturating_add(1) + .saturating_add(i.saturating_mul(2)); + let weight_index = signer_index.saturating_add(1); + + // Get signer address as bytes + let signer = event.data[signer_index].to_hex_string(); + + // Parse weight + let weight = event.data[weight_index] + .to_string() + .parse::() + .map_err(|_| { + SignersRotatedErrors::FailedToParsePayloadData( + "failed to parse signer weight".to_string(), + ) + })?; + + buff_signers.push(Signer { signer, weight }); + } + + // Parse threshold + let threshold = event + .data + .get(signers_end_index) + .ok_or(SignersRotatedErrors::IncorrectThreshold)? + .to_string() + .parse::() + .map_err(|_| SignersRotatedErrors::IncorrectThreshold)?; + + // Parse nonce + let mut nonce = [0_u8; 32]; + let lsb = event + .data + .get(event.data.len().saturating_sub(2)) + .map(Felt::to_bytes_be) + .ok_or(SignersRotatedErrors::MissingNonce)?; + let msb = event + .data + .get(event.data.len().saturating_sub(1)) + .map(Felt::to_bytes_be) + .ok_or(SignersRotatedErrors::MissingNonce)?; + nonce[16..].copy_from_slice(&lsb[16..]); + nonce[..16].copy_from_slice(&msb[16..]); + + Ok(SignersRotatedEvent { + from_address, + epoch, + signers_hash, + signers: WeightedSigners { + signers: buff_signers, + threshold, + nonce, + }, + }) + } +} + +#[cfg(test)] +mod tests { + use futures::stream::{FuturesUnordered, StreamExt}; + use starknet_core::types::{EmittedEvent, Felt}; + + use super::*; + + async fn get_valid_event() -> (Vec, Vec, Felt, Felt) { + let keys_data: Vec = vec![ + Felt::from_hex_unchecked( + "0x01815547484542c49542242a23bc0a1b762af99232f38c0417050825aea8fc93", + ), + Felt::from_hex_unchecked( + "0x0268929df65ee595bb8592323f981351efdc467d564effc6d2e54d2e666e43ca", + ), + Felt::from_hex_unchecked("0x01"), + Felt::from_hex_unchecked("0xd4203fe143363253c89a27a26a6cb81f"), + Felt::from_hex_unchecked("0xe23e7704d24f646e5e362c61407a69d2"), + ]; + + let event_data: Vec = vec![ + Felt::from_hex_unchecked("0x01"), + Felt::from_hex_unchecked("0x3ec7d572a0fe479768ac46355651f22a982b99cc"), + Felt::from_hex_unchecked("0x01"), + Felt::from_hex_unchecked("0x01"), + Felt::from_hex_unchecked("0x2fe49d"), + Felt::from_hex_unchecked("0x00"), + ]; + ( + keys_data, + event_data, + // sender_address + Felt::from_hex_unchecked( + "0x0282b4492e08d8b6bbec8dfe7412e42e897eef9c080c5b97be1537433e583bdc", + ), + // tx_hash + Felt::from_hex_unchecked( + "0x04663231715b17dd58cd08e63d6b31d2c86b158d4730da9a1b75ca2452c9910c", + ), + ) + } + + /// Generate a set of data with random modifications + async fn get_malformed_event() -> (Vec, Vec, Felt, Felt) { + let (mut keys_data, mut event_data, sender_address, tx_hash) = get_valid_event().await; + // Randomly remove an element from either vector + match rand::random::() { + true if !keys_data.is_empty() => { + let random_index = rand::random::() % keys_data.len(); + keys_data.remove(random_index); + } + false if !event_data.is_empty() => { + let random_index = rand::random::() % event_data.len(); + event_data.remove(random_index); + } + _ => {} + } + + // Randomly corrupt data values + if rand::random::() { + if let Some(elem) = keys_data.first_mut() { + *elem = Felt::from_hex_unchecked("0xdeadbeef"); + } + } + if rand::random::() { + if let Some(elem) = event_data.first_mut() { + *elem = Felt::from_hex_unchecked("0xcafebabe"); + } + } + + (keys_data, event_data, sender_address, tx_hash) + } + + #[tokio::test] + async fn test_try_from_event_happy_scenario() { + let (keys_data, event_data, sender_address, tx_hash) = get_valid_event().await; + + assert!(SignersRotatedEvent::try_from(Event { + from_address: sender_address, + keys: keys_data, + data: event_data, + }) + .is_ok()); + } + + #[tokio::test] + async fn test_try_from_empty_event() { + let (_, _, sender_address, tx_hash) = get_valid_event().await; + let result = SignersRotatedEvent::try_from(Event { + data: vec![], + from_address: sender_address, + keys: vec![], + }); + + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_try_from_event_missing_data() { + let (keys_data, _, sender_address, tx_hash) = get_valid_event().await; + let event = SignersRotatedEvent::try_from(Event { + data: vec![], + from_address: sender_address, + keys: keys_data, + }); + + assert!(event.is_err()); + assert!(matches!( + event, + Err(SignersRotatedErrors::MissingPayloadData) + )); + } + + #[tokio::test] + async fn test_try_from_event_missing_keys() { + let (_, event_data, sender_address, tx_hash) = get_valid_event().await; + let event = SignersRotatedEvent::try_from(Event { + data: event_data, + from_address: sender_address, + keys: vec![], + }); + + assert!(event.is_err()); + assert!(matches!(event, Err(SignersRotatedErrors::MissingKeys))); + } + + #[tokio::test] + async fn test_try_from_event_randomly_malformed_data_x1000() { + let mut futures = FuturesUnordered::new(); + + for _ in 0..1000 { + futures.push(async { + let (_, event_data, sender_address, tx_hash) = get_malformed_event().await; + let event = EmittedEvent { + data: event_data, + from_address: sender_address, + keys: vec![], + transaction_hash: tx_hash, + block_hash: None, + block_number: None, + }; + SignersRotatedEvent::try_from(Event { + data: event.data, + from_address: event.from_address, + keys: event.keys, + }) + .is_err() + }); + } + + // if any conversion succeeded then it should have failed + while let Some(result) = futures.next().await { + if !result { + panic!("expected conversion to fail for malformed event"); + } + } + } +} diff --git a/packages/starknet-types/src/lib.rs b/packages/starknet-types/src/lib.rs new file mode 100644 index 000000000..7f2db3c29 --- /dev/null +++ b/packages/starknet-types/src/lib.rs @@ -0,0 +1,3 @@ +pub mod error; +pub mod events; +pub mod types; diff --git a/packages/starknet-types/src/types.rs b/packages/starknet-types/src/types.rs new file mode 100644 index 000000000..90b8423bf --- /dev/null +++ b/packages/starknet-types/src/types.rs @@ -0,0 +1,3 @@ +pub mod array_span; +pub mod byte_array; +pub mod starknet_message; diff --git a/packages/starknet-types/src/types/array_span.rs b/packages/starknet-types/src/types/array_span.rs new file mode 100644 index 000000000..eaf1fc613 --- /dev/null +++ b/packages/starknet-types/src/types/array_span.rs @@ -0,0 +1,187 @@ +use starknet_core::types::Felt; +use thiserror::Error; + +/// Represents Cairo's Array and Span types. +/// Implements `TryFrom>`, which is the way to create it. +/// +/// ## Example usage with the string "hello" +/// +/// ```rust +/// use starknet_types::types::array_span::ArraySpan; +/// use std::str::FromStr; +/// use starknet_core::types::Felt; +/// use starknet_core::types::FromStrError; +/// +/// let data: Result, FromStrError> = vec![ +/// "0x0000000000000000000000000000000000000000000000000000000000000005", +/// "0x0000000000000000000000000000000000000000000000000000000000000068", +/// "0x0000000000000000000000000000000000000000000000000000000000000065", +/// "0x000000000000000000000000000000000000000000000000000000000000006c", +/// "0x000000000000000000000000000000000000000000000000000000000000006c", +/// "0x000000000000000000000000000000000000000000000000000000000000006f", +/// ] +/// .into_iter() +/// .map(Felt::from_str) +/// .collect(); +/// +/// let array_span = ArraySpan::::try_from(data.unwrap()).unwrap(); +/// assert_eq!(array_span.data, vec![104, 101, 108, 108, 111]); +/// assert_eq!(String::from_utf8(array_span.data).unwrap(), "hello"); +/// ``` +/// +/// For more info: +/// https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays +#[derive(Debug)] +pub struct ArraySpan { + pub data: Vec, +} + +#[derive(Error, Debug)] +pub enum ArraySpanError { + #[error("Invalid array/span length")] + InvalidLength, + #[error("Failed to parse felt - {0}")] + ParsingFelt(String), +} + +impl TryFrom> for ArraySpan { + type Error = ArraySpanError; + + fn try_from(data: Vec) -> Result { + // First element is always the array length, which is a felt (so u8 is enough) + let arr_length = + u8::try_from(data[0]).map_err(|e| ArraySpanError::ParsingFelt(e.to_string()))?; + + // -1 because we have to offset the first element (the length itself) + let arr_length_usize = usize::from(arr_length); + if arr_length_usize != data.len().wrapping_sub(1) { + return Err(ArraySpanError::InvalidLength); + } + + let bytes: Result, ArraySpanError> = data + .get(1..) + .ok_or(ArraySpanError::InvalidLength)? + .iter() + .copied() + .map(|data| u8::try_from(data).map_err(|e| ArraySpanError::ParsingFelt(e.to_string()))) + .collect(); + + Ok(ArraySpan { data: bytes? }) + } +} + +#[cfg(test)] +mod array_span_tests { + use std::str::FromStr; + + use starknet_core::types::{Felt, FromStrError}; + + use super::ArraySpan; + + #[test] + fn try_from_valid_zeros() { + // the string "hello", but Felt is bigger than u8::max + let data = vec![Felt::from_str( + "0x0000000000000000000000000000000000000000000000000000000000000000", + ) + .unwrap()]; + + let array_span = ArraySpan::::try_from(data).unwrap(); + assert_eq!(array_span.data, Vec::::new()); + } + + #[test] + fn try_from_failed_to_parse_element_to_u8() { + // the string "hello", but Felt is bigger than u8::max + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "0x0000000000000000000000000000000000000000000000000000000000000065", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006f", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let array_span = ArraySpan::::try_from(data.unwrap()); + assert!(array_span.is_err()); + } + + #[test] + fn try_from_failed_to_parse_elements_length_to_u32() { + // the string "hello", but element count is bigger than u32::max + let data: Result, FromStrError> = vec![ + "0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "0x0000000000000000000000000000000000000000000000000000000000000068", + "0x0000000000000000000000000000000000000000000000000000000000000065", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006f", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let array_span = ArraySpan::::try_from(data.unwrap()); + assert!(array_span.is_err()); + } + + #[test] + fn try_from_invalid_number_of_elements() { + // the string "hello", but with only 4 bytes + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x0000000000000000000000000000000000000000000000000000000000000068", + "0x0000000000000000000000000000000000000000000000000000000000000065", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006c", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let array_span = ArraySpan::::try_from(data.unwrap()); + assert!(array_span.is_err()); + } + + #[test] + fn try_from_invalid_declared_length() { + // the string "hello", with correct number of bytes, but only 4 declared, + // instead of 5 + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x0000000000000000000000000000000000000000000000000000000000000068", + "0x0000000000000000000000000000000000000000000000000000000000000065", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006f", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let array_span = ArraySpan::::try_from(data.unwrap()); + assert!(array_span.is_err()); + } + + #[test] + fn try_from_valid() { + // the string "hello" + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x0000000000000000000000000000000000000000000000000000000000000068", + "0x0000000000000000000000000000000000000000000000000000000000000065", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006c", + "0x000000000000000000000000000000000000000000000000000000000000006f", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let array_span = ArraySpan::::try_from(data.unwrap()).unwrap(); + assert_eq!(array_span.data, vec![104, 101, 108, 108, 111]); + } +} diff --git a/packages/starknet-types/src/types/byte_array.rs b/packages/starknet-types/src/types/byte_array.rs new file mode 100644 index 000000000..e9bc10dcf --- /dev/null +++ b/packages/starknet-types/src/types/byte_array.rs @@ -0,0 +1,444 @@ +use itertools::FoldWhile::{Continue, Done}; +use itertools::Itertools; +use starknet_core::types::Felt; +use starknet_core::utils::parse_cairo_short_string; +use thiserror::Error; + +/// Represents Cairo's ByteArray type. +/// Implements `TryFrom>`, which is the way to create it. +/// +/// ## Example usage with the string "hello" +/// +/// ```rust +/// use starknet_types::types::byte_array::ByteArray; +/// use std::str::FromStr; +/// use starknet_core::types::Felt; +/// use starknet_core::types::FromStrError; +/// +/// let data: Result, FromStrError> = vec![ +/// "0x0000000000000000000000000000000000000000000000000000000000000000", +/// "0x00000000000000000000000000000000000000000000000000000068656c6c6f", +/// "0x0000000000000000000000000000000000000000000000000000000000000005", +/// ] +/// .into_iter() +/// .map(Felt::from_str) +/// .collect(); +/// +/// let byte_array = ByteArray::try_from(data.unwrap()); +/// assert!(byte_array.is_ok()); +/// ``` +/// +/// For more info: +/// https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays +#[derive(Debug, Default)] +pub struct ByteArray { + /// The data byte array. Contains 31-byte chunks of the byte array. + data: Vec, + /// The bytes that remain after filling the data array with full 31-byte + /// chunks + pending_word: Felt, + /// The byte count of the pending_word + pending_word_length: u8, // can't be more than 30 bytes +} + +#[derive(Error, Debug)] +pub enum ByteArrayError { + #[error("Failed to fetch element from byte array at index")] + OutOfBound, + #[error("Invalid byte array - {0}")] + InvalidByteArray(String), + #[error("Failed to convert felt - {0}")] + ParsingFelt(String), + #[error("Failed to convert the byte array into a string")] + ToString, +} + +impl TryFrom> for ByteArray { + type Error = ByteArrayError; + + fn try_from(data: Vec) -> Result { + // pending word is always the next to last element + let pending_word_index = data.len().wrapping_sub(2); + let last_element_index = data.len().wrapping_sub(1); + + let mut byte_array = ByteArray { + ..Default::default() + }; + + if data.len() < 3 { + return Err(ByteArrayError::InvalidByteArray( + "vec should have minimum 3 elements".to_owned(), + )); + } + + // word count is always the first element, which is a felt (so u8 is enough) + let word_count = + u8::try_from(data[0]).map_err(|e| ByteArrayError::ParsingFelt(e.to_string()))?; + + // vec element count should be whatever the word count is + an offset of 3 + // the 3 stands for the minimum 3 elements: + // - word count + // - pending_word + // - pendint_word_length + let word_count_usize = usize::from(word_count.wrapping_add(3)); + if word_count_usize != data.len() { + return Err(ByteArrayError::InvalidByteArray( + "pre-defined count doesn't match actual 31byte element count".to_owned(), + )); + } + + // pending word byte count is always the last element + let pending_word_length_felt = data + .get(last_element_index) + .ok_or(ByteArrayError::OutOfBound)?; + let pending_word_length = u8::try_from(*pending_word_length_felt) + .map_err(|e| ByteArrayError::ParsingFelt(e.to_string()))?; + byte_array.pending_word_length = pending_word_length; + + let pending_word = data + .get(pending_word_index) + .ok_or(ByteArrayError::OutOfBound)?; + byte_array.pending_word = *pending_word; + + // count bytes, excluding leading zeros + let non_zero_pw_length = pending_word + .to_bytes_be() + .iter() + .fold_while(32, |acc: u8, n| { + if *n == 0 { + Continue(acc.saturating_sub(1)) + } else { + Done(acc) + } + }) + .into_inner(); + + if pending_word_length != non_zero_pw_length { + return Err(ByteArrayError::InvalidByteArray( + "pending_word length doesn't match it's defined length".to_owned(), + )); + } + + if word_count > 0 { + let byte_array_data = data + .get(1..pending_word_index) + .ok_or(ByteArrayError::OutOfBound)? + .to_vec(); + + byte_array.data = byte_array_data; + } + + Ok(byte_array) + } +} + +impl ByteArray { + /// Takes the ByteArray struct and tries to parse it as a single string + /// + /// ## Example usage with the string "hello" + /// + /// ```rust + /// use starknet_types::types::byte_array::ByteArray; + /// use std::str::FromStr; + /// use starknet_core::types::Felt; + /// use starknet_core::types::FromStrError; + /// + /// let data: Result, FromStrError> = vec![ + /// "0x0000000000000000000000000000000000000000000000000000000000000000", + /// "0x00000000000000000000000000000000000000000000000000000068656c6c6f", + /// "0x0000000000000000000000000000000000000000000000000000000000000005", + /// ] + /// .into_iter() + /// .map(Felt::from_str) + /// .collect(); + /// + /// let byte_array = ByteArray::try_from(data.unwrap()).unwrap(); + /// assert_eq!("hello", byte_array.try_to_string().unwrap()); + /// ``` + /// + /// Additional documentation you can find here: + /// https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + pub fn try_to_string(&self) -> Result { + match self + .data + .iter() + .chain(std::iter::once(&self.pending_word)) + .map(parse_cairo_short_string) + .collect::>() + { + Ok(s) => Ok(s), + Err(_) => Err(ByteArrayError::ToString), + } + } +} + +#[cfg(test)] +mod byte_array_tests { + use std::str::FromStr; + + use starknet_core::types::{Felt, FromStrError}; + + use super::ByteArray; + + #[test] + fn byte_array_parse_fail_wrong_pending_word_length() { + // Example for a small string (fits in a single felt) taken from here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + // + // So this is the string "hello" + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000068656c6c6f", + // Should be of length 5 bytes, but we put 6 bytes, in order to fail + // the parsing + "0x0000000000000000000000000000000000000000000000000000000000000020", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array = ByteArray::try_from(data.unwrap()); + assert!(byte_array.is_err()); + } + + #[test] + fn byte_array_to_string_error() { + // Example for a small string (fits in a single felt) taken from here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + // + // So this is the string "hello" + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000000", + // Note the 01 in the beginning. This is what causes the parse + // function to error. + "0x01000000000000000000000000000000000000000000000000000068656c6c6f", + // 32(0x20) bytes long pending_word + "0x0000000000000000000000000000000000000000000000000000000000000020", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array = ByteArray::try_from(data.unwrap()).unwrap(); + assert!(byte_array.try_to_string().is_err()); + } + + #[test] + fn byte_array_single_pending_word_only_to_string_valid() { + // Example for a small string (fits in a single felt) taken from here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + // + // So this is the string "hello" + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000068656c6c6f", + "0x0000000000000000000000000000000000000000000000000000000000000005", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array = ByteArray::try_from(data.unwrap()).unwrap(); + assert_eq!("hello", byte_array.try_to_string().unwrap()); + } + + #[test] + fn byte_array_to_long_string_valid() { + // Example for a long string (doesn't fit in a single felt) taken from here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + // + // So this is the string "Long long string, a lot more than 31 characters that + // wouldn't even fit in two felts, so we'll have at least two felts and a + // pending word." + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x00004c6f6e67206c6f6e6720737472696e672c2061206c6f74206d6f72652074", + "0x000068616e2033312063686172616374657273207468617420776f756c646e27", + "0x000074206576656e2066697420696e2074776f2066656c74732c20736f207765", + "0x0000276c6c2068617665206174206c656173742074776f2066656c747320616e", + "0x0000000000000000000000000000006420612070656e64696e6720776f72642e", + "0x0000000000000000000000000000000000000000000000000000000000000011", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array = ByteArray::try_from(data.unwrap()).unwrap(); + assert_eq!("Long long string, a lot more than 31 characters that wouldn't even fit in two felts, so we'll have at least two felts and a pending word.", byte_array.try_to_string().unwrap()); + } + + #[test] + fn try_from_vec_count_less_then_3() { + let data: Result, FromStrError> = + vec!["0x0000000000000000000000000000000000000000000000000000000000000005"] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array_err = ByteArray::try_from(data.unwrap()); + assert!(byte_array_err.is_err()); + } + + #[test] + fn try_from_non_u32_word_count() { + let data: Result, FromStrError> = vec![ + // should be 0, because the message is short + // enough to fit in a single Felt + "0x00000000000000000000000000000000000000000000000000000068656c6c6f", + "0x00000000000000000000000000000000000000000000000000000068656c6c6f", + "0x0000000000000000000000000000000000000000000000000000000000000005", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array_err = ByteArray::try_from(data.unwrap()); + assert!(byte_array_err.is_err()); + } + #[test] + fn try_from_invalid_byte_array_element_count() { + let data: Result, FromStrError> = vec![ + // should be 0, because the message is short + // enough to fit in a single Felt + "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x00000000000000000000000000000000000000000000000000000068656c6c6f", + "0x0000000000000000000000000000000000000000000000000000000000000005", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array_err = ByteArray::try_from(data.unwrap()); + assert!(byte_array_err.is_err()); + } + + #[test] + fn try_from_non_u8_pending_word_length() { + // Example for a small string (fits in a single felt) taken from here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + // + // So this is the string "hello" + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000068656c6c6f", + "0x00000000000000000000000000000000000000000000000000000068656c6c6f", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array = ByteArray::try_from(data.unwrap()); + assert!(byte_array.is_err()); + } + + #[test] + fn try_from_valid_only_pending_word() { + // Example for a small string (fits in a single felt) taken from here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + // + // So this is the string "hello" + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000068656c6c6f", + "0x0000000000000000000000000000000000000000000000000000000000000005", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array = ByteArray::try_from(data.unwrap()).unwrap(); + + assert_eq!(byte_array.data, vec![]); + assert_eq!( + byte_array.pending_word, + Felt::from_str("0x00000000000000000000000000000000000000000000000000000068656c6c6f",) + .unwrap() + ); + assert_eq!(byte_array.pending_word_length, 5); + } + + #[test] + fn try_from_valid_one_big_string_split_in_multiple_data_elements() { + // Example for a long string (doesn't fit in a single felt) taken from here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + // + // So this is the string "Long long string, a lot more than 31 characters that + // wouldn't even fit in two felts, so we'll have at least two felts and a + // pending word." + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x00004c6f6e67206c6f6e6720737472696e672c2061206c6f74206d6f72652074", + "0x000068616e2033312063686172616374657273207468617420776f756c646e27", + "0x000074206576656e2066697420696e2074776f2066656c74732c20736f207765", + "0x0000276c6c2068617665206174206c656173742074776f2066656c747320616e", + "0x0000000000000000000000000000006420612070656e64696e6720776f72642e", + "0x0000000000000000000000000000000000000000000000000000000000000011", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array = ByteArray::try_from(data.unwrap()).unwrap(); + + assert_eq!( + byte_array.data, + vec![ + Felt::from_str( + "0x00004c6f6e67206c6f6e6720737472696e672c2061206c6f74206d6f72652074", + ) + .unwrap(), + Felt::from_str( + "0x000068616e2033312063686172616374657273207468617420776f756c646e27", + ) + .unwrap(), + Felt::from_str( + "0x000074206576656e2066697420696e2074776f2066656c74732c20736f207765", + ) + .unwrap(), + Felt::from_str( + "0x0000276c6c2068617665206174206c656173742074776f2066656c747320616e", + ) + .unwrap() + ] + ); + assert_eq!( + byte_array.pending_word, + Felt::from_str("0x0000000000000000000000000000006420612070656e64696e6720776f72642e",) + .unwrap() + ); + assert_eq!(byte_array.pending_word_length, 17); + } + + #[test] + fn try_from_valid_one_very_big_string() { + // Example for a long string (doesn't fit in a single felt) taken from here: + // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays + // + // So this is the string "Long string, more than 31 characters." + let data: Result, FromStrError> = vec![ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x004c6f6e6720737472696e672c206d6f7265207468616e203331206368617261", + "0x000000000000000000000000000000000000000000000000000063746572732e", + "0x0000000000000000000000000000000000000000000000000000000000000006", + ] + .into_iter() + .map(Felt::from_str) + .collect(); + + let byte_array = ByteArray::try_from(data.unwrap()).unwrap(); + + assert_eq!( + byte_array.data, + vec![Felt::from_str( + "0x004c6f6e6720737472696e672c206d6f7265207468616e203331206368617261", + ) + .unwrap()] + ); + assert_eq!( + byte_array.pending_word, + Felt::from_str("0x000000000000000000000000000000000000000000000000000063746572732e",) + .unwrap() + ); + assert_eq!(byte_array.pending_word_length, 6); + } +} diff --git a/packages/starknet-types/src/types/starknet_message.rs b/packages/starknet-types/src/types/starknet_message.rs new file mode 100644 index 000000000..34dacb137 --- /dev/null +++ b/packages/starknet-types/src/types/starknet_message.rs @@ -0,0 +1,260 @@ +use std::str::FromStr; + +use axelar_wasm_std::utils::does_felt_overflow_from_slice; +use error_stack::{Report, ResultExt}; +use ethers_core::abi::{ + AbiDecode, AbiError, AbiType, Detokenize, FixedBytes, InvalidOutputType, ParamType, Token, + Tokenizable, +}; +use ethers_core::types::{Address, Selector, U256}; +use router_api::Message as RouterMessage; +use starknet_core::types::Felt; + +use crate::error::Error; + +/// A message that is encoded in the prover and later sent to the Starknet gateway. +#[derive(Clone, Debug, PartialEq)] +pub struct StarknetMessage { + pub source_chain: String, + pub message_id: String, + pub source_address: String, + pub contract_address: Felt, + pub payload_hash: U256, +} + +impl TryFrom<&RouterMessage> for StarknetMessage { + type Error = Report; + + fn try_from(msg: &RouterMessage) -> Result { + let contract_address = Felt::from_str(msg.destination_address.as_str()) + .change_context(Error::InvalidAddress)?; + + Ok(StarknetMessage { + source_chain: msg.cc_id.source_chain.to_string(), + message_id: msg.cc_id.message_id.to_string(), + source_address: msg.source_address.to_string(), + contract_address, + payload_hash: U256::from(msg.payload_hash), + }) + } +} + +impl AbiType for StarknetMessage { + fn param_type() -> ParamType { + ParamType::Tuple(vec![ + ethers_core::abi::ParamType::String, + ethers_core::abi::ParamType::String, + ethers_core::abi::ParamType::String, + ethers_core::abi::ParamType::FixedBytes(32usize), + ::param_type(), + ]) + } +} + +impl AbiDecode for StarknetMessage { + fn decode(bytes: impl AsRef<[u8]>) -> Result { + let tokens = ethers_core::abi::decode(&[Self::param_type()], bytes.as_ref())?; + Ok(::from_tokens(tokens)?) + } +} + +impl Tokenizable for StarknetMessage { + fn from_token(token: Token) -> Result + where + Self: Sized, + { + if let Token::Tuple(tokens) = token { + if tokens.len() != 5 { + return Err(InvalidOutputType( + "failed to read tokens: starknet message should have 5 tokens".to_string(), + )); + } + + if let ( + Token::String(source_chain), + Token::String(message_id), + Token::String(source_address), + Token::FixedBytes(contract_address), + Token::Uint(payload_hash), + ) = ( + tokens[0].clone(), + tokens[1].clone(), + tokens[2].clone(), + tokens[3].clone(), + tokens[4].clone(), + ) { + if does_felt_overflow_from_slice(contract_address.as_slice()) { + return Err(InvalidOutputType( + "failed to convert contract_address bytes to field element (felt)" + .to_string(), + )); + } + + let contract_address_felt: Felt = + Felt::from_bytes_be_slice(&contract_address.as_slice()); + + return Ok(StarknetMessage { + source_chain, + message_id, + source_address, + contract_address: contract_address_felt, + payload_hash, + }); + } + } + + Err(InvalidOutputType( + "failed to convert tokens to StarknetMessage".to_string(), + )) + } + + fn into_token(self) -> Token { + let contract_address_bytes = self.contract_address.to_bytes_be().to_vec(); + + Token::Tuple(vec![ + Token::String(self.source_chain), + Token::String(self.message_id), + Token::String(self.source_address), + Token::FixedBytes(contract_address_bytes), + Token::Uint(self.payload_hash), + ]) + } +} + +#[cfg(test)] +mod tests { + use ethers_core::abi::{InvalidOutputType, Token, Tokenizable}; + use ethers_core::types::U256; + use starknet_core::types::Felt; + + use super::StarknetMessage; + + #[test] + fn starknet_message_from_token_should_error_on_non_tuple() { + // pas something else than a Token::Tuple + let starknet_msg_token = Token::String("not a starknet message".to_string()); + + let result = StarknetMessage::from_token(starknet_msg_token); + + // Tested like this, because InvalidOutputType doesn't implement PartialEq + assert!( + matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert tokens to StarknetMessage") + ); + } + + #[test] + fn starknet_message_from_token_should_error_on_failing_felt_conversion() { + // overflow the 31 byte size of a Felt + let starknet_msg_token = Token::Tuple(vec![ + Token::String("starknet".to_string()), + Token::String("some_msg_id".to_string()), + Token::String("some_source_address".to_string()), + Token::FixedBytes(vec![ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + ]), + Token::Uint(U256::from(123)), + ]); + + let result = StarknetMessage::from_token(starknet_msg_token); + + // Tested like this, because InvalidOutputType doesn't implement PartialEq + assert!( + matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert contract_address bytes to field element (felt)") + ); + } + + #[test] + fn starknet_message_from_token_should_error_on_failing_contract_address_conversion() { + // more than 32 bytes for contract address + let starknet_msg_token = Token::Tuple(vec![ + Token::String("starknet".to_string()), + Token::String("some_msg_id".to_string()), + Token::String("some_source_address".to_string()), + Token::FixedBytes(vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 2, 1, + ]), + Token::Uint(U256::from(123)), + ]); + + let result = StarknetMessage::from_token(starknet_msg_token); + + // Tested like this, because InvalidOutputType doesn't implement PartialEq + assert!( + matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert contract_address bytes to field element (felt)") + ); + } + + #[test] + fn starknet_message_from_token_should_error_on_less_tokens() { + // removed last token + let starknet_msg_token = Token::Tuple(vec![ + Token::String("starknet".to_string()), + Token::String("some_msg_id".to_string()), + Token::String("some_source_address".to_string()), + Token::FixedBytes(vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, + ]), + ]); + + let result = StarknetMessage::from_token(starknet_msg_token); + + // Tested like this, because InvalidOutputType doesn't implement PartialEq + assert!( + matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to read tokens: starknet message should have 5 tokens") + ); + } + + #[test] + fn starknet_message_from_token_should_be_converted_from_tokens_successfully() { + let starknet_msg_token = Token::Tuple(vec![ + Token::String("starknet".to_string()), + Token::String("some_msg_id".to_string()), + Token::String("some_source_address".to_string()), + Token::FixedBytes(vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, + ]), + Token::Uint(U256::from(123)), + ]); + + let expected = StarknetMessage { + source_chain: "starknet".to_string(), + message_id: "some_msg_id".to_string(), + source_address: "some_source_address".to_string(), + contract_address: Felt::THREE, + payload_hash: U256::from(123), + }; + + assert_eq!( + StarknetMessage::from_token(starknet_msg_token).unwrap(), + expected + ); + } + + #[test] + fn starknet_message_should_convert_to_token() { + let starknet_message = StarknetMessage { + source_chain: "starknet".to_string(), + message_id: "some_msg_id".to_string(), + source_address: "some_source_address".to_string(), + contract_address: Felt::THREE, + payload_hash: U256::from(123), + }; + + let expected = Token::Tuple(vec![ + Token::String("starknet".to_string()), + Token::String("some_msg_id".to_string()), + Token::String("some_source_address".to_string()), + Token::FixedBytes(vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, + ]), + Token::Uint(U256::from(123)), + ]); + + assert_eq!(starknet_message.into_token(), expected); + } +} From 25f5ed1e2ed071b869ebeb73a344546c20379218 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Mon, 16 Dec 2024 16:31:17 +0200 Subject: [PATCH 02/26] fixes and refactors --- ampd/src/handlers/starknet_verify_msg.rs | 67 ++++++++++--------- .../handlers/starknet_verify_verifier_set.rs | 9 +-- ampd/src/starknet/json_rpc.rs | 34 +++++----- ampd/src/starknet/verifier.rs | 6 +- .../src/events/signers_rotated.rs | 8 +-- .../src/types/starknet_message.rs | 5 +- 6 files changed, 64 insertions(+), 65 deletions(-) diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index eaa098a25..c6f43cac9 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -132,16 +132,16 @@ where .collect::>(); // key is the tx_hash of the tx holding the event - let events: HashMap = try_join_all( - unique_msgs - .iter() - .map(|msg| self.rpc_client.get_event_by_hash(msg.message_id.tx_hash)), - ) - .change_context(Error::TxReceipts) - .await? - .into_iter() - .flatten() - .collect(); + let events: HashMap = + try_join_all(unique_msgs.iter().map(|msg| { + self.rpc_client + .get_event_by_hash_contract_call(msg.message_id.tx_hash) + })) + .change_context(Error::TxReceipts) + .await? + .into_iter() + .flatten() + .collect(); let mut votes = vec![]; for msg in unique_msgs { @@ -191,24 +191,27 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); - rpc_client.expect_get_event_by_hash().returning(|_| { - Ok(Some(( - Felt::from_str( - "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", - ) - .unwrap(), - ContractCallEvent { - from_contract_addr: String::from("source-gw-addr"), - destination_address: String::from("destination-address"), - destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE, - payload_hash: H256::from_slice(&[ - 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, - 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, - ]), - }, - ))) - }); + rpc_client + .expect_get_event_by_hash_contract_call() + .returning(|_| { + Ok(Some(( + Felt::from_str( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", + ) + .unwrap(), + ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address"), + destination_chain: "ethereum".parse().unwrap(), + source_address: Felt::ONE, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, + 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, + 234, 200, + ]), + }, + ))) + }); let event: Event = get_event( get_poll_started_event_with_two_msgs(participants(5, Some(verifier.clone())), 100_u64), @@ -233,7 +236,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_event_by_hash() + .expect_get_event_by_hash_contract_call() .once() .with(eq(Felt::from_str( "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", @@ -284,7 +287,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); - rpc_client.expect_get_event_by_hash().times(0); + rpc_client.expect_get_event_by_hash_contract_call().times(0); let event: Event = get_event( get_poll_started_event_with_duplicate_msgs( @@ -310,7 +313,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); - rpc_client.expect_get_event_by_hash().times(0); + rpc_client.expect_get_event_by_hash_contract_call().times(0); let event: Event = get_event( // woker is not in participat set @@ -334,7 +337,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); - rpc_client.expect_get_event_by_hash().times(0); + rpc_client.expect_get_event_by_hash_contract_call().times(0); let event: Event = get_event( get_poll_started_event_with_duplicate_msgs( diff --git a/ampd/src/handlers/starknet_verify_verifier_set.rs b/ampd/src/handlers/starknet_verify_verifier_set.rs index 7623e8fc5..74cc9462f 100644 --- a/ampd/src/handlers/starknet_verify_verifier_set.rs +++ b/ampd/src/handlers/starknet_verify_verifier_set.rs @@ -5,7 +5,7 @@ use std::convert::TryInto; use async_trait::async_trait; -use axelar_wasm_std::msg_id::HexTxHashAndEventIndex; +use axelar_wasm_std::msg_id::FieldElementAndEventIndex; use axelar_wasm_std::voting::{PollId, Vote}; use cosmrs::cosmwasm::MsgExecuteContract; use cosmrs::tx::Msg; @@ -16,7 +16,6 @@ use events::Event; use events_derive::try_from; use multisig::verifier_set::VerifierSet; use serde::Deserialize; -use starknet_core::types::Felt; use tokio::sync::watch::Receiver; use tracing::{info, info_span}; use valuable::Valuable; @@ -30,7 +29,7 @@ use crate::types::TMAddress; #[derive(Deserialize, Debug)] pub struct VerifierSetConfirmation { - pub message_id: HexTxHashAndEventIndex, // FIXME: in the future replace by FieldElementAndEventIndex + pub message_id: FieldElementAndEventIndex, pub verifier_set: VerifierSet, } @@ -127,9 +126,7 @@ where let transaction_response = self .rpc_client - .get_event_by_hash_signers_rotated(Felt::from_bytes_be( - &verifier_set.message_id.tx_hash, - )) + .get_event_by_hash_signers_rotated(verifier_set.message_id.tx_hash) .await .unwrap(); diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index 2a728dcdd..79d4aba17 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -58,7 +58,10 @@ where pub trait StarknetClient { /// Attempts to fetch a ContractCall event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. - async fn get_event_by_hash(&self, tx_hash: Felt) -> Result>; + async fn get_event_by_hash_contract_call( + &self, + tx_hash: Felt, + ) -> Result>; /// Attempts to fetch a SignersRotated event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. @@ -73,13 +76,10 @@ impl StarknetClient for Client where T: JsonRpcTransport + Send + Sync + 'static, { - async fn get_event_by_hash(&self, tx_hash: Felt) -> Result> { - // TODO: Check ACCEPTED ON L1 times and decide if we should use it - // - // Finality status is always at least ACCEPTED_ON_L2 and this is what we're - // looking for, because ACCEPTED_ON_L1 (Ethereum) will take a very long time. - // - // Check https://github.com/eigerco/giza-axelar-starknet/issues/90 + async fn get_event_by_hash_contract_call( + &self, + tx_hash: Felt, + ) -> Result> { let receipt_with_block_info = self .client .get_transaction_receipt(tx_hash) @@ -201,7 +201,7 @@ mod test { #[tokio::test] async fn deploy_account_tx_fetch() { let mock_client = Client::new_with_transport(DeployAccountMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; assert!(contract_call_event.unwrap().is_none()); } @@ -209,7 +209,7 @@ mod test { #[tokio::test] async fn deploy_tx_fetch() { let mock_client = Client::new_with_transport(DeployMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; assert!(contract_call_event.unwrap().is_none()); } @@ -217,7 +217,7 @@ mod test { #[tokio::test] async fn l1_handler_tx_fetch() { let mock_client = Client::new_with_transport(L1HandlerMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; assert!(contract_call_event.unwrap().is_none()); } @@ -225,7 +225,7 @@ mod test { #[tokio::test] async fn declare_tx_fetch() { let mock_client = Client::new_with_transport(DeclareMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; assert!(contract_call_event.unwrap().is_none()); } @@ -234,7 +234,7 @@ mod test { async fn invalid_contract_call_event_tx_fetch() { let mock_client = Client::new_with_transport(InvalidContractCallEventMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; assert!(contract_call_event.unwrap().is_none()); } @@ -242,7 +242,7 @@ mod test { #[tokio::test] async fn no_events_tx_fetch() { let mock_client = Client::new_with_transport(NoEventsMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; assert!(contract_call_event.unwrap().is_none()); } @@ -250,7 +250,7 @@ mod test { #[tokio::test] async fn reverted_tx_fetch() { let mock_client = Client::new_with_transport(RevertedMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; assert!(contract_call_event .unwrap_err() @@ -260,7 +260,7 @@ mod test { #[tokio::test] async fn failing_tx_fetch() { let mock_client = Client::new_with_transport(FailingMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; assert!(contract_call_event.is_err()); } @@ -308,7 +308,7 @@ mod test { async fn successful_call_contract_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportCallContract).unwrap(); let contract_call_event = mock_client - .get_event_by_hash(Felt::ONE) + .get_event_by_hash_contract_call(Felt::ONE) .await .unwrap() // unwrap the result .unwrap(); // unwrap the option diff --git a/ampd/src/starknet/verifier.rs b/ampd/src/starknet/verifier.rs index 4460c4bdc..e6a25eef1 100644 --- a/ampd/src/starknet/verifier.rs +++ b/ampd/src/starknet/verifier.rs @@ -88,7 +88,7 @@ mod tests { use std::collections::BTreeMap; use std::str::FromStr; - use axelar_wasm_std::msg_id::{FieldElementAndEventIndex, HexTxHashAndEventIndex}; + use axelar_wasm_std::msg_id::FieldElementAndEventIndex; use axelar_wasm_std::voting::Vote; use cosmwasm_std::{Addr, HexBinary, Uint128}; use ethers_core::types::H256; @@ -233,8 +233,8 @@ mod tests { fn mock_valid_confirmation_signers_rotated() -> VerifierSetConfirmation { VerifierSetConfirmation { verifier_set: mock_valid_verifier_set_signers_rotated(), - message_id: HexTxHashAndEventIndex { - tx_hash: [0_u8; 32], + message_id: FieldElementAndEventIndex { + tx_hash: Felt::from_bytes_be(&[0_u8; 32]), event_index: 0, }, } diff --git a/packages/starknet-types/src/events/signers_rotated.rs b/packages/starknet-types/src/events/signers_rotated.rs index 194fc0969..8c1fbd3fa 100644 --- a/packages/starknet-types/src/events/signers_rotated.rs +++ b/packages/starknet-types/src/events/signers_rotated.rs @@ -281,7 +281,7 @@ mod tests { #[tokio::test] async fn test_try_from_event_happy_scenario() { - let (keys_data, event_data, sender_address, tx_hash) = get_valid_event().await; + let (keys_data, event_data, sender_address, _tx_hash) = get_valid_event().await; assert!(SignersRotatedEvent::try_from(Event { from_address: sender_address, @@ -293,7 +293,7 @@ mod tests { #[tokio::test] async fn test_try_from_empty_event() { - let (_, _, sender_address, tx_hash) = get_valid_event().await; + let (_, _, sender_address, _tx_hash) = get_valid_event().await; let result = SignersRotatedEvent::try_from(Event { data: vec![], from_address: sender_address, @@ -305,7 +305,7 @@ mod tests { #[tokio::test] async fn test_try_from_event_missing_data() { - let (keys_data, _, sender_address, tx_hash) = get_valid_event().await; + let (keys_data, _, sender_address, _tx_hash) = get_valid_event().await; let event = SignersRotatedEvent::try_from(Event { data: vec![], from_address: sender_address, @@ -321,7 +321,7 @@ mod tests { #[tokio::test] async fn test_try_from_event_missing_keys() { - let (_, event_data, sender_address, tx_hash) = get_valid_event().await; + let (_, event_data, sender_address, _tx_hash) = get_valid_event().await; let event = SignersRotatedEvent::try_from(Event { data: event_data, from_address: sender_address, diff --git a/packages/starknet-types/src/types/starknet_message.rs b/packages/starknet-types/src/types/starknet_message.rs index 34dacb137..08c0c8c8a 100644 --- a/packages/starknet-types/src/types/starknet_message.rs +++ b/packages/starknet-types/src/types/starknet_message.rs @@ -3,10 +3,9 @@ use std::str::FromStr; use axelar_wasm_std::utils::does_felt_overflow_from_slice; use error_stack::{Report, ResultExt}; use ethers_core::abi::{ - AbiDecode, AbiError, AbiType, Detokenize, FixedBytes, InvalidOutputType, ParamType, Token, - Tokenizable, + AbiDecode, AbiError, AbiType, Detokenize, InvalidOutputType, ParamType, Token, Tokenizable, }; -use ethers_core::types::{Address, Selector, U256}; +use ethers_core::types::U256; use router_api::Message as RouterMessage; use starknet_core::types::Felt; From 05791d17f12da187512d09c08e17e528e97fd8da Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Mon, 16 Dec 2024 17:26:22 +0200 Subject: [PATCH 03/26] remove event type check when parsing events --- packages/starknet-types/src/events.rs | 49 ------------- .../src/events/contract_call.rs | 70 +++++-------------- .../src/events/signers_rotated.rs | 5 ++ 3 files changed, 21 insertions(+), 103 deletions(-) diff --git a/packages/starknet-types/src/events.rs b/packages/starknet-types/src/events.rs index cd1c4fa77..dfe883063 100644 --- a/packages/starknet-types/src/events.rs +++ b/packages/starknet-types/src/events.rs @@ -1,51 +1,2 @@ -use std::sync::OnceLock; - -use starknet_core::types::Felt; -use starknet_core::utils::starknet_keccak; - pub mod contract_call; pub mod signers_rotated; -// Since a keccak hash over a string is a deterministic operation, -// we can use `OnceLock` to eliminate useless hash calculations. -static CALL_CONTRACT_FELT: OnceLock = OnceLock::new(); - -/// All Axelar event types supported by starknet -#[derive(Debug)] -pub enum EventType { - ContractCall, -} - -impl EventType { - fn parse(event_type_felt: Felt) -> Option { - let contract_call_type = - CALL_CONTRACT_FELT.get_or_init(|| starknet_keccak("ContractCall".as_bytes())); - - if event_type_felt == *contract_call_type { - Some(EventType::ContractCall) - } else { - None - } - } -} - -#[cfg(test)] -mod event_type_tests { - use starknet_core::utils::starknet_keccak; - - use super::EventType; - - #[test] - fn parse_contract_call() { - let contract_call_felt = starknet_keccak("ContractCall".as_bytes()); - assert!(matches!( - EventType::parse(contract_call_felt), - Some(EventType::ContractCall) - )); - } - - #[test] - fn parse_unknown_event() { - let contract_call_felt = starknet_keccak("UnknownEvent".as_bytes()); - assert!(EventType::parse(contract_call_felt).is_none()); - } -} diff --git a/packages/starknet-types/src/events/contract_call.rs b/packages/starknet-types/src/events/contract_call.rs index cb243a8a5..d87c45f8a 100644 --- a/packages/starknet-types/src/events/contract_call.rs +++ b/packages/starknet-types/src/events/contract_call.rs @@ -3,7 +3,6 @@ use starknet_core::types::Felt; use starknet_core::utils::{parse_cairo_short_string, ParseCairoShortStringError}; use thiserror::Error; -use crate::events::EventType; use crate::types::byte_array::{ByteArray, ByteArrayError}; /// This is the event emitted by the gateway cairo contract on Starknet, @@ -31,55 +30,40 @@ pub enum ContractCallError { OutOfBound, #[error("ByteArray type error: {0}")] ByteArray(#[from] ByteArrayError), + #[error("missing payload data for transaction")] + MissingPayloadData, + #[error("missing keys for transaction")] + MissingKeys, } impl TryFrom for ContractCallEvent { type Error = ContractCallError; - fn try_from(starknet_event: starknet_core::types::Event) -> Result { - if starknet_event.keys.len() != 2 { - return Err(ContractCallError::InvalidEvent( - "ContractCall should have exactly 2 event keys - event_type and destination_chain" - .to_owned(), - )); + fn try_from(event: starknet_core::types::Event) -> Result { + if event.data.is_empty() { + return Err(ContractCallError::MissingPayloadData); } - - // first key is always the event type - let event_type_felt = starknet_event.keys[0]; - if !matches!( - EventType::parse(event_type_felt), - Some(EventType::ContractCall) - ) { - return Err(ContractCallError::InvalidEvent( - "not a ContractCall event".to_owned(), - )); + if event.keys.is_empty() { + return Err(ContractCallError::MissingKeys); } // `event.from_address` is the contract address, which emitted the event - let from_contract_addr = format!( - "0x{}", - hex::encode(starknet_event.from_address.to_bytes_be()) - ); + let from_contract_addr = format!("0x{}", hex::encode(event.from_address.to_bytes_be())); // destination_chain is the second key in the event keys list (the first key // defined from the event) // // This field, should not exceed 252 bits (a felt's length) - let destination_chain = parse_cairo_short_string(&starknet_event.keys[1])?; + let destination_chain = parse_cairo_short_string(&event.keys[1])?; // source_address represents the original caller of the `call_contract` gateway // method. It is the first field in data, by the order defined in the // event. - // - // TODO: Not sure if `064x` is the correct formatting. Maybe we should calculate - // the pedersen hash of the felt as described here, to get the actual address, - // although I'm not sure that we can do it as described here: - // https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/contract-address/ - let source_address = starknet_event.data[0]; + let source_address = event.data[0]; // destination_contract_address (ByteArray) is composed of FieldElements // from the second element to elemet X. - let destination_address_chunks_count_felt = starknet_event.data[1]; + let destination_address_chunks_count_felt = event.data[1]; let da_chunks_count: usize = u8::try_from(destination_address_chunks_count_felt) .map_err(|err| ContractCallError::TryFromConversion(err.to_string()))? .into(); @@ -89,7 +73,7 @@ impl TryFrom for ContractCallEvent { let da_elements_start_index: usize = 1; let da_elements_end_index: usize = da_chunks_count.wrapping_add(3); let destination_address_byte_array: ByteArray = ByteArray::try_from( - starknet_event + event .data .get(da_elements_start_index..=da_elements_end_index) .ok_or(ContractCallError::OutOfBound)? @@ -103,14 +87,14 @@ impl TryFrom for ContractCallEvent { let ph_chunk1_index: usize = da_elements_end_index.wrapping_add(1); let ph_chunk2_index: usize = ph_chunk1_index.wrapping_add(1); let mut payload_hash = [0; 32]; - let lsb: [u8; 32] = starknet_event + let lsb: [u8; 32] = event .data .get(ph_chunk1_index) .ok_or(ContractCallError::InvalidEvent( "payload_hash chunk 1 out of range".to_owned(), ))? .to_bytes_be(); - let msb: [u8; 32] = starknet_event + let msb: [u8; 32] = event .data .get(ph_chunk2_index) .ok_or(ContractCallError::InvalidEvent( @@ -180,28 +164,6 @@ mod tests { assert!(matches!(event, ContractCallError::Cairo(_))); } - #[test] - fn more_than_2_keys() { - // the payload is the word "hello" - let mut starknet_event = get_dummy_event(); - starknet_event - .keys - .push(starknet_keccak("additional_element".as_bytes())); - - let event = ContractCallEvent::try_from(starknet_event).unwrap_err(); - assert!(matches!(event, ContractCallError::InvalidEvent(_))); - } - - #[test] - fn wrong_event_type() { - // the payload is the word "hello" - let mut starknet_event = get_dummy_event(); - starknet_event.keys[0] = starknet_keccak("NOTContractCall".as_bytes()); - - let event = ContractCallEvent::try_from(starknet_event).unwrap_err(); - assert!(matches!(event, ContractCallError::InvalidEvent(_))); - } - #[test] fn valid_call_contract_event() { // the payload is the word "hello" diff --git a/packages/starknet-types/src/events/signers_rotated.rs b/packages/starknet-types/src/events/signers_rotated.rs index 8c1fbd3fa..0c7d3ec78 100644 --- a/packages/starknet-types/src/events/signers_rotated.rs +++ b/packages/starknet-types/src/events/signers_rotated.rs @@ -23,6 +23,11 @@ pub enum SignersRotatedErrors { #[error("incorrect epoch for transaction")] IncorrectEpoch, + /// Error returned when the first key doesn't correspod to the + /// SignersRotated event. + #[error("not a SignersRotated event")] + InvalidEvent, + /// Error returned when the threshold in a transaction is invalid or /// unexpected. #[error("incorrect threshold for transaction")] From ec362e7743c118193d13723774f74b948ebd6c35 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Tue, 31 Dec 2024 11:48:11 +0200 Subject: [PATCH 04/26] add CheckedFelt type --- Cargo.toml | 1 + ampd/Cargo.toml | 1 + ampd/src/handlers/starknet_verify_msg.rs | 18 +++--- .../handlers/starknet_verify_verifier_set.rs | 2 +- ampd/src/starknet/json_rpc.rs | 58 ++++++++++--------- ampd/src/starknet/verifier.rs | 15 ++--- packages/starknet-types/Cargo.toml | 1 + .../src/types/starknet_message.rs | 28 ++++----- 8 files changed, 65 insertions(+), 59 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1066e5de2..b928073b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ stellar-xdr = { version = "21.2.0" } strum = { version = "0.25", default-features = false, features = ["derive"] } sui-gateway = { version = "^1.0.0", path = "packages/sui-gateway" } sui-types = { version = "^1.0.0", path = "packages/sui-types" } +starknet-checked-felt = { version = "^1.0.0", path = "packages/starknet-checked-felt" } starknet-types-core = { version = "0.1.7" } starknet-types = { version = "^1.0.0", path = "packages/starknet-types" } starknet-core = "0.12.0" diff --git a/ampd/Cargo.toml b/ampd/Cargo.toml index ff770aac6..590272513 100644 --- a/ampd/Cargo.toml +++ b/ampd/Cargo.toml @@ -89,6 +89,7 @@ voting-verifier = { workspace = true } starknet-core = { workspace = true } starknet-providers = { workspace = true } starknet-types = { workspace = true } +starknet-checked-felt = { workspace = true } [dev-dependencies] ed25519-dalek = { workspace = true, features = ["rand_core"] } diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index c6f43cac9..7c23118b7 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -14,7 +14,7 @@ use futures::future::try_join_all; use itertools::Itertools; use router_api::ChainName; use serde::Deserialize; -use starknet_core::types::Felt; +use starknet_checked_felt::CheckedFelt; use starknet_types::events::contract_call::ContractCallEvent; use tokio::sync::watch::Receiver; use tracing::info; @@ -34,7 +34,7 @@ pub struct Message { pub message_id: FieldElementAndEventIndex, pub destination_address: String, pub destination_chain: ChainName, - pub source_address: Felt, + pub source_address: CheckedFelt, pub payload_hash: Hash, } @@ -132,10 +132,10 @@ where .collect::>(); // key is the tx_hash of the tx holding the event - let events: HashMap = + let events: HashMap = try_join_all(unique_msgs.iter().map(|msg| { self.rpc_client - .get_event_by_hash_contract_call(msg.message_id.tx_hash) + .get_event_by_hash_contract_call(msg.message_id.tx_hash.clone()) })) .change_context(Error::TxReceipts) .await? @@ -195,7 +195,7 @@ mod tests { .expect_get_event_by_hash_contract_call() .returning(|_| { Ok(Some(( - Felt::from_str( + CheckedFelt::from_str( "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", ) .unwrap(), @@ -203,7 +203,7 @@ mod tests { from_contract_addr: String::from("source-gw-addr"), destination_address: String::from("destination-address"), destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE, + source_address: Felt::ONE.into(), payload_hash: H256::from_slice(&[ 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, @@ -238,13 +238,13 @@ mod tests { rpc_client .expect_get_event_by_hash_contract_call() .once() - .with(eq(Felt::from_str( + .with(eq(CheckedFelt::from_str( "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", ) .unwrap())) .returning(|_| { Ok(Some(( - Felt::from_str( + CheckedFelt::from_str( "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", ) .unwrap(), @@ -252,7 +252,7 @@ mod tests { from_contract_addr: String::from("source-gw-addr"), destination_address: String::from("destination-address"), destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE, + source_address: Felt::ONE.into(), payload_hash: H256::from_slice(&[ 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, diff --git a/ampd/src/handlers/starknet_verify_verifier_set.rs b/ampd/src/handlers/starknet_verify_verifier_set.rs index 74cc9462f..265b8a767 100644 --- a/ampd/src/handlers/starknet_verify_verifier_set.rs +++ b/ampd/src/handlers/starknet_verify_verifier_set.rs @@ -126,7 +126,7 @@ where let transaction_response = self .rpc_client - .get_event_by_hash_signers_rotated(verifier_set.message_id.tx_hash) + .get_event_by_hash_signers_rotated(verifier_set.message_id.tx_hash.clone()) .await .unwrap(); diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index 79d4aba17..31fe9dead 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -4,7 +4,8 @@ use async_trait::async_trait; use error_stack::Report; use mockall::automock; -use starknet_core::types::{ExecutionResult, Felt, FromStrError, TransactionReceipt}; +use starknet_core::types::{ExecutionResult, FromStrError, TransactionReceipt}; +use starknet_checked_felt::CheckedFelt; use starknet_providers::jsonrpc::JsonRpcTransport; use starknet_providers::{JsonRpcClient, Provider, ProviderError}; use starknet_types::events::contract_call::ContractCallEvent; @@ -60,15 +61,15 @@ pub trait StarknetClient { /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. async fn get_event_by_hash_contract_call( &self, - tx_hash: Felt, - ) -> Result>; + tx_hash: CheckedFelt, + ) -> Result>; /// Attempts to fetch a SignersRotated event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. async fn get_event_by_hash_signers_rotated( &self, - tx_hash: Felt, - ) -> Result>; + tx_hash: CheckedFelt, + ) -> Result>; } #[async_trait] @@ -78,8 +79,8 @@ where { async fn get_event_by_hash_contract_call( &self, - tx_hash: Felt, - ) -> Result> { + tx_hash: CheckedFelt, + ) -> Result> { let receipt_with_block_info = self .client .get_transaction_receipt(tx_hash) @@ -90,7 +91,7 @@ where return Err(Report::new(StarknetClientError::UnsuccessfulTx)); } - let event: Option<(Felt, ContractCallEvent)> = match receipt_with_block_info.receipt { + let event: Option<(CheckedFelt, ContractCallEvent)> = match receipt_with_block_info.receipt { TransactionReceipt::Invoke(tx) => { // NOTE: There should be only one ContractCall event per gateway tx tx.events @@ -99,7 +100,7 @@ where // NOTE: Here we ignore the error, because the event might // not be ContractCall and that by itself is not erroneous behavior if let Ok(cce) = ContractCallEvent::try_from(e.clone()) { - Some((tx.transaction_hash, cce)) + Some((tx.transaction_hash.into(), cce)) } else { None } @@ -134,8 +135,8 @@ where /// * The transaction execution was not successful async fn get_event_by_hash_signers_rotated( &self, - tx_hash: Felt, - ) -> Result> { + tx_hash: CheckedFelt, + ) -> Result> { let receipt_with_block_info = self .client .get_transaction_receipt(tx_hash) @@ -146,13 +147,13 @@ where return Err(Report::new(StarknetClientError::UnsuccessfulTx)); } - let event: Option<(Felt, SignersRotatedEvent)> = match receipt_with_block_info.receipt { + let event: Option<(CheckedFelt, SignersRotatedEvent)> = match receipt_with_block_info.receipt { TransactionReceipt::Invoke(tx) => tx .events .iter() .filter_map(|e| { if let Ok(sre) = SignersRotatedEvent::try_from(e.clone()) { - Some((tx.transaction_hash, sre)) + Some((tx.transaction_hash.into(), sre)) } else { None } @@ -178,6 +179,7 @@ mod test { use serde::de::DeserializeOwned; use serde::Serialize; use starknet_core::types::Felt; + use starknet_checked_felt::CheckedFelt; use starknet_providers::jsonrpc::{ HttpTransportError, JsonRpcMethod, JsonRpcResponse, JsonRpcTransport, }; @@ -192,7 +194,7 @@ mod test { let mock_client = Client::new_with_transport(InvalidSignersRotatedEventMockTransport).unwrap(); let contract_call_event = mock_client - .get_event_by_hash_signers_rotated(Felt::ONE) + .get_event_by_hash_signers_rotated(Felt::ONE.into()) .await; assert!(contract_call_event.unwrap().is_none()); @@ -201,7 +203,7 @@ mod test { #[tokio::test] async fn deploy_account_tx_fetch() { let mock_client = Client::new_with_transport(DeployAccountMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; assert!(contract_call_event.unwrap().is_none()); } @@ -209,7 +211,7 @@ mod test { #[tokio::test] async fn deploy_tx_fetch() { let mock_client = Client::new_with_transport(DeployMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; assert!(contract_call_event.unwrap().is_none()); } @@ -217,7 +219,7 @@ mod test { #[tokio::test] async fn l1_handler_tx_fetch() { let mock_client = Client::new_with_transport(L1HandlerMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; assert!(contract_call_event.unwrap().is_none()); } @@ -225,7 +227,7 @@ mod test { #[tokio::test] async fn declare_tx_fetch() { let mock_client = Client::new_with_transport(DeclareMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; assert!(contract_call_event.unwrap().is_none()); } @@ -234,7 +236,7 @@ mod test { async fn invalid_contract_call_event_tx_fetch() { let mock_client = Client::new_with_transport(InvalidContractCallEventMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; assert!(contract_call_event.unwrap().is_none()); } @@ -242,7 +244,7 @@ mod test { #[tokio::test] async fn no_events_tx_fetch() { let mock_client = Client::new_with_transport(NoEventsMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; assert!(contract_call_event.unwrap().is_none()); } @@ -250,7 +252,7 @@ mod test { #[tokio::test] async fn reverted_tx_fetch() { let mock_client = Client::new_with_transport(RevertedMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; assert!(contract_call_event .unwrap_err() @@ -260,7 +262,7 @@ mod test { #[tokio::test] async fn failing_tx_fetch() { let mock_client = Client::new_with_transport(FailingMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE).await; + let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; assert!(contract_call_event.is_err()); } @@ -268,15 +270,15 @@ mod test { #[tokio::test] async fn successful_signers_rotated_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportSignersRotated).unwrap(); - let signers_rotated_event: (Felt, SignersRotatedEvent) = mock_client - .get_event_by_hash_signers_rotated(Felt::ONE) + let signers_rotated_event: (CheckedFelt, SignersRotatedEvent) = mock_client + .get_event_by_hash_signers_rotated(Felt::ONE.into()) .await .unwrap() // unwrap the result .unwrap(); // unwrap the option assert_eq!( signers_rotated_event.0, - Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") + CheckedFelt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") .unwrap() ); @@ -308,14 +310,14 @@ mod test { async fn successful_call_contract_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportCallContract).unwrap(); let contract_call_event = mock_client - .get_event_by_hash_contract_call(Felt::ONE) + .get_event_by_hash_contract_call(Felt::ONE.into()) .await .unwrap() // unwrap the result .unwrap(); // unwrap the option assert_eq!( contract_call_event.0, - Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") + CheckedFelt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") .unwrap() ); assert_eq!( @@ -325,7 +327,7 @@ mod test { "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), destination_address: String::from("hello"), destination_chain: String::from("destination_chain"), - source_address: Felt::from_str( + source_address: CheckedFelt::from_str( "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca" ) .unwrap(), diff --git a/ampd/src/starknet/verifier.rs b/ampd/src/starknet/verifier.rs index e6a25eef1..6efad8a80 100644 --- a/ampd/src/starknet/verifier.rs +++ b/ampd/src/starknet/verifier.rs @@ -26,7 +26,7 @@ pub fn verify_msg( impl PartialEq for ContractCallEvent { fn eq(&self, axl_msg: &Message) -> bool { - axl_msg.source_address == self.source_address + axl_msg.source_address == self.source_address.into() && axl_msg.destination_chain == self.destination_chain && axl_msg.destination_address == self.destination_address && axl_msg.payload_hash == self.payload_hash @@ -96,6 +96,7 @@ mod tests { use multisig::verifier_set::VerifierSet; use router_api::ChainName; use starknet_core::types::Felt; + use starknet_checked_felt::CheckedFelt; use starknet_types::events::contract_call::ContractCallEvent; use starknet_types::events::signers_rotated::{ Signer as StarknetSigner, SignersRotatedEvent, WeightedSigners, @@ -117,7 +118,7 @@ mod tests { ), destination_address: String::from("destination_address"), destination_chain: String::from("ethereum"), - source_address: Felt::from_str( + source_address: CheckedFelt::from_str( "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca", ) .unwrap(), @@ -131,7 +132,7 @@ mod tests { fn mock_valid_message() -> Message { Message { message_id: FieldElementAndEventIndex { - tx_hash: Felt::from_str( + tx_hash: CheckedFelt::from_str( "0x0000000000000000000000000000000000000000000000000000000000000001", ) .unwrap(), @@ -139,7 +140,7 @@ mod tests { }, destination_address: String::from("destination_address"), destination_chain: ChainName::from_str("ethereum").unwrap(), - source_address: Felt::from_str( + source_address: CheckedFelt::from_str( "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca", ) .unwrap(), @@ -177,7 +178,7 @@ mod tests { assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); let mut event = { mock_valid_event() }; - event.source_address = Felt::THREE; + event.source_address = Felt::THREE.into(); assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); let mut event = { mock_valid_event() }; @@ -204,7 +205,7 @@ mod tests { assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); let mut msg = { mock_valid_message() }; - msg.source_address = Felt::THREE; + msg.source_address = Felt::THREE.into(); assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); let mut msg = { mock_valid_message() }; @@ -234,7 +235,7 @@ mod tests { VerifierSetConfirmation { verifier_set: mock_valid_verifier_set_signers_rotated(), message_id: FieldElementAndEventIndex { - tx_hash: Felt::from_bytes_be(&[0_u8; 32]), + tx_hash: CheckedFelt::try_from(&[0_u8; 32]).unwrap(), event_index: 0, }, } diff --git a/packages/starknet-types/Cargo.toml b/packages/starknet-types/Cargo.toml index 839eeac05..da75861c8 100644 --- a/packages/starknet-types/Cargo.toml +++ b/packages/starknet-types/Cargo.toml @@ -9,6 +9,7 @@ axelar-wasm-std = { workspace = true, features = ["derive"] } cosmwasm-std = { workspace = true } router-api = { workspace = true } ethers-core = { workspace = true } +starknet-checked-felt = { workspace = true } starknet-core = { workspace = true } starknet-types-core = { workspace = true } error-stack = { workspace = true } diff --git a/packages/starknet-types/src/types/starknet_message.rs b/packages/starknet-types/src/types/starknet_message.rs index 08c0c8c8a..caa80d7d4 100644 --- a/packages/starknet-types/src/types/starknet_message.rs +++ b/packages/starknet-types/src/types/starknet_message.rs @@ -1,13 +1,12 @@ use std::str::FromStr; -use axelar_wasm_std::utils::does_felt_overflow_from_slice; use error_stack::{Report, ResultExt}; use ethers_core::abi::{ AbiDecode, AbiError, AbiType, Detokenize, InvalidOutputType, ParamType, Token, Tokenizable, }; use ethers_core::types::U256; use router_api::Message as RouterMessage; -use starknet_core::types::Felt; +use starknet_checked_felt::CheckedFelt; use crate::error::Error; @@ -17,7 +16,7 @@ pub struct StarknetMessage { pub source_chain: String, pub message_id: String, pub source_address: String, - pub contract_address: Felt, + pub contract_address: CheckedFelt, pub payload_hash: U256, } @@ -25,7 +24,7 @@ impl TryFrom<&RouterMessage> for StarknetMessage { type Error = Report; fn try_from(msg: &RouterMessage) -> Result { - let contract_address = Felt::from_str(msg.destination_address.as_str()) + let contract_address = CheckedFelt::from_str(msg.destination_address.as_str()) .change_context(Error::InvalidAddress)?; Ok(StarknetMessage { @@ -82,15 +81,16 @@ impl Tokenizable for StarknetMessage { tokens[3].clone(), tokens[4].clone(), ) { - if does_felt_overflow_from_slice(contract_address.as_slice()) { - return Err(InvalidOutputType( - "failed to convert contract_address bytes to field element (felt)" + let contract_address_felt: CheckedFelt = + CheckedFelt::try_from(contract_address.as_slice()).map_err(|e| { + InvalidOutputType( + format!( + "failed to convert contract_address bytes to field element (felt): {}", + e + ) .to_string(), - )); - } - - let contract_address_felt: Felt = - Felt::from_bytes_be_slice(&contract_address.as_slice()); + ) + })?; return Ok(StarknetMessage { source_chain, @@ -223,7 +223,7 @@ mod tests { source_chain: "starknet".to_string(), message_id: "some_msg_id".to_string(), source_address: "some_source_address".to_string(), - contract_address: Felt::THREE, + contract_address: Felt::THREE.into(), payload_hash: U256::from(123), }; @@ -239,7 +239,7 @@ mod tests { source_chain: "starknet".to_string(), message_id: "some_msg_id".to_string(), source_address: "some_source_address".to_string(), - contract_address: Felt::THREE, + contract_address: Felt::THREE.into(), payload_hash: U256::from(123), }; From 35712fef81cbc95fa844ad5dbfb5221bb10377f2 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Thu, 9 Jan 2025 18:10:10 +0200 Subject: [PATCH 05/26] fixes after merge --- ampd/src/handlers/starknet_verify_msg.rs | 8 +- ampd/src/starknet/json_rpc.rs | 88 +++++++++++++------ ampd/src/starknet/verifier.rs | 9 +- packages/starknet-types/Cargo.toml | 2 +- .../src/events/signers_rotated.rs | 24 ++--- .../src/types/starknet_message.rs | 11 ++- 6 files changed, 93 insertions(+), 49 deletions(-) diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index 7c23118b7..2c451ee22 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -15,6 +15,7 @@ use itertools::Itertools; use router_api::ChainName; use serde::Deserialize; use starknet_checked_felt::CheckedFelt; +use starknet_core::types::Felt; use starknet_types::events::contract_call::ContractCallEvent; use tokio::sync::watch::Receiver; use tracing::info; @@ -132,7 +133,7 @@ where .collect::>(); // key is the tx_hash of the tx holding the event - let events: HashMap = + let events: HashMap = try_join_all(unique_msgs.iter().map(|msg| { self.rpc_client .get_event_by_hash_contract_call(msg.message_id.tx_hash.clone()) @@ -172,6 +173,7 @@ mod tests { use ethers_core::types::H256; use events::Event; use mockall::predicate::eq; + use starknet_core::types::Felt; use tendermint::abci; use tokio::sync::watch; use tokio::test as async_test; @@ -195,7 +197,7 @@ mod tests { .expect_get_event_by_hash_contract_call() .returning(|_| { Ok(Some(( - CheckedFelt::from_str( + Felt::from_str( "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", ) .unwrap(), @@ -244,7 +246,7 @@ mod tests { .unwrap())) .returning(|_| { Ok(Some(( - CheckedFelt::from_str( + Felt::from_str( "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", ) .unwrap(), diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index 31fe9dead..548b6a7c4 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -4,8 +4,8 @@ use async_trait::async_trait; use error_stack::Report; use mockall::automock; -use starknet_core::types::{ExecutionResult, FromStrError, TransactionReceipt}; use starknet_checked_felt::CheckedFelt; +use starknet_core::types::{ExecutionResult, Felt, FromStrError, TransactionReceipt}; use starknet_providers::jsonrpc::JsonRpcTransport; use starknet_providers::{JsonRpcClient, Provider, ProviderError}; use starknet_types::events::contract_call::ContractCallEvent; @@ -62,14 +62,14 @@ pub trait StarknetClient { async fn get_event_by_hash_contract_call( &self, tx_hash: CheckedFelt, - ) -> Result>; + ) -> Result>; /// Attempts to fetch a SignersRotated event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. async fn get_event_by_hash_signers_rotated( &self, tx_hash: CheckedFelt, - ) -> Result>; + ) -> Result>; } #[async_trait] @@ -80,7 +80,7 @@ where async fn get_event_by_hash_contract_call( &self, tx_hash: CheckedFelt, - ) -> Result> { + ) -> Result> { let receipt_with_block_info = self .client .get_transaction_receipt(tx_hash) @@ -91,7 +91,7 @@ where return Err(Report::new(StarknetClientError::UnsuccessfulTx)); } - let event: Option<(CheckedFelt, ContractCallEvent)> = match receipt_with_block_info.receipt { + let event: Option<(Felt, ContractCallEvent)> = match receipt_with_block_info.receipt { TransactionReceipt::Invoke(tx) => { // NOTE: There should be only one ContractCall event per gateway tx tx.events @@ -100,7 +100,7 @@ where // NOTE: Here we ignore the error, because the event might // not be ContractCall and that by itself is not erroneous behavior if let Ok(cce) = ContractCallEvent::try_from(e.clone()) { - Some((tx.transaction_hash.into(), cce)) + Some((tx.transaction_hash, cce)) } else { None } @@ -136,7 +136,7 @@ where async fn get_event_by_hash_signers_rotated( &self, tx_hash: CheckedFelt, - ) -> Result> { + ) -> Result> { let receipt_with_block_info = self .client .get_transaction_receipt(tx_hash) @@ -147,13 +147,13 @@ where return Err(Report::new(StarknetClientError::UnsuccessfulTx)); } - let event: Option<(CheckedFelt, SignersRotatedEvent)> = match receipt_with_block_info.receipt { + let event: Option<(Felt, SignersRotatedEvent)> = match receipt_with_block_info.receipt { TransactionReceipt::Invoke(tx) => tx .events .iter() .filter_map(|e| { if let Ok(sre) = SignersRotatedEvent::try_from(e.clone()) { - Some((tx.transaction_hash.into(), sre)) + Some((tx.transaction_hash, sre)) } else { None } @@ -178,8 +178,8 @@ mod test { use ethers_core::types::H256; use serde::de::DeserializeOwned; use serde::Serialize; - use starknet_core::types::Felt; use starknet_checked_felt::CheckedFelt; + use starknet_core::types::Felt; use starknet_providers::jsonrpc::{ HttpTransportError, JsonRpcMethod, JsonRpcResponse, JsonRpcTransport, }; @@ -194,7 +194,9 @@ mod test { let mock_client = Client::new_with_transport(InvalidSignersRotatedEventMockTransport).unwrap(); let contract_call_event = mock_client - .get_event_by_hash_signers_rotated(Felt::ONE.into()) + .get_event_by_hash_signers_rotated( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) .await; assert!(contract_call_event.unwrap().is_none()); @@ -203,7 +205,11 @@ mod test { #[tokio::test] async fn deploy_account_tx_fetch() { let mock_client = Client::new_with_transport(DeployAccountMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; + let contract_call_event = mock_client + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await; assert!(contract_call_event.unwrap().is_none()); } @@ -211,7 +217,11 @@ mod test { #[tokio::test] async fn deploy_tx_fetch() { let mock_client = Client::new_with_transport(DeployMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; + let contract_call_event = mock_client + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await; assert!(contract_call_event.unwrap().is_none()); } @@ -219,7 +229,11 @@ mod test { #[tokio::test] async fn l1_handler_tx_fetch() { let mock_client = Client::new_with_transport(L1HandlerMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; + let contract_call_event = mock_client + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await; assert!(contract_call_event.unwrap().is_none()); } @@ -227,7 +241,11 @@ mod test { #[tokio::test] async fn declare_tx_fetch() { let mock_client = Client::new_with_transport(DeclareMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; + let contract_call_event = mock_client + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await; assert!(contract_call_event.unwrap().is_none()); } @@ -236,7 +254,11 @@ mod test { async fn invalid_contract_call_event_tx_fetch() { let mock_client = Client::new_with_transport(InvalidContractCallEventMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; + let contract_call_event = mock_client + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await; assert!(contract_call_event.unwrap().is_none()); } @@ -244,7 +266,11 @@ mod test { #[tokio::test] async fn no_events_tx_fetch() { let mock_client = Client::new_with_transport(NoEventsMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; + let contract_call_event = mock_client + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await; assert!(contract_call_event.unwrap().is_none()); } @@ -252,7 +278,11 @@ mod test { #[tokio::test] async fn reverted_tx_fetch() { let mock_client = Client::new_with_transport(RevertedMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; + let contract_call_event = mock_client + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await; assert!(contract_call_event .unwrap_err() @@ -262,7 +292,11 @@ mod test { #[tokio::test] async fn failing_tx_fetch() { let mock_client = Client::new_with_transport(FailingMockTransport).unwrap(); - let contract_call_event = mock_client.get_event_by_hash_contract_call(Felt::ONE.into()).await; + let contract_call_event = mock_client + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await; assert!(contract_call_event.is_err()); } @@ -270,15 +304,17 @@ mod test { #[tokio::test] async fn successful_signers_rotated_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportSignersRotated).unwrap(); - let signers_rotated_event: (CheckedFelt, SignersRotatedEvent) = mock_client - .get_event_by_hash_signers_rotated(Felt::ONE.into()) + let signers_rotated_event: (Felt, SignersRotatedEvent) = mock_client + .get_event_by_hash_signers_rotated( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) .await .unwrap() // unwrap the result .unwrap(); // unwrap the option assert_eq!( signers_rotated_event.0, - CheckedFelt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") + Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") .unwrap() ); @@ -310,14 +346,16 @@ mod test { async fn successful_call_contract_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportCallContract).unwrap(); let contract_call_event = mock_client - .get_event_by_hash_contract_call(Felt::ONE.into()) + .get_event_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) .await .unwrap() // unwrap the result .unwrap(); // unwrap the option assert_eq!( contract_call_event.0, - CheckedFelt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") + Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") .unwrap() ); assert_eq!( @@ -327,7 +365,7 @@ mod test { "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), destination_address: String::from("hello"), destination_chain: String::from("destination_chain"), - source_address: CheckedFelt::from_str( + source_address: Felt::from_str( "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca" ) .unwrap(), diff --git a/ampd/src/starknet/verifier.rs b/ampd/src/starknet/verifier.rs index 6efad8a80..e122ddca6 100644 --- a/ampd/src/starknet/verifier.rs +++ b/ampd/src/starknet/verifier.rs @@ -1,5 +1,6 @@ use axelar_wasm_std::voting::Vote; use cosmwasm_std::HexBinary; +use starknet_core::types::Felt; use starknet_types::events::contract_call::ContractCallEvent; use starknet_types::events::signers_rotated::SignersRotatedEvent; @@ -26,7 +27,7 @@ pub fn verify_msg( impl PartialEq for ContractCallEvent { fn eq(&self, axl_msg: &Message) -> bool { - axl_msg.source_address == self.source_address.into() + Felt::from(axl_msg.source_address.clone()) == self.source_address && axl_msg.destination_chain == self.destination_chain && axl_msg.destination_address == self.destination_address && axl_msg.payload_hash == self.payload_hash @@ -95,8 +96,8 @@ mod tests { use multisig::msg::Signer; use multisig::verifier_set::VerifierSet; use router_api::ChainName; - use starknet_core::types::Felt; use starknet_checked_felt::CheckedFelt; + use starknet_core::types::Felt; use starknet_types::events::contract_call::ContractCallEvent; use starknet_types::events::signers_rotated::{ Signer as StarknetSigner, SignersRotatedEvent, WeightedSigners, @@ -118,7 +119,7 @@ mod tests { ), destination_address: String::from("destination_address"), destination_chain: String::from("ethereum"), - source_address: CheckedFelt::from_str( + source_address: Felt::from_str( "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca", ) .unwrap(), @@ -205,7 +206,7 @@ mod tests { assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); let mut msg = { mock_valid_message() }; - msg.source_address = Felt::THREE.into(); + msg.source_address = CheckedFelt::try_from(&Felt::THREE.to_bytes_be()).unwrap(); assert_eq!(verify_msg(&event, &msg, &source_gw_address), Vote::NotFound); let mut msg = { mock_valid_message() }; diff --git a/packages/starknet-types/Cargo.toml b/packages/starknet-types/Cargo.toml index da75861c8..f6bcf72f0 100644 --- a/packages/starknet-types/Cargo.toml +++ b/packages/starknet-types/Cargo.toml @@ -23,7 +23,7 @@ tokio = { version = "1", features = [ "macros", ] } rand = { workspace = true } -futures = { workspace = true } +# futures = { workspace = true } [lints] workspace = true diff --git a/packages/starknet-types/src/events/signers_rotated.rs b/packages/starknet-types/src/events/signers_rotated.rs index 0c7d3ec78..f022c14c3 100644 --- a/packages/starknet-types/src/events/signers_rotated.rs +++ b/packages/starknet-types/src/events/signers_rotated.rs @@ -213,7 +213,7 @@ impl TryFrom for SignersRotatedEvent { #[cfg(test)] mod tests { - use futures::stream::{FuturesUnordered, StreamExt}; + // use futures::stream::{FuturesUnordered, StreamExt}; use starknet_core::types::{EmittedEvent, Felt}; use super::*; @@ -339,10 +339,10 @@ mod tests { #[tokio::test] async fn test_try_from_event_randomly_malformed_data_x1000() { - let mut futures = FuturesUnordered::new(); + // let mut futures = FuturesUnordered::new(); for _ in 0..1000 { - futures.push(async { + // futures.push(async { let (_, event_data, sender_address, tx_hash) = get_malformed_event().await; let event = EmittedEvent { data: event_data, @@ -352,20 +352,20 @@ mod tests { block_hash: None, block_number: None, }; - SignersRotatedEvent::try_from(Event { + let result = SignersRotatedEvent::try_from(Event { data: event.data, from_address: event.from_address, keys: event.keys, - }) - .is_err() - }); + }); + assert!(result.is_err()); + // }); } // if any conversion succeeded then it should have failed - while let Some(result) = futures.next().await { - if !result { - panic!("expected conversion to fail for malformed event"); - } - } + // while let Some(result) = futures.next().await { + // if !result { + // panic!("expected conversion to fail for malformed event"); + // } + // } } } diff --git a/packages/starknet-types/src/types/starknet_message.rs b/packages/starknet-types/src/types/starknet_message.rs index caa80d7d4..33ada5400 100644 --- a/packages/starknet-types/src/types/starknet_message.rs +++ b/packages/starknet-types/src/types/starknet_message.rs @@ -122,8 +122,11 @@ impl Tokenizable for StarknetMessage { #[cfg(test)] mod tests { + use std::str::FromStr; + use ethers_core::abi::{InvalidOutputType, Token, Tokenizable}; use ethers_core::types::U256; + use starknet_checked_felt::CheckedFelt; use starknet_core::types::Felt; use super::StarknetMessage; @@ -159,7 +162,7 @@ mod tests { // Tested like this, because InvalidOutputType doesn't implement PartialEq assert!( - matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert contract_address bytes to field element (felt)") + matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert contract_address bytes to field element (felt): Felt value overflowing the Felt::MAX, value") ); } @@ -181,7 +184,7 @@ mod tests { // Tested like this, because InvalidOutputType doesn't implement PartialEq assert!( - matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert contract_address bytes to field element (felt)") + matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert contract_address bytes to field element (felt): Felt value overflowing the Felt::MAX, value") ); } @@ -223,7 +226,7 @@ mod tests { source_chain: "starknet".to_string(), message_id: "some_msg_id".to_string(), source_address: "some_source_address".to_string(), - contract_address: Felt::THREE.into(), + contract_address: CheckedFelt::from_str(&Felt::THREE.to_fixed_hex_string()).unwrap(), payload_hash: U256::from(123), }; @@ -239,7 +242,7 @@ mod tests { source_chain: "starknet".to_string(), message_id: "some_msg_id".to_string(), source_address: "some_source_address".to_string(), - contract_address: Felt::THREE.into(), + contract_address: CheckedFelt::from_str(&Felt::THREE.to_fixed_hex_string()).unwrap(), payload_hash: U256::from(123), }; From 451f6258841d192ecb4a10bb31058254501c4220 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 10 Jan 2025 14:59:23 +0200 Subject: [PATCH 06/26] README changes for starknet --- ampd/README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ampd/README.md b/ampd/README.md index 997fbb10c..37b8d7d15 100644 --- a/ampd/README.md +++ b/ampd/README.md @@ -44,14 +44,14 @@ type="MultisigSigner" chain_name=[chain name. Not necessary in the Sui case] chain_rpc_url=[URL of JSON-RPC endpoint for external chain] cosmwasm_contract=[verifier contract address] -type=[handler type. Could be EvmMsgVerifier | SuiMsgVerifier] +type=[handler type. Could be EvmMsgVerifier | SuiMsgVerifier | StarknetMsgVerifier] # handler to verify verifier set rotations. One per supported chain [[handlers]] chain_name=[chain name. Not necessary in the Sui case] chain_rpc_url=[URL of JSON-RPC endpoint for external chain] cosmwasm_contract=[verifier contract address] -type=[handler type. Could be EvmVerifierSetVerifier | SuiVerifierSetVerifier] +type=[handler type. Could be EvmVerifierSetVerifier | SuiVerifierSetVerifier | StarknetVerifierSetVerifier] ``` Below is an example config for connecting to a local axelard node and local tofnd process, and verifying transactions @@ -101,13 +101,17 @@ cosmwasm_contract = 'axelar14lh98gp06zdqh5r9qj3874hdmfzs4sh5tkfzg3cyty4xeqsufdjq chain_name = 'avalanche' chain_rpc_url = "https://api.avax-test.network/ext/bc/C/rpc" +[[handlers]] +type = 'StarknetMsgVerifier' +cosmwasm_contract = 'axelar1f7qqgp0zk8489s69xxszut07kxse7y5j6j5tune36x75dc9ftfsssdkf2u' +chain = 'starknet-devnet-v1' +rpc_url = "https://starknet-sepolia.public.blastapi.io/rpc/v0_7" [[handlers]] type = 'EvmVerifierSetVerifier' cosmwasm_contract = 'axelar14lh98gp06zdqh5r9qj3874hdmfzs4sh5tkfzg3cyty4xeqsufdjqedt3q8' chain_name = 'avalanche' chain_rpc_url = "https://api.avax-test.network/ext/bc/C/rpc" - ``` By default, ampd loads the config file from `~/.ampd/config.toml` when running any command. From 28d0adddff72001294737e2233c9095309b332dc Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 10 Jan 2025 15:09:33 +0200 Subject: [PATCH 07/26] remove crypto bigint --- packages/axelar-wasm-std/Cargo.toml | 1 - packages/axelar-wasm-std/src/utils.rs | 19 ------------------- 2 files changed, 20 deletions(-) diff --git a/packages/axelar-wasm-std/Cargo.toml b/packages/axelar-wasm-std/Cargo.toml index 4a5e5f605..9cfe62182 100644 --- a/packages/axelar-wasm-std/Cargo.toml +++ b/packages/axelar-wasm-std/Cargo.toml @@ -54,7 +54,6 @@ strum = { workspace = true } sui-types = { workspace = true } thiserror = { workspace = true } valuable = { version = "0.1.0", features = ["derive"] } -crypto-bigint = { version = "0.5.5", features = ["rand_core"] } [dev-dependencies] assert_ok = { workspace = true } diff --git a/packages/axelar-wasm-std/src/utils.rs b/packages/axelar-wasm-std/src/utils.rs index 292deb920..e45c0695a 100644 --- a/packages/axelar-wasm-std/src/utils.rs +++ b/packages/axelar-wasm-std/src/utils.rs @@ -1,6 +1,3 @@ -use crypto_bigint::U256; -use starknet_types_core::felt::Felt; - pub trait TryMapExt { type Monad; fn try_map(self, func: impl FnMut(T) -> Result) -> Result, E>; @@ -22,22 +19,6 @@ impl TryMapExt for Vec { } } -/// since the `Felt` type doesn't error on overflow, we have to implement that check -pub fn does_felt_overflow_from_slice(felt_hex_slice: &[u8]) -> bool { - if felt_hex_slice.len() > 32 { - return true; - } - let felt_max_hex_str = format!("{:064x}", Felt::MAX); - U256::from_be_slice(felt_hex_slice) > U256::from_be_hex(&felt_max_hex_str) -} - -/// since the `Felt` type doesn't error on overflow, we have to implement that check -pub fn does_felt_overflow_from_str(felt_hex_str: &str) -> bool { - let felt_hex_str = felt_hex_str.trim_start_matches("0x"); - let felt_max_hex_str = format!("{:064x}", Felt::MAX); - U256::from_be_hex(felt_hex_str) > U256::from_be_hex(&felt_max_hex_str) -} - #[cfg(test)] mod test { use super::*; From 686ec98eb7818f122fbd0fbf509d5e2480378a0c Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 10 Jan 2025 15:10:00 +0200 Subject: [PATCH 08/26] add verifier set missing boilerplate --- ampd/src/config.rs | 13 +++++++++++++ ampd/src/handlers/config.rs | 4 ++++ ampd/src/lib.rs | 16 ++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/ampd/src/config.rs b/ampd/src/config.rs index eaab6ff91..7abbeefa3 100644 --- a/ampd/src/config.rs +++ b/ampd/src/config.rs @@ -132,6 +132,17 @@ mod tests { type = 'StellarVerifierSetVerifier' cosmwasm_contract = '{}' rpc_url = 'http://localhost:7545' + + [[handlers]] + type = 'StarknetMsgVerifier' + cosmwasm_contract = '{}' + rpc_url = 'http://localhost:7545' + + [[handlers]] + type = 'StarknetVerifierSetVerifier' + cosmwasm_contract = '{}' + rpc_url = 'http://localhost:7545' + ", TMAddress::random(PREFIX), TMAddress::random(PREFIX), @@ -143,6 +154,8 @@ mod tests { TMAddress::random(PREFIX), TMAddress::random(PREFIX), TMAddress::random(PREFIX), + TMAddress::random(PREFIX), + TMAddress::random(PREFIX), ); let cfg: Config = toml::from_str(config_str.as_str()).unwrap(); diff --git a/ampd/src/handlers/config.rs b/ampd/src/handlers/config.rs index 36018ac9a..80cc94cea 100644 --- a/ampd/src/handlers/config.rs +++ b/ampd/src/handlers/config.rs @@ -67,6 +67,10 @@ pub enum Config { cosmwasm_contract: TMAddress, rpc_url: Url, }, + StarknetVerifierSetVerifier { + cosmwasm_contract: TMAddress, + rpc_url: Url, + }, } fn validate_starknet_msg_verifier_config<'de, D>(configs: &[Config]) -> Result<(), D::Error> diff --git a/ampd/src/lib.rs b/ampd/src/lib.rs index 381f7b0a5..1fe5bba53 100644 --- a/ampd/src/lib.rs +++ b/ampd/src/lib.rs @@ -407,6 +407,22 @@ where ), event_processor_config.clone(), ), + handlers::config::Config::StarknetVerifierSetVerifier { + cosmwasm_contract, + rpc_url, + } => self.create_handler_task( + "starknet-verifier-set-verifier", + handlers::starknet_verify_verifier_set::Handler::new( + verifier.clone(), + cosmwasm_contract, + starknet::json_rpc::Client::new_with_transport(HttpTransport::new( + &rpc_url, + )) + .unwrap(), + self.block_height_monitor.latest_block_height(), + ), + event_processor_config.clone(), + ), }; self.event_processor = self.event_processor.add_task(task); } From c7515a78f72fd70344be7b9deff7f767dec87dba Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 10 Jan 2025 15:17:27 +0200 Subject: [PATCH 09/26] add to config_template.toml --- ampd/src/tests/config_template.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ampd/src/tests/config_template.toml b/ampd/src/tests/config_template.toml index ec99f3de7..ecce674c8 100644 --- a/ampd/src/tests/config_template.toml +++ b/ampd/src/tests/config_template.toml @@ -82,6 +82,16 @@ type = 'StellarVerifierSetVerifier' cosmwasm_contract = 'axelar1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqecnww6' rpc_url = 'http://127.0.0.1/' +[[handlers]] +type = 'StarknetMsgVerifier' +cosmwasm_contract = 'axelar1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqecnww6' +rpc_url = 'http://127.0.0.1/' + +[[handlers]] +type = 'StarknetVerifierSetVerifier' +cosmwasm_contract = 'axelar1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqecnww6' +rpc_url = 'http://127.0.0.1/' + [tofnd_config] url = 'http://localhost:50051/' party_uid = 'ampd' From 55b49c0e79334547440cfc5bc0ac51f87b193733 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 10 Jan 2025 15:35:21 +0200 Subject: [PATCH 10/26] remove dead code allowance; remove futures dependency --- .../handlers/starknet_verify_verifier_set.rs | 1 - packages/starknet-types/Cargo.toml | 1 - .../src/events/signers_rotated.rs | 51 ++++++++----------- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/ampd/src/handlers/starknet_verify_verifier_set.rs b/ampd/src/handlers/starknet_verify_verifier_set.rs index 265b8a767..fe24baf2e 100644 --- a/ampd/src/handlers/starknet_verify_verifier_set.rs +++ b/ampd/src/handlers/starknet_verify_verifier_set.rs @@ -61,7 +61,6 @@ where /// /// # Type Parameters /// * `C` - A Starknet client type that implements the [`StarknetClient`] trait - #[allow(dead_code)] pub fn new( verifier: TMAddress, voting_verifier_contract: TMAddress, diff --git a/packages/starknet-types/Cargo.toml b/packages/starknet-types/Cargo.toml index f6bcf72f0..37e1a9b38 100644 --- a/packages/starknet-types/Cargo.toml +++ b/packages/starknet-types/Cargo.toml @@ -23,7 +23,6 @@ tokio = { version = "1", features = [ "macros", ] } rand = { workspace = true } -# futures = { workspace = true } [lints] workspace = true diff --git a/packages/starknet-types/src/events/signers_rotated.rs b/packages/starknet-types/src/events/signers_rotated.rs index f022c14c3..2968e341a 100644 --- a/packages/starknet-types/src/events/signers_rotated.rs +++ b/packages/starknet-types/src/events/signers_rotated.rs @@ -213,7 +213,6 @@ impl TryFrom for SignersRotatedEvent { #[cfg(test)] mod tests { - // use futures::stream::{FuturesUnordered, StreamExt}; use starknet_core::types::{EmittedEvent, Felt}; use super::*; @@ -259,11 +258,15 @@ mod tests { // Randomly remove an element from either vector match rand::random::() { true if !keys_data.is_empty() => { - let random_index = rand::random::() % keys_data.len(); + let random_index = rand::random::() + .checked_rem(keys_data.len()) + .unwrap(); keys_data.remove(random_index); } false if !event_data.is_empty() => { - let random_index = rand::random::() % event_data.len(); + let random_index = rand::random::() + .checked_rem(event_data.len()) + .unwrap(); event_data.remove(random_index); } _ => {} @@ -339,33 +342,23 @@ mod tests { #[tokio::test] async fn test_try_from_event_randomly_malformed_data_x1000() { - // let mut futures = FuturesUnordered::new(); - for _ in 0..1000 { - // futures.push(async { - let (_, event_data, sender_address, tx_hash) = get_malformed_event().await; - let event = EmittedEvent { - data: event_data, - from_address: sender_address, - keys: vec![], - transaction_hash: tx_hash, - block_hash: None, - block_number: None, - }; - let result = SignersRotatedEvent::try_from(Event { - data: event.data, - from_address: event.from_address, - keys: event.keys, - }); - assert!(result.is_err()); - // }); + let (_, event_data, sender_address, tx_hash) = get_malformed_event().await; + let event = EmittedEvent { + data: event_data, + from_address: sender_address, + keys: vec![], + transaction_hash: tx_hash, + block_hash: None, + block_number: None, + }; + let result = SignersRotatedEvent::try_from(Event { + data: event.data, + from_address: event.from_address, + keys: event.keys, + }); + + assert!(result.is_err()); } - - // if any conversion succeeded then it should have failed - // while let Some(result) = futures.next().await { - // if !result { - // panic!("expected conversion to fail for malformed event"); - // } - // } } } From 2807dd0388824f1bf2c12da881bc6e0b236bfd07 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 10 Jan 2025 18:28:09 +0200 Subject: [PATCH 11/26] add verifier set tests; various fixes and refactors --- ampd/src/config.rs | 14 +- ampd/src/handlers/errors.rs | 2 + ampd/src/handlers/starknet_verify_msg.rs | 8 +- .../handlers/starknet_verify_verifier_set.rs | 141 +++++++++++++++++- 4 files changed, 161 insertions(+), 4 deletions(-) diff --git a/ampd/src/config.rs b/ampd/src/config.rs index 7abbeefa3..0fb3a95a5 100644 --- a/ampd/src/config.rs +++ b/ampd/src/config.rs @@ -159,7 +159,7 @@ mod tests { ); let cfg: Config = toml::from_str(config_str.as_str()).unwrap(); - assert_eq!(cfg.handlers.len(), 10); + assert_eq!(cfg.handlers.len(), 12); } #[test] @@ -363,6 +363,18 @@ mod tests { ), rpc_url: Url::from_str("http://127.0.0.1").unwrap(), }, + HandlerConfig::StarknetMsgVerifier { + cosmwasm_contract: TMAddress::from( + AccountId::new("axelar", &[0u8; 32]).unwrap(), + ), + rpc_url: Url::from_str("http://127.0.0.1").unwrap(), + }, + HandlerConfig::StarknetVerifierSetVerifier { + cosmwasm_contract: TMAddress::from( + AccountId::new("axelar", &[0u8; 32]).unwrap(), + ), + rpc_url: Url::from_str("http://127.0.0.1").unwrap(), + }, ], ..Config::default() } diff --git a/ampd/src/handlers/errors.rs b/ampd/src/handlers/errors.rs index 876912a3b..365ea9280 100644 --- a/ampd/src/handlers/errors.rs +++ b/ampd/src/handlers/errors.rs @@ -10,4 +10,6 @@ pub enum Error { Sign, #[error("failed to get transaction receipts")] TxReceipts, + #[error("starknet client failed")] + StarknetClient, } diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index 2c451ee22..2f2fbbfa9 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -205,7 +205,7 @@ mod tests { from_contract_addr: String::from("source-gw-addr"), destination_address: String::from("destination-address"), destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE.into(), + source_address: Felt::ONE, payload_hash: H256::from_slice(&[ 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, @@ -254,7 +254,7 @@ mod tests { from_contract_addr: String::from("source-gw-addr"), destination_address: String::from("destination-address"), destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE.into(), + source_address: Felt::ONE, payload_hash: H256::from_slice(&[ 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, @@ -398,6 +398,7 @@ mod tests { .collect(), }, messages: vec![ + #[allow(deprecated)] // TODO: Use message_id, on deprecating tx_id and event_index TxEventConfirmation { tx_id: "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e" .parse() @@ -420,6 +421,7 @@ mod tests { ]) .into(), }, + #[allow(deprecated)] // TODO: Use message_id, on deprecating tx_id and event_index TxEventConfirmation { tx_id: "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f" .parse() @@ -463,6 +465,7 @@ mod tests { .collect(), }, messages: vec![ + #[allow(deprecated)] // TODO: Use message_id, on deprecating tx_id and event_index TxEventConfirmation { tx_id: "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f" .parse() @@ -485,6 +488,7 @@ mod tests { ]) .into(), }, + #[allow(deprecated)] // TODO: Use message_id, on deprecating tx_id and event_index TxEventConfirmation { tx_id: "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f" .parse() diff --git a/ampd/src/handlers/starknet_verify_verifier_set.rs b/ampd/src/handlers/starknet_verify_verifier_set.rs index fe24baf2e..5140917f3 100644 --- a/ampd/src/handlers/starknet_verify_verifier_set.rs +++ b/ampd/src/handlers/starknet_verify_verifier_set.rs @@ -127,7 +127,7 @@ where .rpc_client .get_event_by_hash_signers_rotated(verifier_set.message_id.tx_hash.clone()) .await - .unwrap(); + .change_context(Error::StarknetClient)?; let vote = info_span!( "verify a new verifier set", @@ -155,3 +155,142 @@ where .expect("vote msg should serialize")]) } } + +#[cfg(test)] +mod tests { + use std::convert::TryInto; + use std::str::FromStr; + + use axelar_wasm_std::msg_id::FieldElementAndEventIndex; + use base64::engine::general_purpose::STANDARD; + use base64::Engine; + use error_stack::{Report, Result}; + use ethers_core::types::U256; + use events::Event; + use multisig::key::KeyType; + use multisig::test::common::{build_verifier_set, ecdsa_test_data}; + use rand::Rng; + use starknet_checked_felt::CheckedFelt; + use tendermint::abci; + use tokio::sync::watch; + use tokio::test as async_test; + use voting_verifier::events::{PollMetadata, PollStarted, VerifierSetConfirmation}; + + use crate::event_processor::EventHandler; + use crate::handlers::starknet_verify_verifier_set::PollStartedEvent; + use crate::starknet::json_rpc::{MockStarknetClient, StarknetClientError}; + use crate::types::TMAddress; + use crate::PREFIX; + + #[test] + fn should_deserialize_correct_event() { + let event: Event = to_event( + poll_started_event(participants(5, None), 100), + &TMAddress::random(PREFIX), + ); + let event: Result = event.try_into(); + + assert!(event.is_ok()); + } + + #[async_test] + async fn should_skip_expired_poll() { + let mut rpc_client = MockStarknetClient::new(); + // mock the rpc client as erroring. If the handler successfully ignores the poll, we won't hit this + rpc_client + .expect_get_event_by_hash_signers_rotated() + .returning(|_| Err(Report::from(StarknetClientError::UnsuccessfulTx))); + + let voting_verifier = TMAddress::random(PREFIX); + let verifier = TMAddress::random(PREFIX); + let expiration = 100u64; + let event: Event = to_event( + poll_started_event(participants(5, Some(verifier.clone())), expiration), + &voting_verifier, + ); + + let (tx, rx) = watch::channel(expiration - 1); + + let handler = super::Handler::new(verifier, voting_verifier, rpc_client, rx); + + // poll is not expired yet, should hit rpc error + assert!(handler.handle(&event).await.is_err()); + + let _ = tx.send(expiration + 1); + + // poll is expired, should not hit rpc error now + assert_eq!(handler.handle(&event).await.unwrap(), vec![]); + } + + fn random_hash() -> String { + // Generate a random 256-bit value + let mut rng = rand::thread_rng(); + let mut bytes = [0u8; 32]; // Allocate a fixed-size array of 32 bytes + rng.fill(&mut bytes); // Fill the array with random bytes + + let number = U256::from_big_endian(&bytes); + + let max_felt_in_bytes: [u8; 32] = [ + 8, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]; + let max: U256 = U256::from_big_endian(&max_felt_in_bytes); + + let result = number.checked_rem(max).expect("modulo operation failed"); + + format!("0x{:064x}", result) + } + + fn poll_started_event(participants: Vec, expires_at: u64) -> PollStarted { + let random_felt = CheckedFelt::from_str(&random_hash()).unwrap(); + let msg_id = FieldElementAndEventIndex::new(random_felt, 100u64).unwrap(); + PollStarted::VerifierSet { + #[allow(deprecated)] // TODO: The below event uses the deprecated tx_id and event_index fields. Remove this attribute when those fields are removed + verifier_set: VerifierSetConfirmation { + tx_id: msg_id.tx_hash_as_hex(), + event_index: u32::try_from(msg_id.event_index).unwrap(), + message_id: msg_id.to_string().parse().unwrap(), + verifier_set: build_verifier_set(KeyType::Ecdsa, &ecdsa_test_data::signers()), + }, + metadata: PollMetadata { + poll_id: "100".parse().unwrap(), + source_chain: "starknet-devnet-v1".parse().unwrap(), + source_gateway_address: "0x049ec69cd2e0c987857fbda7966ff59077e2e92c18959bdb9b0012438c452047" + .parse() + .unwrap(), + confirmation_height: 15, + expires_at, + participants: participants + .into_iter() + .map(|addr| cosmwasm_std::Addr::unchecked(addr.to_string())) + .collect(), + }, + } + } + + fn to_event(event: impl Into, contract_address: &TMAddress) -> Event { + let mut event: cosmwasm_std::Event = event.into(); + + event.ty = format!("wasm-{}", event.ty); + event = event.add_attribute("_contract_address", contract_address.to_string()); + + abci::Event::new( + event.ty, + event + .attributes + .into_iter() + .map(|cosmwasm_std::Attribute { key, value }| { + (STANDARD.encode(key), STANDARD.encode(value)) + }), + ) + .try_into() + .unwrap() + } + + fn participants(n: u8, verifier: Option) -> Vec { + (0..n) + .map(|_| TMAddress::random(PREFIX)) + .chain(verifier) + .collect() + } +} From 2fb6ce0ba02590a604e2e6145adb1c06256a9a15 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Sun, 12 Jan 2025 19:41:21 +0200 Subject: [PATCH 12/26] implement multicall, handling multiple msgs in one tx --- ampd/src/handlers/starknet_verify_msg.rs | 178 ++++++++++-- ampd/src/starknet/json_rpc.rs | 273 ++++++++++++++---- .../starknet_field_element_event_index.rs | 2 +- .../src/events/contract_call.rs | 16 +- 4 files changed, 393 insertions(+), 76 deletions(-) diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index 2f2fbbfa9..6e36d96af 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -15,7 +15,6 @@ use itertools::Itertools; use router_api::ChainName; use serde::Deserialize; use starknet_checked_felt::CheckedFelt; -use starknet_core::types::Felt; use starknet_types::events::contract_call::ContractCallEvent; use tokio::sync::watch::Receiver; use tracing::info; @@ -129,14 +128,14 @@ where let unique_msgs = messages .iter() - .unique_by(|msg| &msg.message_id.tx_hash) + .unique_by(|msg| msg.message_id.to_string()) .collect::>(); - // key is the tx_hash of the tx holding the event - let events: HashMap = + // key is the message_id of the tx holding the event + let mut events: HashMap = try_join_all(unique_msgs.iter().map(|msg| { self.rpc_client - .get_event_by_hash_contract_call(msg.message_id.tx_hash.clone()) + .get_events_by_hash_contract_call(msg.message_id.tx_hash.clone()) })) .change_context(Error::TxReceipts) .await? @@ -146,12 +145,12 @@ where let mut votes = vec![]; for msg in unique_msgs { - if !events.contains_key(&msg.message_id.tx_hash) { + if !events.contains_key(&msg.message_id) { votes.push(Vote::NotFound); continue; } votes.push(verify_msg( - events.get(&msg.message_id.tx_hash).unwrap(), // safe to unwrap, because of previous check + &events.remove(&msg.message_id).unwrap(), // safe to unwrap, because of previous check msg, &source_gateway_address, )); @@ -183,6 +182,72 @@ mod tests { use crate::starknet::json_rpc::MockStarknetClient; use crate::PREFIX; + #[async_test] + async fn should_correctly_validate_two_messages_within_the_same_tx() { + // Setup the context + let voting_verifier = TMAddress::random(PREFIX); + let verifier = TMAddress::random(PREFIX); + let expiration = 100u64; + let (_, rx) = watch::channel(expiration - 1); + + // Prepare the rpc client, which fetches the event and the vote broadcaster + let mut rpc_client = MockStarknetClient::new(); + rpc_client + .expect_get_events_by_hash_contract_call() + .returning(|_| { + Ok(vec![ + ( + FieldElementAndEventIndex::from_str( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0", + ) + .unwrap(), + ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address"), + destination_chain: "ethereum".parse().unwrap(), + source_address: Felt::ONE, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, + 40, 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, + 109, 234, 200, + ]), + }, + ), + ( + FieldElementAndEventIndex::from_str( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-1", + ) + .unwrap(), + ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address-1"), + destination_chain: "ethereum-1".parse().unwrap(), + source_address: Felt::TWO, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, + 40, 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, + 109, 234, 200, + ]), + }, + ), + ]) + }); + + let event: Event = get_event( + get_two_poll_started_events_within_the_same_tx( + participants(5, Some(verifier.clone())), + 100_u64, + ), + &voting_verifier, + ); + + let handler = super::Handler::new(verifier, voting_verifier, rpc_client, rx); + let result = handler.handle(&event).await.unwrap(); + + assert_eq!(result.len(), 1); + assert!(MsgExecuteContract::from_any(result.first().unwrap()).is_ok()); + } + #[async_test] async fn should_correctly_validate_messages() { // Setup the context @@ -194,11 +259,11 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_event_by_hash_contract_call() + .expect_get_events_by_hash_contract_call() .returning(|_| { - Ok(Some(( - Felt::from_str( - "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e", + Ok(vec![( + FieldElementAndEventIndex::from_str( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0", ) .unwrap(), ContractCallEvent { @@ -212,7 +277,7 @@ mod tests { 234, 200, ]), }, - ))) + )]) }); let event: Event = get_event( @@ -238,16 +303,16 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_event_by_hash_contract_call() + .expect_get_events_by_hash_contract_call() .once() .with(eq(CheckedFelt::from_str( "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", ) .unwrap())) .returning(|_| { - Ok(Some(( - Felt::from_str( - "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", + Ok(vec![( + FieldElementAndEventIndex::from_str( + "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f-0", ) .unwrap(), ContractCallEvent { @@ -261,7 +326,7 @@ mod tests { 234, 200, ]), }, - ))) + )]) }); let event: Event = get_event( @@ -289,7 +354,9 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); - rpc_client.expect_get_event_by_hash_contract_call().times(0); + rpc_client + .expect_get_events_by_hash_contract_call() + .times(0); let event: Event = get_event( get_poll_started_event_with_duplicate_msgs( @@ -315,7 +382,9 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); - rpc_client.expect_get_event_by_hash_contract_call().times(0); + rpc_client + .expect_get_events_by_hash_contract_call() + .times(0); let event: Event = get_event( // woker is not in participat set @@ -339,7 +408,9 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); - rpc_client.expect_get_event_by_hash_contract_call().times(0); + rpc_client + .expect_get_events_by_hash_contract_call() + .times(0); let event: Event = get_event( get_poll_started_event_with_duplicate_msgs( @@ -381,6 +452,73 @@ mod tests { .unwrap() } + fn get_two_poll_started_events_within_the_same_tx( + participants: Vec, + expires_at: u64, + ) -> PollStarted { + PollStarted::Messages { + metadata: PollMetadata { + poll_id: "100".parse().unwrap(), + source_chain: "starknet".parse().unwrap(), + source_gateway_address: "source-gw-addr".parse().unwrap(), + confirmation_height: 15, + expires_at, + participants: participants + .into_iter() + .map(|addr| cosmwasm_std::Addr::unchecked(addr.to_string())) + .collect(), + }, + messages: vec![ + #[allow(deprecated)] // TODO: Use message_id, on deprecating tx_id and event_index + TxEventConfirmation { + tx_id: "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e" + .parse() + .unwrap(), + message_id: + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0" + .parse() + .unwrap(), + event_index: 0, + source_address: + "0x0000000000000000000000000000000000000000000000000000000000000001" + .parse() + .unwrap(), + destination_chain: "ethereum".parse().unwrap(), + destination_address: "destination-address".parse().unwrap(), + payload_hash: H256::from_slice(&[ + // keccak256("hello") + 28, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, + 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]) + .into(), + }, + #[allow(deprecated)] // TODO: Use message_id, on deprecating tx_id and event_index + TxEventConfirmation { + tx_id: "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e" + .parse() + .unwrap(), + message_id: + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-1" + .parse() + .unwrap(), + event_index: 1, + source_address: + "0x0000000000000000000000000000000000000000000000000000000000000002" + .parse() + .unwrap(), + destination_chain: "ethereum-1".parse().unwrap(), + destination_address: "destination-address-1".parse().unwrap(), + payload_hash: H256::from_slice(&[ + // keccak256("hello") + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]) + .into(), + }, + ], + } + } + fn get_poll_started_event_with_two_msgs( participants: Vec, expires_at: u64, diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index 548b6a7c4..3710a48fe 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -2,6 +2,7 @@ //! transaction existence use async_trait::async_trait; +use axelar_wasm_std::msg_id::{Error as MessageFormatError, FieldElementAndEventIndex}; use error_stack::Report; use mockall::automock; use starknet_checked_felt::CheckedFelt; @@ -26,6 +27,10 @@ pub enum StarknetClientError { FeltFromString(#[from] FromStrError), #[error("Tx not successful")] UnsuccessfulTx, + #[error("u64 overflowed")] + OverflowingU64, + #[error("Failed to construct message_id from event: {0}")] + MessageIdConstruction(#[from] MessageFormatError), } /// Implementor of verification method(s) for given network using JSON RPC @@ -59,10 +64,10 @@ where pub trait StarknetClient { /// Attempts to fetch a ContractCall event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. - async fn get_event_by_hash_contract_call( + async fn get_events_by_hash_contract_call( &self, tx_hash: CheckedFelt, - ) -> Result>; + ) -> Result>; /// Attempts to fetch a SignersRotated event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. @@ -77,13 +82,13 @@ impl StarknetClient for Client where T: JsonRpcTransport + Send + Sync + 'static, { - async fn get_event_by_hash_contract_call( + async fn get_events_by_hash_contract_call( &self, tx_hash: CheckedFelt, - ) -> Result> { + ) -> Result> { let receipt_with_block_info = self .client - .get_transaction_receipt(tx_hash) + .get_transaction_receipt(tx_hash.clone()) .await .map_err(StarknetClientError::FetchingReceipt)?; @@ -91,29 +96,31 @@ where return Err(Report::new(StarknetClientError::UnsuccessfulTx)); } - let event: Option<(Felt, ContractCallEvent)> = match receipt_with_block_info.receipt { + let mut message_id_and_event_pairs: Vec<(FieldElementAndEventIndex, ContractCallEvent)> = + vec![]; + + match receipt_with_block_info.receipt { TransactionReceipt::Invoke(tx) => { - // NOTE: There should be only one ContractCall event per gateway tx - tx.events - .iter() - .filter_map(|e| { - // NOTE: Here we ignore the error, because the event might - // not be ContractCall and that by itself is not erroneous behavior - if let Ok(cce) = ContractCallEvent::try_from(e.clone()) { - Some((tx.transaction_hash, cce)) - } else { - None - } - }) - .next() + let mut event_index: u64 = 0; + for e in tx.events.clone() { + if let Ok(cce) = ContractCallEvent::try_from(e.clone()) { + let message_id = + FieldElementAndEventIndex::new(tx_hash.clone(), event_index) + .map_err(StarknetClientError::MessageIdConstruction)?; + message_id_and_event_pairs.push((message_id, cce)); + event_index = event_index + .checked_add(1) + .ok_or(StarknetClientError::OverflowingU64)?; + } + } } - TransactionReceipt::L1Handler(_) => None, - TransactionReceipt::Declare(_) => None, - TransactionReceipt::Deploy(_) => None, - TransactionReceipt::DeployAccount(_) => None, + TransactionReceipt::L1Handler(_) => (), + TransactionReceipt::Declare(_) => (), + TransactionReceipt::Deploy(_) => (), + TransactionReceipt::DeployAccount(_) => (), }; - Ok(event) + Ok(message_id_and_event_pairs) } /// Fetches a transaction receipt by hash and extracts a SignersRotatedEvent if present @@ -174,6 +181,7 @@ mod test { use std::str::FromStr; + use axelar_wasm_std::msg_id::FieldElementAndEventIndex; use axum::async_trait; use ethers_core::types::H256; use serde::de::DeserializeOwned; @@ -205,81 +213,81 @@ mod test { #[tokio::test] async fn deploy_account_tx_fetch() { let mock_client = Client::new_with_transport(DeployAccountMockTransport).unwrap(); - let contract_call_event = mock_client - .get_event_by_hash_contract_call( + let contract_call_events = mock_client + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await; - assert!(contract_call_event.unwrap().is_none()); + assert!(contract_call_events.unwrap().is_empty()); } #[tokio::test] async fn deploy_tx_fetch() { let mock_client = Client::new_with_transport(DeployMockTransport).unwrap(); - let contract_call_event = mock_client - .get_event_by_hash_contract_call( + let contract_call_events = mock_client + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await; - assert!(contract_call_event.unwrap().is_none()); + assert!(contract_call_events.unwrap().is_empty()); } #[tokio::test] async fn l1_handler_tx_fetch() { let mock_client = Client::new_with_transport(L1HandlerMockTransport).unwrap(); - let contract_call_event = mock_client - .get_event_by_hash_contract_call( + let contract_call_events = mock_client + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await; - assert!(contract_call_event.unwrap().is_none()); + assert!(contract_call_events.unwrap().is_empty()); } #[tokio::test] async fn declare_tx_fetch() { let mock_client = Client::new_with_transport(DeclareMockTransport).unwrap(); - let contract_call_event = mock_client - .get_event_by_hash_contract_call( + let contract_call_events = mock_client + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await; - assert!(contract_call_event.unwrap().is_none()); + assert!(contract_call_events.unwrap().is_empty()); } #[tokio::test] async fn invalid_contract_call_event_tx_fetch() { let mock_client = Client::new_with_transport(InvalidContractCallEventMockTransport).unwrap(); - let contract_call_event = mock_client - .get_event_by_hash_contract_call( + let contract_call_events = mock_client + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await; - assert!(contract_call_event.unwrap().is_none()); + assert!(contract_call_events.unwrap().is_empty()); } #[tokio::test] async fn no_events_tx_fetch() { let mock_client = Client::new_with_transport(NoEventsMockTransport).unwrap(); - let contract_call_event = mock_client - .get_event_by_hash_contract_call( + let contract_call_events = mock_client + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await; - assert!(contract_call_event.unwrap().is_none()); + assert!(contract_call_events.unwrap().is_empty()); } #[tokio::test] async fn reverted_tx_fetch() { let mock_client = Client::new_with_transport(RevertedMockTransport).unwrap(); let contract_call_event = mock_client - .get_event_by_hash_contract_call( + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await; @@ -293,7 +301,7 @@ mod test { async fn failing_tx_fetch() { let mock_client = Client::new_with_transport(FailingMockTransport).unwrap(); let contract_call_event = mock_client - .get_event_by_hash_contract_call( + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await; @@ -342,24 +350,87 @@ mod test { assert_eq!(actual, expected); } + #[tokio::test] + async fn successful_two_call_contracts_in_one_tx_fetch() { + let mock_client = + Client::new_with_transport(ValidMockTransportTwoCallContractsInOneTx).unwrap(); + let contract_call_events = mock_client + .get_events_by_hash_contract_call( + CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + ) + .await + .unwrap(); // unwrap the option + + assert_eq!( + contract_call_events[0].0, + FieldElementAndEventIndex::from_str( + "0x0000000000000000000000000000000000000000000000000000000000000001-0" + ) + .unwrap() + ); + assert_eq!( + contract_call_events[0].1, + ContractCallEvent { + from_contract_addr: + "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), + destination_address: String::from("hello"), + destination_chain: String::from("destination_chain"), + source_address: Felt::from_str( + "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca" + ) + .unwrap(), + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, + 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200 + ]) + } + ); + + assert_eq!( + contract_call_events[1].0, + FieldElementAndEventIndex::from_str( + "0x0000000000000000000000000000000000000000000000000000000000000001-1" + ) + .unwrap() + ); + assert_eq!( + contract_call_events[1].1, + ContractCallEvent { + from_contract_addr: + "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), + destination_address: String::from("hello"), + destination_chain: String::from("destination_chain"), + source_address: Felt::from_str( + "0x00b3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca" + ) + .unwrap(), + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, 86, + 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200 + ]) + } + ); + } + #[tokio::test] async fn successful_call_contract_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportCallContract).unwrap(); - let contract_call_event = mock_client - .get_event_by_hash_contract_call( + let contract_call_events = mock_client + .get_events_by_hash_contract_call( CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), ) .await - .unwrap() // unwrap the result .unwrap(); // unwrap the option assert_eq!( - contract_call_event.0, - Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") - .unwrap() + contract_call_events[0].0, + FieldElementAndEventIndex::from_str( + "0x0000000000000000000000000000000000000000000000000000000000000001-0" + ) + .unwrap() ); assert_eq!( - contract_call_event.1, + contract_call_events[0].1, ContractCallEvent { from_contract_addr: "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), @@ -1011,6 +1082,106 @@ mod test { } } + struct ValidMockTransportTwoCallContractsInOneTx; + + #[async_trait] + impl JsonRpcTransport for ValidMockTransportTwoCallContractsInOneTx { + type Error = HttpTransportError; + + async fn send_requests( + &self, + _requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + unimplemented!(); + } + + async fn send_request( + &self, + _method: JsonRpcMethod, + _params: P, + ) -> Result, Self::Error> + where + P: Serialize + Send + Sync, + R: DeserializeOwned, + { + let response_mock = "{ + \"jsonrpc\": \"2.0\", + \"result\": { + \"type\": \"INVOKE\", + \"transaction_hash\": \"0x0000000000000000000000000000000000000000000000000000000000000001\", + \"actual_fee\": { + \"amount\": \"0x3062e4c46d4\", + \"unit\": \"WEI\" + }, + \"execution_status\": \"SUCCEEDED\", + \"finality_status\": \"ACCEPTED_ON_L2\", + \"block_hash\": \"0x5820e3a0aaceebdbda0b308fdf666eff64f263f6ed8ee74d6f78683b65a997b\", + \"block_number\": 637493, + \"messages_sent\": [], + \"events\": [ + { + \"from_address\": \"0x0000000000000000000000000000000000000000000000000000000000000002\", + \"keys\": [ + \"0x034d074b86d78f064ec0a29639fcfab989c7a3ea6343653633624b2df9ec08f6\", + \"0x00000000000000000000000000000064657374696e6174696f6e5f636861696e\" + ], + \"data\": [ + \"0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca\", + \"0x0000000000000000000000000000000000000000000000000000000000000000\", + \"0x00000000000000000000000000000000000000000000000000000068656c6c6f\", + \"0x0000000000000000000000000000000000000000000000000000000000000005\", + \"0x0000000000000000000000000000000056d9517b9c948127319a09a7a36deac8\", + \"0x000000000000000000000000000000001c8aff950685c2ed4bc3174f3472287b\", + \"0x0000000000000000000000000000000000000000000000000000000000000005\", + \"0x0000000000000000000000000000000000000000000000000000000000000068\", + \"0x0000000000000000000000000000000000000000000000000000000000000065\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006f\" + ] + }, { + \"from_address\": \"0x0000000000000000000000000000000000000000000000000000000000000002\", + \"keys\": [ + \"0x034d074b86d78f064ec0a29639fcfab989c7a3ea6343653633624b2df9ec08f6\", + \"0x00000000000000000000000000000064657374696e6174696f6e5f636861696e\" + ], + \"data\": [ + \"0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca\", + \"0x0000000000000000000000000000000000000000000000000000000000000000\", + \"0x00000000000000000000000000000000000000000000000000000068656c6c6f\", + \"0x0000000000000000000000000000000000000000000000000000000000000005\", + \"0x0000000000000000000000000000000056d9517b9c948127319a09a7a36deac8\", + \"0x000000000000000000000000000000001c8aff950685c2ed4bc3174f3472287b\", + \"0x0000000000000000000000000000000000000000000000000000000000000005\", + \"0x0000000000000000000000000000000000000000000000000000000000000068\", + \"0x0000000000000000000000000000000000000000000000000000000000000065\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006c\", + \"0x000000000000000000000000000000000000000000000000000000000000006f\" + ] + } + ], + \"execution_resources\": { + \"data_availability\": { + \"l1_data_gas\": 0, + \"l1_gas\": 0 + }, + \"memory_holes\": 1176, + \"pedersen_builtin_applications\": 34, + \"range_check_builtin_applications\": 1279, + \"steps\": 17574 + } + }, + \"id\": 0 +}"; + let parsed_response = serde_json::from_str(response_mock).map_err(Self::Error::Json)?; + + Ok(parsed_response) + } + } struct ValidMockTransportCallContract; #[async_trait] diff --git a/packages/axelar-wasm-std/src/msg_id/starknet_field_element_event_index.rs b/packages/axelar-wasm-std/src/msg_id/starknet_field_element_event_index.rs index 8c97acd89..926924425 100644 --- a/packages/axelar-wasm-std/src/msg_id/starknet_field_element_event_index.rs +++ b/packages/axelar-wasm-std/src/msg_id/starknet_field_element_event_index.rs @@ -12,7 +12,7 @@ use starknet_checked_felt::CheckedFelt; use super::Error; use crate::nonempty; -#[derive(Debug, DeserializeFromStr, Clone)] +#[derive(Debug, DeserializeFromStr, Clone, Hash, Eq, PartialEq)] pub struct FieldElementAndEventIndex { pub tx_hash: CheckedFelt, pub event_index: u64, diff --git a/packages/starknet-types/src/events/contract_call.rs b/packages/starknet-types/src/events/contract_call.rs index d87c45f8a..0f8eacf4d 100644 --- a/packages/starknet-types/src/events/contract_call.rs +++ b/packages/starknet-types/src/events/contract_call.rs @@ -54,17 +54,25 @@ impl TryFrom for ContractCallEvent { // defined from the event) // // This field, should not exceed 252 bits (a felt's length) - let destination_chain = parse_cairo_short_string(&event.keys[1])?; + let destination_chain = + parse_cairo_short_string(event.keys.get(1).ok_or(ContractCallError::InvalidEvent( + "destinatino chain event key missing from ContractCall event".to_owned(), + ))?)?; // source_address represents the original caller of the `call_contract` gateway // method. It is the first field in data, by the order defined in the // event. - let source_address = event.data[0]; + let source_address = *event.data.first().ok_or(ContractCallError::InvalidEvent( + "source address event data missing from ContractCall event".to_owned(), + ))?; // destination_contract_address (ByteArray) is composed of FieldElements // from the second element to elemet X. - let destination_address_chunks_count_felt = event.data[1]; - let da_chunks_count: usize = u8::try_from(destination_address_chunks_count_felt) + let destination_address_chunks_count_felt = + event.data.get(1).ok_or(ContractCallError::InvalidEvent( + "destination address length missing from ContractCall event".to_owned(), + ))?; + let da_chunks_count: usize = u8::try_from(*destination_address_chunks_count_felt) .map_err(|err| ContractCallError::TryFromConversion(err.to_string()))? .into(); From c43524e6200c92803145e55032efc145fdcd3f2e Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Sun, 12 Jan 2025 22:45:25 +0200 Subject: [PATCH 13/26] small refactors --- Cargo.lock | 868 ++++++++++-------- ampd/src/starknet/json_rpc.rs | 24 +- packages/axelar-wasm-std/Cargo.toml | 2 +- packages/starknet-types/src/types.rs | 1 - .../starknet-types/src/types/array_span.rs | 187 ---- 5 files changed, 511 insertions(+), 571 deletions(-) delete mode 100644 packages/starknet-types/src/types/array_span.rs diff --git a/Cargo.lock b/Cargo.lock index fa0c159f4..99f06e9c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,9 +174,9 @@ dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -190,9 +190,9 @@ dependencies = [ "heck 0.5.0", "indexmap 2.7.0", "proc-macro-error", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", "syn-solidity", "tiny-keccak", ] @@ -206,9 +206,9 @@ dependencies = [ "const-hex", "dunce", "heck 0.5.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", "syn-solidity", ] @@ -278,6 +278,10 @@ dependencies = [ "serde_with", "service-registry-api", "sha3", + "starknet-checked-felt", + "starknet-core", + "starknet-providers", + "starknet-types", "stellar", "stellar-rpc-client", "stellar-xdr", @@ -339,7 +343,7 @@ dependencies = [ "rand", "rcgen", "ring 0.17.8", - "rustls 0.23.20", + "rustls 0.23.21", "rustls-webpki 0.102.8", "serde", "serde_json", @@ -404,9 +408,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "ark-bls12-381" @@ -546,7 +550,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint 0.4.6", "num-traits", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -629,7 +633,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -701,7 +705,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", "synstructure 0.12.6", @@ -713,7 +717,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -766,20 +770,20 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -805,9 +809,9 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -873,6 +877,7 @@ dependencies = [ "serde_with", "sha3", "starknet-checked-felt", + "starknet-types-core", "stellar-xdr", "strum 0.25.0", "sui-types 1.0.0", @@ -889,12 +894,12 @@ dependencies = [ "error-stack", "heck 0.5.0", "itertools 0.11.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "report", "serde", "serde_json", - "syn 2.0.92", + "syn 2.0.96", "thiserror 1.0.69", ] @@ -938,7 +943,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.31", + "hyper 0.14.32", "itoa", "matchit 0.7.3", "memchr", @@ -968,7 +973,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.1", + "hyper 1.5.2", "hyper-util", "itoa", "matchit 0.7.3", @@ -1035,9 +1040,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -1167,7 +1172,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3deeecb812ca5300b7d3f66f730cc2ebd3511c3d36c691dd79c165d5b19a26e3" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -1266,9 +1271,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" [[package]] name = "bitmaps" @@ -1397,9 +1402,9 @@ checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" [[package]] name = "bnum" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50202def95bf36cb7d1d7a7962cea1c36a3f8ad42425e5d2b71d7acb8041b5b8" +checksum = "f781dba93de3a5ef6dc5b17c9958b208f6f3f021623b360fb605ea51ce443f10" [[package]] name = "brotli" @@ -1440,9 +1445,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "serde", @@ -1468,9 +1473,9 @@ checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "bytemuck" -version = "1.20.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" [[package]] name = "byteorder" @@ -1530,9 +1535,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.4" +version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" dependencies = [ "jobserver", "libc", @@ -1605,9 +1610,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.23" +version = "4.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" dependencies = [ "clap_builder", "clap_derive", @@ -1615,9 +1620,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" dependencies = [ "anstream", "anstyle", @@ -1628,14 +1633,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -1683,12 +1688,12 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1724,14 +1729,14 @@ dependencies = [ [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] @@ -1868,21 +1873,22 @@ dependencies = [ [[package]] name = "cosmwasm-core" -version = "2.1.5" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabbba3cbcf1ebdf61c782509916657a3b4e079ed68cb3ec38866f9ecb492ba4" +checksum = "c34c440d4d8e3ecec783d0f9c89d25565168b0f4cdb80a1f6a387cf2168c0740" [[package]] name = "cosmwasm-crypto" -version = "2.1.5" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58587c713490d96f92c36584dcb29f324df58907d9185f762b71ac2b08ac07eb" +checksum = "134e765161d60228cc27635032d2a466542ca83fd6c87f3c87f4963c0bd51008" dependencies = [ "ark-bls12-381", "ark-ec", "ark-ff 0.4.2", "ark-serialize 0.4.2", "cosmwasm-core", + "curve25519-dalek", "digest 0.10.7", "ecdsa", "ed25519-zebra", @@ -1897,20 +1903,20 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.1.5" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae47fa8399bfe9a5b92a6312a1144912231fa1665759562dddb0497c1c917712" +checksum = "3c94a4b93e722c91d2e58471cfe69480f4a656cfccacd8bfda5638f2a5d4512b" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] name = "cosmwasm-schema" -version = "2.1.5" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a7f53fb0011af2ce8d79379ff21a34cd90622e387ebaa00920bac1099ea71d1" +checksum = "3e9a7b56d154870ec4b57b224509854f706c9744449548d8a3bf91ac75c59192" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -1921,20 +1927,20 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.1.5" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae75370266380e777f075be5a0e092792af69469ed1231825505f9c4bd17e54" +checksum = "edd3d80310cd7b86b09dbe886f4f2ca235a5ddb8d478493c6e50e720a3b38a42" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] name = "cosmwasm-std" -version = "2.1.5" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5165aa666dfa923b480babec2ddba16ab91617179d9fb404dfb600c3f0733cef" +checksum = "4434e556b0aebff34bf082e75d175b5d7edbcf1d90d4cedb59623a1249fff567" dependencies = [ "base64 0.22.1", "bech32 0.11.0", @@ -1945,6 +1951,7 @@ dependencies = [ "derive_more 1.0.0", "hex", "rand_core", + "rmp-serde", "schemars", "serde", "serde-json-wasm", @@ -1984,9 +1991,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -2003,9 +2010,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -2067,9 +2074,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2102,7 +2109,7 @@ dependencies = [ "schemars", "serde", "sha2 0.10.8", - "thiserror 2.0.6", + "thiserror 2.0.11", ] [[package]] @@ -2111,7 +2118,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90e7828ea0175c45743178f8b0290513752e949b2fdfa5bda52a7389d732610" dependencies = [ - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2182,7 +2189,7 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "strsim 0.10.0", "syn 1.0.109", @@ -2196,10 +2203,10 @@ checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "strsim 0.11.1", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2221,7 +2228,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2306,9 +2313,9 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2327,7 +2334,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4255bb7dd538590188bd0aea52e48bd699b19bd90b0d069ec2ced8461fe23273" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -2338,7 +2345,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -2350,10 +2357,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "rustc_version 0.4.1", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2371,9 +2378,9 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", "unicode-xid 0.2.6", ] @@ -2464,9 +2471,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2494,9 +2501,9 @@ checksum = "973659d4a62084e32a7f9332509455436d33684b316bb3bc2bb6dcea51a68c63" dependencies = [ "convert_case 0.6.0", "optfield", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2625,9 +2632,9 @@ dependencies = [ [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" @@ -2670,7 +2677,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f16ef37b2a9b242295d61a154ee91ae884afff6b8b933b486b12481cc58310ca" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -2682,9 +2689,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2797,13 +2804,13 @@ dependencies = [ "dunce", "ethers-core", "eyre", - "prettyplease 0.2.25", - "proc-macro2 1.0.92", + "prettyplease 0.2.29", + "proc-macro2 1.0.93", "quote 1.0.38", "regex", "serde", "serde_json", - "syn 2.0.92", + "syn 2.0.96", "toml 0.8.19", "walkdir", ] @@ -2818,10 +2825,10 @@ dependencies = [ "const-hex", "ethers-contract-abigen", "ethers-core", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "serde_json", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -2847,7 +2854,7 @@ dependencies = [ "serde", "serde_json", "strum 0.26.3", - "syn 2.0.92", + "syn 2.0.96", "tempfile", "thiserror 1.0.69", "tiny-keccak", @@ -2925,7 +2932,7 @@ dependencies = [ "quote 1.0.38", "serde", "serde_json", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -3060,7 +3067,7 @@ dependencies = [ "num-bigint 0.4.6", "once_cell", "regex", - "reqwest 0.12.9", + "reqwest 0.12.12", "schemars", "serde", "serde_json", @@ -3093,11 +3100,22 @@ dependencies = [ "bytes", ] +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + [[package]] name = "faux" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5750c6d0319d85c09ea699a4c90a8acdbe7f0e81b7ad2c4b7b593a412f90ff98" +checksum = "4a8e414cd04dc036003ccd2cc56492d5a7365e9d3f40b27c43606e42b54e5d1f" dependencies = [ "faux_macros", "paste", @@ -3105,14 +3123,14 @@ dependencies = [ [[package]] name = "faux_macros" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b958764c0cca84c4dcbe9495f9e8fa632628240eb975ae5eb99be5d18bd4b09" +checksum = "dfc583ba3a3c259f1986c68e1501228013a34224b9ac97d17b30d7f017213b2a" dependencies = [ "darling 0.20.10", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", "uuid", ] @@ -3140,7 +3158,7 @@ dependencies = [ "num-bigint 0.3.3", "num-integer", "num-traits", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -3327,9 +3345,9 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -3465,9 +3483,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "globset" @@ -3682,11 +3700,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3781,9 +3799,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.31" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -3805,9 +3823,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", @@ -3831,7 +3849,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.32", "log", "rustls 0.20.9", "rustls-native-certs", @@ -3848,7 +3866,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.32", "log", "rustls 0.21.12", "rustls-native-certs", @@ -3858,15 +3876,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.2.0", - "hyper 1.5.1", + "hyper 1.5.2", "hyper-util", - "rustls 0.23.20", + "rustls 0.23.21", "rustls-pki-types", "tokio", "tokio-rustls 0.26.1", @@ -3880,7 +3898,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.31", + "hyper 0.14.32", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -3892,7 +3910,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.5.1", + "hyper 1.5.2", "hyper-util", "pin-project-lite", "tokio", @@ -3907,7 +3925,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.1", + "hyper 1.5.2", "hyper-util", "native-tls", "tokio", @@ -3926,7 +3944,7 @@ dependencies = [ "futures-util", "http 1.2.0", "http-body 1.0.1", - "hyper 1.5.1", + "hyper 1.5.2", "pin-project-lite", "socket2", "tokio", @@ -4070,9 +4088,9 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -4167,9 +4185,9 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -4218,13 +4236,13 @@ dependencies = [ [[package]] name = "insta" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8" +checksum = "6513e4067e16e69ed1db5ab56048ed65db32d10ba5fc1217f5393f8f17d8b5a5" dependencies = [ "console", - "lazy_static", "linked-hash-map", + "once_cell", "pest", "pest_derive", "serde", @@ -4309,7 +4327,7 @@ dependencies = [ "error-stack", "quote 1.0.38", "report", - "syn 2.0.92", + "syn 2.0.96", "thiserror 1.0.69", ] @@ -4464,7 +4482,7 @@ dependencies = [ "futures-timer", "futures-util", "globset", - "hyper 0.14.31", + "hyper 0.14.32", "jsonrpsee-types 0.16.2", "parking_lot", "rand", @@ -4487,7 +4505,7 @@ dependencies = [ "async-trait", "beef", "futures-util", - "hyper 0.14.31", + "hyper 0.14.32", "jsonrpsee-types 0.20.4", "serde", "serde_json", @@ -4502,7 +4520,7 @@ version = "0.16.2" source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" dependencies = [ "async-trait", - "hyper 0.14.31", + "hyper 0.14.32", "hyper-rustls 0.23.2", "jsonrpsee-core 0.16.2", "jsonrpsee-types 0.16.2", @@ -4521,7 +4539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c7b9f95208927653e7965a98525e7fc641781cab89f0e27c43fa2974405683" dependencies = [ "async-trait", - "hyper 0.14.31", + "hyper 0.14.32", "hyper-rustls 0.24.2", "jsonrpsee-core 0.20.4", "jsonrpsee-types 0.20.4", @@ -4541,7 +4559,7 @@ source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcd dependencies = [ "heck 0.4.1", "proc-macro-crate 1.1.3", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -4554,7 +4572,7 @@ dependencies = [ "futures-channel", "futures-util", "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.32", "jsonrpsee-core 0.16.2", "jsonrpsee-types 0.16.2", "serde", @@ -4691,9 +4709,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libm" @@ -4707,7 +4725,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "libc", ] @@ -4719,9 +4737,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" @@ -4821,9 +4839,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] @@ -4865,7 +4883,7 @@ dependencies = [ "fragile", "lazy_static", "mockall_derive 0.12.1", - "predicates 3.1.2", + "predicates 3.1.3", "predicates-tree", ] @@ -4876,7 +4894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -4888,9 +4906,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" dependencies = [ "cfg-if", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -5149,7 +5167,7 @@ source = "git+https://github.com/mystenlabs/sui?tag=testnet-v1.39.1#e2a147185dbe dependencies = [ "enum-compat-util", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -5218,9 +5236,9 @@ dependencies = [ "cosmwasm-std", "error-stack", "itertools 0.11.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -5229,7 +5247,7 @@ version = "0.1.0" source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=9c6636c399d5c60a1759f1670b1c07b3d408799a#9c6636c399d5c60a1759f1670b1c07b3d408799a" dependencies = [ "darling 0.14.4", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -5283,7 +5301,7 @@ checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ "proc-macro-crate 1.1.3", "proc-macro-error", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", "synstructure 0.12.6", @@ -5392,7 +5410,7 @@ dependencies = [ "pbkdf2", "pem 3.0.4", "rand", - "reqwest 0.12.9", + "reqwest 0.12.12", "scrypt", "serde", "serde_json", @@ -5437,7 +5455,7 @@ dependencies = [ "eyre", "futures", "http 1.2.0", - "hyper-rustls 0.27.3", + "hyper-rustls 0.27.5", "hyper-util", "multiaddr", "once_cell", @@ -5596,7 +5614,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -5607,9 +5625,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -5688,9 +5706,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro-crate 1.1.3", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -5700,16 +5718,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate 3.2.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -5755,7 +5773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" dependencies = [ "bytes", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -5777,7 +5795,7 @@ version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "cfg-if", "foreign-types", "libc", @@ -5792,9 +5810,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -5831,9 +5849,9 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa59f025cde9c698fcb4fcb3533db4621795374065bee908215263488f2d2a1d" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -5871,9 +5889,9 @@ checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -5949,7 +5967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" dependencies = [ "proc-macro-crate 1.1.3", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -5961,7 +5979,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate 3.2.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -5995,7 +6013,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "499cff8432e71c5f8784d9645aac0f9fca604d67f59b68a606170b5e229c6538" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "ciborium", "coset", "data-encoding", @@ -6075,7 +6093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdad6a1d9cf116a059582ce415d5f5566aabcd4008646779dab7fdc2a9a9d426" dependencies = [ "peg-runtime", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", ] @@ -6135,7 +6153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 2.0.6", + "thiserror 2.0.11", "ucd-trie", ] @@ -6157,9 +6175,9 @@ checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -6205,9 +6223,9 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros", "phf_shared", @@ -6215,9 +6233,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", "rand", @@ -6225,51 +6243,51 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ "phf_generator", "phf_shared", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -6358,9 +6376,9 @@ dependencies = [ [[package]] name = "predicates" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", "predicates-core", @@ -6368,15 +6386,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", @@ -6398,18 +6416,18 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "syn 1.0.109", ] [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ - "proc-macro2 1.0.92", - "syn 2.0.92", + "proc-macro2 1.0.93", + "syn 2.0.96", ] [[package]] @@ -6473,7 +6491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", "version_check", @@ -6485,7 +6503,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "version_check", ] @@ -6501,9 +6519,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -6541,7 +6559,7 @@ checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.6.0", + "bitflags 2.7.0", "lazy_static", "num-traits", "rand", @@ -6624,7 +6642,7 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -6637,9 +6655,9 @@ checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -6650,9 +6668,9 @@ checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" dependencies = [ "anyhow", "itertools 0.13.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -6718,9 +6736,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.0", - "rustls 0.23.20", + "rustls 0.23.21", "socket2", - "thiserror 2.0.6", + "thiserror 2.0.11", "tokio", "tracing", ] @@ -6736,10 +6754,10 @@ dependencies = [ "rand", "ring 0.17.8", "rustc-hash 2.1.0", - "rustls 0.23.20", + "rustls 0.23.21", "rustls-pki-types", "slab", - "thiserror 2.0.6", + "thiserror 2.0.11", "tinyvec", "tracing", "web-time", @@ -6747,9 +6765,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" dependencies = [ "cfg_aliases", "libc", @@ -6774,7 +6792,7 @@ version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", ] [[package]] @@ -6868,9 +6886,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54077e1872c46788540de1ea3d7f4ccb1983d12f9aa909b234468676c1a36779" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" dependencies = [ "pem 3.0.4", "ring 0.17.8", @@ -6885,9 +6903,9 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a25d631e41bfb5fdcde1d4e2215f62f7f0afa3ff11e26563765bd6ea1d229aeb" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -6896,7 +6914,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", ] [[package]] @@ -6925,9 +6943,9 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -6999,7 +7017,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.31", + "hyper 0.14.32", "hyper-rustls 0.24.2", "ipnet", "js-sys", @@ -7029,9 +7047,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64 0.22.1", "bytes", @@ -7043,8 +7061,8 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.1", - "hyper-rustls 0.27.3", + "hyper 1.5.2", + "hyper-rustls 0.27.5", "hyper-tls", "hyper-util", "ipnet", @@ -7056,7 +7074,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.20", + "rustls 0.23.21", "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", @@ -7067,6 +7085,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls 0.26.1", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -7162,16 +7181,38 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "roaring" -version = "0.10.9" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41589aba99537475bf697f2118357cad1c31590c5a1b9f6d9fc4ad6d07503661" +checksum = "a652edd001c53df0b3f96a36a8dc93fce6866988efc16808235653c6bcac8bf2" dependencies = [ "bytemuck", "byteorder", @@ -7264,16 +7305,18 @@ dependencies = [ [[package]] name = "ruint" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes", - "fastrlp", + "fastrlp 0.3.1", + "fastrlp 0.4.0", "num-bigint 0.4.6", + "num-integer", "num-traits", "parity-scale-codec 3.6.12", "primitive-types 0.12.2", @@ -7355,11 +7398,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "errno", "libc", "linux-raw-sys", @@ -7392,9 +7435,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.20" +version = "0.23.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" dependencies = [ "log", "once_cell", @@ -7467,9 +7510,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "rusty-fork" @@ -7526,9 +7569,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ "proc-macro-crate 3.2.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -7559,10 +7602,10 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "serde_derive_internals", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -7633,7 +7676,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "core-foundation", "core-foundation-sys", "libc", @@ -7642,9 +7685,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -7691,9 +7734,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] @@ -7760,13 +7803,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -7775,16 +7818,16 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] name = "serde_json" -version = "1.0.134" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "indexmap 2.7.0", "itoa", @@ -7793,6 +7836,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_json_pythonic" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62212da9872ca2a0cad0093191ee33753eddff9266cbbc1b4a602d13a3a768db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_path_to_error" version = "0.1.16" @@ -7809,9 +7863,9 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -7837,9 +7891,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64 0.22.1", "chrono", @@ -7855,14 +7909,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling 0.20.10", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -8087,9 +8141,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "sized-chunks" @@ -8212,6 +8266,93 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "starknet-core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538240cbe6663c673fe77465f294da707080f39678dd7066761554899e46100" +dependencies = [ + "base64 0.21.7", + "crypto-bigint", + "flate2", + "hex", + "serde", + "serde_json", + "serde_json_pythonic", + "serde_with", + "sha3", + "starknet-crypto", + "starknet-types-core", +] + +[[package]] +name = "starknet-crypto" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded22ccf4cb9e572ce3f77de6066af53560cd2520d508876c83bb1e6b29d5cbc" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "rfc6979", + "sha2 0.10.8", + "starknet-curve", + "starknet-types-core", + "zeroize", +] + +[[package]] +name = "starknet-curve" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcde6bd74269b8161948190ace6cf069ef20ac6e79cd2ba09b320efa7500b6de" +dependencies = [ + "starknet-types-core", +] + +[[package]] +name = "starknet-providers" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e8e69ba7a36dea2d28333be82b4011f8784333d3ae5618482b6587c1ffb66c" +dependencies = [ + "async-trait", + "auto_impl", + "ethereum-types", + "flate2", + "getrandom", + "log", + "reqwest 0.11.27", + "serde", + "serde_json", + "serde_with", + "starknet-core", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "starknet-types" +version = "1.0.0" +dependencies = [ + "axelar-wasm-std", + "cosmwasm-std", + "error-stack", + "ethers-core", + "hex", + "itertools 0.11.0", + "rand", + "router-api", + "starknet-checked-felt", + "starknet-core", + "starknet-types-core", + "thiserror 1.0.69", + "tokio", +] + [[package]] name = "starknet-types-core" version = "0.1.7" @@ -8361,7 +8502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "rustversion", "syn 1.0.109", @@ -8374,10 +8515,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "rustversion", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -8387,10 +8528,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "rustversion", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -8524,10 +8665,10 @@ version = "0.7.0" source = "git+https://github.com/mystenlabs/sui?tag=testnet-v1.39.1#e2a147185dbeb6402daa43811507e29bc0d5df28" dependencies = [ "msim-macros", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "sui-enum-compat-util", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -8551,7 +8692,7 @@ name = "sui-protocol-config-macros" version = "0.1.0" source = "git+https://github.com/mystenlabs/sui?tag=testnet-v1.39.1#e2a147185dbeb6402daa43811507e29bc0d5df28" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -8579,7 +8720,7 @@ dependencies = [ "prost 0.13.4", "prost-types 0.13.4", "rand", - "reqwest 0.12.9", + "reqwest 0.12.12", "roaring", "schemars", "serde", @@ -8605,7 +8746,7 @@ dependencies = [ "base64ct", "bcs", "blake2", - "bnum 0.12.0", + "bnum 0.12.1", "bs58 0.5.1", "hex", "roaring", @@ -8714,18 +8855,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.92" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "unicode-ident", ] @@ -8737,9 +8878,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" dependencies = [ "paste", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -8763,7 +8904,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", "unicode-xid 0.2.6", @@ -8775,9 +8916,9 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -8797,7 +8938,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "core-foundation", "system-configuration-sys 0.6.0", ] @@ -8841,7 +8982,7 @@ checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -8854,12 +8995,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand 2.3.0", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -9045,9 +9187,9 @@ dependencies = [ [[package]] name = "termtree" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "thiserror" @@ -9060,11 +9202,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.6" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl 2.0.6", + "thiserror-impl 2.0.11", ] [[package]] @@ -9073,20 +9215,20 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] name = "thiserror-impl" -version = "2.0.6" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -9160,9 +9302,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -9196,9 +9338,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.42.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -9224,13 +9366,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -9270,7 +9412,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.20", + "rustls 0.23.21", "tokio", ] @@ -9385,7 +9527,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.31", + "hyper 0.14.32", "hyper-timeout 0.4.1", "percent-encoding", "pin-project", @@ -9413,7 +9555,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.1", + "hyper 1.5.2", "hyper-timeout 0.5.2", "hyper-util", "percent-encoding", @@ -9438,7 +9580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" dependencies = [ "prettyplease 0.1.25", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "prost-build", "quote 1.0.38", "syn 1.0.109", @@ -9502,7 +9644,7 @@ checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "async-compression", "base64 0.21.7", - "bitflags 2.6.0", + "bitflags 2.7.0", "bytes", "futures-core", "futures-util", @@ -9555,9 +9697,9 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -9632,7 +9774,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -9696,9 +9838,9 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -9735,7 +9877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a615d6c2764852a2e88a4f16e9ce1ea49bb776b5872956309e170d63a042a34f" dependencies = [ "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -9764,9 +9906,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" @@ -9884,9 +10026,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4" dependencies = [ "getrandom", "rand", @@ -9907,7 +10049,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d44690c645190cfce32f91a1582281654b2338c6073fa250b0949fd25c55b32" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", "syn 1.0.109", ] @@ -10035,9 +10177,9 @@ checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", "wasm-bindgen-shared", ] @@ -10070,9 +10212,9 @@ version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -10369,9 +10511,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" dependencies = [ "memchr", ] @@ -10492,9 +10634,9 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", "synstructure 0.13.1", ] @@ -10514,9 +10656,9 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -10534,9 +10676,9 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", "synstructure 0.13.1", ] @@ -10555,9 +10697,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] @@ -10577,9 +10719,9 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ - "proc-macro2 1.0.92", + "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.92", + "syn 2.0.96", ] [[package]] diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index 3710a48fe..f45e9a433 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -37,14 +37,14 @@ pub enum StarknetClientError { /// client. pub struct Client where - T: JsonRpcTransport + Send + Sync + 'static, + T: JsonRpcTransport + Send + Sync, { client: JsonRpcClient, } impl Client where - T: JsonRpcTransport + Send + Sync + 'static, + T: JsonRpcTransport + Send + Sync, { /// Constructor. /// Expects URL of any JSON RPC entry point of Starknet, which you can find @@ -82,6 +82,8 @@ impl StarknetClient for Client where T: JsonRpcTransport + Send + Sync + 'static, { + // Fetches a transaction receipt by hash and extracts one or multiple + // `ContractCallEvent` async fn get_events_by_hash_contract_call( &self, tx_hash: CheckedFelt, @@ -123,23 +125,7 @@ where Ok(message_id_and_event_pairs) } - /// Fetches a transaction receipt by hash and extracts a SignersRotatedEvent if present - /// - /// # Arguments - /// - /// * `tx_hash` - The hash of the transaction to fetch - /// - /// # Returns - /// - /// * `Ok(Some((tx_hash, SignersRotatedEvent)))` - If the transaction exists and contains a valid SignersRotatedEvent - /// * `Ok(None)` - If the transaction exists but contains no SignersRotatedEvent - /// * `Err(StarknetClientError)` - If there was an error fetching the receipt or the transaction failed - /// - /// # Errors - /// - /// Returns a `StarknetClientError` if: - /// * Failed to fetch the transaction receipt from the node - /// * The transaction execution was not successful + // Fetches a transaction receipt by hash and extracts a `SignersRotatedEvent` if present async fn get_event_by_hash_signers_rotated( &self, tx_hash: CheckedFelt, diff --git a/packages/axelar-wasm-std/Cargo.toml b/packages/axelar-wasm-std/Cargo.toml index 9cfe62182..948a120fd 100644 --- a/packages/axelar-wasm-std/Cargo.toml +++ b/packages/axelar-wasm-std/Cargo.toml @@ -60,7 +60,7 @@ assert_ok = { workspace = true } cw-multi-test = { workspace = true } goldie = { workspace = true } rand = { workspace = true } -hex = { version = "0.4.3", default-features = false } +hex = { workspace = true, default-features = false } [lints] workspace = true diff --git a/packages/starknet-types/src/types.rs b/packages/starknet-types/src/types.rs index 90b8423bf..ec5766d15 100644 --- a/packages/starknet-types/src/types.rs +++ b/packages/starknet-types/src/types.rs @@ -1,3 +1,2 @@ -pub mod array_span; pub mod byte_array; pub mod starknet_message; diff --git a/packages/starknet-types/src/types/array_span.rs b/packages/starknet-types/src/types/array_span.rs deleted file mode 100644 index eaf1fc613..000000000 --- a/packages/starknet-types/src/types/array_span.rs +++ /dev/null @@ -1,187 +0,0 @@ -use starknet_core::types::Felt; -use thiserror::Error; - -/// Represents Cairo's Array and Span types. -/// Implements `TryFrom>`, which is the way to create it. -/// -/// ## Example usage with the string "hello" -/// -/// ```rust -/// use starknet_types::types::array_span::ArraySpan; -/// use std::str::FromStr; -/// use starknet_core::types::Felt; -/// use starknet_core::types::FromStrError; -/// -/// let data: Result, FromStrError> = vec![ -/// "0x0000000000000000000000000000000000000000000000000000000000000005", -/// "0x0000000000000000000000000000000000000000000000000000000000000068", -/// "0x0000000000000000000000000000000000000000000000000000000000000065", -/// "0x000000000000000000000000000000000000000000000000000000000000006c", -/// "0x000000000000000000000000000000000000000000000000000000000000006c", -/// "0x000000000000000000000000000000000000000000000000000000000000006f", -/// ] -/// .into_iter() -/// .map(Felt::from_str) -/// .collect(); -/// -/// let array_span = ArraySpan::::try_from(data.unwrap()).unwrap(); -/// assert_eq!(array_span.data, vec![104, 101, 108, 108, 111]); -/// assert_eq!(String::from_utf8(array_span.data).unwrap(), "hello"); -/// ``` -/// -/// For more info: -/// https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays -#[derive(Debug)] -pub struct ArraySpan { - pub data: Vec, -} - -#[derive(Error, Debug)] -pub enum ArraySpanError { - #[error("Invalid array/span length")] - InvalidLength, - #[error("Failed to parse felt - {0}")] - ParsingFelt(String), -} - -impl TryFrom> for ArraySpan { - type Error = ArraySpanError; - - fn try_from(data: Vec) -> Result { - // First element is always the array length, which is a felt (so u8 is enough) - let arr_length = - u8::try_from(data[0]).map_err(|e| ArraySpanError::ParsingFelt(e.to_string()))?; - - // -1 because we have to offset the first element (the length itself) - let arr_length_usize = usize::from(arr_length); - if arr_length_usize != data.len().wrapping_sub(1) { - return Err(ArraySpanError::InvalidLength); - } - - let bytes: Result, ArraySpanError> = data - .get(1..) - .ok_or(ArraySpanError::InvalidLength)? - .iter() - .copied() - .map(|data| u8::try_from(data).map_err(|e| ArraySpanError::ParsingFelt(e.to_string()))) - .collect(); - - Ok(ArraySpan { data: bytes? }) - } -} - -#[cfg(test)] -mod array_span_tests { - use std::str::FromStr; - - use starknet_core::types::{Felt, FromStrError}; - - use super::ArraySpan; - - #[test] - fn try_from_valid_zeros() { - // the string "hello", but Felt is bigger than u8::max - let data = vec![Felt::from_str( - "0x0000000000000000000000000000000000000000000000000000000000000000", - ) - .unwrap()]; - - let array_span = ArraySpan::::try_from(data).unwrap(); - assert_eq!(array_span.data, Vec::::new()); - } - - #[test] - fn try_from_failed_to_parse_element_to_u8() { - // the string "hello", but Felt is bigger than u8::max - let data: Result, FromStrError> = vec![ - "0x0000000000000000000000000000000000000000000000000000000000000005", - "0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "0x0000000000000000000000000000000000000000000000000000000000000065", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006f", - ] - .into_iter() - .map(Felt::from_str) - .collect(); - - let array_span = ArraySpan::::try_from(data.unwrap()); - assert!(array_span.is_err()); - } - - #[test] - fn try_from_failed_to_parse_elements_length_to_u32() { - // the string "hello", but element count is bigger than u32::max - let data: Result, FromStrError> = vec![ - "0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "0x0000000000000000000000000000000000000000000000000000000000000068", - "0x0000000000000000000000000000000000000000000000000000000000000065", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006f", - ] - .into_iter() - .map(Felt::from_str) - .collect(); - - let array_span = ArraySpan::::try_from(data.unwrap()); - assert!(array_span.is_err()); - } - - #[test] - fn try_from_invalid_number_of_elements() { - // the string "hello", but with only 4 bytes - let data: Result, FromStrError> = vec![ - "0x0000000000000000000000000000000000000000000000000000000000000005", - "0x0000000000000000000000000000000000000000000000000000000000000068", - "0x0000000000000000000000000000000000000000000000000000000000000065", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006c", - ] - .into_iter() - .map(Felt::from_str) - .collect(); - - let array_span = ArraySpan::::try_from(data.unwrap()); - assert!(array_span.is_err()); - } - - #[test] - fn try_from_invalid_declared_length() { - // the string "hello", with correct number of bytes, but only 4 declared, - // instead of 5 - let data: Result, FromStrError> = vec![ - "0x0000000000000000000000000000000000000000000000000000000000000004", - "0x0000000000000000000000000000000000000000000000000000000000000068", - "0x0000000000000000000000000000000000000000000000000000000000000065", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006f", - ] - .into_iter() - .map(Felt::from_str) - .collect(); - - let array_span = ArraySpan::::try_from(data.unwrap()); - assert!(array_span.is_err()); - } - - #[test] - fn try_from_valid() { - // the string "hello" - let data: Result, FromStrError> = vec![ - "0x0000000000000000000000000000000000000000000000000000000000000005", - "0x0000000000000000000000000000000000000000000000000000000000000068", - "0x0000000000000000000000000000000000000000000000000000000000000065", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006c", - "0x000000000000000000000000000000000000000000000000000000000000006f", - ] - .into_iter() - .map(Felt::from_str) - .collect(); - - let array_span = ArraySpan::::try_from(data.unwrap()).unwrap(); - assert_eq!(array_span.data, vec![104, 101, 108, 108, 111]); - } -} From c811313da89c88d8df0a157f6cc2f934f8bc3e3c Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 17 Jan 2025 14:54:09 +0200 Subject: [PATCH 14/26] remove unwrap --- ampd/src/handlers/starknet_verify_msg.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index 6e36d96af..c28db400d 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -145,15 +145,13 @@ where let mut votes = vec![]; for msg in unique_msgs { - if !events.contains_key(&msg.message_id) { - votes.push(Vote::NotFound); - continue; + match events.remove(&msg.message_id) { + Some(gateway_event) => { + votes.push(verify_msg(&gateway_event, msg, &source_gateway_address)); + } + + None => votes.push(Vote::NotFound), } - votes.push(verify_msg( - &events.remove(&msg.message_id).unwrap(), // safe to unwrap, because of previous check - msg, - &source_gateway_address, - )); } Ok(vec![self From 8c14dc250493e8a42811edfe6971aa8c1c778f64 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 17 Jan 2025 14:55:57 +0200 Subject: [PATCH 15/26] fix the event index iteration --- ampd/src/starknet/json_rpc.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index f45e9a433..aef3ad438 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -104,16 +104,21 @@ where match receipt_with_block_info.receipt { TransactionReceipt::Invoke(tx) => { let mut event_index: u64 = 0; + // The RPC node always returns the events in the same order, + // so we can be sure that the msg ids will have the same indexes + // when iterating them for e in tx.events.clone() { if let Ok(cce) = ContractCallEvent::try_from(e.clone()) { let message_id = FieldElementAndEventIndex::new(tx_hash.clone(), event_index) .map_err(StarknetClientError::MessageIdConstruction)?; message_id_and_event_pairs.push((message_id, cce)); - event_index = event_index - .checked_add(1) - .ok_or(StarknetClientError::OverflowingU64)?; } + // we iterate regardless of the event type, + // because that's what we do in the relayer + event_index = event_index + .checked_add(1) + .ok_or(StarknetClientError::OverflowingU64)?; } } TransactionReceipt::L1Handler(_) => (), From f46f33ab42a3fa5f17417e46e9f65e64d06a8152 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Fri, 17 Jan 2025 17:19:34 +0200 Subject: [PATCH 16/26] rename starknet-types and move part of the modules to ampd --- Cargo.lock | 32 +++++++------------ Cargo.toml | 2 +- ampd/Cargo.toml | 1 - ampd/src/handlers/starknet_verify_msg.rs | 2 +- ampd/src/starknet/json_rpc.rs | 13 ++++---- ampd/src/starknet/verifier.rs | 12 +++---- ampd/src/types/mod.rs | 2 +- .../src/types/starknet}/byte_array.rs | 8 ++--- .../types/starknet}/events/contract_call.rs | 6 ++-- ampd/src/types/starknet/events/mod.rs | 2 ++ .../types/starknet}/events/signers_rotated.rs | 5 --- ampd/src/types/starknet/mod.rs | 2 ++ packages/starknet-message/Cargo.toml | 28 ++++++++++++++++ .../src/lib.rs} | 9 ++++-- packages/starknet-types/Cargo.toml | 28 ---------------- packages/starknet-types/src/error.rs | 7 ---- packages/starknet-types/src/events.rs | 2 -- packages/starknet-types/src/lib.rs | 3 -- packages/starknet-types/src/types.rs | 2 -- 19 files changed, 72 insertions(+), 94 deletions(-) rename {packages/starknet-types/src/types => ampd/src/types/starknet}/byte_array.rs (99%) rename {packages/starknet-types/src => ampd/src/types/starknet}/events/contract_call.rs (97%) create mode 100644 ampd/src/types/starknet/events/mod.rs rename {packages/starknet-types/src => ampd/src/types/starknet}/events/signers_rotated.rs (98%) create mode 100644 ampd/src/types/starknet/mod.rs create mode 100644 packages/starknet-message/Cargo.toml rename packages/{starknet-types/src/types/starknet_message.rs => starknet-message/src/lib.rs} (98%) delete mode 100644 packages/starknet-types/Cargo.toml delete mode 100644 packages/starknet-types/src/error.rs delete mode 100644 packages/starknet-types/src/events.rs delete mode 100644 packages/starknet-types/src/lib.rs delete mode 100644 packages/starknet-types/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 99f06e9c5..335093ae0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -281,7 +281,6 @@ dependencies = [ "starknet-checked-felt", "starknet-core", "starknet-providers", - "starknet-types", "stellar", "stellar-rpc-client", "stellar-xdr", @@ -8313,6 +8312,18 @@ dependencies = [ "starknet-types-core", ] +[[package]] +name = "starknet-message" +version = "1.0.0" +dependencies = [ + "error-stack", + "ethers-core", + "router-api", + "starknet-checked-felt", + "starknet-types-core", + "thiserror 1.0.69", +] + [[package]] name = "starknet-providers" version = "0.12.0" @@ -8334,25 +8345,6 @@ dependencies = [ "url", ] -[[package]] -name = "starknet-types" -version = "1.0.0" -dependencies = [ - "axelar-wasm-std", - "cosmwasm-std", - "error-stack", - "ethers-core", - "hex", - "itertools 0.11.0", - "rand", - "router-api", - "starknet-checked-felt", - "starknet-core", - "starknet-types-core", - "thiserror 1.0.69", - "tokio", -] - [[package]] name = "starknet-types-core" version = "0.1.7" diff --git a/Cargo.toml b/Cargo.toml index ed8dd7aad..b8ce8baaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,7 +80,7 @@ sui-gateway = { version = "^1.0.0", path = "packages/sui-gateway" } sui-types = { version = "^1.0.0", path = "packages/sui-types" } starknet-checked-felt = { version = "^1.0.0", path = "packages/starknet-checked-felt" } starknet-types-core = { version = "0.1.7" } -starknet-types = { version = "^1.0.0", path = "packages/starknet-types" } +starknet-message = { version = "^1.0.0", path = "packages/starknet-message" } starknet-core = "0.12.0" starknet-providers = "0.12.0" syn = "2.0.92" diff --git a/ampd/Cargo.toml b/ampd/Cargo.toml index 202fa78de..683000957 100644 --- a/ampd/Cargo.toml +++ b/ampd/Cargo.toml @@ -82,7 +82,6 @@ voting-verifier = { workspace = true } starknet-core = { workspace = true } starknet-providers = { workspace = true } -starknet-types = { workspace = true } starknet-checked-felt = { workspace = true } [dev-dependencies] diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index c28db400d..14e6b397a 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -15,7 +15,6 @@ use itertools::Itertools; use router_api::ChainName; use serde::Deserialize; use starknet_checked_felt::CheckedFelt; -use starknet_types::events::contract_call::ContractCallEvent; use tokio::sync::watch::Receiver; use tracing::info; use voting_verifier::msg::ExecuteMsg; @@ -25,6 +24,7 @@ use crate::handlers::errors::Error; use crate::handlers::errors::Error::DeserializeEvent; use crate::starknet::json_rpc::StarknetClient; use crate::starknet::verifier::verify_msg; +use crate::types::starknet::events::contract_call::ContractCallEvent; use crate::types::{Hash, TMAddress}; type Result = error_stack::Result; diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index aef3ad438..7ead3a6f2 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -9,10 +9,11 @@ use starknet_checked_felt::CheckedFelt; use starknet_core::types::{ExecutionResult, Felt, FromStrError, TransactionReceipt}; use starknet_providers::jsonrpc::JsonRpcTransport; use starknet_providers::{JsonRpcClient, Provider, ProviderError}; -use starknet_types::events::contract_call::ContractCallEvent; -use starknet_types::events::signers_rotated::SignersRotatedEvent; use thiserror::Error; +use crate::types::starknet::events::contract_call::ContractCallEvent; +use crate::types::starknet::events::signers_rotated::SignersRotatedEvent; + type Result = error_stack::Result; #[derive(Debug, Error)] @@ -183,10 +184,10 @@ mod test { HttpTransportError, JsonRpcMethod, JsonRpcResponse, JsonRpcTransport, }; use starknet_providers::{ProviderError, ProviderRequestData}; - use starknet_types::events::contract_call::ContractCallEvent; - use starknet_types::events::signers_rotated::SignersRotatedEvent; use super::{Client, StarknetClient, StarknetClientError}; + use crate::types::starknet::events::contract_call::ContractCallEvent; + use crate::types::starknet::events::signers_rotated::SignersRotatedEvent; #[tokio::test] async fn invalid_signers_rotated_event_tx_fetch() { @@ -325,8 +326,8 @@ mod test { 226, 62, 119, 4, 210, 79, 100, 110, 94, 54, 44, 97, 64, 122, 105, 210, 212, 32, 63, 225, 67, 54, 50, 83, 200, 154, 39, 162, 106, 108, 184, 31, ], - signers: starknet_types::events::signers_rotated::WeightedSigners { - signers: vec![starknet_types::events::signers_rotated::Signer { + signers: crate::types::starknet::events::signers_rotated::WeightedSigners { + signers: vec![crate::types::starknet::events::signers_rotated::Signer { signer: "0x3ec7d572a0fe479768ac46355651f22a982b99cc".to_string(), weight: 1, }], diff --git a/ampd/src/starknet/verifier.rs b/ampd/src/starknet/verifier.rs index e122ddca6..5b8915338 100644 --- a/ampd/src/starknet/verifier.rs +++ b/ampd/src/starknet/verifier.rs @@ -1,11 +1,11 @@ use axelar_wasm_std::voting::Vote; use cosmwasm_std::HexBinary; use starknet_core::types::Felt; -use starknet_types::events::contract_call::ContractCallEvent; -use starknet_types::events::signers_rotated::SignersRotatedEvent; use crate::handlers::starknet_verify_msg::Message; use crate::handlers::starknet_verify_verifier_set::VerifierSetConfirmation; +use crate::types::starknet::events::contract_call::ContractCallEvent; +use crate::types::starknet::events::signers_rotated::SignersRotatedEvent; /// Attempts to fetch the tx provided in `axl_msg.tx_id`. /// If successful, extracts and parses the ContractCall event @@ -98,15 +98,15 @@ mod tests { use router_api::ChainName; use starknet_checked_felt::CheckedFelt; use starknet_core::types::Felt; - use starknet_types::events::contract_call::ContractCallEvent; - use starknet_types::events::signers_rotated::{ - Signer as StarknetSigner, SignersRotatedEvent, WeightedSigners, - }; use super::verify_msg; use crate::handlers::starknet_verify_msg::Message; use crate::handlers::starknet_verify_verifier_set::VerifierSetConfirmation; use crate::starknet::verifier::verify_verifier_set; + use crate::types::starknet::events::contract_call::ContractCallEvent; + use crate::types::starknet::events::signers_rotated::{ + Signer as StarknetSigner, SignersRotatedEvent, WeightedSigners, + }; // "hello" as payload // "hello" as destination address diff --git a/ampd/src/types/mod.rs b/ampd/src/types/mod.rs index 121c2ee7c..80047e8fb 100644 --- a/ampd/src/types/mod.rs +++ b/ampd/src/types/mod.rs @@ -6,7 +6,7 @@ use ethers_core::types::{Address, H256}; use serde::{Deserialize, Serialize}; mod key; - +pub(crate) mod starknet; pub use key::{CosmosPublicKey, PublicKey}; pub type EVMAddress = Address; diff --git a/packages/starknet-types/src/types/byte_array.rs b/ampd/src/types/starknet/byte_array.rs similarity index 99% rename from packages/starknet-types/src/types/byte_array.rs rename to ampd/src/types/starknet/byte_array.rs index e9bc10dcf..7d885d941 100644 --- a/packages/starknet-types/src/types/byte_array.rs +++ b/ampd/src/types/starknet/byte_array.rs @@ -9,8 +9,7 @@ use thiserror::Error; /// /// ## Example usage with the string "hello" /// -/// ```rust -/// use starknet_types::types::byte_array::ByteArray; +/// use ampd::types::starknet::byte_array::ByteArray; /// use std::str::FromStr; /// use starknet_core::types::Felt; /// use starknet_core::types::FromStrError; @@ -26,7 +25,6 @@ use thiserror::Error; /// /// let byte_array = ByteArray::try_from(data.unwrap()); /// assert!(byte_array.is_ok()); -/// ``` /// /// For more info: /// https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays @@ -137,8 +135,7 @@ impl ByteArray { /// /// ## Example usage with the string "hello" /// - /// ```rust - /// use starknet_types::types::byte_array::ByteArray; + /// use ampd::types::starknet::byte_array::ByteArray; /// use std::str::FromStr; /// use starknet_core::types::Felt; /// use starknet_core::types::FromStrError; @@ -154,7 +151,6 @@ impl ByteArray { /// /// let byte_array = ByteArray::try_from(data.unwrap()).unwrap(); /// assert_eq!("hello", byte_array.try_to_string().unwrap()); - /// ``` /// /// Additional documentation you can find here: /// https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/serialization_of_Cairo_types/#serialization_of_byte_arrays diff --git a/packages/starknet-types/src/events/contract_call.rs b/ampd/src/types/starknet/events/contract_call.rs similarity index 97% rename from packages/starknet-types/src/events/contract_call.rs rename to ampd/src/types/starknet/events/contract_call.rs index 0f8eacf4d..fa141f7c5 100644 --- a/packages/starknet-types/src/events/contract_call.rs +++ b/ampd/src/types/starknet/events/contract_call.rs @@ -3,7 +3,7 @@ use starknet_core::types::Felt; use starknet_core::utils::{parse_cairo_short_string, ParseCairoShortStringError}; use thiserror::Error; -use crate::types::byte_array::{ByteArray, ByteArrayError}; +use crate::types::starknet::byte_array::{ByteArray, ByteArrayError}; /// This is the event emitted by the gateway cairo contract on Starknet, /// when the call_contract method is called from a third party. @@ -134,8 +134,8 @@ mod tests { use starknet_core::utils::starknet_keccak; use super::ContractCallEvent; - use crate::events::contract_call::ContractCallError; - use crate::types::byte_array::ByteArrayError; + use crate::types::starknet::byte_array::ByteArrayError; + use crate::types::starknet::events::contract_call::ContractCallError; #[test] fn destination_address_chunks_offset_out_of_range() { diff --git a/ampd/src/types/starknet/events/mod.rs b/ampd/src/types/starknet/events/mod.rs new file mode 100644 index 000000000..f5637736b --- /dev/null +++ b/ampd/src/types/starknet/events/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod contract_call; +pub(crate) mod signers_rotated; diff --git a/packages/starknet-types/src/events/signers_rotated.rs b/ampd/src/types/starknet/events/signers_rotated.rs similarity index 98% rename from packages/starknet-types/src/events/signers_rotated.rs rename to ampd/src/types/starknet/events/signers_rotated.rs index 2968e341a..5e953dbff 100644 --- a/packages/starknet-types/src/events/signers_rotated.rs +++ b/ampd/src/types/starknet/events/signers_rotated.rs @@ -23,11 +23,6 @@ pub enum SignersRotatedErrors { #[error("incorrect epoch for transaction")] IncorrectEpoch, - /// Error returned when the first key doesn't correspod to the - /// SignersRotated event. - #[error("not a SignersRotated event")] - InvalidEvent, - /// Error returned when the threshold in a transaction is invalid or /// unexpected. #[error("incorrect threshold for transaction")] diff --git a/ampd/src/types/starknet/mod.rs b/ampd/src/types/starknet/mod.rs new file mode 100644 index 000000000..5411ea2d7 --- /dev/null +++ b/ampd/src/types/starknet/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod byte_array; +pub(crate) mod events; diff --git a/packages/starknet-message/Cargo.toml b/packages/starknet-message/Cargo.toml new file mode 100644 index 000000000..593119fcc --- /dev/null +++ b/packages/starknet-message/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "starknet-message" +version = "1.0.0" +rust-version.workspace = true +edition.workspace = true + +[dependencies] +# axelar-wasm-std = { workspace = true, features = ["derive"] } +# cosmwasm-std = { workspace = true } +router-api = { workspace = true } +ethers-core = { workspace = true } +starknet-checked-felt = { workspace = true } +# starknet-core = { workspace = true } +starknet-types-core = { workspace = true } +error-stack = { workspace = true } +thiserror = { workspace = true } +# itertools = { workspace = true } +# hex = { workspace = true } +# tokio = { version = "1", features = [ +# "rt", +# "signal", +# "rt-multi-thread", +# "macros", +# ] } +# rand = { workspace = true } + +[lints] +workspace = true diff --git a/packages/starknet-types/src/types/starknet_message.rs b/packages/starknet-message/src/lib.rs similarity index 98% rename from packages/starknet-types/src/types/starknet_message.rs rename to packages/starknet-message/src/lib.rs index 33ada5400..823fb65b6 100644 --- a/packages/starknet-types/src/types/starknet_message.rs +++ b/packages/starknet-message/src/lib.rs @@ -7,8 +7,13 @@ use ethers_core::abi::{ use ethers_core::types::U256; use router_api::Message as RouterMessage; use starknet_checked_felt::CheckedFelt; +use thiserror::Error; -use crate::error::Error; +#[derive(Error, Debug)] +pub enum Error { + #[error("invalid starknet address")] + InvalidAddress, +} /// A message that is encoded in the prover and later sent to the Starknet gateway. #[derive(Clone, Debug, PartialEq)] @@ -127,7 +132,7 @@ mod tests { use ethers_core::abi::{InvalidOutputType, Token, Tokenizable}; use ethers_core::types::U256; use starknet_checked_felt::CheckedFelt; - use starknet_core::types::Felt; + use starknet_types_core::felt::Felt; use super::StarknetMessage; diff --git a/packages/starknet-types/Cargo.toml b/packages/starknet-types/Cargo.toml deleted file mode 100644 index 37e1a9b38..000000000 --- a/packages/starknet-types/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "starknet-types" -version = "1.0.0" -rust-version.workspace = true -edition.workspace = true - -[dependencies] -axelar-wasm-std = { workspace = true, features = ["derive"] } -cosmwasm-std = { workspace = true } -router-api = { workspace = true } -ethers-core = { workspace = true } -starknet-checked-felt = { workspace = true } -starknet-core = { workspace = true } -starknet-types-core = { workspace = true } -error-stack = { workspace = true } -thiserror = { workspace = true } -itertools = { workspace = true } -hex = { workspace = true } -tokio = { version = "1", features = [ - "rt", - "signal", - "rt-multi-thread", - "macros", -] } -rand = { workspace = true } - -[lints] -workspace = true diff --git a/packages/starknet-types/src/error.rs b/packages/starknet-types/src/error.rs deleted file mode 100644 index a8e5bc2b8..000000000 --- a/packages/starknet-types/src/error.rs +++ /dev/null @@ -1,7 +0,0 @@ -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum Error { - #[error("invalid starknet address")] - InvalidAddress, -} diff --git a/packages/starknet-types/src/events.rs b/packages/starknet-types/src/events.rs deleted file mode 100644 index dfe883063..000000000 --- a/packages/starknet-types/src/events.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod contract_call; -pub mod signers_rotated; diff --git a/packages/starknet-types/src/lib.rs b/packages/starknet-types/src/lib.rs deleted file mode 100644 index 7f2db3c29..000000000 --- a/packages/starknet-types/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod error; -pub mod events; -pub mod types; diff --git a/packages/starknet-types/src/types.rs b/packages/starknet-types/src/types.rs deleted file mode 100644 index ec5766d15..000000000 --- a/packages/starknet-types/src/types.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod byte_array; -pub mod starknet_message; From 4068eb5af7d452647246d7f403f244b09d65bec4 Mon Sep 17 00:00:00 2001 From: Marcin Bieszke Date: Tue, 21 Jan 2025 13:00:06 +0100 Subject: [PATCH 17/26] PartialEq implementetation for SignersRotatedEvent, returns false if couldn't deserialise the key --- ampd/src/starknet/verifier.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ampd/src/starknet/verifier.rs b/ampd/src/starknet/verifier.rs index 5b8915338..e57caf890 100644 --- a/ampd/src/starknet/verifier.rs +++ b/ampd/src/starknet/verifier.rs @@ -57,15 +57,17 @@ impl PartialEq for SignersRotatedEvent { let mut expected_signers = expected .signers .values() - .map(|signer| { - if let multisig::key::PublicKey::Ecdsa(pubkey) = &signer.pub_key { - (pubkey.clone(), signer.weight.u128()) - } else { - // Skip non-ECDSA keys - (HexBinary::from_hex("").unwrap(), 0) + .filter_map(|signer| match &signer.pub_key { + multisig::key::PublicKey::Ecdsa(pubkey) => { + Some((pubkey.clone(), signer.weight.u128())) } + _ => None, }) .collect::>(); + + if expected_signers.is_empty() { + return false; + } expected_signers.sort(); // Convert and sort actual signers from the event From a06cec2b9990b7a6ba610134d4e715d1612c1f98 Mon Sep 17 00:00:00 2001 From: Marcin Bieszke Date: Tue, 21 Jan 2025 13:01:49 +0100 Subject: [PATCH 18/26] remove zero nonce check from verify_verifier_set --- ampd/src/starknet/verifier.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ampd/src/starknet/verifier.rs b/ampd/src/starknet/verifier.rs index e57caf890..2458132a2 100644 --- a/ampd/src/starknet/verifier.rs +++ b/ampd/src/starknet/verifier.rs @@ -39,10 +39,7 @@ pub fn verify_verifier_set( confirmation: &VerifierSetConfirmation, source_gateway_address: &str, ) -> Vote { - if event.signers.nonce != [0_u8; 32] - && event == confirmation - && event.from_address == source_gateway_address - { + if event == confirmation && event.from_address == source_gateway_address { Vote::SucceededOnChain } else { Vote::NotFound From 356c9909078ce6e3caa80d645db29e9e2c3364b2 Mon Sep 17 00:00:00 2001 From: Marcin Bieszke Date: Tue, 21 Jan 2025 13:05:05 +0100 Subject: [PATCH 19/26] remove obsolete test for non-zero nonce / functionality at check isn't there anymore --- ampd/src/starknet/verifier.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/ampd/src/starknet/verifier.rs b/ampd/src/starknet/verifier.rs index 2458132a2..a6ebff07e 100644 --- a/ampd/src/starknet/verifier.rs +++ b/ampd/src/starknet/verifier.rs @@ -319,19 +319,6 @@ mod tests { ); } - #[test] - fn should_not_verify_verifier_set_if_nonce_zero() { - let mut event = mock_valid_event_signers_rotated(); - event.signers.nonce = [0_u8; 32]; - let gateway_address = - String::from("0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e"); - let confirmation = mock_valid_confirmation_signers_rotated(); - - assert_eq!( - verify_verifier_set(&event, &confirmation, &gateway_address), - Vote::NotFound - ); - } #[test] fn shoud_not_verify_verifier_set_if_signers_mismatch() { let source_gw_address = From d56b276b78c1b74593dad3a9ec22ce7a75849050 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Tue, 28 Jan 2025 14:46:26 +0200 Subject: [PATCH 20/26] move starknet-messages to eiger's fork --- Cargo.lock | 12 -- Cargo.toml | 1 - packages/starknet-message/Cargo.toml | 28 --- packages/starknet-message/src/lib.rs | 267 --------------------------- 4 files changed, 308 deletions(-) delete mode 100644 packages/starknet-message/Cargo.toml delete mode 100644 packages/starknet-message/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 43976d519..0ee614175 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8312,18 +8312,6 @@ dependencies = [ "starknet-types-core", ] -[[package]] -name = "starknet-message" -version = "1.0.0" -dependencies = [ - "error-stack", - "ethers-core", - "router-api", - "starknet-checked-felt", - "starknet-types-core", - "thiserror 1.0.69", -] - [[package]] name = "starknet-providers" version = "0.12.0" diff --git a/Cargo.toml b/Cargo.toml index 5e54a74c2..078c73c8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,7 +80,6 @@ sui-gateway = { version = "^1.0.0", path = "packages/sui-gateway" } sui-types = { version = "^1.0.0", path = "packages/sui-types" } starknet-checked-felt = { version = "^1.0.0", path = "packages/starknet-checked-felt" } starknet-types-core = { version = "0.1.7" } -starknet-message = { version = "^1.0.0", path = "packages/starknet-message" } starknet-core = "0.12.0" starknet-providers = "0.12.0" syn = "2.0.92" diff --git a/packages/starknet-message/Cargo.toml b/packages/starknet-message/Cargo.toml deleted file mode 100644 index 593119fcc..000000000 --- a/packages/starknet-message/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "starknet-message" -version = "1.0.0" -rust-version.workspace = true -edition.workspace = true - -[dependencies] -# axelar-wasm-std = { workspace = true, features = ["derive"] } -# cosmwasm-std = { workspace = true } -router-api = { workspace = true } -ethers-core = { workspace = true } -starknet-checked-felt = { workspace = true } -# starknet-core = { workspace = true } -starknet-types-core = { workspace = true } -error-stack = { workspace = true } -thiserror = { workspace = true } -# itertools = { workspace = true } -# hex = { workspace = true } -# tokio = { version = "1", features = [ -# "rt", -# "signal", -# "rt-multi-thread", -# "macros", -# ] } -# rand = { workspace = true } - -[lints] -workspace = true diff --git a/packages/starknet-message/src/lib.rs b/packages/starknet-message/src/lib.rs deleted file mode 100644 index 823fb65b6..000000000 --- a/packages/starknet-message/src/lib.rs +++ /dev/null @@ -1,267 +0,0 @@ -use std::str::FromStr; - -use error_stack::{Report, ResultExt}; -use ethers_core::abi::{ - AbiDecode, AbiError, AbiType, Detokenize, InvalidOutputType, ParamType, Token, Tokenizable, -}; -use ethers_core::types::U256; -use router_api::Message as RouterMessage; -use starknet_checked_felt::CheckedFelt; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum Error { - #[error("invalid starknet address")] - InvalidAddress, -} - -/// A message that is encoded in the prover and later sent to the Starknet gateway. -#[derive(Clone, Debug, PartialEq)] -pub struct StarknetMessage { - pub source_chain: String, - pub message_id: String, - pub source_address: String, - pub contract_address: CheckedFelt, - pub payload_hash: U256, -} - -impl TryFrom<&RouterMessage> for StarknetMessage { - type Error = Report; - - fn try_from(msg: &RouterMessage) -> Result { - let contract_address = CheckedFelt::from_str(msg.destination_address.as_str()) - .change_context(Error::InvalidAddress)?; - - Ok(StarknetMessage { - source_chain: msg.cc_id.source_chain.to_string(), - message_id: msg.cc_id.message_id.to_string(), - source_address: msg.source_address.to_string(), - contract_address, - payload_hash: U256::from(msg.payload_hash), - }) - } -} - -impl AbiType for StarknetMessage { - fn param_type() -> ParamType { - ParamType::Tuple(vec![ - ethers_core::abi::ParamType::String, - ethers_core::abi::ParamType::String, - ethers_core::abi::ParamType::String, - ethers_core::abi::ParamType::FixedBytes(32usize), - ::param_type(), - ]) - } -} - -impl AbiDecode for StarknetMessage { - fn decode(bytes: impl AsRef<[u8]>) -> Result { - let tokens = ethers_core::abi::decode(&[Self::param_type()], bytes.as_ref())?; - Ok(::from_tokens(tokens)?) - } -} - -impl Tokenizable for StarknetMessage { - fn from_token(token: Token) -> Result - where - Self: Sized, - { - if let Token::Tuple(tokens) = token { - if tokens.len() != 5 { - return Err(InvalidOutputType( - "failed to read tokens: starknet message should have 5 tokens".to_string(), - )); - } - - if let ( - Token::String(source_chain), - Token::String(message_id), - Token::String(source_address), - Token::FixedBytes(contract_address), - Token::Uint(payload_hash), - ) = ( - tokens[0].clone(), - tokens[1].clone(), - tokens[2].clone(), - tokens[3].clone(), - tokens[4].clone(), - ) { - let contract_address_felt: CheckedFelt = - CheckedFelt::try_from(contract_address.as_slice()).map_err(|e| { - InvalidOutputType( - format!( - "failed to convert contract_address bytes to field element (felt): {}", - e - ) - .to_string(), - ) - })?; - - return Ok(StarknetMessage { - source_chain, - message_id, - source_address, - contract_address: contract_address_felt, - payload_hash, - }); - } - } - - Err(InvalidOutputType( - "failed to convert tokens to StarknetMessage".to_string(), - )) - } - - fn into_token(self) -> Token { - let contract_address_bytes = self.contract_address.to_bytes_be().to_vec(); - - Token::Tuple(vec![ - Token::String(self.source_chain), - Token::String(self.message_id), - Token::String(self.source_address), - Token::FixedBytes(contract_address_bytes), - Token::Uint(self.payload_hash), - ]) - } -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use ethers_core::abi::{InvalidOutputType, Token, Tokenizable}; - use ethers_core::types::U256; - use starknet_checked_felt::CheckedFelt; - use starknet_types_core::felt::Felt; - - use super::StarknetMessage; - - #[test] - fn starknet_message_from_token_should_error_on_non_tuple() { - // pas something else than a Token::Tuple - let starknet_msg_token = Token::String("not a starknet message".to_string()); - - let result = StarknetMessage::from_token(starknet_msg_token); - - // Tested like this, because InvalidOutputType doesn't implement PartialEq - assert!( - matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert tokens to StarknetMessage") - ); - } - - #[test] - fn starknet_message_from_token_should_error_on_failing_felt_conversion() { - // overflow the 31 byte size of a Felt - let starknet_msg_token = Token::Tuple(vec![ - Token::String("starknet".to_string()), - Token::String("some_msg_id".to_string()), - Token::String("some_source_address".to_string()), - Token::FixedBytes(vec![ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - ]), - Token::Uint(U256::from(123)), - ]); - - let result = StarknetMessage::from_token(starknet_msg_token); - - // Tested like this, because InvalidOutputType doesn't implement PartialEq - assert!( - matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert contract_address bytes to field element (felt): Felt value overflowing the Felt::MAX, value") - ); - } - - #[test] - fn starknet_message_from_token_should_error_on_failing_contract_address_conversion() { - // more than 32 bytes for contract address - let starknet_msg_token = Token::Tuple(vec![ - Token::String("starknet".to_string()), - Token::String("some_msg_id".to_string()), - Token::String("some_source_address".to_string()), - Token::FixedBytes(vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 2, 1, - ]), - Token::Uint(U256::from(123)), - ]); - - let result = StarknetMessage::from_token(starknet_msg_token); - - // Tested like this, because InvalidOutputType doesn't implement PartialEq - assert!( - matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to convert contract_address bytes to field element (felt): Felt value overflowing the Felt::MAX, value") - ); - } - - #[test] - fn starknet_message_from_token_should_error_on_less_tokens() { - // removed last token - let starknet_msg_token = Token::Tuple(vec![ - Token::String("starknet".to_string()), - Token::String("some_msg_id".to_string()), - Token::String("some_source_address".to_string()), - Token::FixedBytes(vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, - ]), - ]); - - let result = StarknetMessage::from_token(starknet_msg_token); - - // Tested like this, because InvalidOutputType doesn't implement PartialEq - assert!( - matches!(result, Err(InvalidOutputType(msg)) if msg == "failed to read tokens: starknet message should have 5 tokens") - ); - } - - #[test] - fn starknet_message_from_token_should_be_converted_from_tokens_successfully() { - let starknet_msg_token = Token::Tuple(vec![ - Token::String("starknet".to_string()), - Token::String("some_msg_id".to_string()), - Token::String("some_source_address".to_string()), - Token::FixedBytes(vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, - ]), - Token::Uint(U256::from(123)), - ]); - - let expected = StarknetMessage { - source_chain: "starknet".to_string(), - message_id: "some_msg_id".to_string(), - source_address: "some_source_address".to_string(), - contract_address: CheckedFelt::from_str(&Felt::THREE.to_fixed_hex_string()).unwrap(), - payload_hash: U256::from(123), - }; - - assert_eq!( - StarknetMessage::from_token(starknet_msg_token).unwrap(), - expected - ); - } - - #[test] - fn starknet_message_should_convert_to_token() { - let starknet_message = StarknetMessage { - source_chain: "starknet".to_string(), - message_id: "some_msg_id".to_string(), - source_address: "some_source_address".to_string(), - contract_address: CheckedFelt::from_str(&Felt::THREE.to_fixed_hex_string()).unwrap(), - payload_hash: U256::from(123), - }; - - let expected = Token::Tuple(vec![ - Token::String("starknet".to_string()), - Token::String("some_msg_id".to_string()), - Token::String("some_source_address".to_string()), - Token::FixedBytes(vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, - ]), - Token::Uint(U256::from(123)), - ]); - - assert_eq!(starknet_message.into_token(), expected); - } -} From d03f7648c1e006b5b581261b183fb120ec489d0f Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Tue, 28 Jan 2025 18:57:52 +0200 Subject: [PATCH 21/26] use event_index to fetch only needed events --- ampd/src/handlers/starknet_verify_msg.rs | 104 ++++++------- ampd/src/starknet/json_rpc.rs | 178 +++++++++++------------ 2 files changed, 140 insertions(+), 142 deletions(-) diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index 14e6b397a..f32db0859 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -7,10 +7,10 @@ use axelar_wasm_std::voting::{PollId, Vote}; use cosmrs::cosmwasm::MsgExecuteContract; use cosmrs::tx::Msg; use cosmrs::Any; -use error_stack::{FutureExt, ResultExt}; +use error_stack::ResultExt; use events::Error::EventTypeMismatch; use events_derive::try_from; -use futures::future::try_join_all; +use futures::future::join_all; use itertools::Itertools; use router_api::ChainName; use serde::Deserialize; @@ -133,12 +133,11 @@ where // key is the message_id of the tx holding the event let mut events: HashMap = - try_join_all(unique_msgs.iter().map(|msg| { + join_all(unique_msgs.iter().map(|msg| { self.rpc_client - .get_events_by_hash_contract_call(msg.message_id.tx_hash.clone()) + .get_events_by_hash_contract_call(msg.message_id.clone()) })) - .change_context(Error::TxReceipts) - .await? + .await .into_iter() .flatten() .collect(); @@ -193,42 +192,42 @@ mod tests { rpc_client .expect_get_events_by_hash_contract_call() .returning(|_| { - Ok(vec![ - ( - FieldElementAndEventIndex::from_str( - "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0", - ) - .unwrap(), - ContractCallEvent { - from_contract_addr: String::from("source-gw-addr"), - destination_address: String::from("destination-address"), - destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE, - payload_hash: H256::from_slice(&[ - 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, - 40, 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, - 109, 234, 200, - ]), - }, - ), - ( - FieldElementAndEventIndex::from_str( - "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-1", - ) - .unwrap(), - ContractCallEvent { - from_contract_addr: String::from("source-gw-addr"), - destination_address: String::from("destination-address-1"), - destination_chain: "ethereum-1".parse().unwrap(), - source_address: Felt::TWO, - payload_hash: H256::from_slice(&[ - 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, - 40, 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, - 109, 234, 200, - ]), - }, - ), - ]) + Some(( + FieldElementAndEventIndex::from_str( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0", + ) + .unwrap(), + ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address"), + destination_chain: "ethereum".parse().unwrap(), + source_address: Felt::ONE, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, + 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, + 234, 200, + ]), + }, + )) + }) + .returning(|_| { + Some(( + FieldElementAndEventIndex::from_str( + "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-1", + ) + .unwrap(), + ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address-1"), + destination_chain: "ethereum-1".parse().unwrap(), + source_address: Felt::TWO, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, + 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, + 234, 200, + ]), + }, + )) }); let event: Event = get_event( @@ -259,7 +258,7 @@ mod tests { rpc_client .expect_get_events_by_hash_contract_call() .returning(|_| { - Ok(vec![( + Some(( FieldElementAndEventIndex::from_str( "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0", ) @@ -275,7 +274,7 @@ mod tests { 234, 200, ]), }, - )]) + )) }); let event: Event = get_event( @@ -303,14 +302,17 @@ mod tests { rpc_client .expect_get_events_by_hash_contract_call() .once() - .with(eq(CheckedFelt::from_str( - "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", - ) - .unwrap())) + .with(eq(FieldElementAndEventIndex { + tx_hash: CheckedFelt::from_str( + "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f", + ) + .unwrap(), + event_index: 1, + })) .returning(|_| { - Ok(vec![( + Some(( FieldElementAndEventIndex::from_str( - "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f-0", + "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f-1", ) .unwrap(), ContractCallEvent { @@ -324,7 +326,7 @@ mod tests { 234, 200, ]), }, - )]) + )) }); let event: Event = get_event( diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index 7ead3a6f2..61a5c6db5 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -2,36 +2,32 @@ //! transaction existence use async_trait::async_trait; -use axelar_wasm_std::msg_id::{Error as MessageFormatError, FieldElementAndEventIndex}; +use axelar_wasm_std::msg_id::FieldElementAndEventIndex; use error_stack::Report; use mockall::automock; use starknet_checked_felt::CheckedFelt; -use starknet_core::types::{ExecutionResult, Felt, FromStrError, TransactionReceipt}; +use starknet_core::types::{ExecutionResult, Felt, TransactionReceipt}; use starknet_providers::jsonrpc::JsonRpcTransport; use starknet_providers::{JsonRpcClient, Provider, ProviderError}; use thiserror::Error; -use crate::types::starknet::events::contract_call::ContractCallEvent; +use crate::types::starknet::events::contract_call::{ContractCallError, ContractCallEvent}; use crate::types::starknet::events::signers_rotated::SignersRotatedEvent; type Result = error_stack::Result; #[derive(Debug, Error)] pub enum StarknetClientError { + #[error(transparent)] + ContractCallError(#[from] ContractCallError), #[error(transparent)] UrlParseError(#[from] url::ParseError), #[error(transparent)] JsonDeserializeError(#[from] serde_json::Error), #[error("Failed to fetch tx receipt: {0}")] FetchingReceipt(#[from] ProviderError), - #[error("Failed to create field element from string: {0}")] - FeltFromString(#[from] FromStrError), #[error("Tx not successful")] UnsuccessfulTx, - #[error("u64 overflowed")] - OverflowingU64, - #[error("Failed to construct message_id from event: {0}")] - MessageIdConstruction(#[from] MessageFormatError), } /// Implementor of verification method(s) for given network using JSON RPC @@ -63,12 +59,12 @@ where #[automock] #[async_trait] pub trait StarknetClient { - /// Attempts to fetch a ContractCall event, by a given `tx_hash`. - /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. + /// Attempts to fetch a ContractCall event, by a given `message_id`. + /// Returns the event or a `StarknetClientError`. async fn get_events_by_hash_contract_call( &self, - tx_hash: CheckedFelt, - ) -> Result>; + message_id: FieldElementAndEventIndex, + ) -> Option<(FieldElementAndEventIndex, ContractCallEvent)>; /// Attempts to fetch a SignersRotated event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. @@ -87,48 +83,32 @@ where // `ContractCallEvent` async fn get_events_by_hash_contract_call( &self, - tx_hash: CheckedFelt, - ) -> Result> { + message_id: FieldElementAndEventIndex, + ) -> Option<(FieldElementAndEventIndex, ContractCallEvent)> { let receipt_with_block_info = self .client - .get_transaction_receipt(tx_hash.clone()) + .get_transaction_receipt(message_id.tx_hash.clone()) .await - .map_err(StarknetClientError::FetchingReceipt)?; + .ok()?; if *receipt_with_block_info.receipt.execution_result() != ExecutionResult::Succeeded { - return Err(Report::new(StarknetClientError::UnsuccessfulTx)); + return None; } - let mut message_id_and_event_pairs: Vec<(FieldElementAndEventIndex, ContractCallEvent)> = - vec![]; - match receipt_with_block_info.receipt { TransactionReceipt::Invoke(tx) => { - let mut event_index: u64 = 0; - // The RPC node always returns the events in the same order, - // so we can be sure that the msg ids will have the same indexes - // when iterating them - for e in tx.events.clone() { - if let Ok(cce) = ContractCallEvent::try_from(e.clone()) { - let message_id = - FieldElementAndEventIndex::new(tx_hash.clone(), event_index) - .map_err(StarknetClientError::MessageIdConstruction)?; - message_id_and_event_pairs.push((message_id, cce)); - } - // we iterate regardless of the event type, - // because that's what we do in the relayer - event_index = event_index - .checked_add(1) - .ok_or(StarknetClientError::OverflowingU64)?; - } - } - TransactionReceipt::L1Handler(_) => (), - TransactionReceipt::Declare(_) => (), - TransactionReceipt::Deploy(_) => (), - TransactionReceipt::DeployAccount(_) => (), - }; + let event_index: usize = message_id.event_index.try_into().ok()?; + let event = tx.events.get(event_index)?; - Ok(message_id_and_event_pairs) + ContractCallEvent::try_from(event.clone()) + .map(|cce| (message_id, cce)) + .ok() + } + TransactionReceipt::L1Handler(_) => None, + TransactionReceipt::Declare(_) => None, + TransactionReceipt::Deploy(_) => None, + TransactionReceipt::DeployAccount(_) => None, + } } // Fetches a transaction receipt by hash and extracts a `SignersRotatedEvent` if present @@ -206,48 +186,52 @@ mod test { async fn deploy_account_tx_fetch() { let mock_client = Client::new_with_transport(DeployAccountMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_events.unwrap().is_empty()); + assert!(contract_call_events.is_none()); } #[tokio::test] async fn deploy_tx_fetch() { let mock_client = Client::new_with_transport(DeployMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_events.unwrap().is_empty()); + assert!(contract_call_events.is_none()); } #[tokio::test] async fn l1_handler_tx_fetch() { let mock_client = Client::new_with_transport(L1HandlerMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_events.unwrap().is_empty()); + assert!(contract_call_events.is_none()); } #[tokio::test] async fn declare_tx_fetch() { let mock_client = Client::new_with_transport(DeclareMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_events.unwrap().is_empty()); + assert!(contract_call_events.is_none()); } #[tokio::test] @@ -255,50 +239,52 @@ mod test { let mock_client = Client::new_with_transport(InvalidContractCallEventMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_events.unwrap().is_empty()); + assert!(contract_call_events.is_none()); } #[tokio::test] async fn no_events_tx_fetch() { let mock_client = Client::new_with_transport(NoEventsMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_events.unwrap().is_empty()); + assert!(contract_call_events.is_none()); } #[tokio::test] async fn reverted_tx_fetch() { let mock_client = Client::new_with_transport(RevertedMockTransport).unwrap(); let contract_call_event = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_event - .unwrap_err() - .contains::()); + assert!(contract_call_event.is_none()) } #[tokio::test] async fn failing_tx_fetch() { let mock_client = Client::new_with_transport(FailingMockTransport).unwrap(); let contract_call_event = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_event.is_err()); + assert!(contract_call_event.is_none()); } #[tokio::test] @@ -347,21 +333,22 @@ mod test { let mock_client = Client::new_with_transport(ValidMockTransportTwoCallContractsInOneTx).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await .unwrap(); // unwrap the option assert_eq!( - contract_call_events[0].0, + contract_call_events.0, FieldElementAndEventIndex::from_str( "0x0000000000000000000000000000000000000000000000000000000000000001-0" ) .unwrap() ); assert_eq!( - contract_call_events[0].1, + contract_call_events.1, ContractCallEvent { from_contract_addr: "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), @@ -378,15 +365,23 @@ mod test { } ); + let contract_call_events_1 = mock_client + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 1, + }) + .await + .unwrap(); // unwrap the option + assert_eq!( - contract_call_events[1].0, + contract_call_events_1.0, FieldElementAndEventIndex::from_str( "0x0000000000000000000000000000000000000000000000000000000000000001-1" ) .unwrap() ); assert_eq!( - contract_call_events[1].1, + contract_call_events_1.1, ContractCallEvent { from_contract_addr: "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), @@ -408,21 +403,22 @@ mod test { async fn successful_call_contract_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportCallContract).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_events_by_hash_contract_call(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await .unwrap(); // unwrap the option assert_eq!( - contract_call_events[0].0, + contract_call_events.0, FieldElementAndEventIndex::from_str( "0x0000000000000000000000000000000000000000000000000000000000000001-0" ) .unwrap() ); assert_eq!( - contract_call_events[0].1, + contract_call_events.1, ContractCallEvent { from_contract_addr: "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), From 3aee888d2dbba763b8e8b327490402723eef2421 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Wed, 29 Jan 2025 17:33:08 +0200 Subject: [PATCH 22/26] remove uneccessary iteration --- ampd/src/handlers/starknet_verify_msg.rs | 153 +++++++++-------------- ampd/src/starknet/json_rpc.rs | 47 ++----- 2 files changed, 66 insertions(+), 134 deletions(-) diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index f32db0859..7e165391f 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::convert::TryInto; use async_trait::async_trait; @@ -24,7 +23,6 @@ use crate::handlers::errors::Error; use crate::handlers::errors::Error::DeserializeEvent; use crate::starknet::json_rpc::StarknetClient; use crate::starknet::verifier::verify_msg; -use crate::types::starknet::events::contract_call::ContractCallEvent; use crate::types::{Hash, TMAddress}; type Result = error_stack::Result; @@ -126,32 +124,22 @@ where return Ok(vec![]); } - let unique_msgs = messages - .iter() - .unique_by(|msg| msg.message_id.to_string()) - .collect::>(); - - // key is the message_id of the tx holding the event - let mut events: HashMap = - join_all(unique_msgs.iter().map(|msg| { - self.rpc_client - .get_events_by_hash_contract_call(msg.message_id.clone()) - })) - .await - .into_iter() - .flatten() - .collect(); - - let mut votes = vec![]; - for msg in unique_msgs { - match events.remove(&msg.message_id) { - Some(gateway_event) => { - votes.push(verify_msg(&gateway_event, msg, &source_gateway_address)); - } - - None => votes.push(Vote::NotFound), - } - } + let votes = join_all( + messages + .iter() + .unique_by(|msg| msg.message_id.to_string()) + .map(|msg| async { + match self + .rpc_client + .get_events_by_hash_contract_call(msg.message_id.clone()) + .await + { + Some(event) => verify_msg(&event, msg, &source_gateway_address), + None => Vote::NotFound, + } + }), + ) + .await; Ok(vec![self .vote_msg(poll_id, votes) @@ -164,6 +152,7 @@ where mod tests { use std::str::FromStr; + use crate::types::starknet::events::contract_call::ContractCallEvent; use base64::engine::general_purpose::STANDARD; use base64::Engine; use ethers_core::types::H256; @@ -192,42 +181,28 @@ mod tests { rpc_client .expect_get_events_by_hash_contract_call() .returning(|_| { - Some(( - FieldElementAndEventIndex::from_str( - "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0", - ) - .unwrap(), - ContractCallEvent { - from_contract_addr: String::from("source-gw-addr"), - destination_address: String::from("destination-address"), - destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE, - payload_hash: H256::from_slice(&[ - 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, - 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, - 234, 200, - ]), - }, - )) + Some(ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address"), + destination_chain: "ethereum".parse().unwrap(), + source_address: Felt::ONE, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]), + }) }) .returning(|_| { - Some(( - FieldElementAndEventIndex::from_str( - "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-1", - ) - .unwrap(), - ContractCallEvent { - from_contract_addr: String::from("source-gw-addr"), - destination_address: String::from("destination-address-1"), - destination_chain: "ethereum-1".parse().unwrap(), - source_address: Felt::TWO, - payload_hash: H256::from_slice(&[ - 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, - 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, - 234, 200, - ]), - }, - )) + Some(ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address-1"), + destination_chain: "ethereum-1".parse().unwrap(), + source_address: Felt::TWO, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]), + }) }); let event: Event = get_event( @@ -258,23 +233,16 @@ mod tests { rpc_client .expect_get_events_by_hash_contract_call() .returning(|_| { - Some(( - FieldElementAndEventIndex::from_str( - "0x035410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439e-0", - ) - .unwrap(), - ContractCallEvent { - from_contract_addr: String::from("source-gw-addr"), - destination_address: String::from("destination-address"), - destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE, - payload_hash: H256::from_slice(&[ - 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, - 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, - 234, 200, - ]), - }, - )) + Some(ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address"), + destination_chain: "ethereum".parse().unwrap(), + source_address: Felt::ONE, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]), + }) }); let event: Event = get_event( @@ -310,23 +278,16 @@ mod tests { event_index: 1, })) .returning(|_| { - Some(( - FieldElementAndEventIndex::from_str( - "0x045410be6f4bf3f67f7c1bb4a93119d9d410b2f981bfafbf5dbbf5d37ae7439f-1", - ) - .unwrap(), - ContractCallEvent { - from_contract_addr: String::from("source-gw-addr"), - destination_address: String::from("destination-address"), - destination_chain: "ethereum".parse().unwrap(), - source_address: Felt::ONE, - payload_hash: H256::from_slice(&[ - 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, - 123, 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, - 234, 200, - ]), - }, - )) + Some(ContractCallEvent { + from_contract_addr: String::from("source-gw-addr"), + destination_address: String::from("destination-address"), + destination_chain: "ethereum".parse().unwrap(), + source_address: Felt::ONE, + payload_hash: H256::from_slice(&[ + 28u8, 138, 255, 149, 6, 133, 194, 237, 75, 195, 23, 79, 52, 114, 40, 123, + 86, 217, 81, 123, 156, 148, 129, 39, 49, 154, 9, 167, 163, 109, 234, 200, + ]), + }) }); let event: Event = get_event( diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index 61a5c6db5..01dfd25e2 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -64,7 +64,7 @@ pub trait StarknetClient { async fn get_events_by_hash_contract_call( &self, message_id: FieldElementAndEventIndex, - ) -> Option<(FieldElementAndEventIndex, ContractCallEvent)>; + ) -> Option; /// Attempts to fetch a SignersRotated event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. @@ -84,7 +84,7 @@ where async fn get_events_by_hash_contract_call( &self, message_id: FieldElementAndEventIndex, - ) -> Option<(FieldElementAndEventIndex, ContractCallEvent)> { + ) -> Option { let receipt_with_block_info = self .client .get_transaction_receipt(message_id.tx_hash.clone()) @@ -100,14 +100,9 @@ where let event_index: usize = message_id.event_index.try_into().ok()?; let event = tx.events.get(event_index)?; - ContractCallEvent::try_from(event.clone()) - .map(|cce| (message_id, cce)) - .ok() + ContractCallEvent::try_from(event.clone()).ok() } - TransactionReceipt::L1Handler(_) => None, - TransactionReceipt::Declare(_) => None, - TransactionReceipt::Deploy(_) => None, - TransactionReceipt::DeployAccount(_) => None, + _ => None, } } @@ -138,10 +133,7 @@ where } }) .next(), - TransactionReceipt::L1Handler(_) => None, - TransactionReceipt::Declare(_) => None, - TransactionReceipt::Deploy(_) => None, - TransactionReceipt::DeployAccount(_) => None, + _ => None, }; Ok(event) @@ -165,7 +157,7 @@ mod test { }; use starknet_providers::{ProviderError, ProviderRequestData}; - use super::{Client, StarknetClient, StarknetClientError}; + use super::{Client, StarknetClient}; use crate::types::starknet::events::contract_call::ContractCallEvent; use crate::types::starknet::events::signers_rotated::SignersRotatedEvent; @@ -341,14 +333,7 @@ mod test { .unwrap(); // unwrap the option assert_eq!( - contract_call_events.0, - FieldElementAndEventIndex::from_str( - "0x0000000000000000000000000000000000000000000000000000000000000001-0" - ) - .unwrap() - ); - assert_eq!( - contract_call_events.1, + contract_call_events, ContractCallEvent { from_contract_addr: "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), @@ -374,14 +359,7 @@ mod test { .unwrap(); // unwrap the option assert_eq!( - contract_call_events_1.0, - FieldElementAndEventIndex::from_str( - "0x0000000000000000000000000000000000000000000000000000000000000001-1" - ) - .unwrap() - ); - assert_eq!( - contract_call_events_1.1, + contract_call_events_1, ContractCallEvent { from_contract_addr: "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), @@ -411,14 +389,7 @@ mod test { .unwrap(); // unwrap the option assert_eq!( - contract_call_events.0, - FieldElementAndEventIndex::from_str( - "0x0000000000000000000000000000000000000000000000000000000000000001-0" - ) - .unwrap() - ); - assert_eq!( - contract_call_events.1, + contract_call_events, ContractCallEvent { from_contract_addr: "0x0000000000000000000000000000000000000000000000000000000000000002".to_owned(), From 95622bdad61ad54cced0eeb22b7445adbbf6e719 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Wed, 29 Jan 2025 17:36:33 +0200 Subject: [PATCH 23/26] smaller fixes --- ampd/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ampd/src/lib.rs b/ampd/src/lib.rs index 1fe5bba53..1806138a0 100644 --- a/ampd/src/lib.rs +++ b/ampd/src/lib.rs @@ -41,7 +41,7 @@ mod health_check; mod json_rpc; mod mvx; mod queue; -pub(crate) mod starknet; +mod starknet; mod stellar; mod sui; mod tm_client; @@ -402,7 +402,7 @@ where starknet::json_rpc::Client::new_with_transport(HttpTransport::new( &rpc_url, )) - .unwrap(), + .change_context(Error::Connection)?, self.block_height_monitor.latest_block_height(), ), event_processor_config.clone(), @@ -418,7 +418,7 @@ where starknet::json_rpc::Client::new_with_transport(HttpTransport::new( &rpc_url, )) - .unwrap(), + .change_context(Error::Connection)?, self.block_height_monitor.latest_block_height(), ), event_processor_config.clone(), From dcbb6d1883b192b65ed9ae7d500a77c880c7ff9a Mon Sep 17 00:00:00 2001 From: puhtaytow <18026645+puhtaytow@users.noreply.github.com> Date: Fri, 31 Jan 2025 09:41:53 +0100 Subject: [PATCH 24/26] fix: takes into account index when checking for events in verify verifier set (#58) * take into account index on checking for events in verify verifier set * remove useless tuple with felt and event; now its only event * fix functions name for verifier set and verify contract call * return None on verify verifier set, if something went wrong / remove result and some errors that applied to prev scenario * simplify logic of verify verifier set --- ampd/src/handlers/errors.rs | 2 - ampd/src/handlers/starknet_verify_msg.rs | 16 +-- .../handlers/starknet_verify_verifier_set.rs | 34 +++--- ampd/src/starknet/json_rpc.rs | 106 ++++++++---------- 4 files changed, 71 insertions(+), 87 deletions(-) diff --git a/ampd/src/handlers/errors.rs b/ampd/src/handlers/errors.rs index 365ea9280..876912a3b 100644 --- a/ampd/src/handlers/errors.rs +++ b/ampd/src/handlers/errors.rs @@ -10,6 +10,4 @@ pub enum Error { Sign, #[error("failed to get transaction receipts")] TxReceipts, - #[error("starknet client failed")] - StarknetClient, } diff --git a/ampd/src/handlers/starknet_verify_msg.rs b/ampd/src/handlers/starknet_verify_msg.rs index 7e165391f..70d03f5a2 100644 --- a/ampd/src/handlers/starknet_verify_msg.rs +++ b/ampd/src/handlers/starknet_verify_msg.rs @@ -131,7 +131,7 @@ where .map(|msg| async { match self .rpc_client - .get_events_by_hash_contract_call(msg.message_id.clone()) + .get_event_by_message_id_contract_call(msg.message_id.clone()) .await { Some(event) => verify_msg(&event, msg, &source_gateway_address), @@ -152,7 +152,6 @@ where mod tests { use std::str::FromStr; - use crate::types::starknet::events::contract_call::ContractCallEvent; use base64::engine::general_purpose::STANDARD; use base64::Engine; use ethers_core::types::H256; @@ -166,6 +165,7 @@ mod tests { use super::*; use crate::starknet::json_rpc::MockStarknetClient; + use crate::types::starknet::events::contract_call::ContractCallEvent; use crate::PREFIX; #[async_test] @@ -179,7 +179,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_events_by_hash_contract_call() + .expect_get_event_by_message_id_contract_call() .returning(|_| { Some(ContractCallEvent { from_contract_addr: String::from("source-gw-addr"), @@ -231,7 +231,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_events_by_hash_contract_call() + .expect_get_event_by_message_id_contract_call() .returning(|_| { Some(ContractCallEvent { from_contract_addr: String::from("source-gw-addr"), @@ -268,7 +268,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_events_by_hash_contract_call() + .expect_get_event_by_message_id_contract_call() .once() .with(eq(FieldElementAndEventIndex { tx_hash: CheckedFelt::from_str( @@ -316,7 +316,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_events_by_hash_contract_call() + .expect_get_event_by_message_id_contract_call() .times(0); let event: Event = get_event( @@ -344,7 +344,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_events_by_hash_contract_call() + .expect_get_event_by_message_id_contract_call() .times(0); let event: Event = get_event( @@ -370,7 +370,7 @@ mod tests { // Prepare the rpc client, which fetches the event and the vote broadcaster let mut rpc_client = MockStarknetClient::new(); rpc_client - .expect_get_events_by_hash_contract_call() + .expect_get_event_by_message_id_contract_call() .times(0); let event: Event = get_event( diff --git a/ampd/src/handlers/starknet_verify_verifier_set.rs b/ampd/src/handlers/starknet_verify_verifier_set.rs index 5140917f3..78d565bc1 100644 --- a/ampd/src/handlers/starknet_verify_verifier_set.rs +++ b/ampd/src/handlers/starknet_verify_verifier_set.rs @@ -125,9 +125,8 @@ where let transaction_response = self .rpc_client - .get_event_by_hash_signers_rotated(verifier_set.message_id.tx_hash.clone()) - .await - .change_context(Error::StarknetClient)?; + .get_event_by_message_id_signers_rotated(verifier_set.message_id.clone()) + .await; let vote = info_span!( "verify a new verifier set", @@ -137,9 +136,12 @@ where .in_scope(|| { info!("ready to verify verifier set in poll",); - let vote = transaction_response.map_or(Vote::NotFound, |tx_receipt| { - verify_verifier_set(&tx_receipt.1, &verifier_set, &source_gateway_address) - }); + let vote = match transaction_response { + None => Vote::NotFound, + Some(tx_receipt) => { + verify_verifier_set(&tx_receipt, &verifier_set, &source_gateway_address) + } + }; info!( vote = vote.as_value(), @@ -164,7 +166,7 @@ mod tests { use axelar_wasm_std::msg_id::FieldElementAndEventIndex; use base64::engine::general_purpose::STANDARD; use base64::Engine; - use error_stack::{Report, Result}; + use error_stack::Result; use ethers_core::types::U256; use events::Event; use multisig::key::KeyType; @@ -178,7 +180,7 @@ mod tests { use crate::event_processor::EventHandler; use crate::handlers::starknet_verify_verifier_set::PollStartedEvent; - use crate::starknet::json_rpc::{MockStarknetClient, StarknetClientError}; + use crate::starknet::json_rpc::MockStarknetClient; use crate::types::TMAddress; use crate::PREFIX; @@ -198,8 +200,8 @@ mod tests { let mut rpc_client = MockStarknetClient::new(); // mock the rpc client as erroring. If the handler successfully ignores the poll, we won't hit this rpc_client - .expect_get_event_by_hash_signers_rotated() - .returning(|_| Err(Report::from(StarknetClientError::UnsuccessfulTx))); + .expect_get_event_by_message_id_signers_rotated() + .returning(|_| None); let voting_verifier = TMAddress::random(PREFIX); let verifier = TMAddress::random(PREFIX); @@ -213,9 +215,6 @@ mod tests { let handler = super::Handler::new(verifier, voting_verifier, rpc_client, rx); - // poll is not expired yet, should hit rpc error - assert!(handler.handle(&event).await.is_err()); - let _ = tx.send(expiration + 1); // poll is expired, should not hit rpc error now @@ -245,7 +244,7 @@ mod tests { let random_felt = CheckedFelt::from_str(&random_hash()).unwrap(); let msg_id = FieldElementAndEventIndex::new(random_felt, 100u64).unwrap(); PollStarted::VerifierSet { - #[allow(deprecated)] // TODO: The below event uses the deprecated tx_id and event_index fields. Remove this attribute when those fields are removed + #[allow(deprecated)] verifier_set: VerifierSetConfirmation { tx_id: msg_id.tx_hash_as_hex(), event_index: u32::try_from(msg_id.event_index).unwrap(), @@ -255,9 +254,10 @@ mod tests { metadata: PollMetadata { poll_id: "100".parse().unwrap(), source_chain: "starknet-devnet-v1".parse().unwrap(), - source_gateway_address: "0x049ec69cd2e0c987857fbda7966ff59077e2e92c18959bdb9b0012438c452047" - .parse() - .unwrap(), + source_gateway_address: + "0x049ec69cd2e0c987857fbda7966ff59077e2e92c18959bdb9b0012438c452047" + .parse() + .unwrap(), confirmation_height: 15, expires_at, participants: participants diff --git a/ampd/src/starknet/json_rpc.rs b/ampd/src/starknet/json_rpc.rs index 01dfd25e2..2f67990c8 100644 --- a/ampd/src/starknet/json_rpc.rs +++ b/ampd/src/starknet/json_rpc.rs @@ -3,10 +3,8 @@ use async_trait::async_trait; use axelar_wasm_std::msg_id::FieldElementAndEventIndex; -use error_stack::Report; use mockall::automock; -use starknet_checked_felt::CheckedFelt; -use starknet_core::types::{ExecutionResult, Felt, TransactionReceipt}; +use starknet_core::types::{ExecutionResult, TransactionReceipt}; use starknet_providers::jsonrpc::JsonRpcTransport; use starknet_providers::{JsonRpcClient, Provider, ProviderError}; use thiserror::Error; @@ -26,8 +24,6 @@ pub enum StarknetClientError { JsonDeserializeError(#[from] serde_json::Error), #[error("Failed to fetch tx receipt: {0}")] FetchingReceipt(#[from] ProviderError), - #[error("Tx not successful")] - UnsuccessfulTx, } /// Implementor of verification method(s) for given network using JSON RPC @@ -61,17 +57,17 @@ where pub trait StarknetClient { /// Attempts to fetch a ContractCall event, by a given `message_id`. /// Returns the event or a `StarknetClientError`. - async fn get_events_by_hash_contract_call( + async fn get_event_by_message_id_contract_call( &self, message_id: FieldElementAndEventIndex, ) -> Option; /// Attempts to fetch a SignersRotated event, by a given `tx_hash`. /// Returns a tuple `(tx_hash, event)` or a `StarknetClientError`. - async fn get_event_by_hash_signers_rotated( + async fn get_event_by_message_id_signers_rotated( &self, - tx_hash: CheckedFelt, - ) -> Result>; + message_id: FieldElementAndEventIndex, + ) -> Option; } #[async_trait] @@ -81,7 +77,7 @@ where { // Fetches a transaction receipt by hash and extracts one or multiple // `ContractCallEvent` - async fn get_events_by_hash_contract_call( + async fn get_event_by_message_id_contract_call( &self, message_id: FieldElementAndEventIndex, ) -> Option { @@ -107,36 +103,30 @@ where } // Fetches a transaction receipt by hash and extracts a `SignersRotatedEvent` if present - async fn get_event_by_hash_signers_rotated( + async fn get_event_by_message_id_signers_rotated( &self, - tx_hash: CheckedFelt, - ) -> Result> { + message_id: FieldElementAndEventIndex, + ) -> Option { let receipt_with_block_info = self .client - .get_transaction_receipt(tx_hash) + .get_transaction_receipt(message_id.tx_hash.clone()) .await - .map_err(StarknetClientError::FetchingReceipt)?; + .ok()?; if *receipt_with_block_info.receipt.execution_result() != ExecutionResult::Succeeded { - return Err(Report::new(StarknetClientError::UnsuccessfulTx)); - } - - let event: Option<(Felt, SignersRotatedEvent)> = match receipt_with_block_info.receipt { - TransactionReceipt::Invoke(tx) => tx - .events - .iter() - .filter_map(|e| { - if let Ok(sre) = SignersRotatedEvent::try_from(e.clone()) { - Some((tx.transaction_hash, sre)) - } else { - None - } - }) - .next(), - _ => None, + return None; }; - Ok(event) + // get event from receipt by index + match receipt_with_block_info.receipt { + TransactionReceipt::Invoke(tx) => { + let event_index: usize = message_id.event_index.try_into().ok()?; + let event = tx.events.get(event_index)?; + + SignersRotatedEvent::try_from(event.clone()).ok() + } + _ => None, + } } } @@ -166,19 +156,20 @@ mod test { let mock_client = Client::new_with_transport(InvalidSignersRotatedEventMockTransport).unwrap(); let contract_call_event = mock_client - .get_event_by_hash_signers_rotated( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + .get_event_by_message_id_signers_rotated(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await; - assert!(contract_call_event.unwrap().is_none()); + assert!(contract_call_event.is_none()); } #[tokio::test] async fn deploy_account_tx_fetch() { let mock_client = Client::new_with_transport(DeployAccountMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -191,7 +182,7 @@ mod test { async fn deploy_tx_fetch() { let mock_client = Client::new_with_transport(DeployMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -204,7 +195,7 @@ mod test { async fn l1_handler_tx_fetch() { let mock_client = Client::new_with_transport(L1HandlerMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -217,7 +208,7 @@ mod test { async fn declare_tx_fetch() { let mock_client = Client::new_with_transport(DeclareMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -231,7 +222,7 @@ mod test { let mock_client = Client::new_with_transport(InvalidContractCallEventMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -244,7 +235,7 @@ mod test { async fn no_events_tx_fetch() { let mock_client = Client::new_with_transport(NoEventsMockTransport).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -257,7 +248,7 @@ mod test { async fn reverted_tx_fetch() { let mock_client = Client::new_with_transport(RevertedMockTransport).unwrap(); let contract_call_event = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -270,7 +261,7 @@ mod test { async fn failing_tx_fetch() { let mock_client = Client::new_with_transport(FailingMockTransport).unwrap(); let contract_call_event = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -282,21 +273,16 @@ mod test { #[tokio::test] async fn successful_signers_rotated_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportSignersRotated).unwrap(); - let signers_rotated_event: (Felt, SignersRotatedEvent) = mock_client - .get_event_by_hash_signers_rotated( - CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), - ) + let signers_rotated_event = mock_client + .get_event_by_message_id_signers_rotated(FieldElementAndEventIndex { + tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), + event_index: 0, + }) .await - .unwrap() // unwrap the result - .unwrap(); // unwrap the option + .unwrap(); - assert_eq!( - signers_rotated_event.0, - Felt::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") - .unwrap() - ); + assert_eq!(signers_rotated_event.from_address, "0x2".to_string()); - let actual: SignersRotatedEvent = signers_rotated_event.1; let expected: SignersRotatedEvent = SignersRotatedEvent { from_address: "0x2".to_string(), epoch: 1, @@ -317,7 +303,7 @@ mod test { }, }; - assert_eq!(actual, expected); + assert_eq!(signers_rotated_event, expected); } #[tokio::test] @@ -325,7 +311,7 @@ mod test { let mock_client = Client::new_with_transport(ValidMockTransportTwoCallContractsInOneTx).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) @@ -351,7 +337,7 @@ mod test { ); let contract_call_events_1 = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 1, }) @@ -381,7 +367,7 @@ mod test { async fn successful_call_contract_tx_fetch() { let mock_client = Client::new_with_transport(ValidMockTransportCallContract).unwrap(); let contract_call_events = mock_client - .get_events_by_hash_contract_call(FieldElementAndEventIndex { + .get_event_by_message_id_contract_call(FieldElementAndEventIndex { tx_hash: CheckedFelt::try_from(&Felt::ONE.to_bytes_be()).unwrap(), event_index: 0, }) From be059ef1741d9560c7cbabf90fc486bc698daed5 Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Thu, 6 Feb 2025 16:09:21 +0200 Subject: [PATCH 25/26] update Cargo.lock --- Cargo.lock | 863 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 495 insertions(+), 368 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd5e65d6f..dd487686c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", ] @@ -93,7 +93,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -142,14 +142,14 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more 0.99.18", - "getrandom", + "derive_more 0.99.19", + "getrandom 0.2.15", "hex-literal", "itoa", "k256", "keccak-asm", "proptest", - "rand", + "rand 0.8.5", "ruint", "serde", "tiny-keccak", @@ -157,9 +157,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" +checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" dependencies = [ "arrayvec", "bytes", @@ -176,7 +176,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -188,11 +188,11 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck 0.5.0", - "indexmap 2.7.0", + "indexmap 2.7.1", "proc-macro-error", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", "syn-solidity", "tiny-keccak", ] @@ -208,7 +208,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", "syn-solidity", ] @@ -267,7 +267,7 @@ dependencies = [ "openssl", "prost 0.11.9", "prost-types 0.11.9", - "rand", + "rand 0.8.5", "random-string", "report", "reqwest 0.11.27", @@ -339,10 +339,10 @@ dependencies = [ "pkcs8 0.9.0", "quinn", "quinn-proto", - "rand", + "rand 0.8.5", "rcgen", "ring 0.17.8", - "rustls 0.23.21", + "rustls 0.23.22", "rustls-webpki 0.102.8", "serde", "serde_json", @@ -397,11 +397,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] @@ -656,7 +657,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -666,7 +667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", "rayon", ] @@ -771,18 +772,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -804,13 +805,13 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "auto_impl" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -836,7 +837,7 @@ dependencies = [ "error-stack", "goldie", "hex", - "rand", + "rand 0.8.5", "router-api", "schemars", "serde", @@ -866,11 +867,11 @@ dependencies = [ "itertools 0.11.0", "lazy_static", "num-traits", - "rand", + "rand 0.8.5", "regex", "report", "schemars", - "semver 1.0.24", + "semver 1.0.25", "serde", "serde_json", "serde_with", @@ -898,10 +899,10 @@ dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", "report", - "semver 1.0.24", + "semver 1.0.25", "serde", "serde_json", - "syn 2.0.96", + "syn 2.0.98", "thiserror 1.0.69", ] @@ -923,7 +924,7 @@ dependencies = [ "hex", "itertools 0.11.0", "msgs-derive", - "rand", + "rand 0.8.5", "report", "router-api", "serde", @@ -975,7 +976,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "itoa", "matchit 0.7.3", @@ -1044,7 +1045,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -1190,17 +1191,18 @@ dependencies = [ [[package]] name = "bip32" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +checksum = "db40d3dfbeab4e031d78c844642fa0caa0b0db11ce1607ac9d2986dff1405c69" dependencies = [ "bs58 0.5.1", "hmac", "k256", "once_cell", "pbkdf2", - "rand_core", + "rand_core 0.6.4", "ripemd", + "secp256k1", "sha2 0.10.8", "subtle", "zeroize", @@ -1213,8 +1215,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" dependencies = [ "bitcoin_hashes 0.13.0", - "rand", - "rand_core", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "unicode-normalization", ] @@ -1273,9 +1275,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitmaps" @@ -1321,9 +1323,9 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +checksum = "06e903a20b159e944f91ec8499fe1e55651480c541ea0a584f5d967c49ad9d99" dependencies = [ "arrayref", "arrayvec", @@ -1332,9 +1334,9 @@ dependencies = [ [[package]] name = "blake2s_simd" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" +checksum = "e90f7deecfac93095eb874a40febd69427776e24e1bd7f87f33ac62d6f0174df" dependencies = [ "arrayref", "arrayvec", @@ -1391,7 +1393,7 @@ dependencies = [ "ff", "group", "pairing", - "rand_core", + "rand_core 0.6.4", "serde", "subtle", ] @@ -1421,9 +1423,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1457,9 +1459,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byte-slice-cast" @@ -1487,9 +1489,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" dependencies = [ "serde", ] @@ -1520,7 +1522,7 @@ checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", - "semver 1.0.24", + "semver 1.0.25", "serde", "serde_json", "thiserror 1.0.69", @@ -1537,9 +1539,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.9" +version = "1.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" +checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2" dependencies = [ "jobserver", "libc", @@ -1612,9 +1614,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.26" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" dependencies = [ "clap_builder", "clap_derive", @@ -1622,9 +1624,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" dependencies = [ "anstream", "anstyle", @@ -1635,14 +1637,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck 0.5.0", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -1724,7 +1726,7 @@ source = "git+https://github.com/mystenlabs/sui?tag=testnet-v1.39.1#e2a147185dbe dependencies = [ "fastcrypto", "mysten-network", - "rand", + "rand 0.8.5", "serde", "shared-crypto", ] @@ -1800,7 +1802,7 @@ dependencies = [ "multisig", "report", "router-api", - "semver 1.0.24", + "semver 1.0.25", "service-registry-api", "thiserror 1.0.69", "tofn", @@ -1863,9 +1865,9 @@ dependencies = [ "cosmos-sdk-proto", "ecdsa", "eyre", - "getrandom", + "getrandom 0.2.15", "k256", - "rand_core", + "rand_core 0.6.4", "serde", "serde_json", "subtle-encoding", @@ -1875,15 +1877,15 @@ dependencies = [ [[package]] name = "cosmwasm-core" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34c440d4d8e3ecec783d0f9c89d25565168b0f4cdb80a1f6a387cf2168c0740" +checksum = "de32156e4fd80c59be39ed6f4ebb596d59b0a4eaf01d6f146e27628ec7e8f8c1" [[package]] name = "cosmwasm-crypto" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134e765161d60228cc27635032d2a466542ca83fd6c87f3c87f4963c0bd51008" +checksum = "38fe1e6107ae3c9ba5e1f14178dd8bd52210535030d07f0609cf0d754c1f7de2" dependencies = [ "ark-bls12-381", "ark-ec", @@ -1897,7 +1899,7 @@ dependencies = [ "k256", "num-traits", "p256", - "rand_core", + "rand_core 0.6.4", "rayon", "sha2 0.10.8", "thiserror 1.0.69", @@ -1905,20 +1907,20 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c94a4b93e722c91d2e58471cfe69480f4a656cfccacd8bfda5638f2a5d4512b" +checksum = "484926c9dc8b90c59a717946c86bb272182003cbaabb378560086648d4056656" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] name = "cosmwasm-schema" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9a7b56d154870ec4b57b224509854f706c9744449548d8a3bf91ac75c59192" +checksum = "d2a25988c48703d1450a5ac5e7cd3ad82ec8a7552f3dde8f9b8927e682bd02c7" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -1929,20 +1931,20 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd3d80310cd7b86b09dbe886f4f2ca235a5ddb8d478493c6e50e720a3b38a42" +checksum = "bbd08fac60d30e341d9365033f519c0a36fdf38bde6ec196179e653d2723aebd" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] name = "cosmwasm-std" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434e556b0aebff34bf082e75d175b5d7edbcf1d90d4cedb59623a1249fff567" +checksum = "c92be4747d9abe3a96a5a78af34d29947992b3f67f602987ff8a87142ce9c413" dependencies = [ "base64 0.22.1", "bech32 0.11.0", @@ -1952,7 +1954,7 @@ dependencies = [ "cosmwasm-derive", "derive_more 1.0.0", "hex", - "rand_core", + "rand_core 0.6.4", "rmp-serde", "schemars", "serde", @@ -1964,9 +1966,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -2018,9 +2020,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-bigint" @@ -2029,7 +2031,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -2041,7 +2043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -2078,7 +2080,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2089,16 +2091,16 @@ checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core", + "rand_core 0.6.4", "subtle-ng", "zeroize", ] [[package]] name = "cw-multi-test" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1149fe104344cc4f4ca0fc784b7411042fd1626813fe85fd412b05252a0ae9d8" +checksum = "8b00c3a218ed6abc6f1dd9be8146d4f23d8f41cf4e6d53cdfa71bab4514e1fc3" dependencies = [ "anyhow", "bech32 0.11.0", @@ -2106,7 +2108,7 @@ dependencies = [ "cosmwasm-std", "cw-storage-plus", "cw-utils", - "itertools 0.13.0", + "itertools 0.14.0", "prost 0.13.4", "schemars", "serde", @@ -2120,7 +2122,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90e7828ea0175c45743178f8b0290513752e949b2fdfa5bda52a7389d732610" dependencies = [ - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2158,7 +2160,7 @@ dependencies = [ "cosmwasm-std", "cw-storage-plus", "schemars", - "semver 1.0.24", + "semver 1.0.25", "serde", "thiserror 1.0.69", ] @@ -2208,7 +2210,7 @@ dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", "strsim 0.11.1", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2230,7 +2232,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2248,15 +2250,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f" [[package]] name = "data-encoding-macro" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" +checksum = "5b16d9d0d88a5273d830dac8b78ceb217ffc9b1d5404e5597a3542515329405b" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2264,12 +2266,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" +checksum = "1145d32e826a7748b69ee8fc62d3e6355ff7f1051df53141e7048162fc90481b" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.98", ] [[package]] @@ -2317,7 +2319,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2354,15 +2356,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.18" +version = "0.99.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" dependencies = [ "convert_case 0.4.0", "proc-macro2 1.0.93", "quote 1.0.38", "rustc_version 0.4.1", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2382,7 +2384,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", "unicode-xid 0.2.6", ] @@ -2475,7 +2477,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2505,7 +2507,7 @@ dependencies = [ "optfield", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2522,9 +2524,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "feeef44e73baff3a26d371801df019877a9866a8c493d315ab00177843314f35" [[package]] name = "ecdsa" @@ -2569,7 +2571,7 @@ checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" dependencies = [ "curve25519-dalek-ng", "hex", - "rand_core", + "rand_core 0.6.4", "serde", "sha2 0.9.9", "thiserror 1.0.69", @@ -2584,7 +2586,7 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519 2.2.3", - "rand_core", + "rand_core 0.6.4", "sha2 0.10.8", "signature 2.2.0", "subtle", @@ -2601,7 +2603,7 @@ dependencies = [ "ed25519 2.2.3", "hashbrown 0.14.5", "hex", - "rand_core", + "rand_core 0.6.4", "sha2 0.10.8", "zeroize", ] @@ -2626,7 +2628,7 @@ dependencies = [ "group", "pem-rfc7468 0.7.0", "pkcs8 0.10.2", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -2658,7 +2660,7 @@ dependencies = [ "hex", "k256", "log", - "rand", + "rand 0.8.5", "rlp", "serde", "sha3", @@ -2693,7 +2695,7 @@ dependencies = [ "once_cell", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2812,8 +2814,8 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.96", - "toml 0.8.19", + "syn 2.0.98", + "toml 0.8.20", "walkdir", ] @@ -2830,7 +2832,7 @@ dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", "serde_json", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2851,12 +2853,12 @@ dependencies = [ "num_enum 0.7.3", "once_cell", "open-fastrlp", - "rand", + "rand 0.8.5", "rlp", "serde", "serde_json", "strum 0.26.3", - "syn 2.0.96", + "syn 2.0.98", "tempfile", "thiserror 1.0.69", "tiny-keccak", @@ -2934,7 +2936,7 @@ dependencies = [ "quote 1.0.38", "serde", "serde_json", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -2984,7 +2986,7 @@ dependencies = [ "cbc", "ctr", "curve25519-dalek-ng", - "derive_more 0.99.18", + "derive_more 0.99.19", "digest 0.10.7", "ecdsa", "ed25519-consensus", @@ -2998,7 +3000,7 @@ dependencies = [ "num-bigint 0.4.6", "once_cell", "p256", - "rand", + "rand 0.8.5", "readonly", "rfc6979", "rsa", @@ -3036,7 +3038,7 @@ dependencies = [ "fastcrypto", "hex", "itertools 0.10.5", - "rand", + "rand 0.8.5", "serde", "sha3", "tap", @@ -3059,7 +3061,7 @@ dependencies = [ "ark-snark", "bcs", "byte-slice-cast", - "derive_more 0.99.18", + "derive_more 0.99.19", "fastcrypto", "ff", "im", @@ -3132,7 +3134,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", "uuid", ] @@ -3145,7 +3147,7 @@ dependencies = [ "bitvec 1.0.1", "byteorder", "ff_derive", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -3178,7 +3180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" dependencies = [ "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -3190,7 +3192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -3251,6 +3253,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" + [[package]] name = "foreign-types" version = "0.3.2" @@ -3349,7 +3357,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -3417,10 +3425,10 @@ dependencies = [ "gateway-api", "goldie", "itertools 0.11.0", - "rand", + "rand 0.8.5", "report", "router-api", - "semver 1.0.24", + "semver 1.0.25", "serde", "serde_json", "thiserror 1.0.69", @@ -3463,10 +3471,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + [[package]] name = "ghash" version = "0.5.1" @@ -3536,8 +3556,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand", - "rand_core", + "rand 0.8.5", + "rand_core 0.6.4", "rand_xorshift", "subtle", ] @@ -3554,7 +3574,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.7.0", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -3573,7 +3593,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.2.0", - "indexmap 2.7.0", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -3773,9 +3793,9 @@ checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "httpdate" @@ -3825,9 +3845,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", @@ -3884,14 +3904,14 @@ checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.2.0", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", - "rustls 0.23.21", + "rustls 0.23.22", "rustls-pki-types", "tokio", "tokio-rustls 0.26.1", "tower-service", - "webpki-roots 0.26.7", + "webpki-roots 0.26.8", ] [[package]] @@ -3912,7 +3932,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "pin-project-lite", "tokio", @@ -3927,7 +3947,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "native-tls", "tokio", @@ -3946,7 +3966,7 @@ dependencies = [ "futures-util", "http 1.2.0", "http-body 1.0.1", - "hyper 1.5.2", + "hyper 1.6.0", "pin-project-lite", "socket2", "tokio", @@ -4092,7 +4112,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -4129,7 +4149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ "bitmaps", - "rand_core", + "rand_core 0.6.4", "rand_xoshiro", "sized-chunks", "typenum", @@ -4189,7 +4209,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -4211,9 +4231,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -4238,15 +4258,16 @@ dependencies = [ [[package]] name = "insta" -version = "1.42.0" +version = "1.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513e4067e16e69ed1db5ab56048ed65db32d10ba5fc1217f5393f8f17d8b5a5" +checksum = "71c1b125e30d93896b365e156c33dadfffab45ee8400afcbba4752f59de08a86" dependencies = [ "console", "linked-hash-map", "once_cell", "pest", "pest_derive", + "pin-project", "serde", "similar", ] @@ -4276,7 +4297,7 @@ dependencies = [ "k256", "multisig", "multisig-prover", - "rand", + "rand 0.8.5", "report", "rewards", "router", @@ -4329,15 +4350,15 @@ dependencies = [ "error-stack", "quote 1.0.38", "report", - "syn 2.0.96", + "syn 2.0.98", "thiserror 1.0.69", ] [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" @@ -4391,6 +4412,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -4408,9 +4438,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -4487,7 +4517,7 @@ dependencies = [ "hyper 0.14.32", "jsonrpsee-types 0.16.2", "parking_lot", - "rand", + "rand 0.8.5", "rustc-hash 1.1.0", "serde", "serde_json", @@ -4727,7 +4757,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "libc", ] @@ -4761,9 +4791,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" dependencies = [ "serde", ] @@ -4841,9 +4871,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] @@ -4855,7 +4885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -4910,7 +4940,7 @@ dependencies = [ "cfg-if", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -4968,7 +4998,7 @@ version = "0.1.0" source = "git+https://github.com/mystenlabs/sui?tag=testnet-v1.39.1#e2a147185dbeb6402daa43811507e29bc0d5df28" dependencies = [ "anyhow", - "indexmap 2.7.0", + "indexmap 2.7.1", "move-binary-format", "move-core-types", "petgraph 0.5.1", @@ -5068,7 +5098,7 @@ dependencies = [ "num", "once_cell", "primitive-types 0.10.1", - "rand", + "rand 0.8.5", "ref-cast", "serde", "serde_bytes", @@ -5087,7 +5117,7 @@ dependencies = [ "clap", "codespan", "colored", - "indexmap 2.7.0", + "indexmap 2.7.1", "move-abstract-interpreter", "move-binary-format", "move-bytecode-source-map", @@ -5169,7 +5199,7 @@ source = "git+https://github.com/mystenlabs/sui?tag=testnet-v1.39.1#e2a147185dbe dependencies = [ "enum-compat-util", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -5240,7 +5270,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -5332,7 +5362,7 @@ dependencies = [ "ed25519-dalek", "enum-display-derive", "error-stack", - "getrandom", + "getrandom 0.2.15", "goldie", "hex", "itertools 0.11.0", @@ -5381,7 +5411,7 @@ dependencies = [ "prost 0.12.6", "report", "router-api", - "semver 1.0.24", + "semver 1.0.25", "serde_json", "service-registry", "service-registry-api", @@ -5411,7 +5441,7 @@ dependencies = [ "log", "pbkdf2", "pem 3.0.4", - "rand", + "rand 0.8.5", "reqwest 0.12.12", "scrypt", "serde", @@ -5476,9 +5506,9 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" dependencies = [ "libc", "log", @@ -5575,7 +5605,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -5590,7 +5620,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "smallvec", "zeroize", ] @@ -5629,7 +5659,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -5710,7 +5740,7 @@ dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -5722,7 +5752,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -5785,7 +5815,7 @@ name = "openapiv3" version = "2.0.0" source = "git+https://github.com/bmwill/openapiv3.git?rev=ca4b4845b7c159a39f5c68ad8f7f76cb6f4d6963#ca4b4845b7c159a39f5c68ad8f7f76cb6f4d6963" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "schemars", "serde", "serde_json", @@ -5793,11 +5823,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "cfg-if", "foreign-types", "libc", @@ -5814,14 +5844,14 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" @@ -5834,9 +5864,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" dependencies = [ "cc", "libc", @@ -5853,7 +5883,7 @@ checksum = "fa59f025cde9c698fcb4fcb3533db4621795374065bee908215263488f2d2a1d" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -5893,7 +5923,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -6015,12 +6045,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "499cff8432e71c5f8784d9645aac0f9fca604d67f59b68a606170b5e229c6538" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "ciborium", "coset", "data-encoding", - "indexmap 2.7.0", - "rand", + "indexmap 2.7.1", + "rand 0.8.5", "serde", "serde_json", "sha2 0.10.8", @@ -6035,7 +6065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -6050,7 +6080,7 @@ dependencies = [ "group", "hex", "lazy_static", - "rand", + "rand 0.8.5", "serde", "static_assertions", "subtle", @@ -6179,7 +6209,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -6210,7 +6240,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset 0.4.2", - "indexmap 2.7.0", + "indexmap 2.7.1", ] [[package]] @@ -6240,7 +6270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand", + "rand 0.8.5", ] [[package]] @@ -6253,7 +6283,7 @@ dependencies = [ "phf_shared", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -6267,22 +6297,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -6359,7 +6389,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -6429,7 +6459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ "proc-macro2 1.0.93", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -6561,11 +6591,11 @@ checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.7.0", + "bitflags 2.8.0", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax 0.8.5", "rusty-fork", @@ -6659,7 +6689,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -6672,7 +6702,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -6737,8 +6767,8 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.0", - "rustls 0.23.21", + "rustc-hash 2.1.1", + "rustls 0.23.22", "socket2", "thiserror 2.0.11", "tokio", @@ -6752,11 +6782,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", - "getrandom", - "rand", + "getrandom 0.2.15", + "rand 0.8.5", "ring 0.17.8", - "rustc-hash 2.1.0", - "rustls 0.23.21", + "rustc-hash 2.1.1", + "rustls 0.23.22", "rustls-pki-types", "slab", "thiserror 2.0.11", @@ -6816,8 +6846,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.0", + "zerocopy 0.8.16", ] [[package]] @@ -6827,7 +6868,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0", ] [[package]] @@ -6836,7 +6887,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +dependencies = [ + "getrandom 0.3.1", + "zerocopy 0.8.16", ] [[package]] @@ -6845,7 +6906,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -6854,7 +6915,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -6907,7 +6968,7 @@ checksum = "a25d631e41bfb5fdcde1d4e2215f62f7f0afa3ff11e26563765bd6ea1d229aeb" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -6916,7 +6977,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", ] [[package]] @@ -6925,7 +6986,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", "thiserror 1.0.69", ] @@ -6947,7 +7008,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -7063,7 +7124,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-rustls 0.27.5", "hyper-tls", "hyper-util", @@ -7076,7 +7137,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.21", + "rustls 0.23.22", "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", @@ -7093,7 +7154,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.7", + "webpki-roots 0.26.8", "windows-registry", ] @@ -7150,7 +7211,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -7253,10 +7314,10 @@ dependencies = [ "itertools 0.11.0", "mockall 0.12.1", "msgs-derive", - "rand", + "rand 0.8.5", "report", "router-api", - "semver 1.0.24", + "semver 1.0.25", "serde_json", "thiserror 1.0.69", ] @@ -7274,7 +7335,7 @@ dependencies = [ "flagset", "hex", "msgs-derive", - "rand", + "rand 0.8.5", "report", "schemars", "serde", @@ -7298,7 +7359,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8 0.9.0", - "rand_core", + "rand_core 0.6.4", "sha2 0.10.8", "signature 2.2.0", "subtle", @@ -7323,7 +7384,7 @@ dependencies = [ "parity-scale-codec 3.6.12", "primitive-types 0.12.2", "proptest", - "rand", + "rand 0.8.5", "rlp", "ruint-macro", "serde", @@ -7361,9 +7422,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-hex" @@ -7386,7 +7447,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.24", + "semver 1.0.25", ] [[package]] @@ -7400,11 +7461,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", @@ -7437,9 +7498,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.21" +version = "0.23.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" +checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" dependencies = [ "log", "once_cell", @@ -7482,9 +7543,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" dependencies = [ "web-time", ] @@ -7530,9 +7591,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "salsa20" @@ -7573,7 +7634,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -7607,7 +7668,7 @@ dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", "serde_derive_internals", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -7659,7 +7720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ "bitcoin_hashes 0.12.0", - "rand", + "rand 0.8.5", "secp256k1-sys", ] @@ -7678,7 +7739,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "core-foundation", "core-foundation-sys", "libc", @@ -7706,9 +7767,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" dependencies = [ "serde", ] @@ -7811,7 +7872,7 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -7822,16 +7883,16 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "itoa", "memchr", "ryu", @@ -7867,7 +7928,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -7901,7 +7962,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.0", + "indexmap 2.7.1", "serde", "serde_derive", "serde_json", @@ -7918,7 +7979,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -8104,7 +8165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -8119,9 +8180,9 @@ dependencies = [ [[package]] name = "similar" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple-server-timing-header" @@ -8131,13 +8192,13 @@ checksum = "16e78919e05c9b8e123d435a4ad104b488ad1585631830e413830985c214086e" [[package]] name = "simple_asn1" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint 0.4.6", "num-traits", - "thiserror 1.0.69", + "thiserror 2.0.11", "time", ] @@ -8200,7 +8261,7 @@ dependencies = [ "http 0.2.12", "httparse", "log", - "rand", + "rand 0.8.5", "sha-1", ] @@ -8270,28 +8331,43 @@ dependencies = [ [[package]] name = "starknet-core" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538240cbe6663c673fe77465f294da707080f39678dd7066761554899e46100" +checksum = "37abf0af45a3b866dd108880ace9949ae7830f6830adb8963024302ae9e82c24" dependencies = [ "base64 0.21.7", "crypto-bigint", "flate2", + "foldhash", "hex", + "indexmap 2.7.1", + "num-traits", "serde", "serde_json", "serde_json_pythonic", "serde_with", "sha3", + "starknet-core-derive", "starknet-crypto", "starknet-types-core", ] +[[package]] +name = "starknet-core-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08520b7d80eda7bf1a223e8db4f9bb5779a12846f15ebf8f8d76667eca7f5ad" +dependencies = [ + "proc-macro2 1.0.93", + "quote 1.0.38", + "syn 2.0.98", +] + [[package]] name = "starknet-crypto" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded22ccf4cb9e572ce3f77de6066af53560cd2520d508876c83bb1e6b29d5cbc" +checksum = "039a3bad70806b494c9e6b21c5238a6c8a373d66a26071859deb0ccca6f93634" dependencies = [ "crypto-bigint", "hex", @@ -8317,15 +8393,15 @@ dependencies = [ [[package]] name = "starknet-providers" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e8e69ba7a36dea2d28333be82b4011f8784333d3ae5618482b6587c1ffb66c" +checksum = "a9256247f718564b3e4c73cc941735012691c14903fbc25cea306745bcbfa384" dependencies = [ "async-trait", "auto_impl", "ethereum-types", "flate2", - "getrandom", + "getrandom 0.2.15", "log", "reqwest 0.11.27", "serde", @@ -8366,7 +8442,7 @@ dependencies = [ "goldie", "hex", "multisig", - "rand", + "rand 0.8.5", "router-api", "serde", "serde_json", @@ -8501,7 +8577,7 @@ dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", "rustversion", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -8514,7 +8590,7 @@ dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", "rustversion", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -8556,7 +8632,7 @@ dependencies = [ "error-stack", "hex", "multisig", - "rand", + "rand 0.8.5", "router-api", "serde", "serde_json", @@ -8651,7 +8727,7 @@ dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", "sui-enum-compat-util", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -8702,7 +8778,7 @@ dependencies = [ "prometheus", "prost 0.13.4", "prost-types 0.13.4", - "rand", + "rand 0.8.5", "reqwest 0.12.12", "roaring", "schemars", @@ -8738,7 +8814,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_with", - "winnow", + "winnow 0.6.26", ] [[package]] @@ -8762,7 +8838,7 @@ dependencies = [ "fastcrypto-tbls", "fastcrypto-zkp", "im", - "indexmap 2.7.0", + "indexmap 2.7.1", "itertools 0.13.0", "jsonrpsee", "lru", @@ -8787,7 +8863,7 @@ dependencies = [ "prometheus", "proptest", "proptest-derive", - "rand", + "rand 0.8.5", "roaring", "schemars", "serde", @@ -8816,7 +8892,7 @@ version = "1.0.0" dependencies = [ "error-stack", "hex", - "rand", + "rand 0.8.5", "serde", "thiserror 1.0.69", ] @@ -8845,9 +8921,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.96" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", @@ -8863,7 +8939,7 @@ dependencies = [ "paste", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -8901,7 +8977,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -8921,7 +8997,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "core-foundation", "system-configuration-sys 0.6.0", ] @@ -8978,13 +9054,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.15.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand 2.3.0", - "getrandom", + "getrandom 0.3.1", "once_cell", "rustix", "windows-sys 0.59.0", @@ -9060,7 +9136,7 @@ dependencies = [ "serde", "serde_json", "tendermint 0.35.0", - "toml 0.8.19", + "toml 0.8.20", "url", ] @@ -9110,12 +9186,12 @@ dependencies = [ "bytes", "flex-error", "futures", - "getrandom", + "getrandom 0.2.15", "peg", "pin-project", - "rand", + "rand 0.8.5", "reqwest 0.11.27", - "semver 1.0.24", + "semver 1.0.25", "serde", "serde_bytes", "serde_json", @@ -9200,7 +9276,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -9211,7 +9287,7 @@ checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -9311,8 +9387,8 @@ dependencies = [ "ed25519-dalek", "hmac", "k256", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "serde", "sha2 0.10.8", "tracing", @@ -9355,7 +9431,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -9395,7 +9471,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.21", + "rustls 0.23.22", "tokio", ] @@ -9463,9 +9539,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -9484,15 +9560,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.7.1", ] [[package]] @@ -9538,7 +9614,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-timeout 0.5.2", "hyper-util", "percent-encoding", @@ -9553,7 +9629,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", - "webpki-roots 0.26.7", + "webpki-roots 0.26.8", ] [[package]] @@ -9594,7 +9670,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project", "pin-project-lite", - "rand", + "rand 0.8.5", "slab", "tokio", "tokio-util", @@ -9627,7 +9703,7 @@ checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "async-compression", "base64 0.21.7", - "bitflags 2.7.0", + "bitflags 2.8.0", "bytes", "futures-core", "futures-util", @@ -9682,7 +9758,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -9780,7 +9856,7 @@ dependencies = [ "http 0.2.12", "httparse", "log", - "rand", + "rand 0.8.5", "rustls 0.21.12", "sha1", "thiserror 1.0.69", @@ -9800,7 +9876,7 @@ dependencies = [ "http 1.2.0", "httparse", "log", - "rand", + "rand 0.8.5", "sha1", "thiserror 1.0.69", "utf-8", @@ -9823,7 +9899,7 @@ checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -9860,7 +9936,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a615d6c2764852a2e88a4f16e9ce1ea49bb776b5872956309e170d63a042a34f" dependencies = [ "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -9895,9 +9971,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "unicode-normalization" @@ -10009,39 +10085,39 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4" +checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" dependencies = [ - "getrandom", - "rand", + "getrandom 0.3.1", + "rand 0.9.0", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" dependencies = [ "valuable-derive", ] [[package]] name = "valuable-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d44690c645190cfce32f91a1582281654b2338c6073fa250b0949fd25c55b32" +checksum = "4e3a32a9bcc0f6c6ccfd5b27bcf298c58e753bcc9eeff268157a303393183a6d" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 1.0.109", + "syn 2.0.98", ] [[package]] name = "valuable-serde" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5285cfff30cdabe26626736a54d989687dd9cab84f51f4048b61d6d0ae8b0907" +checksum = "2ee0548edecd1b907be7e67789923b7d02275b9ba4a33ebc33300e2c947a8cb1" dependencies = [ "serde", "valuable", @@ -10095,7 +10171,7 @@ dependencies = [ "itertools 0.11.0", "msgs-derive", "multisig", - "rand", + "rand 0.8.5", "report", "rewards", "router-api", @@ -10109,9 +10185,9 @@ dependencies = [ [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] @@ -10141,36 +10217,46 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", @@ -10181,9 +10267,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote 1.0.38", "wasm-bindgen-macro-support", @@ -10191,28 +10277,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -10255,9 +10344,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.7" +version = "0.26.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" dependencies = [ "rustls-pki-types", ] @@ -10494,9 +10583,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.24" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f" dependencies = [ "memchr", ] @@ -10511,6 +10609,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -10619,7 +10726,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", "synstructure 0.13.1", ] @@ -10630,7 +10737,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8c07a70861ce02bad1607b5753ecb2501f67847b9f9ada7c160fff0ec6300c" +dependencies = [ + "zerocopy-derive 0.8.16", ] [[package]] @@ -10641,7 +10757,18 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5226bc9a9a9836e7428936cde76bb6b22feea1a8bfdbc0d241136e4d13417e25" +dependencies = [ + "proc-macro2 1.0.93", + "quote 1.0.38", + "syn 2.0.98", ] [[package]] @@ -10661,7 +10788,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", "synstructure 0.13.1", ] @@ -10682,7 +10809,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] @@ -10704,7 +10831,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.98", ] [[package]] From f9b03530e9bf2c8537dfc716864d173403700f7b Mon Sep 17 00:00:00 2001 From: Stoyan Kirov Date: Thu, 6 Feb 2025 16:54:22 +0200 Subject: [PATCH 26/26] sort Cargo.toml and update Cargo.lock --- Cargo.lock | 1 - ampd/Cargo.toml | 8 ++++---- packages/axelar-wasm-std/Cargo.toml | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd487686c..2bd53eca9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -877,7 +877,6 @@ dependencies = [ "serde_with", "sha3", "starknet-checked-felt", - "starknet-types-core", "stellar-xdr", "strum 0.25.0", "sui-types 1.0.0", diff --git a/ampd/Cargo.toml b/ampd/Cargo.toml index 683000957..379edae2a 100644 --- a/ampd/Cargo.toml +++ b/ampd/Cargo.toml @@ -53,6 +53,10 @@ serde_json = { workspace = true } serde_with = "3.2.0" service-registry-api = { workspace = true } sha3 = { workspace = true } +starknet-checked-felt = { workspace = true } + +starknet-core = { workspace = true } +starknet-providers = { workspace = true } stellar = { workspace = true } stellar-rpc-client = "21.4.0" stellar-xdr = { workspace = true, features = ["serde_json"] } @@ -80,10 +84,6 @@ valuable = { version = "0.1.0", features = ["derive"] } valuable-serde = { version = "0.1.0", features = ["std"] } voting-verifier = { workspace = true } -starknet-core = { workspace = true } -starknet-providers = { workspace = true } -starknet-checked-felt = { workspace = true } - [dev-dependencies] assert_ok = { workspace = true } ed25519-dalek = { workspace = true, features = ["rand_core"] } diff --git a/packages/axelar-wasm-std/Cargo.toml b/packages/axelar-wasm-std/Cargo.toml index 948a120fd..fb7baa2a9 100644 --- a/packages/axelar-wasm-std/Cargo.toml +++ b/packages/axelar-wasm-std/Cargo.toml @@ -49,7 +49,6 @@ serde_with = { version = "3.11.0", features = ["macros"] } sha3 = { workspace = true } starknet-checked-felt = { workspace = true } stellar-xdr = { workspace = true } -starknet-types-core = { workspace = true } strum = { workspace = true } sui-types = { workspace = true } thiserror = { workspace = true } @@ -59,8 +58,8 @@ valuable = { version = "0.1.0", features = ["derive"] } assert_ok = { workspace = true } cw-multi-test = { workspace = true } goldie = { workspace = true } -rand = { workspace = true } hex = { workspace = true, default-features = false } +rand = { workspace = true } [lints] workspace = true