diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a31d403208..c3d9a6b3c1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -231,7 +231,9 @@ jobs: - name: run pedantic clippy on workspace crates run: | cargo clippy --all-targets --all-features \ - -- --warn clippy::pedantic --warn clippy::arithmetic-side-effects --deny warnings + -- --warn clippy::pedantic --warn clippy::arithmetic-side-effects \ + --warn clippy::allow_attributes --warn clippy::allow_attributes_without_reason \ + --deny warnings - name: run pedantic clippy on tools/protobuf-compiler run: | cargo clippy --manifest-path tools/protobuf-compiler/Cargo.toml \ diff --git a/crates/astria-bridge-contracts/Cargo.toml b/crates/astria-bridge-contracts/Cargo.toml index f417e32e7a..7276680038 100644 --- a/crates/astria-bridge-contracts/Cargo.toml +++ b/crates/astria-bridge-contracts/Cargo.toml @@ -2,6 +2,7 @@ name = "astria-bridge-contracts" version = "0.1.0" edition = "2021" +rust-version = "1.81.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/astria-bridge-contracts/src/lib.rs b/crates/astria-bridge-contracts/src/lib.rs index ad584ea723..f6cb8b7b8f 100644 --- a/crates/astria-bridge-contracts/src/lib.rs +++ b/crates/astria-bridge-contracts/src/lib.rs @@ -1,5 +1,5 @@ #[rustfmt::skip] -#[allow(clippy::pedantic)] +#[expect(clippy::pedantic, clippy::allow_attributes, clippy::allow_attributes_without_reason)] mod generated; use std::{ borrow::Cow, diff --git a/crates/astria-bridge-withdrawer/src/api.rs b/crates/astria-bridge-withdrawer/src/api.rs index 2a1abe248c..1a2291eab4 100644 --- a/crates/astria-bridge-withdrawer/src/api.rs +++ b/crates/astria-bridge-withdrawer/src/api.rs @@ -51,7 +51,6 @@ pub(crate) fn start(socket_addr: SocketAddr, withdrawer_state: WithdrawerState) axum::Server::bind(&socket_addr).serve(app.into_make_service()) } -#[allow(clippy::unused_async)] // Permit because axum handlers must be async #[instrument(skip_all)] async fn get_healthz(State(withdrawer_state): State) -> Healthz { if withdrawer_state.borrow().is_healthy() { @@ -67,7 +66,6 @@ async fn get_healthz(State(withdrawer_state): State) -> Healthz /// /// + there is a current sequencer height (implying a block from sequencer was received) /// + there is a current data availability height (implying a height was received from the DA) -#[allow(clippy::unused_async)] // Permit because axum handlers must be async #[instrument(skip_all)] async fn get_readyz(State(withdrawer_state): State) -> Readyz { let is_withdrawer_online = withdrawer_state.borrow().is_ready(); @@ -78,7 +76,6 @@ async fn get_readyz(State(withdrawer_state): State) -> Readyz { } } -#[allow(clippy::unused_async)] // Permit because axum handlers must be async #[instrument(skip_all)] async fn get_status(State(withdrawer_state): State) -> Json { Json(withdrawer_state.borrow().clone()) diff --git a/crates/astria-bridge-withdrawer/src/bridge_withdrawer/mod.rs b/crates/astria-bridge-withdrawer/src/bridge_withdrawer/mod.rs index 242d10001f..527e75e0d2 100644 --- a/crates/astria-bridge-withdrawer/src/bridge_withdrawer/mod.rs +++ b/crates/astria-bridge-withdrawer/src/bridge_withdrawer/mod.rs @@ -167,8 +167,11 @@ impl BridgeWithdrawer { self.api_server.local_addr() } - // Panic won't happen because `startup_task` is unwraped lazily after checking if it's `Some`. - #[allow(clippy::missing_panics_doc)] + #[expect( + clippy::missing_panics_doc, + reason = "Panic won't happen because `startup_task` is unwraped lazily after checking if \ + it's `Some`." + )] pub async fn run(self) { let Self { shutdown_token, @@ -255,7 +258,10 @@ impl BridgeWithdrawer { } } -#[allow(clippy::struct_field_names)] // allow: for parity with the `Shutdown` struct. +#[expect( + clippy::struct_field_names, + reason = "for parity with the `Shutdown` struct" +)] struct TaskHandles { api_task: JoinHandle>, startup_task: Option>>, diff --git a/crates/astria-bridge-withdrawer/src/config.rs b/crates/astria-bridge-withdrawer/src/config.rs index 0cbf462daf..d78726282c 100644 --- a/crates/astria-bridge-withdrawer/src/config.rs +++ b/crates/astria-bridge-withdrawer/src/config.rs @@ -4,9 +4,11 @@ use serde::{ Serialize, }; -// Allowed `struct_excessive_bools` because this is used as a container -// for deserialization. Making this a builder-pattern is not actionable. -#[allow(clippy::struct_excessive_bools)] +#[expect( + clippy::struct_excessive_bools, + reason = "This is used as a container for deserialization. Making this a builder-pattern is \ + not actionable" +)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] /// The single config for creating an astria-bridge service. pub struct Config { diff --git a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/ethereum.rs b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/ethereum.rs index 71a881d325..25c893417e 100644 --- a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/ethereum.rs +++ b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/ethereum.rs @@ -31,8 +31,10 @@ use super::test_bridge_withdrawer::{ default_native_asset, }; -// allow: want the name to reflect this is a test config. -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "want the name to reflect this is a test config" +)] pub struct TestEthereum { contract_address: ethers::types::Address, provider: Arc>, @@ -226,7 +228,10 @@ impl TestEthereumConfig { } } -#[allow(clippy::struct_field_names)] +#[expect( + clippy::struct_field_names, + reason = "we want struct field names to be specific" +)] pub struct AstriaWithdrawerDeployerConfig { pub base_chain_asset_precision: u32, pub base_chain_bridge_address: astria_core::primitive::v1::Address, diff --git a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mock_sequencer.rs b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mock_sequencer.rs index ed37d660da..21a630f5f6 100644 --- a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mock_sequencer.rs +++ b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mock_sequencer.rs @@ -38,7 +38,10 @@ use tonic::{ const GET_PENDING_NONCE_GRPC_NAME: &str = "get_pending_nonce"; -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "naming is helpful for clarity here" +)] pub struct MockSequencerServer { _server: JoinHandle>, pub(crate) mock_server: MockServer, diff --git a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mod.rs b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mod.rs index 9c0586ff42..78ffafd458 100644 --- a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mod.rs +++ b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mod.rs @@ -1,6 +1,3 @@ -// These are tests; failing with panics is ok. -#![allow(clippy::missing_panics_doc)] - mod ethereum; mod mock_cometbft; mod mock_sequencer; diff --git a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/test_bridge_withdrawer.rs b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/test_bridge_withdrawer.rs index dbb8a53b1b..7048b4cf2f 100644 --- a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/test_bridge_withdrawer.rs +++ b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/test_bridge_withdrawer.rs @@ -237,7 +237,7 @@ impl TestBridgeWithdrawer { } } -#[allow(clippy::module_name_repetitions)] +#[expect(clippy::module_name_repetitions, reason = "naming is for clarity here")] pub struct TestBridgeWithdrawerConfig { /// Configures the rollup's withdrawal smart contract to either native or ERC20. pub ethereum_config: TestEthereumConfig, diff --git a/crates/astria-bridge-withdrawer/tests/blackbox/main.rs b/crates/astria-bridge-withdrawer/tests/blackbox/main.rs index af595c1f22..af3e32dff2 100644 --- a/crates/astria-bridge-withdrawer/tests/blackbox/main.rs +++ b/crates/astria-bridge-withdrawer/tests/blackbox/main.rs @@ -1,3 +1,8 @@ +#![expect( + clippy::missing_panics_doc, + reason = "These are tests; failing with panics is ok." +)] + use astria_core::protocol::transaction::v1alpha1::Action; use helpers::{ assert_actions_eq, diff --git a/crates/astria-build-info/Cargo.toml b/crates/astria-build-info/Cargo.toml index b0083bbc69..ceab67fe22 100644 --- a/crates/astria-build-info/Cargo.toml +++ b/crates/astria-build-info/Cargo.toml @@ -2,6 +2,7 @@ name = "astria-build-info" version = "0.1.0" edition = "2021" +rust-version = "1.81.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/astria-cli/src/cli/bridge.rs b/crates/astria-cli/src/cli/bridge.rs index efd0eccd25..09bed2d1b0 100644 --- a/crates/astria-cli/src/cli/bridge.rs +++ b/crates/astria-cli/src/cli/bridge.rs @@ -2,9 +2,11 @@ use clap::Subcommand; use color_eyre::eyre; /// Interact with a Sequencer node -// allow: these are one-shot variants. the size doesn't matter as they are -// passed around only once. -#[allow(clippy::large_enum_variant)] +#[expect( + clippy::large_enum_variant, + reason = "these are one-shot variants. the size doesn't matter as they are passed around only \ + once" +)] #[derive(Debug, Subcommand)] pub(crate) enum Command { /// Commands for interacting with Sequencer accounts diff --git a/crates/astria-composer/src/api.rs b/crates/astria-composer/src/api.rs index a73dc2c487..ed0c2a76cc 100644 --- a/crates/astria-composer/src/api.rs +++ b/crates/astria-composer/src/api.rs @@ -74,9 +74,6 @@ impl IntoResponse for Readyz { } } -// axum does not allow non-async handlers. This attribute can be removed -// once this method contains `await` statements. -#[allow(clippy::unused_async)] #[instrument(skip_all)] async fn readyz(State(composer_status): State) -> Readyz { debug!("received readyz request"); diff --git a/crates/astria-composer/src/composer.rs b/crates/astria-composer/src/composer.rs index a4b82f27b4..dc9ab4ce17 100644 --- a/crates/astria-composer/src/composer.rs +++ b/crates/astria-composer/src/composer.rs @@ -217,9 +217,11 @@ impl Composer { /// /// # Panics /// It panics if the Composer cannot set the SIGTERM listener. - // allow: it seems splitting this into smaller functions makes the code less readable due to - // the high number of params needed for these functions. - #[allow(clippy::too_many_lines)] + #[expect( + clippy::too_many_lines, + reason = "it seems splitting this into smaller functions makes the code less readable due \ + to the high number of params needed for these functions" + )] pub async fn run_until_stopped(self) -> eyre::Result<()> { let Self { api_server, diff --git a/crates/astria-composer/src/config.rs b/crates/astria-composer/src/config.rs index c8e125d963..b3f127d9ab 100644 --- a/crates/astria-composer/src/config.rs +++ b/crates/astria-composer/src/config.rs @@ -13,8 +13,10 @@ use crate::rollup::{ Rollup, }; -// this is a config, may have many boolean values -#[allow(clippy::struct_excessive_bools)] +#[expect( + clippy::struct_excessive_bools, + reason = "this is a config, may have many boolean values" +)] #[derive(Debug, Deserialize, Serialize)] /// The high-level config for creating an astria-composer service. pub struct Config { diff --git a/crates/astria-composer/src/executor/bundle_factory/tests.rs b/crates/astria-composer/src/executor/bundle_factory/tests.rs index dd8af22cf7..4dab9b056a 100644 --- a/crates/astria-composer/src/executor/bundle_factory/tests.rs +++ b/crates/astria-composer/src/executor/bundle_factory/tests.rs @@ -164,8 +164,10 @@ mod bundle_factory { // assert that the bundle factory has one bundle in the finished queue, that the factory is // full and that err was returned - // allow: this is intended to match all possible variants - #[allow(clippy::match_wildcard_for_single_variants)] + #[expect( + clippy::match_wildcard_for_single_variants, + reason = "this is intended to match all possible variants" + )] match err { BundleFactoryError::FinishedQueueFull(_) => {} other => panic!("expected a FinishedQueueFull variant, but got {other:?}"), @@ -211,8 +213,10 @@ mod bundle_factory { // assert that the bundle factory has one bundle in the finished queue, that the factory is // full and that err was returned - // allow: this is intended to match all possible variants - #[allow(clippy::match_wildcard_for_single_variants)] + #[expect( + clippy::match_wildcard_for_single_variants, + reason = "this is intended to match all possible variants" + )] match err { BundleFactoryError::FinishedQueueFull(_) => {} other => panic!("expected a FinishedQueueFull variant, but got {other:?}"), diff --git a/crates/astria-composer/src/executor/mod.rs b/crates/astria-composer/src/executor/mod.rs index 0f2533cd79..5e88d5fbba 100644 --- a/crates/astria-composer/src/executor/mod.rs +++ b/crates/astria-composer/src/executor/mod.rs @@ -669,7 +669,8 @@ pin_project! { impl Future for SubmitFut { type Output = eyre::Result; - #[allow(clippy::too_many_lines)] + // FIXME (https://github.com/astriaorg/astria/issues/1572): This function is too long and should be refactored. + #[expect(clippy::too_many_lines, reason = "this may warrant a refactor")] fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { const INVALID_NONCE: Code = Code::Err(AbciErrorCode::INVALID_NONCE.value()); loop { diff --git a/crates/astria-conductor/src/celestia/verify.rs b/crates/astria-conductor/src/celestia/verify.rs index 67b964ed9c..a63254bec6 100644 --- a/crates/astria-conductor/src/celestia/verify.rs +++ b/crates/astria-conductor/src/celestia/verify.rs @@ -456,9 +456,11 @@ impl RateLimitedVerificationClient { mut self, height: SequencerHeight, ) -> Result, BoxError> { - // allow: it is desired that the wildcard matches all future added variants because - // this call must only return a single specific variant, panicking otherwise. - #[allow(clippy::match_wildcard_for_single_variants)] + #[expect( + clippy::match_wildcard_for_single_variants, + reason = "it is desired that the wildcard matches all future added variants because \ + this call must only return a single specific variant, panicking otherwise" + )] match self .inner .ready() @@ -479,9 +481,11 @@ impl RateLimitedVerificationClient { prev_height: SequencerHeight, height: SequencerHeight, ) -> Result, BoxError> { - // allow: it is desired that the wildcard matches all future added variants because - // this call must only return a single specific variant, panicking otherwise. - #[allow(clippy::match_wildcard_for_single_variants)] + #[expect( + clippy::match_wildcard_for_single_variants, + reason = "it is desired that the wildcard matches all future added variants because \ + this call must only return a single specific variant, panicking otherwise" + )] match self .inner .ready() diff --git a/crates/astria-conductor/src/config.rs b/crates/astria-conductor/src/config.rs index d459641d64..0cb8c0969d 100644 --- a/crates/astria-conductor/src/config.rs +++ b/crates/astria-conductor/src/config.rs @@ -33,9 +33,11 @@ impl std::fmt::Display for CommitLevel { } } -// Allowed `struct_excessive_bools` because this is used as a container -// for deserialization. Making this a builder-pattern is not actionable. -#[allow(clippy::struct_excessive_bools)] +#[expect( + clippy::struct_excessive_bools, + reason = "This is used as a container for deserialization. Making this a builder-pattern is \ + not actionable" +)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { /// The block time of Celestia network in milliseconds. diff --git a/crates/astria-conductor/src/executor/channel.rs b/crates/astria-conductor/src/executor/channel.rs index 450dfb23d9..955d62d9b3 100644 --- a/crates/astria-conductor/src/executor/channel.rs +++ b/crates/astria-conductor/src/executor/channel.rs @@ -58,8 +58,6 @@ impl From> for SendError { } } -// allow: this is mimicking tokio's `SendError` that returns the stack-allocated object. -#[allow(clippy::result_large_err)] #[derive(Debug, thiserror::Error, PartialEq)] pub(crate) enum TrySendError { #[error("the channel is closed")] @@ -105,8 +103,6 @@ impl Sender { /// Attempts to send a block without blocking. /// /// Returns an error if the channel is out of permits or if it has been closed. - // allow: this is mimicking tokio's `TrySendError` that returns the stack-allocated object. - #[allow(clippy::result_large_err)] pub(super) fn try_send(&self, block: T) -> Result<(), TrySendError> { let sem = match self.sem.upgrade() { None => return Err(TrySendError::Closed(block)), diff --git a/crates/astria-conductor/src/executor/mod.rs b/crates/astria-conductor/src/executor/mod.rs index 916a951e28..b923728e88 100644 --- a/crates/astria-conductor/src/executor/mod.rs +++ b/crates/astria-conductor/src/executor/mod.rs @@ -153,8 +153,6 @@ impl Handle { Ok(()) } - // allow: return value of tokio's mpsc send try_send method - #[allow(clippy::result_large_err)] pub(crate) fn try_send_firm_block( &self, block: ReconstructedBlock, @@ -178,8 +176,6 @@ impl Handle { Ok(()) } - // allow: this is mimicking tokio's `SendError` that returns the stack-allocated object. - #[allow(clippy::result_large_err)] pub(crate) fn try_send_soft_block( &self, block: FilteredSequencerBlock, diff --git a/crates/astria-conductor/tests/blackbox/main.rs b/crates/astria-conductor/tests/blackbox/main.rs index ad73c93448..b24f0d17d8 100644 --- a/crates/astria-conductor/tests/blackbox/main.rs +++ b/crates/astria-conductor/tests/blackbox/main.rs @@ -1,6 +1,9 @@ -// allow: clippy lints that are not ok in production code but acceptable or wanted in tests +#![expect( + clippy::missing_panics_doc, + reason = "clippy lints that are not ok in production code but acceptable or wanted in tests" +)] + pub mod firm_only; -#[allow(clippy::missing_panics_doc)] pub mod helpers; pub mod shutdown; pub mod soft_and_firm; diff --git a/crates/astria-conductor/tests/blackbox/soft_and_firm.rs b/crates/astria-conductor/tests/blackbox/soft_and_firm.rs index 4d66792592..cfbcca851e 100644 --- a/crates/astria-conductor/tests/blackbox/soft_and_firm.rs +++ b/crates/astria-conductor/tests/blackbox/soft_and_firm.rs @@ -325,7 +325,7 @@ async fn executes_firm_then_soft_at_next_height() { ); } -#[allow(clippy::too_many_lines)] // it's a test, it's fine +#[expect(clippy::too_many_lines, reason = "it's a test, it's fine")] #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn missing_block_is_fetched_for_updating_firm_commitment() { let test_conductor = spawn_conductor(CommitLevel::SoftAndFirm).await; @@ -451,7 +451,10 @@ async fn missing_block_is_fetched_for_updating_firm_commitment() { /// Astria Geth will return a `PermissionDenied` error if the `execute_block` RPC is called /// before `get_genesis_info` and `get_commitment_state` are called, which would happen in the /// case of a restart. This response is mounted to cause the conductor to restart. -#[allow(clippy::too_many_lines)] // allow: all lines fairly necessary, and I don't think a test warrants a refactor +#[expect( + clippy::too_many_lines, + reason = "all lines fairly necessary, and I don't think a test warrants a refactor" +)] #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn conductor_restarts_on_permission_denied() { let test_conductor = spawn_conductor(CommitLevel::SoftAndFirm).await; diff --git a/crates/astria-core/src/celestia.rs b/crates/astria-core/src/celestia.rs index 9fc448c521..b9762e6736 100644 --- a/crates/astria-core/src/celestia.rs +++ b/crates/astria-core/src/celestia.rs @@ -5,7 +5,6 @@ pub use celestia_types::nmt::Namespace; /// Panics if `bytes` contains less then 10 bytes. #[must_use = "a celestia namespace must be used in order to be useful"] pub const fn namespace_v0_from_first_10_bytes(bytes: &[u8]) -> Namespace { - #[allow(clippy::assertions_on_constants)] const _: () = assert!( 10 == celestia_types::nmt::NS_ID_V0_SIZE, "verify that the celestia v0 namespace was changed from 10 bytes" diff --git a/crates/astria-core/src/crypto.rs b/crates/astria-core/src/crypto.rs index a0d7290f51..65b5499854 100644 --- a/crates/astria-core/src/crypto.rs +++ b/crates/astria-core/src/crypto.rs @@ -178,7 +178,6 @@ impl VerificationKey { } /// this ensures that `ADDRESS_LEN` is never accidentally changed to a value /// that would violate this assumption. - #[allow(clippy::assertions_on_constants)] const _: () = assert!(ADDRESS_LEN <= 32); let bytes: [u8; 32] = Sha256::digest(self).into(); first_20(bytes) @@ -311,8 +310,10 @@ mod tests { // From https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html #[test] - // allow: we want explicit assertions here to match the documented expected behavior. - #[allow(clippy::nonminimal_bool)] + #[expect( + clippy::nonminimal_bool, + reason = "we want explicit assertions here to match the documented expected behavior" + )] fn verification_key_comparisons_should_be_consistent() { // A key which compares greater than "low" ones below, and with its address uninitialized. let high_uninit = VerificationKey { diff --git a/crates/astria-core/src/lib.rs b/crates/astria-core/src/lib.rs index 4fecf8dddd..5c97446d17 100644 --- a/crates/astria-core/src/lib.rs +++ b/crates/astria-core/src/lib.rs @@ -6,6 +6,11 @@ compile_error!( ); #[rustfmt::skip] +#[allow( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "cannot prevent allow attributes in generated files" +)] pub mod generated; pub mod crypto; diff --git a/crates/astria-core/src/primitive/v1/asset/denom.rs b/crates/astria-core/src/primitive/v1/asset/denom.rs index 91dd06bf24..412f557ecf 100644 --- a/crates/astria-core/src/primitive/v1/asset/denom.rs +++ b/crates/astria-core/src/primitive/v1/asset/denom.rs @@ -634,8 +634,10 @@ mod tests { TooManySegments, }; #[track_caller] - // allow: silly lint - #[allow(clippy::needless_pass_by_value)] + #[expect( + clippy::needless_pass_by_value, + reason = "asserting on owned variants is less noisy then passing them by reference" + )] fn assert_error(input: &str, kind: ParseIbcPrefixedErrorKind) { let error = input .parse::() @@ -643,8 +645,6 @@ mod tests { assert_eq!(kind, error.0); } #[track_caller] - // allow: silly lint - #[allow(clippy::needless_pass_by_value)] fn assert_hex_error(input: &str) { let error = input .parse::() @@ -675,8 +675,10 @@ mod tests { Whitespace, }; #[track_caller] - // allow: silly lint - #[allow(clippy::needless_pass_by_value)] + #[expect( + clippy::needless_pass_by_value, + reason = "asserting on owned variants is less noisy then passing them by reference" + )] fn assert_error(input: &str, kind: ParseTracePrefixedErrorKind) { let error = input .parse::() diff --git a/crates/astria-core/src/primitive/v1/mod.rs b/crates/astria-core/src/primitive/v1/mod.rs index b544fa4241..29cd265b40 100644 --- a/crates/astria-core/src/primitive/v1/mod.rs +++ b/crates/astria-core/src/primitive/v1/mod.rs @@ -356,7 +356,7 @@ impl AddressBuilder { /// /// The verification key is hashed with SHA256 and the first 20 bytes are used as the address /// bytes. - #[allow(clippy::missing_panics_doc)] // allow clippy, as the conversion is infallible + #[expect(clippy::missing_panics_doc, reason = "the conversion is infallible")] #[must_use = "the builder must be built to construct an address to be useful"] pub fn verification_key( self, @@ -558,8 +558,10 @@ impl Address { impl Address { /// Convert [`Address`] to a [`raw::Address`]. - // allow: panics are checked to not happen - #[allow(clippy::missing_panics_doc)] + #[expect( + clippy::missing_panics_doc, + reason = "panics are checked to not happen" + )] #[must_use] pub fn to_raw(&self) -> raw::Address { let bech32m = @@ -567,8 +569,6 @@ impl Address { .expect( "should not fail because len(prefix) + len(bytes) <= 63 < BECH32M::CODELENGTH", ); - // allow: the field is deprecated, but we must still fill it in - #[allow(deprecated)] raw::Address { bech32m, } diff --git a/crates/astria-core/src/protocol/abci.rs b/crates/astria-core/src/protocol/abci.rs index c70c9165dd..5caf357459 100644 --- a/crates/astria-core/src/protocol/abci.rs +++ b/crates/astria-core/src/protocol/abci.rs @@ -1,7 +1,10 @@ use std::num::NonZeroU32; #[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "we want consistent and specific naming" +)] pub struct AbciErrorCode(NonZeroU32); #[rustfmt::skip] diff --git a/crates/astria-core/src/protocol/genesis/v1alpha1.rs b/crates/astria-core/src/protocol/genesis/v1alpha1.rs index c5a03b5918..79a69eaef4 100644 --- a/crates/astria-core/src/protocol/genesis/v1alpha1.rs +++ b/crates/astria-core/src/protocol/genesis/v1alpha1.rs @@ -131,6 +131,12 @@ impl Protobuf for GenesisAppState { type Error = GenesisAppStateError; type Raw = raw::GenesisAppState; + // TODO (https://github.com/astriaorg/astria/issues/1580): remove this once Rust is upgraded to/past 1.83 + #[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "false positive on `allowed_fee_assets` due to \"allow\" in the name" + )] fn try_from_raw_ref(raw: &Self::Raw) -> Result { let Self::Raw { address_prefixes, diff --git a/crates/astria-core/src/protocol/test_utils.rs b/crates/astria-core/src/protocol/test_utils.rs index d5a3a3b8c6..bc39e94edf 100644 --- a/crates/astria-core/src/protocol/test_utils.rs +++ b/crates/astria-core/src/protocol/test_utils.rs @@ -59,7 +59,10 @@ pub struct ConfigureSequencerBlock { impl ConfigureSequencerBlock { /// Construct a [`SequencerBlock`] with the configured parameters. #[must_use] - #[allow(clippy::missing_panics_doc)] // This should only be used in tests, so everything here is unwrapped + #[expect( + clippy::missing_panics_doc, + reason = "This should only be used in tests, so everything here is unwrapped" + )] pub fn make(self) -> SequencerBlock { use tendermint::Time; diff --git a/crates/astria-core/src/protocol/transaction/v1alpha1/action.rs b/crates/astria-core/src/protocol/transaction/v1alpha1/action.rs index d4bc1b8c6e..c6d8caf716 100644 --- a/crates/astria-core/src/protocol/transaction/v1alpha1/action.rs +++ b/crates/astria-core/src/protocol/transaction/v1alpha1/action.rs @@ -263,7 +263,10 @@ impl TryFrom for Action { } } -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "for parity with the Protobuf spec" +)] #[derive(Debug, thiserror::Error)] #[error(transparent)] pub struct ActionError(ActionErrorKind); @@ -393,7 +396,10 @@ enum SequenceActionErrorKind { } #[derive(Clone, Debug)] -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "for parity with the Protobuf spec" +)] pub struct SequenceAction { pub rollup_id: RollupId, pub data: Bytes, @@ -445,7 +451,10 @@ impl Protobuf for SequenceAction { } #[derive(Clone, Debug)] -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "for parity with the Protobuf spec" +)] pub struct TransferAction { pub to: Address, pub amount: u128, @@ -691,7 +700,10 @@ impl TryFrom, pub params: TransactionParams, diff --git a/crates/astria-core/src/sequencerblock/v1alpha1/block.rs b/crates/astria-core/src/sequencerblock/v1alpha1/block.rs index 8a677956af..8dee1fdd80 100644 --- a/crates/astria-core/src/sequencerblock/v1alpha1/block.rs +++ b/crates/astria-core/src/sequencerblock/v1alpha1/block.rs @@ -535,7 +535,6 @@ enum SequencerBlockHeaderErrorKind { /// /// Exists to provide convenient access to fields of a [`SequencerBlock`]. #[derive(Clone, Debug, PartialEq)] -#[allow(clippy::module_name_repetitions)] pub struct SequencerBlockParts { pub block_hash: [u8; 32], pub header: SequencerBlockHeader, @@ -547,7 +546,10 @@ pub struct SequencerBlockParts { /// `SequencerBlock` is constructed from a tendermint/cometbft block by /// converting its opaque `data` bytes into sequencer specific types. #[derive(Clone, Debug, PartialEq)] -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "we want consistent and specific naming" +)] pub struct SequencerBlock { /// The result of hashing the cometbft header. Guaranteed to not be `None` as compared to /// the cometbft/tendermint-rs return type. @@ -952,7 +954,6 @@ where /// /// Exists to provide convenient access to fields of a [`FilteredSequencerBlock`]. #[derive(Debug, Clone, PartialEq)] -#[allow(clippy::module_name_repetitions)] pub struct FilteredSequencerBlockParts { pub block_hash: [u8; 32], pub header: SequencerBlockHeader, @@ -967,7 +968,10 @@ pub struct FilteredSequencerBlockParts { } #[derive(Debug, Clone, PartialEq)] -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "we want consistent and specific naming" +)] pub struct FilteredSequencerBlock { block_hash: [u8; 32], header: SequencerBlockHeader, diff --git a/crates/astria-core/src/sequencerblock/v1alpha1/celestia.rs b/crates/astria-core/src/sequencerblock/v1alpha1/celestia.rs index 1646e9af3a..3e6f456d02 100644 --- a/crates/astria-core/src/sequencerblock/v1alpha1/celestia.rs +++ b/crates/astria-core/src/sequencerblock/v1alpha1/celestia.rs @@ -74,7 +74,6 @@ impl PreparedBlock { #[derive(Debug, thiserror::Error)] #[error("failed constructing a celestia rollup blob")] -#[allow(clippy::module_name_repetitions)] pub struct SubmittedRollupDataError { #[source] kind: SubmittedRollupDataErrorKind, @@ -153,7 +152,6 @@ impl UncheckedSubmittedRollupData { } #[derive(Clone, Debug)] -#[allow(clippy::module_name_repetitions)] pub struct SubmittedRollupData { /// The hash of the sequencer block. Must be 32 bytes. sequencer_block_hash: [u8; 32], @@ -280,7 +278,6 @@ impl SubmittedRollupData { #[derive(Debug, thiserror::Error)] #[error("failed constructing a celestia sequencer blob")] -#[allow(clippy::module_name_repetitions)] pub struct SubmittedMetadataError { #[source] kind: SubmittedMetadataErrorKind, @@ -475,7 +472,6 @@ impl UncheckedSubmittedMetadata { } #[derive(Clone, Debug)] -#[allow(clippy::module_name_repetitions)] pub struct SubmittedMetadata { /// The block hash obtained from hashing `.header`. block_hash: [u8; 32], diff --git a/crates/astria-eyre/Cargo.toml b/crates/astria-eyre/Cargo.toml index ab413456e4..6ee2bb106a 100644 --- a/crates/astria-eyre/Cargo.toml +++ b/crates/astria-eyre/Cargo.toml @@ -2,6 +2,7 @@ name = "astria-eyre" version = "0.1.0" edition = "2021" +rust-version = "1.81.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/astria-grpc-mock-test/Cargo.toml b/crates/astria-grpc-mock-test/Cargo.toml index 75193f992e..1767b42a7f 100644 --- a/crates/astria-grpc-mock-test/Cargo.toml +++ b/crates/astria-grpc-mock-test/Cargo.toml @@ -2,6 +2,7 @@ name = "astria-grpc-mock-test" version = "0.1.0" edition = "2021" +rust-version = "1.81.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/astria-grpc-mock-test/src/lib.rs b/crates/astria-grpc-mock-test/src/lib.rs index 3bc3f0398e..6dad4f20cb 100644 --- a/crates/astria-grpc-mock-test/src/lib.rs +++ b/crates/astria-grpc-mock-test/src/lib.rs @@ -1,5 +1,15 @@ -#![allow(unreachable_pub, clippy::pedantic, clippy::arithmetic_side_effects)] +#![allow( + unreachable_pub, + clippy::pedantic, + clippy::arithmetic_side_effects, + reason = "this crate is for testing only" +)] +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "cannot prevent generated files from having allow attributes" +)] pub mod health { include!("generated/grpc.health.v1.rs"); include!("generated/grpc.health.v1.serde.rs"); diff --git a/crates/astria-grpc-mock-test/tests/health/main.rs b/crates/astria-grpc-mock-test/tests/health/main.rs index beaef29db3..c90ce8f59b 100644 --- a/crates/astria-grpc-mock-test/tests/health/main.rs +++ b/crates/astria-grpc-mock-test/tests/health/main.rs @@ -1,5 +1,7 @@ -// allow just make the tests work for now -#![allow(clippy::should_panic_without_expect)] +#![expect( + clippy::should_panic_without_expect, + reason = "just make the tests work for now" +)] use std::{ net::SocketAddr, diff --git a/crates/astria-grpc-mock/Cargo.toml b/crates/astria-grpc-mock/Cargo.toml index 408ceaf43e..97f7c6a5b8 100644 --- a/crates/astria-grpc-mock/Cargo.toml +++ b/crates/astria-grpc-mock/Cargo.toml @@ -2,6 +2,7 @@ name = "astria-grpc-mock" version = "0.1.0" edition = "2021" +rust-version = "1.81.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/astria-grpc-mock/src/lib.rs b/crates/astria-grpc-mock/src/lib.rs index c709515f2c..3a5c898bcb 100644 --- a/crates/astria-grpc-mock/src/lib.rs +++ b/crates/astria-grpc-mock/src/lib.rs @@ -1,9 +1,10 @@ // allow: to be fixed in future PRs. This is used for testing and is not in a critical path. -#![allow( +#![expect( clippy::module_name_repetitions, clippy::missing_errors_doc, clippy::missing_panics_doc, - clippy::arithmetic_side_effects + clippy::arithmetic_side_effects, + reason = "only used for testing" )] use std::any::Any; diff --git a/crates/astria-merkle/benches/benchmark.rs b/crates/astria-merkle/benches/benchmark.rs index 3d10f45d34..085561efa6 100644 --- a/crates/astria-merkle/benches/benchmark.rs +++ b/crates/astria-merkle/benches/benchmark.rs @@ -7,9 +7,8 @@ use divan::{ }; use sha2::Sha256; -// allow: unused warning if `bench_include_allocs` feature is not enabled. -#[allow(dead_code)] #[cfg_attr(feature = "bench_include_allocs", global_allocator)] +#[cfg(feature = "bench_include_allocs")] static ALLOC: divan::AllocProfiler = divan::AllocProfiler::system(); /// Used to specify the size of data for leaves. diff --git a/crates/astria-merkle/src/lib.rs b/crates/astria-merkle/src/lib.rs index 2f3c5ae6af..9ca82b184a 100644 --- a/crates/astria-merkle/src/lib.rs +++ b/crates/astria-merkle/src/lib.rs @@ -218,7 +218,10 @@ impl<'a> LeafBuilder<'a> { /// Writes `bytes` into the builder, appending to the leaf. /// /// See [`Tree::build_leaf`] for example usage. - #[allow(clippy::missing_panics_doc)] // invariant of the system + #[expect( + clippy::missing_panics_doc, + reason = "invariant of the system: the hasher must be set" + )] pub fn write(&mut self, bytes: &[u8]) -> &mut Self { let hasher = self .hasher diff --git a/crates/astria-sequencer-client/src/extension_trait.rs b/crates/astria-sequencer-client/src/extension_trait.rs index 671d562310..a863911517 100644 --- a/crates/astria-sequencer-client/src/extension_trait.rs +++ b/crates/astria-sequencer-client/src/extension_trait.rs @@ -672,7 +672,6 @@ pub trait SequencerClientExt: Client { /// - If the transaction is not found. /// - If the transaction execution failed. /// - If the transaction proof is missing. - #[allow(clippy::blocks_in_conditions)] // Allow: erroneous clippy warning. Should be fixed in Rust 1.81 #[instrument(skip_all)] async fn wait_for_tx_inclusion( &self, diff --git a/crates/astria-sequencer-relayer/src/api.rs b/crates/astria-sequencer-relayer/src/api.rs index 11fc4d6bb4..96eba98e54 100644 --- a/crates/astria-sequencer-relayer/src/api.rs +++ b/crates/astria-sequencer-relayer/src/api.rs @@ -51,7 +51,6 @@ pub(crate) fn start(socket_addr: SocketAddr, relayer_state: RelayerState) -> Api axum::Server::bind(&socket_addr).serve(app.into_make_service()) } -#[allow(clippy::unused_async)] // Permit because axum handlers must be async #[instrument(skip_all)] async fn get_healthz(State(relayer_state): State) -> Healthz { if relayer_state.borrow().is_healthy() { @@ -67,7 +66,6 @@ async fn get_healthz(State(relayer_state): State) -> Healthz { /// /// + there is a current sequencer height (implying a block from sequencer was received) /// + there is a current data availability height (implying a height was received from the DA) -#[allow(clippy::unused_async)] // Permit because axum handlers must be async #[instrument(skip_all)] async fn get_readyz(State(relayer_state): State) -> Readyz { let is_relayer_online = relayer_state.borrow().is_ready(); @@ -78,7 +76,6 @@ async fn get_readyz(State(relayer_state): State) -> Readyz { } } -#[allow(clippy::unused_async)] // Permit because axum handlers must be async #[instrument(skip_all)] async fn get_status(State(relayer_state): State) -> Json { Json(*relayer_state.borrow()) diff --git a/crates/astria-sequencer-relayer/src/config.rs b/crates/astria-sequencer-relayer/src/config.rs index b884634e81..ee6a99e829 100644 --- a/crates/astria-sequencer-relayer/src/config.rs +++ b/crates/astria-sequencer-relayer/src/config.rs @@ -18,9 +18,11 @@ use serde::{ Serialize, }; -// Allowed `struct_excessive_bools` because this is used as a container -// for deserialization. Making this a builder-pattern is not actionable. -#[allow(clippy::struct_excessive_bools)] +#[expect( + clippy::struct_excessive_bools, + reason = "this is used as a container for deserialization. Making this a builder-pattern is \ + not actionable" +)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] /// The single config for creating an astria-sequencer-relayer service. pub struct Config { diff --git a/crates/astria-sequencer-relayer/src/relayer/celestia_client/celestia_keys.rs b/crates/astria-sequencer-relayer/src/relayer/celestia_client/celestia_keys.rs index 237c017e40..5a4a22a8e4 100644 --- a/crates/astria-sequencer-relayer/src/relayer/celestia_client/celestia_keys.rs +++ b/crates/astria-sequencer-relayer/src/relayer/celestia_client/celestia_keys.rs @@ -124,8 +124,11 @@ mod tests { #[test] fn should_fail_to_construct_from_missing_file() { let error = CelestiaKeys::from_path("missing").unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + // TODO (https://github.com/astriaorg/astria/issues/1581): create function for handling this and remove #[expect] (here and below) + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, Error::ReadFile(_)) { panic!("expected an error variant `Error::ReadFile`, got {error:?}"); } @@ -136,8 +139,10 @@ mod tests { let tmp_file = tempfile::NamedTempFile::new().unwrap(); fs::write(tmp_file.path(), b"not hex").unwrap(); let error = CelestiaKeys::from_path(tmp_file.path()).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure." + )] if !matches!(error, Error::DecodeFromHex(_)) { panic!("expected an error variant `Error::DecodeFromHex`, got {error:?}"); } @@ -148,8 +153,10 @@ mod tests { let tmp_file = tempfile::NamedTempFile::new().unwrap(); fs::write(tmp_file.path(), b"abcdef").unwrap(); let error = CelestiaKeys::from_path(tmp_file.path()).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure." + )] if !matches!(error, Error::InvalidSigningKey) { panic!("expected an error variant `Error::InvalidSigningKey`, got {error:?}"); } diff --git a/crates/astria-sequencer-relayer/src/relayer/celestia_client/mod.rs b/crates/astria-sequencer-relayer/src/relayer/celestia_client/mod.rs index b45a0e38ad..bc149b92f8 100644 --- a/crates/astria-sequencer-relayer/src/relayer/celestia_client/mod.rs +++ b/crates/astria-sequencer-relayer/src/relayer/celestia_client/mod.rs @@ -624,14 +624,13 @@ fn calculate_fee( // Calculate the fee from the provided values. // From https://github.com/celestiaorg/celestia-node/blob/v0.12.4/state/core_access.go#L225 - // - // allow: the gas limit should never be negative, and truncation/precision is not a problem - // as this is a best-effort calculation. If the result is incorrect, the retry will use - // the fee provided in the failure response. - #[allow( + #[expect( clippy::cast_sign_loss, clippy::cast_possible_truncation, - clippy::cast_precision_loss + clippy::cast_precision_loss, + reason = "the gas limit should never be negative, and truncation/precision is not a \ + problem as this is a best-effort calculation. If the result is incorrect, the \ + retry will use the fee provided in the failure response" )] let calculated_fee = (cost_params.min_gas_price() * gas_limit.0 as f64).ceil() as u64; diff --git a/crates/astria-sequencer-relayer/src/relayer/celestia_client/tests.rs b/crates/astria-sequencer-relayer/src/relayer/celestia_client/tests.rs index 7d59fdf02c..f6c4106230 100644 --- a/crates/astria-sequencer-relayer/src/relayer/celestia_client/tests.rs +++ b/crates/astria-sequencer-relayer/src/relayer/celestia_client/tests.rs @@ -28,8 +28,10 @@ fn new_msg_pay_for_blobs_should_succeed() { .collect(); assert_eq!(msg.namespaces, namespaces); - // allow: data length is small in this test case. - #[allow(clippy::cast_possible_truncation)] + #[expect( + clippy::cast_possible_truncation, + reason = "data length is small in this test case" + )] let blob_sizes: Vec<_> = blobs.iter().map(|blob| blob.data.len() as u32).collect(); assert_eq!(msg.blob_sizes, blob_sizes); @@ -55,8 +57,12 @@ fn new_msg_pay_for_blobs_should_fail_for_large_blob() { commitment: Commitment([0; 32]), }; let error = new_msg_pay_for_blobs(&[blob], Bech32Address("a".to_string())).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + + // TODO (https://github.com/astriaorg/astria/issues/1581): create function for handling this and remove #[expect] (here and below) + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::BlobTooLarge { byte_count } if byte_count == u32::MAX as usize + 1) { panic!("expected `Error::BlobTooLarge` with byte_count == u32::MAX + 1, got {error:?}"); @@ -87,8 +93,10 @@ fn account_from_good_response_should_succeed() { fn account_from_bad_response_should_fail() { // Should return `FailedToGetAccountInfo` if outer response is an error. let error = account_from_response(Err(Status::internal(""))).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::FailedToGetAccountInfo(_)) { panic!("expected `Error::FailedToGetAccountInfo`, got {error:?}"); } @@ -98,8 +106,10 @@ fn account_from_bad_response_should_fail() { account: None, })); let error = account_from_response(response).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::EmptyAccountInfo) { panic!("expected `Error::EmptyAccountInfo`, got {error:?}"); } @@ -135,8 +145,10 @@ fn account_from_bad_response_should_fail() { account: Some(bad_value_account), })); let error = account_from_response(response).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::DecodeAccountInfo(_)) { panic!("expected `Error::DecodeAccountInfo`, got {error:?}"); } @@ -149,8 +161,10 @@ fn min_gas_price_from_good_response_should_succeed() { minimum_gas_price: format!("{min_gas_price}utia"), }); let extracted_price = min_gas_price_from_response(Ok(response)).unwrap(); - // allow: this floating point comparison should be ok due to the hard-coded values chosen. - #[allow(clippy::float_cmp)] + #[expect( + clippy::float_cmp, + reason = "this floating point comparison should be ok due to the hard-coded values chosen" + )] { assert_eq!(min_gas_price, extracted_price); } @@ -160,8 +174,10 @@ fn min_gas_price_from_good_response_should_succeed() { fn min_gas_price_from_bad_response_should_fail() { // Should return `FailedToGetMinGasPrice` if outer response is an error. let error = min_gas_price_from_response(Err(Status::internal(""))).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::FailedToGetMinGasPrice(_)) { panic!("expected `Error::FailedToGetMinGasPrice`, got {error:?}"); } @@ -275,8 +291,10 @@ fn tx_hash_from_good_response_should_succeed() { fn tx_hash_from_bad_response_should_fail() { // Should return `FailedToBroadcastTx` if outer response is an error. let error = lowercase_hex_encoded_tx_hash_from_response(Err(Status::internal(""))).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::FailedToBroadcastTx(_)) { panic!("expected `Error::FailedToBroadcastTx`, got {error:?}"); } @@ -286,8 +304,10 @@ fn tx_hash_from_bad_response_should_fail() { tx_response: None, })); let error = lowercase_hex_encoded_tx_hash_from_response(response).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::EmptyBroadcastTxResponse) { panic!("expected `Error::EmptyBroadcastTxResponse`, got {error:?}"); } @@ -341,8 +361,10 @@ fn block_height_from_good_response_should_succeed() { fn block_height_from_bad_response_should_fail() { // Should return `FailedToGetTx` if outer response is an error other than `NotFound`. let error = block_height_from_response(Err(Status::internal(""))).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::FailedToGetTx(_)) { panic!("expected `Error::FailedToGetTx`, got {error:?}"); } @@ -353,8 +375,10 @@ fn block_height_from_bad_response_should_fail() { tx_response: None, })); let error = block_height_from_response(response).unwrap_err(); - // allow: `assert!(matches!(..))` provides poor feedback on failure. - #[allow(clippy::manual_assert)] + #[expect( + clippy::manual_assert, + reason = "`assert!(matches!(..))` provides poor feedback on failure" + )] if !matches!(error, TrySubmitError::EmptyGetTxResponse) { panic!("expected `Error::EmptyGetTxResponse`, got {error:?}"); } diff --git a/crates/astria-sequencer-relayer/src/relayer/mod.rs b/crates/astria-sequencer-relayer/src/relayer/mod.rs index 34d3f57410..9446beacb3 100644 --- a/crates/astria-sequencer-relayer/src/relayer/mod.rs +++ b/crates/astria-sequencer-relayer/src/relayer/mod.rs @@ -85,8 +85,11 @@ use crate::{ pub(crate) struct Relayer { /// A token to notify relayer that it should shut down. - // allow: want the prefix to disambiguate between this token and `submitter_shutdown_token`. - #[allow(clippy::struct_field_names)] + #[expect( + clippy::struct_field_names, + reason = "want the prefix to disambiguate between this token and \ + `submitter_shutdown_token`" + )] relayer_shutdown_token: CancellationToken, /// A child token of `relayer_shutdown_token` to notify the submitter task to shut down. diff --git a/crates/astria-sequencer-relayer/src/relayer/submission.rs b/crates/astria-sequencer-relayer/src/relayer/submission.rs index 54fb203cfb..bc9daa7493 100644 --- a/crates/astria-sequencer-relayer/src/relayer/submission.rs +++ b/crates/astria-sequencer-relayer/src/relayer/submission.rs @@ -470,8 +470,10 @@ mod as_number { use super::SequencerHeight; - // Allow: the function signature is dictated by the serde(with) attribute. - #[allow(clippy::trivially_copy_pass_by_ref)] + #[expect( + clippy::trivially_copy_pass_by_ref, + reason = "the function signature is dictated by the serde(with) attribute" + )] pub(super) fn serialize(height: &SequencerHeight, serializer: S) -> Result where S: Serializer, diff --git a/crates/astria-sequencer-relayer/src/relayer/write/conversion.rs b/crates/astria-sequencer-relayer/src/relayer/write/conversion.rs index c8dc9d354f..bb9b4a94d9 100644 --- a/crates/astria-sequencer-relayer/src/relayer/write/conversion.rs +++ b/crates/astria-sequencer-relayer/src/relayer/write/conversion.rs @@ -72,9 +72,11 @@ impl Submission { } /// The ratio of uncompressed blob size to compressed size. - // allow: used for metric gauges, which require f64. Precision loss is ok and of no - // significance. - #[allow(clippy::cast_precision_loss)] + #[expect( + clippy::cast_precision_loss, + reason = "used for metric gauges, which require f64. Precision loss is ok and of no \ + significance" + )] pub(super) fn compression_ratio(&self) -> f64 { self.uncompressed_size() as f64 / self.compressed_size() as f64 } diff --git a/crates/astria-sequencer-relayer/src/relayer/write/mod.rs b/crates/astria-sequencer-relayer/src/relayer/write/mod.rs index 4d41a74112..e9098cc4de 100644 --- a/crates/astria-sequencer-relayer/src/relayer/write/mod.rs +++ b/crates/astria-sequencer-relayer/src/relayer/write/mod.rs @@ -86,8 +86,6 @@ impl BlobSubmitterHandle { /// Send a block to the blob submitter immediately. /// /// This is a thin wrapper around [`mpsc::Sender::try_send`]. - // allow: just forwarding the error type - #[allow(clippy::result_large_err)] pub(super) fn try_send( &self, block: SequencerBlock, @@ -98,8 +96,6 @@ impl BlobSubmitterHandle { /// Sends a block to the blob submitter. /// /// This is a thin wrapper around [`mpsc::Sender::send`]. - // allow: just forwarding the error type - #[allow(clippy::result_large_err)] pub(super) async fn send( &self, block: SequencerBlock, diff --git a/crates/astria-sequencer-relayer/tests/blackbox/helpers/mock_sequencer_server.rs b/crates/astria-sequencer-relayer/tests/blackbox/helpers/mock_sequencer_server.rs index 3b7d7c25a3..c6135fda19 100644 --- a/crates/astria-sequencer-relayer/tests/blackbox/helpers/mock_sequencer_server.rs +++ b/crates/astria-sequencer-relayer/tests/blackbox/helpers/mock_sequencer_server.rs @@ -96,8 +96,6 @@ impl MockSequencerServer { } } -// allow: this is not performance-critical, with likely only one instance per test fixture. -#[allow(clippy::large_enum_variant)] pub enum SequencerBlockToMount { GoodAtHeight(u32), BadAtHeight(u32), diff --git a/crates/astria-sequencer-relayer/tests/blackbox/helpers/test_sequencer_relayer.rs b/crates/astria-sequencer-relayer/tests/blackbox/helpers/test_sequencer_relayer.rs index b1d57f9a4c..130d0e28a5 100644 --- a/crates/astria-sequencer-relayer/tests/blackbox/helpers/test_sequencer_relayer.rs +++ b/crates/astria-sequencer-relayer/tests/blackbox/helpers/test_sequencer_relayer.rs @@ -652,8 +652,10 @@ impl TestSequencerRelayer { } } -// allow: want the name to reflect this is a test config. -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "want the name to reflect this is a test config" +)] pub struct TestSequencerRelayerConfig { /// Sets the start height of relayer and configures the on-disk submission-state file to /// look accordingly. diff --git a/crates/astria-sequencer-relayer/tests/blackbox/main.rs b/crates/astria-sequencer-relayer/tests/blackbox/main.rs index 4598c6a827..93770c5dce 100644 --- a/crates/astria-sequencer-relayer/tests/blackbox/main.rs +++ b/crates/astria-sequencer-relayer/tests/blackbox/main.rs @@ -1,4 +1,7 @@ -#![allow(clippy::missing_panics_doc)] +#![expect( + clippy::missing_panics_doc, + reason = "these are tests, ok to not have panic docs" +)] pub mod helpers; diff --git a/crates/astria-sequencer-utils/src/blob_parser.rs b/crates/astria-sequencer-utils/src/blob_parser.rs index d63627946f..56658d244a 100644 --- a/crates/astria-sequencer-utils/src/blob_parser.rs +++ b/crates/astria-sequencer-utils/src/blob_parser.rs @@ -104,13 +104,17 @@ pub fn run( Ok(()) } +#[expect( + clippy::cast_precision_loss, + reason = "sizes mainly used for compression ratio" +)] fn parse(input: &str, verbose: bool) -> Result { let raw = get_decoded_blob_data(input)?; - #[allow(clippy::cast_precision_loss)] + let compressed_size = raw.len() as f32; let decompressed = Bytes::from(decompress_bytes(&raw).wrap_err("failed to decompress decoded bytes")?); - #[allow(clippy::cast_precision_loss)] + let decompressed_size = decompressed.len() as f32; let compression_ratio = decompressed_size / compressed_size; @@ -560,8 +564,7 @@ impl Display for PrintableDeposit { } } -// allow: not performance-critical. -#[allow(clippy::large_enum_variant)] +#[expect(clippy::large_enum_variant, reason = "not performance-critical")] #[derive(Serialize, Debug)] enum RollupDataDetails { #[serde(rename = "rollup_transaction")] diff --git a/crates/astria-sequencer/src/accounts/state_ext.rs b/crates/astria-sequencer/src/accounts/state_ext.rs index 49596f92e9..268798bfac 100644 --- a/crates/astria-sequencer/src/accounts/state_ext.rs +++ b/crates/astria-sequencer/src/accounts/state_ext.rs @@ -186,8 +186,6 @@ pub(crate) trait StateReadExt: StateRead + crate::assets::StateReadExt { } } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, fields(address = %address.display_address(), %asset), err)] async fn get_account_balance<'a, TAddress, TAsset>( &self, @@ -269,8 +267,6 @@ pub(crate) trait StateWriteExt: StateWrite { Ok(()) } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, fields(address = %address.display_address(), %asset, amount), err)] async fn increase_balance( &mut self, diff --git a/crates/astria-sequencer/src/address/state_ext.rs b/crates/astria-sequencer/src/address/state_ext.rs index 448a80e22a..df4d0d33d3 100644 --- a/crates/astria-sequencer/src/address/state_ext.rs +++ b/crates/astria-sequencer/src/address/state_ext.rs @@ -53,8 +53,6 @@ pub(crate) trait StateReadExt: StateRead { .wrap_err("failed to construct address from byte slice and state-provided base prefix") } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, err)] async fn get_base_prefix(&self) -> Result { let Some(bytes) = self @@ -68,8 +66,6 @@ pub(crate) trait StateReadExt: StateRead { String::from_utf8(bytes).context("prefix retrieved from storage is not valid utf8") } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, err)] async fn get_ibc_compat_prefix(&self) -> Result { let Some(bytes) = self diff --git a/crates/astria-sequencer/src/app/mod.rs b/crates/astria-sequencer/src/app/mod.rs index acaa7b2b9b..921f0fe9ac 100644 --- a/crates/astria-sequencer/src/app/mod.rs +++ b/crates/astria-sequencer/src/app/mod.rs @@ -174,9 +174,10 @@ pub(crate) struct App { // the currently committed `AppHash` of the application state. // set whenever `commit` is called. - // - // allow clippy because we need be specific as to what hash this is. - #[allow(clippy::struct_field_names)] + #[expect( + clippy::struct_field_names, + reason = "we need to be specific as to what hash this is" + )] app_hash: AppHash, metrics: &'static Metrics, diff --git a/crates/astria-sequencer/src/app/test_utils.rs b/crates/astria-sequencer/src/app/test_utils.rs index 0290b3ccf0..be68c81fc3 100644 --- a/crates/astria-sequencer/src/app/test_utils.rs +++ b/crates/astria-sequencer/src/app/test_utils.rs @@ -56,6 +56,11 @@ pub(crate) const CAROL_ADDRESS: &str = "4e8846b82a8f31fd59265a9005959c4a030fc44c pub(crate) const JUDY_ADDRESS: &str = "989a77160cb0e96e2d168083ab72ffe89b41c199"; pub(crate) const TED_ADDRESS: &str = "4c4f91d8a918357ab5f6f19c1e179968fc39bb44"; +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn get_alice_signing_key() -> SigningKey { // this secret key corresponds to ALICE_ADDRESS @@ -67,6 +72,11 @@ pub(crate) fn get_alice_signing_key() -> SigningKey { SigningKey::from(alice_secret_bytes) } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn get_bob_signing_key() -> SigningKey { // this secret key corresponds to ALICE_ADDRESS @@ -78,6 +88,11 @@ pub(crate) fn get_bob_signing_key() -> SigningKey { SigningKey::from(bob_secret_bytes) } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn get_carol_signing_key() -> SigningKey { // this secret key corresponds to ALICE_ADDRESS @@ -89,6 +104,11 @@ pub(crate) fn get_carol_signing_key() -> SigningKey { SigningKey::from(carol_secret_bytes) } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn get_judy_signing_key() -> SigningKey { // this secret key corresponds to ALICE_ADDRESS @@ -100,6 +120,11 @@ pub(crate) fn get_judy_signing_key() -> SigningKey { SigningKey::from(judy_secret_bytes) } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn get_bridge_signing_key() -> SigningKey { let bridge_secret_bytes: [u8; 32] = @@ -127,6 +152,11 @@ pub(crate) fn default_genesis_accounts() -> Vec { ] } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn default_fees() -> astria_core::protocol::genesis::v1alpha1::Fees { astria_core::protocol::genesis::v1alpha1::Fees { @@ -208,6 +238,11 @@ pub(crate) async fn initialize_app_with_storage( (app, storage.clone()) } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) async fn initialize_app( genesis_state: Option, @@ -217,6 +252,11 @@ pub(crate) async fn initialize_app( app } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn mock_tx( nonce: u32, @@ -306,6 +346,11 @@ pub(crate) fn mock_tx_cost( costs } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn mock_state_put_account_balances( state: &mut StateDelta, @@ -317,6 +362,11 @@ pub(crate) fn mock_state_put_account_balances( } } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn mock_state_put_account_nonce( state: &mut StateDelta, @@ -326,6 +376,11 @@ pub(crate) fn mock_state_put_account_nonce( state.put_account_nonce(address, nonce).unwrap(); } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) async fn mock_state_getter() -> StateDelta { let storage = cnidarium::TempStorage::new().await.unwrap(); diff --git a/crates/astria-sequencer/src/app/tests_app/mempool.rs b/crates/astria-sequencer/src/app/tests_app/mempool.rs index 65d327af80..ec325f6e28 100644 --- a/crates/astria-sequencer/src/app/tests_app/mempool.rs +++ b/crates/astria-sequencer/src/app/tests_app/mempool.rs @@ -41,7 +41,6 @@ use crate::{ }, }; -#[allow(clippy::too_many_lines)] #[tokio::test] async fn trigger_cleaning() { // check that cleaning is triggered by the prepare, process, and finalize block flows @@ -195,7 +194,7 @@ async fn do_not_trigger_cleaning() { assert!(!app.recost_mempool, "flag should not have been set"); } -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines, reason = "it's a test")] #[tokio::test] async fn maintenance_recosting_promotes() { // check that transaction promotion from recosting works @@ -374,7 +373,7 @@ async fn maintenance_recosting_promotes() { ); } -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines, reason = "it's a test")] #[tokio::test] async fn maintenance_funds_added_promotes() { // check that transaction promotion from new funds works diff --git a/crates/astria-sequencer/src/app/tests_app/mod.rs b/crates/astria-sequencer/src/app/tests_app/mod.rs index 9b41f44732..f62c655bf9 100644 --- a/crates/astria-sequencer/src/app/tests_app/mod.rs +++ b/crates/astria-sequencer/src/app/tests_app/mod.rs @@ -391,9 +391,11 @@ async fn app_create_sequencer_block_with_sequenced_data_and_deposits() { assert_eq!(*deposits[0], expected_deposit); } -// it's a test, so allow a lot of lines #[tokio::test] -#[allow(clippy::too_many_lines)] +#[expect( + clippy::too_many_lines, + reason = "it's a test, so allow a lot of lines" +)] async fn app_execution_results_match_proposal_vs_after_proposal() { let alice = get_alice_signing_key(); let (mut app, storage) = initialize_app_with_storage(None, vec![]).await; diff --git a/crates/astria-sequencer/src/app/tests_breaking_changes.rs b/crates/astria-sequencer/src/app/tests_breaking_changes.rs index c15c2ec7c5..4fd6225973 100644 --- a/crates/astria-sequencer/src/app/tests_breaking_changes.rs +++ b/crates/astria-sequencer/src/app/tests_breaking_changes.rs @@ -161,7 +161,7 @@ async fn app_finalize_block_snapshot() { // // If new actions are added to the app, they must be added to this test, // and the respective PR must be marked as breaking. -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines, reason = "it's a test")] #[tokio::test] async fn app_execute_transaction_with_every_action_snapshot() { use astria_core::protocol::transaction::v1alpha1::action::{ diff --git a/crates/astria-sequencer/src/assets/state_ext.rs b/crates/astria-sequencer/src/assets/state_ext.rs index 11075bb0d9..647e3740ef 100644 --- a/crates/astria-sequencer/src/assets/state_ext.rs +++ b/crates/astria-sequencer/src/assets/state_ext.rs @@ -99,8 +99,6 @@ pub(crate) trait StateReadExt: StateRead { .is_some()) } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, fields(%asset), err)] async fn map_ibc_to_trace_prefixed_asset( &self, diff --git a/crates/astria-sequencer/src/benchmark_utils.rs b/crates/astria-sequencer/src/benchmark_utils.rs index 2e5cfe8225..cbf9faafca 100644 --- a/crates/astria-sequencer/src/benchmark_utils.rs +++ b/crates/astria-sequencer/src/benchmark_utils.rs @@ -74,8 +74,10 @@ pub(crate) fn transactions(tx_types: TxTypes) -> &'static Vec Vec> { let mut nonces_and_chain_ids = HashMap::new(); signing_keys() diff --git a/crates/astria-sequencer/src/bridge/bridge_lock_action.rs b/crates/astria-sequencer/src/bridge/bridge_lock_action.rs index 6e9279f49a..6c4bc83246 100644 --- a/crates/astria-sequencer/src/bridge/bridge_lock_action.rs +++ b/crates/astria-sequencer/src/bridge/bridge_lock_action.rs @@ -289,7 +289,10 @@ mod tests { } #[track_caller] - #[allow(clippy::arithmetic_side_effects)] // allow: test will never overflow u128 + #[expect( + clippy::arithmetic_side_effects, + reason = "adding length of strings will never overflow u128 on currently existing machines" + )] fn assert_correct_base_deposit_fee(deposit: &Deposit) { let calculated_len = calculate_base_deposit_fee(deposit).unwrap(); let expected_len = DEPOSIT_BASE_FEE diff --git a/crates/astria-sequencer/src/bridge/query.rs b/crates/astria-sequencer/src/bridge/query.rs index fe619a9dd8..2acd2dd23a 100644 --- a/crates/astria-sequencer/src/bridge/query.rs +++ b/crates/astria-sequencer/src/bridge/query.rs @@ -41,9 +41,9 @@ fn error_query_response( } } -// allow / FIXME: there is a lot of code duplication due to `error_query_response`. +// FIXME (https://github.com/astriaorg/astria/issues/1582): there is a lot of code duplication due to `error_query_response`. // this could be significantly shortened. -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines, reason = "should be refactored")] async fn get_bridge_account_info( snapshot: cnidarium::Snapshot, address: Address, diff --git a/crates/astria-sequencer/src/bridge/state_ext.rs b/crates/astria-sequencer/src/bridge/state_ext.rs index 6f0f0dbe4e..f88b6ecfec 100644 --- a/crates/astria-sequencer/src/bridge/state_ext.rs +++ b/crates/astria-sequencer/src/bridge/state_ext.rs @@ -174,8 +174,6 @@ pub(crate) trait StateReadExt: StateRead + address::StateReadExt { Ok(maybe_id.is_some()) } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, fields(address = %address.display_address()), err)] async fn get_bridge_account_rollup_id( &self, @@ -196,8 +194,6 @@ pub(crate) trait StateReadExt: StateRead + address::StateReadExt { Ok(Some(rollup_id)) } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, fields(address = %address.display_address()), err)] async fn get_bridge_account_ibc_asset( &self, @@ -713,7 +709,6 @@ mod tests { } #[tokio::test] - #[allow(clippy::too_many_lines)] // allow: it's a test async fn get_deposits() { let storage = cnidarium::TempStorage::new().await.unwrap(); let snapshot = storage.latest_snapshot(); diff --git a/crates/astria-sequencer/src/config.rs b/crates/astria-sequencer/src/config.rs index 234a67ca5e..74955647c8 100644 --- a/crates/astria-sequencer/src/config.rs +++ b/crates/astria-sequencer/src/config.rs @@ -5,9 +5,11 @@ use serde::{ Serialize, }; -// Allowed `struct_excessive_bools` because this is used as a container -// for deserialization. Making this a builder-pattern is not actionable. -#[allow(clippy::struct_excessive_bools)] +#[expect( + clippy::struct_excessive_bools, + reason = "this is used as a container for deserialization. Making this a builder-pattern is \ + not actionable" +)] #[derive(Debug, Deserialize, Serialize)] pub struct Config { /// The endpoint on which Sequencer will listen for ABCI requests diff --git a/crates/astria-sequencer/src/ibc/ics20_transfer.rs b/crates/astria-sequencer/src/ibc/ics20_transfer.rs index 67126d817e..0462e9e768 100644 --- a/crates/astria-sequencer/src/ibc/ics20_transfer.rs +++ b/crates/astria-sequencer/src/ibc/ics20_transfer.rs @@ -345,8 +345,6 @@ impl AppHandlerExecute for Ics20Transfer { async fn chan_close_init_execute(_: S, _: &MsgChannelCloseInit) {} - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, err)] async fn recv_packet_execute( mut state: S, @@ -373,8 +371,6 @@ impl AppHandlerExecute for Ics20Transfer { .context("failed to write acknowledgement") } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, err)] async fn timeout_packet_execute( mut state: S, @@ -385,8 +381,6 @@ impl AppHandlerExecute for Ics20Transfer { }) } - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, err)] async fn acknowledge_packet_execute( mut state: S, diff --git a/crates/astria-sequencer/src/ibc/state_ext.rs b/crates/astria-sequencer/src/ibc/state_ext.rs index 09b3cb3db5..c490dcb8d1 100644 --- a/crates/astria-sequencer/src/ibc/state_ext.rs +++ b/crates/astria-sequencer/src/ibc/state_ext.rs @@ -72,8 +72,6 @@ fn ibc_relayer_key(address: &T) -> String { #[async_trait] pub(crate) trait StateReadExt: StateRead { - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, fields(%channel, %asset), err)] async fn get_ibc_channel_balance( &self, @@ -142,8 +140,6 @@ impl StateReadExt for T {} #[async_trait] pub(crate) trait StateWriteExt: StateWrite { - // allow: false positive due to proc macro; fixed with rust/clippy 1.81 - #[allow(clippy::blocks_in_conditions)] #[instrument(skip_all, fields(%channel, %asset, amount), err)] async fn decrease_ibc_channel_balance( &mut self, diff --git a/crates/astria-sequencer/src/mempool/benchmarks.rs b/crates/astria-sequencer/src/mempool/benchmarks.rs index d8df9dc718..cbf430e3c2 100644 --- a/crates/astria-sequencer/src/mempool/benchmarks.rs +++ b/crates/astria-sequencer/src/mempool/benchmarks.rs @@ -2,7 +2,7 @@ //! ```sh //! cargo bench --features=benchmark -qp astria-sequencer mempool //! ``` -#![allow(non_camel_case_types)] +#![expect(non_camel_case_types, reason = "for benchmark")] use std::{ sync::Arc, @@ -285,9 +285,11 @@ fn run_maintenance(bencher: divan::Bencher) { .unwrap(); // Set the new nonce so that the entire `REMOVAL_CACHE_SIZE` entries in the // `comet_bft_removal_cache` are filled (assuming this test case has enough txs). - // allow: this is test-only code, using small values, and where the result is not critical. - #[allow(clippy::arithmetic_side_effects, clippy::cast_possible_truncation)] - let new_nonce = (super::REMOVAL_CACHE_SIZE as u32 / u32::from(SIGNER_COUNT)) + 1; + let new_nonce = u32::try_from(super::REMOVAL_CACHE_SIZE) + .unwrap() + .checked_div(u32::from(SIGNER_COUNT)) + .and_then(|res| res.checked_add(1)) + .unwrap(); let mock_balances = mock_balances(0, 0); let mut mock_state = runtime.block_on(mock_state_getter()); @@ -325,9 +327,11 @@ fn run_maintenance_tx_recosting(bencher: divan::Bencher) { .unwrap(); // Set the new nonce so that the entire `REMOVAL_CACHE_SIZE` entries in the // `comet_bft_removal_cache` are filled (assuming this test case has enough txs). - // allow: this is test-only code, using small values, and where the result is not critical. - #[allow(clippy::arithmetic_side_effects, clippy::cast_possible_truncation)] - let new_nonce = (super::REMOVAL_CACHE_SIZE as u32 / u32::from(SIGNER_COUNT)) + 1; + let new_nonce = u32::try_from(super::REMOVAL_CACHE_SIZE) + .unwrap() + .checked_div(u32::from(SIGNER_COUNT)) + .and_then(|res| res.checked_add(1)) + .unwrap(); let mock_balances = mock_balances(0, 0); let mut mock_state = runtime.block_on(mock_state_getter()); diff --git a/crates/astria-sequencer/src/mempool/mod.rs b/crates/astria-sequencer/src/mempool/mod.rs index b47f2482a3..5916b85123 100644 --- a/crates/astria-sequencer/src/mempool/mod.rs +++ b/crates/astria-sequencer/src/mempool/mod.rs @@ -640,7 +640,6 @@ mod tests { ); } - #[allow(clippy::too_many_lines)] #[tokio::test] async fn run_maintenance_demotion() { let mempool = Mempool::new(); diff --git a/crates/astria-sequencer/src/mempool/transactions_container.rs b/crates/astria-sequencer/src/mempool/transactions_container.rs index 62cd0d2fbd..25d5cad27e 100644 --- a/crates/astria-sequencer/src/mempool/transactions_container.rs +++ b/crates/astria-sequencer/src/mempool/transactions_container.rs @@ -827,8 +827,11 @@ mod tests { // From https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html #[test] - // allow: we want explicit assertions here to match the documented expected behavior. - #[allow(clippy::nonminimal_bool)] + // TODO (https://github.com/astriaorg/astria/issues/1583): rework assertions and remove attribute + #[expect( + clippy::nonminimal_bool, + reason = "we want explicit assertions here to match the documented expected behavior" + )] fn transaction_priority_comparisons_should_be_consistent_nonce_diff() { let instant = Instant::now(); @@ -878,8 +881,10 @@ mod tests { // From https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html #[test] - // allow: we want explicit assertions here to match the documented expected behavior. - #[allow(clippy::nonminimal_bool)] + #[expect( + clippy::nonminimal_bool, + reason = "we want explicit assertions here to match the documented expected behavior" + )] fn transaction_priority_comparisons_should_be_consistent_time_gap() { let high = TransactionPriority { nonce_diff: 0, diff --git a/crates/astria-sequencer/src/metrics.rs b/crates/astria-sequencer/src/metrics.rs index d051c68cfc..8dadf7fcdc 100644 --- a/crates/astria-sequencer/src/metrics.rs +++ b/crates/astria-sequencer/src/metrics.rs @@ -158,9 +158,11 @@ impl Metrics { impl telemetry::Metrics for Metrics { type Config = (); - // allow: this is reasonable as we have a lot of metrics to register; the function is not - // complex, just long. - #[allow(clippy::too_many_lines)] + #[expect( + clippy::too_many_lines, + reason = "this is reasonable as we have a lot of metrics to register; the function is not \ + complex, just long" + )] fn register( builder: &mut RegisteringBuilder, _config: &Self::Config, diff --git a/crates/astria-sequencer/src/service/mempool.rs b/crates/astria-sequencer/src/service/mempool.rs index 73f79f8ffc..b0077e820b 100644 --- a/crates/astria-sequencer/src/service/mempool.rs +++ b/crates/astria-sequencer/src/service/mempool.rs @@ -110,7 +110,6 @@ impl Service for Mempool { /// as well as stateful checks (nonce and balance checks). /// /// If the tx passes all checks, status code 0 is returned. -#[allow(clippy::too_many_lines)] #[instrument(skip_all)] async fn handle_check_tx( req: request::CheckTx, diff --git a/crates/astria-sequencer/src/test_utils.rs b/crates/astria-sequencer/src/test_utils.rs index 0d3bdd35df..2fcf2b9d95 100644 --- a/crates/astria-sequencer/src/test_utils.rs +++ b/crates/astria-sequencer/src/test_utils.rs @@ -15,6 +15,11 @@ pub(crate) fn astria_address(bytes: &[u8]) -> Address { .unwrap() } +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] #[cfg_attr(feature = "benchmark", allow(dead_code))] pub(crate) fn astria_compat_address(bytes: &[u8]) -> Address { Address::builder() diff --git a/crates/astria-sequencer/src/transaction/mod.rs b/crates/astria-sequencer/src/transaction/mod.rs index 9dc97c7ee1..5a1c2d2e32 100644 --- a/crates/astria-sequencer/src/transaction/mod.rs +++ b/crates/astria-sequencer/src/transaction/mod.rs @@ -154,10 +154,10 @@ impl ActionHandler for SignedTransaction { Ok(()) } - // allowed / FIXME: because most lines come from delegating (and error wrapping) to the + // FIXME (https://github.com/astriaorg/astria/issues/1584): because most lines come from delegating (and error wrapping) to the // individual actions. This could be tidied up by implementing `ActionHandler for Action` // and letting it delegate. - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines, reason = "should be refactored")] async fn check_and_execute(&self, mut state: S) -> Result<()> { // Add the current signed transaction into the ephemeral state in case // downstream actions require access to it. diff --git a/crates/astria-telemetry/src/metrics/builders.rs b/crates/astria-telemetry/src/metrics/builders.rs index 4e3a202681..7832e81b87 100644 --- a/crates/astria-telemetry/src/metrics/builders.rs +++ b/crates/astria-telemetry/src/metrics/builders.rs @@ -83,8 +83,10 @@ impl ConfigBuilder { /// respectively, starts the http server if enabled, sets the global metrics recorder if /// requested and returns a new metrics object of type `T` along with a handle for rendering /// current metrics. - // allow: no useful error info can be added without writing excessive details. - #[allow(clippy::missing_errors_doc)] + #[expect( + clippy::missing_errors_doc, + reason = "no useful error info can be added without writing excessive details" + )] pub fn build(self, config: &T::Config) -> Result<(T, Handle), Error> { // Apply settings to the prometheus builder. let mut prometheus_builder = PrometheusBuilder::new(); diff --git a/crates/astria-telemetry/src/metrics/error.rs b/crates/astria-telemetry/src/metrics/error.rs index 1e12ba2bd7..f0cfa264f0 100644 --- a/crates/astria-telemetry/src/metrics/error.rs +++ b/crates/astria-telemetry/src/metrics/error.rs @@ -74,6 +74,8 @@ pub enum Error { /// An error while starting the metrics exporter server. #[derive(Error, Debug)] #[error(transparent)] -// allow: the name correctly reflects the type. -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "the name correctly reflects the type" +)] pub struct StartListeningError(#[from] metrics_exporter_prometheus::BuildError); diff --git a/crates/astria-telemetry/src/metrics/into_f64.rs b/crates/astria-telemetry/src/metrics/into_f64.rs index 078d6211c8..e99165029b 100644 --- a/crates/astria-telemetry/src/metrics/into_f64.rs +++ b/crates/astria-telemetry/src/metrics/into_f64.rs @@ -59,8 +59,10 @@ impl IntoF64 for f32 { } impl IntoF64 for usize { - // allow: precision loss is unlikely (values too small) but also unimportant in metrics. - #[allow(clippy::cast_precision_loss)] + #[expect( + clippy::cast_precision_loss, + reason = "precision loss is unlikely (values too small) but also unimportant in metrics" + )] fn into_f64(self) -> f64 { self as f64 } diff --git a/crates/astria-test-utils/src/mock/geth.rs b/crates/astria-test-utils/src/mock/geth.rs index a7f56eee46..4551f6e2c7 100644 --- a/crates/astria-test-utils/src/mock/geth.rs +++ b/crates/astria-test-utils/src/mock/geth.rs @@ -62,7 +62,10 @@ use std::net::SocketAddr; -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "naming is helpful for clarity here" +)] pub use __rpc_traits::GethServer; use ethers::types::Transaction; use jsonrpsee::{ @@ -136,7 +139,10 @@ impl From for SubscriptionCommand { } } -#[allow(clippy::module_name_repetitions)] +#[expect( + clippy::module_name_repetitions, + reason = "naming is helpful for clarity here" +)] pub struct GethImpl { command: Sender, } diff --git a/lint/tracing_debug_field/ui/main.rs b/lint/tracing_debug_field/ui/main.rs index a278bfe4f4..4aa135c9b7 100644 --- a/lint/tracing_debug_field/ui/main.rs +++ b/lint/tracing_debug_field/ui/main.rs @@ -1,4 +1,4 @@ -#[allow(clippy::all)] +#[expect(clippy::all)] use tracing::info; #[expect(