From 40e86f02daceac85fa0424acd075eb1ba94628a6 Mon Sep 17 00:00:00 2001 From: Josh Bowen Date: Wed, 23 Oct 2024 15:49:35 -0600 Subject: [PATCH] Add `sign` and `submit` subcommands to `sequencer` CLI (#1696) ## Summary > [!NOTE] > Most of the code is copied from Sam (https://github.com/astriaorg/astria/pull/1695) and Jordan's (https://github.com/astriaorg/astria/pull/1694) PRs. Add two new subcommands `sign` and `submit` to the `sequencer` subcommand. ### `sign` 1. Reads a pbjson formatted `astria.protocol.transaction.v1.TransactionBody` from a file or `STDIN` (`file` is a positional argument; `STDIN` is read when providing `-` as the trailing argument). 2. Signs it with a given private key (`--private-key`). 3. Writes the pbjson formatted `astria.protocol.transaction.v1.Transaction` to `--output`/`-o`, if provided, or `STDOUT`. ### `submit` 1. 1. Reads a pbjson formatted `astria.protocol.transaction.v1.Transaction` from a file or `STDIN` (`file` is a positional argument; `STDIN` is read when providing `-` as the trailing argument). 2. Submits it to a sequencer's CometBFT url (`--sequencer-url`) ## Background We want to be able to test the submitting txs signed via FROST threshold signing (see https://github.com/astriaorg/astria/pull/1654) but do not have a CLI command to submit already signed transactions. The `submit` command resolves this. To test the `submit` command it is desirable to have a corresponding `sign` command which creates a signed `Transaction` from a single private key. ## Changes - List changes which were made. ## Testing 1. Run a local sequencer network using `astria-cli-go` ``` just run dev purge all just run dev init just run dev run --network local ``` 2. Sign a `TransactionBody`: ``` cargo run -p astria-cli -- sequencer sign --private-key 2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90 - < --------- Co-authored-by: Sam Bukowski Co-authored-by: Richard Janis Goldschmidt Co-authored-by: Fraser Hutchison Co-authored-by: Jordan Oroshiba --- Cargo.lock | 10 + .../src/bridge_withdrawer/startup.rs | 1 + .../tests/blackbox/helpers/mock_cometbft.rs | 1 + crates/astria-cli/Cargo.toml | 4 + crates/astria-cli/src/sequencer/mod.rs | 13 + crates/astria-cli/src/sequencer/sign.rs | 99 ++++++++ crates/astria-cli/src/sequencer/submit.rs | 73 ++++++ crates/astria-composer/src/executor/mod.rs | 1 + .../tests/blackbox/helper/mod.rs | 1 + crates/astria-core/src/protocol/test_utils.rs | 1 + .../src/protocol/transaction/v1/mod.rs | 235 ++++++++++++------ .../src/extension_trait.rs | 21 +- crates/astria-sequencer/src/app/mod.rs | 1 + .../src/app/tests_block_ordering.rs | 9 +- crates/astria-sequencer/src/fees/query.rs | 1 + .../astria-sequencer/src/service/consensus.rs | 1 + .../src/service/mempool/mod.rs | 1 + .../src/service/mempool/tests.rs | 1 + 18 files changed, 382 insertions(+), 92 deletions(-) create mode 100644 crates/astria-cli/src/sequencer/sign.rs create mode 100644 crates/astria-cli/src/sequencer/submit.rs diff --git a/Cargo.lock b/Cargo.lock index 6830613bac..cd9411c55e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -566,6 +566,7 @@ dependencies = [ "astria-core", "astria-sequencer-client", "clap", + "clap-stdin", "color-eyre", "ethers", "frost-ed25519", @@ -1779,6 +1780,15 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap-stdin" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471df7896633bfc1e7d3da5b598422891e4cb8931210168ec63ea586e285803f" +dependencies = [ + "thiserror", +] + [[package]] name = "clap_builder" version = "4.5.15" diff --git a/crates/astria-bridge-withdrawer/src/bridge_withdrawer/startup.rs b/crates/astria-bridge-withdrawer/src/bridge_withdrawer/startup.rs index 74e98d882e..033b53f0a2 100644 --- a/crates/astria-bridge-withdrawer/src/bridge_withdrawer/startup.rs +++ b/crates/astria-bridge-withdrawer/src/bridge_withdrawer/startup.rs @@ -15,6 +15,7 @@ use astria_core::{ memos, transaction::v1::Action, }, + Protobuf as _, }; use astria_eyre::eyre::{ self, diff --git a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mock_cometbft.rs b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mock_cometbft.rs index 6fd9403da8..c3f23d53fc 100644 --- a/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mock_cometbft.rs +++ b/crates/astria-bridge-withdrawer/tests/blackbox/helpers/mock_cometbft.rs @@ -3,6 +3,7 @@ use std::time::Duration; use astria_core::{ primitive::v1::asset, protocol::bridge::v1::BridgeAccountLastTxHashResponse, + Protobuf as _, }; use prost::Message as _; use sequencer_client::{ diff --git a/crates/astria-cli/Cargo.toml b/crates/astria-cli/Cargo.toml index 6c8ecfa352..ef82a17fb1 100644 --- a/crates/astria-cli/Cargo.toml +++ b/crates/astria-cli/Cargo.toml @@ -8,8 +8,12 @@ readme = "README.md" repository = "https://github.com/astriaorg/astria" homepage = "https://astria.org" +[[bin]] +name = "astria-cli" + [dependencies] color-eyre = "0.6" +clap-stdin = "0.5.1" # v2.0.0-rc.0 - can be updated once https://github.com/ZcashFoundation/frost/issues/755 is closed frost-ed25519 = { version = "2.0.0-rc.0", features = [] } serde_yaml = "0.9.25" diff --git a/crates/astria-cli/src/sequencer/mod.rs b/crates/astria-cli/src/sequencer/mod.rs index 6a62680681..e972907a66 100644 --- a/crates/astria-cli/src/sequencer/mod.rs +++ b/crates/astria-cli/src/sequencer/mod.rs @@ -8,6 +8,8 @@ mod block_height; mod bridge_lock; mod ics20_withdrawal; mod init_bridge_account; +mod sign; +mod submit; mod sudo; mod threshold; mod transfer; @@ -31,6 +33,8 @@ impl Command { SubCommand::Transfer(transfer) => transfer.run().await, SubCommand::Threshold(threshold) => threshold.run().await, SubCommand::Ics20Withdrawal(ics20_withdrawal) => ics20_withdrawal.run().await, + SubCommand::Submit(submit) => submit.run().await, + SubCommand::Sign(sign) => sign.run(), } } } @@ -59,4 +63,13 @@ enum SubCommand { Threshold(threshold::Command), /// Command for withdrawing an ICS20 asset Ics20Withdrawal(ics20_withdrawal::Command), + /// Submit the signed pbjson formatted Transaction. + Submit(submit::Command), + /// Sign a pbjson formatted TransactionBody to produce a Transaction. + #[expect( + clippy::doc_markdown, + reason = "doc comments are turned into CLI help strings which currently don't use \ + backticks" + )] + Sign(sign::Command), } diff --git a/crates/astria-cli/src/sequencer/sign.rs b/crates/astria-cli/src/sequencer/sign.rs new file mode 100644 index 0000000000..19dce260dc --- /dev/null +++ b/crates/astria-cli/src/sequencer/sign.rs @@ -0,0 +1,99 @@ +use std::{ + io::Write, + path::{ + Path, + PathBuf, + }, +}; + +use astria_core::{ + protocol::transaction::v1::TransactionBody, + Protobuf, +}; +use clap_stdin::FileOrStdin; +use color_eyre::eyre::{ + self, + WrapErr as _, +}; + +use crate::utils::signing_key_from_private_key; + +#[derive(clap::Args, Debug)] +pub(super) struct Command { + /// The private key of account being sent from + #[arg(long, env = "SEQUENCER_PRIVATE_KEY")] + // TODO: https://github.com/astriaorg/astria/issues/594 + // Don't use a plain text private, prefer wrapper like from + // the secrecy crate with specialized `Debug` and `Drop` implementations + // that overwrite the key on drop and don't reveal it when printing. + private_key: String, + /// Target to write the signed transaction in pbjson format (omit to write to STDOUT). + #[arg(long, short)] + output: Option, + /// Forces an overwrite of `--output` if a file at that location exists. + #[arg(long, short)] + force: bool, + /// The source to read the pbjson formatted astra.protocol.transaction.v1.Transaction (use `-` + /// to pass via STDIN). + input: FileOrStdin, +} + +// The goal of the `sign` CLI command is to take in a `TransactionBody` and to sign with a private +// key to create a `Transaction`. This signed `Transaction` should be printed to the console in +// pbjson format. +impl Command { + pub(super) fn run(self) -> eyre::Result<()> { + let key = signing_key_from_private_key(self.private_key.as_str())?; + + let filename = self.input.filename().to_string(); + let transaction_body = read_transaction_body(self.input) + .wrap_err_with(|| format!("failed to read transaction body from `{filename}`"))?; + let transaction = transaction_body.sign(&key); + + serde_json::to_writer( + stdout_or_file(self.output.as_ref(), self.force) + .wrap_err("failed to determine output target")?, + &transaction.to_raw(), + ) + .wrap_err("failed to write signed transaction")?; + Ok(()) + } +} + +fn read_transaction_body(input: FileOrStdin) -> eyre::Result { + let wire_body: ::Raw = serde_json::from_reader( + std::io::BufReader::new(input.into_reader()?), + ) + .wrap_err_with(|| { + format!( + "failed to parse input as json `{}`", + TransactionBody::full_name() + ) + })?; + TransactionBody::try_from_raw(wire_body).wrap_err("failed to validate transaction body") +} + +fn stdout_or_file>( + output: Option

, + force_overwrite: bool, +) -> eyre::Result> { + let writer = match output { + Some(path) => { + let file = if force_overwrite { + std::fs::File::options() + .write(true) + .truncate(true) + .open(path) + } else { + std::fs::File::options() + .create_new(true) + .write(true) + .open(path) + } + .wrap_err("failed to open file for writing")?; + Box::new(file) as Box + } + None => Box::new(std::io::stdout()), + }; + Ok(writer) +} diff --git a/crates/astria-cli/src/sequencer/submit.rs b/crates/astria-cli/src/sequencer/submit.rs new file mode 100644 index 0000000000..577ef59c23 --- /dev/null +++ b/crates/astria-cli/src/sequencer/submit.rs @@ -0,0 +1,73 @@ +use astria_core::{ + self, + protocol::transaction::v1::Transaction, + Protobuf, +}; +use astria_sequencer_client::{ + HttpClient, + SequencerClientExt as _, +}; +use clap_stdin::FileOrStdin; +use color_eyre::eyre::{ + self, + ensure, + WrapErr as _, +}; + +#[derive(clap::Args, Debug)] +pub(super) struct Command { + /// The URL at which the Sequencer node is listening for ABCI commands. + #[arg( + long, + env = "SEQUENCER_URL", + default_value = crate::DEFAULT_SEQUENCER_RPC + )] + sequencer_url: String, + /// The source to read the pbjson formatted astra.protocol.transaction.v1.Transaction (use `-` + /// to pass via STDIN). + input: FileOrStdin, +} + +// The 'submit' command takes a 'Transaction' in pbjson form and submits it to the sequencer +impl Command { + pub(super) async fn run(self) -> eyre::Result<()> { + let sequencer_client = HttpClient::new(self.sequencer_url.as_str()) + .wrap_err("failed constructing http sequencer client")?; + + let filename = self.input.filename().to_string(); + let transaction = read_transaction(self.input) + .wrap_err_with(|| format!("to signed transaction from `{filename}`"))?; + + let res = sequencer_client + .submit_transaction_sync(transaction) + .await + .wrap_err("failed to submit transaction")?; + + ensure!(res.code.is_ok(), "failed to check tx: {}", res.log); + + let tx_response = sequencer_client.wait_for_tx_inclusion(res.hash).await; + + ensure!( + tx_response.tx_result.code.is_ok(), + "failed to execute tx: {}", + tx_response.tx_result.log + ); + + println!("Submission completed!"); + println!("Included in block: {}", tx_response.height); + Ok(()) + } +} + +fn read_transaction(input: FileOrStdin) -> eyre::Result { + let wire_body: ::Raw = serde_json::from_reader( + std::io::BufReader::new(input.into_reader()?), + ) + .wrap_err_with(|| { + format!( + "failed to parse input as json `{}`", + Transaction::full_name() + ) + })?; + Transaction::try_from_raw(wire_body).wrap_err("failed to validate transaction body") +} diff --git a/crates/astria-composer/src/executor/mod.rs b/crates/astria-composer/src/executor/mod.rs index 1052b143bb..a07b2e4fe6 100644 --- a/crates/astria-composer/src/executor/mod.rs +++ b/crates/astria-composer/src/executor/mod.rs @@ -26,6 +26,7 @@ use astria_core::{ Transaction, }, }, + Protobuf as _, }; use astria_eyre::eyre::{ self, diff --git a/crates/astria-composer/tests/blackbox/helper/mod.rs b/crates/astria-composer/tests/blackbox/helper/mod.rs index 06eaadd12d..93f7f6a1a7 100644 --- a/crates/astria-composer/tests/blackbox/helper/mod.rs +++ b/crates/astria-composer/tests/blackbox/helper/mod.rs @@ -26,6 +26,7 @@ use astria_core::{ abci::AbciErrorCode, transaction::v1::Transaction, }, + Protobuf as _, }; use astria_eyre::eyre; use ethers::prelude::Transaction as EthersTransaction; diff --git a/crates/astria-core/src/protocol/test_utils.rs b/crates/astria-core/src/protocol/test_utils.rs index c31497a294..510c78e57e 100644 --- a/crates/astria-core/src/protocol/test_utils.rs +++ b/crates/astria-core/src/protocol/test_utils.rs @@ -20,6 +20,7 @@ use crate::{ block::Deposit, SequencerBlock, }, + Protobuf as _, }; #[derive(Default)] diff --git a/crates/astria-core/src/protocol/transaction/v1/mod.rs b/crates/astria-core/src/protocol/transaction/v1/mod.rs index 3861748240..cee2049215 100644 --- a/crates/astria-core/src/protocol/transaction/v1/mod.rs +++ b/crates/astria-core/src/protocol/transaction/v1/mod.rs @@ -16,7 +16,7 @@ use crate::{ TransactionId, ADDRESS_LEN, }, - Protobuf as _, + Protobuf, }; pub mod action; @@ -81,34 +81,69 @@ pub struct Transaction { body_bytes: bytes::Bytes, } -impl Transaction { - pub fn address_bytes(&self) -> &[u8; ADDRESS_LEN] { - self.verification_key.address_bytes() +impl Protobuf for Transaction { + type Error = TransactionError; + type Raw = raw::Transaction; + + fn try_from_raw_ref(raw: &Self::Raw) -> Result { + let Self::Raw { + signature, + public_key, + body, + } = raw; + let signature = Signature::try_from(&**signature).map_err(TransactionError::signature)?; + let verification_key = + VerificationKey::try_from(&**public_key).map_err(TransactionError::verification_key)?; + let Some(body) = body else { + return Err(TransactionError::unset_body()); + }; + let bytes = body.value.clone(); + verification_key + .verify(&signature, &bytes) + .map_err(TransactionError::verification)?; + let transaction = + TransactionBody::try_from_any(body.clone()).map_err(TransactionError::body)?; + Ok(Self { + signature, + verification_key, + body: transaction, + body_bytes: bytes, + }) } - /// Returns the transaction ID, containing the transaction hash. - /// - /// The transaction hash is calculated by protobuf-encoding the transaction - /// and hashing the resulting bytes with sha256. - #[must_use] - pub fn id(&self) -> TransactionId { - use sha2::{ - Digest as _, - Sha256, + fn try_from_raw(raw: Self::Raw) -> Result { + let Self::Raw { + signature, + public_key, + body, + } = raw; + let signature = Signature::try_from(&*signature).map_err(TransactionError::signature)?; + let verification_key = + VerificationKey::try_from(&*public_key).map_err(TransactionError::verification_key)?; + let Some(body) = body else { + return Err(TransactionError::unset_body()); }; - let bytes = self.to_raw().encode_to_vec(); - TransactionId::new(Sha256::digest(bytes).into()) + let bytes = body.value.clone(); + verification_key + .verify(&signature, &bytes) + .map_err(TransactionError::verification)?; + let transaction = TransactionBody::try_from_any(body).map_err(TransactionError::body)?; + Ok(Self { + signature, + verification_key, + body: transaction, + body_bytes: bytes, + }) } - #[must_use] - pub fn into_raw(self) -> raw::Transaction { + fn into_raw(self) -> raw::Transaction { let Self { signature, verification_key, body_bytes: transaction_bytes, .. } = self; - raw::Transaction { + Self::Raw { signature: Bytes::copy_from_slice(&signature.to_bytes()), public_key: Bytes::copy_from_slice(&verification_key.to_bytes()), body: Some(pbjson_types::Any { @@ -118,15 +153,14 @@ impl Transaction { } } - #[must_use] - pub fn to_raw(&self) -> raw::Transaction { + fn to_raw(&self) -> raw::Transaction { let Self { signature, verification_key, body_bytes: transaction_bytes, .. } = self; - raw::Transaction { + Self::Raw { signature: Bytes::copy_from_slice(&signature.to_bytes()), public_key: Bytes::copy_from_slice(&verification_key.to_bytes()), body: Some(pbjson_types::Any { @@ -135,39 +169,25 @@ impl Transaction { }), } } +} - /// Attempt to convert from a raw, unchecked protobuf [`raw::Transaction`]. - /// - /// # Errors +impl Transaction { + pub fn address_bytes(&self) -> &[u8; ADDRESS_LEN] { + self.verification_key.address_bytes() + } + + /// Returns the transaction ID, containing the transaction hash. /// - /// Will return an error if signature or verification key cannot be reconstructed from the bytes - /// contained in the raw input, if the transaction field was empty (meaning it was mapped to - /// `None`), if the inner transaction could not be verified given the key and signature, or - /// if the native [`Body`] could not be created from the inner raw - /// [`raw::Body`]. - pub fn try_from_raw(proto: raw::Transaction) -> Result { - let raw::Transaction { - signature, - public_key, - body, - } = proto; - let signature = Signature::try_from(&*signature).map_err(TransactionError::signature)?; - let verification_key = - VerificationKey::try_from(&*public_key).map_err(TransactionError::verification_key)?; - let Some(body) = body else { - return Err(TransactionError::unset_body()); + /// The transaction hash is calculated by protobuf-encoding the transaction + /// and hashing the resulting bytes with sha256. + #[must_use] + pub fn id(&self) -> TransactionId { + use sha2::{ + Digest as _, + Sha256, }; - let bytes = body.value.clone(); - verification_key - .verify(&signature, &bytes) - .map_err(TransactionError::verification)?; - let transaction = TransactionBody::try_from_any(body).map_err(TransactionError::body)?; - Ok(Self { - signature, - verification_key, - body: transaction, - body_bytes: bytes, - }) + let bytes = self.to_raw().encode_to_vec(); + TransactionId::new(Sha256::digest(bytes).into()) } #[must_use] @@ -215,12 +235,82 @@ impl Transaction { } } +impl From for raw::Transaction { + fn from(value: Transaction) -> Self { + value.into_raw() + } +} + +impl TryFrom for Transaction { + type Error = TransactionError; + + fn try_from(value: raw::Transaction) -> Result { + Self::try_from_raw(value) + } +} + #[derive(Clone, Debug)] pub struct TransactionBody { actions: Actions, params: TransactionParams, } +impl Protobuf for TransactionBody { + type Error = TransactionBodyError; + type Raw = raw::TransactionBody; + + fn try_from_raw_ref(raw: &Self::Raw) -> Result { + let raw::TransactionBody { + actions, + params, + } = raw; + + let Some(params) = params else { + return Err(TransactionBodyError::unset_params()); + }; + let params = TransactionParams::from_raw_ref(params); + let actions: Vec<_> = actions + .iter() + .map(Action::try_from_raw_ref) + .collect::>() + .map_err(TransactionBodyError::action)?; + + TransactionBody::builder() + .actions(actions) + .chain_id(params.chain_id) + .nonce(params.nonce) + .try_build() + .map_err(TransactionBodyError::group) + } + + fn try_from_raw(proto: Self::Raw) -> Result { + let raw::TransactionBody { + actions, + params, + } = proto; + let Some(params) = params else { + return Err(TransactionBodyError::unset_params()); + }; + let params = TransactionParams::from_raw(params); + let actions: Vec<_> = actions + .into_iter() + .map(Action::try_from_raw) + .collect::>() + .map_err(TransactionBodyError::action)?; + + TransactionBody::builder() + .actions(actions) + .chain_id(params.chain_id) + .nonce(params.nonce) + .try_build() + .map_err(TransactionBodyError::group) + } + + fn to_raw(&self) -> Self::Raw { + todo!() + } +} + impl TransactionBody { #[must_use] pub fn builder() -> TransactionBodyBuilder { @@ -303,35 +393,6 @@ impl TransactionBody { self.clone().into_any() } - /// Attempt to convert from a raw, unchecked protobuf [`raw::Body`]. - /// - /// # Errors - /// - /// Returns an error if one of the inner raw actions could not be converted to a native - /// [`Action`]. - pub fn try_from_raw(proto: raw::TransactionBody) -> Result { - let raw::TransactionBody { - actions, - params, - } = proto; - let Some(params) = params else { - return Err(TransactionBodyError::unset_params()); - }; - let params = TransactionParams::from_raw(params); - let actions: Vec<_> = actions - .into_iter() - .map(Action::try_from_raw) - .collect::>() - .map_err(TransactionBodyError::action)?; - - TransactionBody::builder() - .actions(actions) - .chain_id(params.chain_id) - .nonce(params.nonce) - .try_build() - .map_err(TransactionBodyError::group) - } - /// Attempt to convert from a protobuf [`pbjson_types::Any`]. /// /// # Errors @@ -493,6 +554,20 @@ impl TransactionParams { chain_id, } } + + /// Convert from a raw protobuf [`raw::Body`]. + #[must_use] + pub fn from_raw_ref(proto: &raw::TransactionParams) -> Self { + let raw::TransactionParams { + nonce, + chain_id, + } = proto; + + Self { + nonce: *nonce, + chain_id: chain_id.clone(), + } + } } #[cfg(test)] diff --git a/crates/astria-sequencer-client/src/extension_trait.rs b/crates/astria-sequencer-client/src/extension_trait.rs index d12488bae0..59cab0f7e5 100644 --- a/crates/astria-sequencer-client/src/extension_trait.rs +++ b/crates/astria-sequencer-client/src/extension_trait.rs @@ -33,15 +33,6 @@ use std::{ sync::Arc, }; -use astria_core::protocol::{ - asset::v1::AllowedFeeAssetsResponse, - bridge::v1::{ - BridgeAccountInfoResponse, - BridgeAccountLastTxHashResponse, - }, - fees::v1::TransactionFeeResponse, - transaction::v1::TransactionBody, -}; pub use astria_core::{ primitive::v1::Address, protocol::{ @@ -56,6 +47,18 @@ pub use astria_core::{ SequencerBlock, }, }; +use astria_core::{ + protocol::{ + asset::v1::AllowedFeeAssetsResponse, + bridge::v1::{ + BridgeAccountInfoResponse, + BridgeAccountLastTxHashResponse, + }, + fees::v1::TransactionFeeResponse, + transaction::v1::TransactionBody, + }, + Protobuf as _, +}; use async_trait::async_trait; use futures::Stream; use prost::{ diff --git a/crates/astria-sequencer/src/app/mod.rs b/crates/astria-sequencer/src/app/mod.rs index 31caf18b56..90efb8bdfc 100644 --- a/crates/astria-sequencer/src/app/mod.rs +++ b/crates/astria-sequencer/src/app/mod.rs @@ -34,6 +34,7 @@ use astria_core::{ }, }, sequencerblock::v1::block::SequencerBlock, + Protobuf as _, }; use astria_eyre::{ anyhow_to_eyre, diff --git a/crates/astria-sequencer/src/app/tests_block_ordering.rs b/crates/astria-sequencer/src/app/tests_block_ordering.rs index b8366cbaa3..f6c7f4642f 100644 --- a/crates/astria-sequencer/src/app/tests_block_ordering.rs +++ b/crates/astria-sequencer/src/app/tests_block_ordering.rs @@ -3,9 +3,12 @@ use std::{ ops::Deref, }; -use astria_core::protocol::transaction::v1::{ - action::group::Group, - Transaction, +use astria_core::{ + protocol::transaction::v1::{ + action::group::Group, + Transaction, + }, + Protobuf as _, }; use bytes::Bytes; use prost::Message; diff --git a/crates/astria-sequencer/src/fees/query.rs b/crates/astria-sequencer/src/fees/query.rs index d2fe02879d..8b7084c67c 100644 --- a/crates/astria-sequencer/src/fees/query.rs +++ b/crates/astria-sequencer/src/fees/query.rs @@ -11,6 +11,7 @@ use astria_core::{ TransactionBody, }, }, + Protobuf as _, }; use astria_eyre::eyre::{ self, diff --git a/crates/astria-sequencer/src/service/consensus.rs b/crates/astria-sequencer/src/service/consensus.rs index 4a40dff7e9..2d0443513b 100644 --- a/crates/astria-sequencer/src/service/consensus.rs +++ b/crates/astria-sequencer/src/service/consensus.rs @@ -213,6 +213,7 @@ mod tests { action::RollupDataSubmission, TransactionBody, }, + Protobuf as _, }; use bytes::Bytes; use prost::Message as _; diff --git a/crates/astria-sequencer/src/service/mempool/mod.rs b/crates/astria-sequencer/src/service/mempool/mod.rs index ea2a0f89b1..88b59a5b77 100644 --- a/crates/astria-sequencer/src/service/mempool/mod.rs +++ b/crates/astria-sequencer/src/service/mempool/mod.rs @@ -16,6 +16,7 @@ use astria_core::{ abci::AbciErrorCode, transaction::v1::Transaction, }, + Protobuf as _, }; use astria_eyre::eyre::WrapErr as _; use bytes::Bytes; diff --git a/crates/astria-sequencer/src/service/mempool/tests.rs b/crates/astria-sequencer/src/service/mempool/tests.rs index b43f7865b5..1edb81e541 100644 --- a/crates/astria-sequencer/src/service/mempool/tests.rs +++ b/crates/astria-sequencer/src/service/mempool/tests.rs @@ -1,5 +1,6 @@ use std::num::NonZeroU32; +use astria_core::Protobuf as _; use prost::Message as _; use telemetry::Metrics; use tendermint::{