Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 30 additions & 28 deletions crates/astria-composer/src/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ use sequencer_client::{
Address,
SequencerClientExt as _,
};
use tendermint::crypto::Sha256;
use tendermint::{
abci::Code,
crypto::Sha256,
};
use tokio::{
select,
sync::{
Expand Down Expand Up @@ -643,6 +646,7 @@ impl Future for SubmitFut {

#[allow(clippy::too_many_lines)]
fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
const INVALID_NONCE: Code = Code::Err(AbciErrorCode::INVALID_NONCE.value());
loop {
let this = self.as_mut().project();

Expand Down Expand Up @@ -671,8 +675,8 @@ impl Future for SubmitFut {
SubmitStateProj::WaitingForSend {
fut,
} => match ready!(fut.poll(cx)) {
Ok(rsp) => {
let tendermint::abci::Code::Err(code) = rsp.code else {
Ok(rsp) => match rsp.code {
tendermint::abci::Code::Ok => {
info!("sequencer responded with ok; submission successful");

this.metrics
Expand All @@ -685,35 +689,33 @@ impl Future for SubmitFut {
.nonce
.checked_add(1)
.expect("nonce should not overflow")));
};
match AbciErrorCode::from(code) {
AbciErrorCode::INVALID_NONCE => {
info!(
"sequencer rejected transaction due to invalid nonce; \
fetching new nonce"
);
SubmitState::WaitingForNonce {
fut: get_latest_nonce(
this.client.clone(),
*this.address,
self.metrics,
)
.boxed(),
}
}
INVALID_NONCE => {
info!(
"sequencer rejected transaction due to invalid nonce; fetching \
new nonce"
);
SubmitState::WaitingForNonce {
fut: get_latest_nonce(
this.client.clone(),
*this.address,
self.metrics,
)
.boxed(),
}
_other => {
warn!(
abci.code = rsp.code.value(),
abci.log = rsp.log,
"sequencer rejected the transaction; the bundle is likely lost",
);
}
tendermint::abci::Code::Err(_) => {
warn!(
abci.code = rsp.code.value(),
abci.log = rsp.log,
"sequencer rejected the transaction; the bundle is likely lost",
);

this.metrics.increment_sequencer_submission_failure_count();
this.metrics.increment_sequencer_submission_failure_count();

return Poll::Ready(Ok(*this.nonce));
}
return Poll::Ready(Ok(*this.nonce));
}
}
},
Err(error) => {
error!(%error, "failed sending transaction to sequencer");

Expand Down
2 changes: 1 addition & 1 deletion crates/astria-composer/tests/blackbox/helper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ pub async fn mount_broadcast_tx_sync_invalid_nonce_mock(
let jsonrpc_rsp = response::Wrapper::new_with_id(
Id::Num(1),
Some(tx_sync::Response {
code: AbciErrorCode::INVALID_NONCE.into(),
code: tendermint::abci::Code::Err(AbciErrorCode::INVALID_NONCE.value()),
data: vec![].into(),
log: String::new(),
hash: tendermint::Hash::Sha256([0; 32]),
Expand Down
97 changes: 39 additions & 58 deletions crates/astria-core/src/protocol/abci.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,57 @@
use std::{
borrow::Cow,
num::NonZeroU32,
};
use std::num::NonZeroU32;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[allow(clippy::module_name_repetitions)]
pub struct AbciErrorCode(u32);
pub struct AbciErrorCode(NonZeroU32);

#[rustfmt::skip]
impl AbciErrorCode {
pub const UNSPECIFIED: Self = Self(0);
pub const UNKNOWN_PATH: Self = Self(1);
pub const INVALID_PARAMETER: Self = Self(2);
pub const INTERNAL_ERROR: Self = Self(3);
pub const INVALID_NONCE: Self = Self(4);
pub const TRANSACTION_TOO_LARGE: Self = Self(5);
pub const INSUFFICIENT_FUNDS: Self = Self(6);
pub const INVALID_CHAIN_ID: Self = Self(7);
pub const VALUE_NOT_FOUND: Self = Self(8);
pub const TRANSACTION_EXPIRED: Self = Self(9);
pub const TRANSACTION_FAILED: Self = Self(10);
pub const BAD_REQUEST: Self = Self(11);
pub const UNKNOWN_PATH: Self = Self(unsafe { NonZeroU32::new_unchecked(1) });
pub const INVALID_PARAMETER: Self = Self(unsafe { NonZeroU32::new_unchecked(2) });
pub const INTERNAL_ERROR: Self = Self(unsafe { NonZeroU32::new_unchecked(3) });
pub const INVALID_NONCE: Self = Self(unsafe { NonZeroU32::new_unchecked(4) });
pub const TRANSACTION_TOO_LARGE: Self = Self(unsafe { NonZeroU32::new_unchecked(5) });
pub const INSUFFICIENT_FUNDS: Self = Self(unsafe { NonZeroU32::new_unchecked(6) });
pub const INVALID_CHAIN_ID: Self = Self(unsafe { NonZeroU32::new_unchecked(7) });
pub const VALUE_NOT_FOUND: Self = Self(unsafe { NonZeroU32::new_unchecked(8) });
pub const TRANSACTION_EXPIRED: Self = Self(unsafe { NonZeroU32::new_unchecked(9) });
pub const TRANSACTION_FAILED: Self = Self(unsafe { NonZeroU32::new_unchecked(10) });
pub const BAD_REQUEST: Self = Self(unsafe { NonZeroU32::new_unchecked(11) });
}

impl AbciErrorCode {
/// Returns the wrapped `NonZeroU32`.
#[must_use]
pub fn info(self) -> Cow<'static, str> {
match self.0 {
0 => "unspecified".into(),
1 => "provided path is unknown".into(),
2 => "one or more path parameters were invalid".into(),
3 => "an internal server error occurred".into(),
4 => "the provided nonce was invalid".into(),
5 => "the provided transaction was too large".into(),
6 => "insufficient funds".into(),
7 => "the provided chain id was invalid".into(),
8 => "the requested value was not found".into(),
9 => "the transaction expired in the app's mempool".into(),
10 => "the transaction failed to execute in prepare_proposal()".into(),
11 => "the request payload was malformed".into(),
other => format!("unknown non-zero abci error code: {other}").into(),
pub const fn value(self) -> NonZeroU32 {
self.0
}

/// Returns brief information on the meaning of the error.
#[must_use]
pub fn info(self) -> String {
match self {
Self::UNKNOWN_PATH => "provided path is unknown".into(),
Self::INVALID_PARAMETER => "one or more path parameters were invalid".into(),
Self::INTERNAL_ERROR => "an internal server error occurred".into(),
Self::INVALID_NONCE => "the provided nonce was invalid".into(),
Self::TRANSACTION_TOO_LARGE => "the provided transaction was too large".into(),
Self::INSUFFICIENT_FUNDS => "insufficient funds".into(),
Self::INVALID_CHAIN_ID => "the provided chain id was invalid".into(),
Self::VALUE_NOT_FOUND => "the requested value was not found".into(),
Self::TRANSACTION_EXPIRED => "the transaction expired in the app's mempool".into(),
Self::TRANSACTION_FAILED => {
"the transaction failed to execute in prepare_proposal()".into()
}
Self::BAD_REQUEST => "the request payload was malformed".into(),
Self(other) => {
format!("invalid error code {other}: should be unreachable (this is a bug)")
}
}
}
}

impl std::fmt::Display for AbciErrorCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.info())
}
}

impl From<AbciErrorCode> for tendermint::abci::Code {
fn from(value: AbciErrorCode) -> Self {
value.0.into()
}
}

impl From<NonZeroU32> for AbciErrorCode {
fn from(value: NonZeroU32) -> Self {
match value.get() {
1 => Self::UNKNOWN_PATH,
2 => Self::INVALID_PARAMETER,
3 => Self::INTERNAL_ERROR,
4 => Self::INVALID_NONCE,
5 => Self::TRANSACTION_TOO_LARGE,
6 => Self::INSUFFICIENT_FUNDS,
7 => Self::INVALID_CHAIN_ID,
8 => Self::VALUE_NOT_FOUND,
9 => Self::TRANSACTION_EXPIRED,
10 => Self::TRANSACTION_FAILED,
11 => Self::BAD_REQUEST,
other => Self(other),
}
write!(f, "{}: {}", self.0, self.info())
}
}
23 changes: 12 additions & 11 deletions crates/astria-sequencer/src/accounts/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use tendermint::{
abci::{
request,
response,
Code,
},
block::Height,
};
Expand All @@ -36,9 +37,9 @@ pub(crate) async fn balance_request(
Ok(balance) => balance,
Err(err) => {
return response::Query {
code: AbciErrorCode::INTERNAL_ERROR.into(),
info: AbciErrorCode::INTERNAL_ERROR.to_string(),
log: format!("failed getting balance for provided address: {err:?}"),
code: Code::Err(AbciErrorCode::INTERNAL_ERROR.value()),
info: AbciErrorCode::INTERNAL_ERROR.info(),
log: format!("failed getting balance for provided address: {err:#}"),
height,
..response::Query::default()
};
Expand Down Expand Up @@ -134,8 +135,8 @@ async fn preprocess_request(
.find_map(|(k, v)| (k == "account").then_some(v))
else {
return Err(response::Query {
code: AbciErrorCode::INVALID_PARAMETER.into(),
info: AbciErrorCode::INVALID_PARAMETER.to_string(),
code: Code::Err(AbciErrorCode::INVALID_PARAMETER.value()),
info: AbciErrorCode::INVALID_PARAMETER.info(),
log: "path did not contain path parameter".into(),
..response::Query::default()
});
Expand All @@ -144,18 +145,18 @@ async fn preprocess_request(
.parse()
.context("failed to parse argument as address")
.map_err(|err| response::Query {
code: AbciErrorCode::INVALID_PARAMETER.into(),
info: AbciErrorCode::INVALID_PARAMETER.to_string(),
log: format!("address could not be constructed from provided parameter: {err:?}"),
code: Code::Err(AbciErrorCode::INVALID_PARAMETER.value()),
info: AbciErrorCode::INVALID_PARAMETER.info(),
log: format!("address could not be constructed from provided parameter: {err:#}"),
..response::Query::default()
})?;
let (snapshot, height) = match get_snapshot_and_height(storage, request.height).await {
Ok(tup) => tup,
Err(err) => {
return Err(response::Query {
code: AbciErrorCode::INTERNAL_ERROR.into(),
info: AbciErrorCode::INTERNAL_ERROR.to_string(),
log: format!("failed to query internal storage for snapshot and height: {err:?}"),
code: Code::Err(AbciErrorCode::INTERNAL_ERROR.value()),
info: AbciErrorCode::INTERNAL_ERROR.info(),
log: format!("failed to query internal storage for snapshot and height: {err:#}"),
..response::Query::default()
});
}
Expand Down
7 changes: 4 additions & 3 deletions crates/astria-sequencer/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ use tendermint::{
abci::{
self,
types::ExecTxResult,
Code,
Event,
},
account,
Expand Down Expand Up @@ -831,9 +832,9 @@ impl App {
AbciErrorCode::INTERNAL_ERROR
};
tx_results.push(ExecTxResult {
code: code.into(),
info: code.to_string(),
log: format!("{e:?}"),
code: Code::Err(code.value()),
info: code.info(),
log: format!("{e:#}"),
..Default::default()
});
}
Expand Down
29 changes: 15 additions & 14 deletions crates/astria-sequencer/src/assets/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use prost::Message as _;
use tendermint::abci::{
request,
response,
Code,
};

use crate::{
Expand Down Expand Up @@ -41,8 +42,8 @@ pub(crate) async fn denom_request(
Ok(height) => height,
Err(err) => {
return response::Query {
code: AbciErrorCode::INTERNAL_ERROR.into(),
info: AbciErrorCode::INTERNAL_ERROR.to_string(),
code: Code::Err(AbciErrorCode::INTERNAL_ERROR.value()),
info: AbciErrorCode::INTERNAL_ERROR.info(),
log: format!("failed getting block height: {err:#}"),
..response::Query::default()
};
Expand All @@ -53,8 +54,8 @@ pub(crate) async fn denom_request(
Ok(maybe_denom) => maybe_denom,
Err(err) => {
return response::Query {
code: AbciErrorCode::INTERNAL_ERROR.into(),
info: AbciErrorCode::INTERNAL_ERROR.to_string(),
code: Code::Err(AbciErrorCode::INTERNAL_ERROR.value()),
info: AbciErrorCode::INTERNAL_ERROR.info(),
log: format!("failed to retrieve denomination `{asset}`: {err:#}"),
..response::Query::default()
};
Expand All @@ -63,8 +64,8 @@ pub(crate) async fn denom_request(

let Some(denom) = maybe_denom else {
return response::Query {
code: AbciErrorCode::VALUE_NOT_FOUND.into(),
info: AbciErrorCode::VALUE_NOT_FOUND.to_string(),
code: Code::Err(AbciErrorCode::VALUE_NOT_FOUND.value()),
info: AbciErrorCode::VALUE_NOT_FOUND.info(),
log: format!("failed to retrieve value for denomination ID`{asset}`"),
..response::Query::default()
};
Expand Down Expand Up @@ -93,8 +94,8 @@ fn preprocess_request(
) -> anyhow::Result<asset::IbcPrefixed, response::Query> {
let Some(asset_id) = params.iter().find_map(|(k, v)| (k == "id").then_some(v)) else {
return Err(response::Query {
code: AbciErrorCode::INVALID_PARAMETER.into(),
info: AbciErrorCode::INVALID_PARAMETER.to_string(),
code: Code::Err(AbciErrorCode::INVALID_PARAMETER.value()),
info: AbciErrorCode::INVALID_PARAMETER.info(),
log: "path did not contain asset ID parameter".into(),
..response::Query::default()
});
Expand All @@ -103,8 +104,8 @@ fn preprocess_request(
.context("failed decoding hex encoded bytes")
.map(asset::IbcPrefixed::new)
.map_err(|err| response::Query {
code: AbciErrorCode::INVALID_PARAMETER.into(),
info: AbciErrorCode::INVALID_PARAMETER.to_string(),
code: Code::Err(AbciErrorCode::INVALID_PARAMETER.value()),
info: AbciErrorCode::INVALID_PARAMETER.info(),
log: format!("asset ID could not be constructed from provided parameter: {err:#}"),
..response::Query::default()
})?;
Expand All @@ -124,8 +125,8 @@ pub(crate) async fn allowed_fee_assets_request(
Ok(height) => height,
Err(err) => {
return response::Query {
code: AbciErrorCode::INTERNAL_ERROR.into(),
info: AbciErrorCode::INTERNAL_ERROR.to_string(),
code: Code::Err(AbciErrorCode::INTERNAL_ERROR.value()),
info: AbciErrorCode::INTERNAL_ERROR.info(),
log: format!("failed getting block height: {err:#}"),
..response::Query::default()
};
Expand All @@ -137,8 +138,8 @@ pub(crate) async fn allowed_fee_assets_request(
Ok(fee_assets) => fee_assets,
Err(err) => {
return response::Query {
code: AbciErrorCode::INTERNAL_ERROR.into(),
info: AbciErrorCode::INTERNAL_ERROR.to_string(),
code: Code::Err(AbciErrorCode::INTERNAL_ERROR.value()),
info: AbciErrorCode::INTERNAL_ERROR.info(),
log: format!("failed to retrieve allowed fee assets: {err:#}"),
..response::Query::default()
};
Expand Down
Loading