Skip to content
Open
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
14 changes: 2 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ alloy-dyn-abi = "=1.6.1"
alloy-json-abi = "=1.6.1"
revm-inspectors = { version = "=0.42.0", features = ["js-tracer"] }
revm-state = "42.0.0"
rlp = "=0.6.1"
alloy-rlp = { version = "=0.3.16", features = ["derive"] }

# network
jsonrpsee = { version = "=0.26.0", features = ["server", "client"] }
Expand Down
1 change: 1 addition & 0 deletions src/eth/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub use types::LogFilterInputTopic;
pub use types::MulticallError;
pub use types::RpcClientApp;
pub use types::RpcError;
pub use types::TransactionDecodeError;

// -----------------------------------------------------------------------------
// Tests
Expand Down
10 changes: 7 additions & 3 deletions src/eth/rpc/parser.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
//! Helper functions for parsing RPC requests and responses.

use alloy_rlp::Decodable;
use jsonrpsee::Extensions;
use jsonrpsee::types::ParamsSequence;
use rlp::Decodable;
use tracing::Span;

use super::middleware::Authentication;
use crate::eth::rpc::RpcClientApp;
use crate::eth::rpc::RpcError;
use crate::eth::rpc::TransactionDecodeError;
use crate::ext::type_basename;
use crate::infra::tracing::EnteredWrap;

Expand Down Expand Up @@ -77,8 +78,11 @@ where
///
/// https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp
pub fn parse_rpc_rlp<T: Decodable>(value: &[u8]) -> Result<T, RpcError> {
match rlp::decode::<T>(value) {
let mut buf = value;
match T::decode(&mut buf) {
Ok(trx) => Ok(trx),
Err(e) => Err(RpcError::TransactionInvalid { decode_error: e.to_string() }),
Err(e) => Err(RpcError::TransactionInvalid {
decode_error: TransactionDecodeError::Custom(e.to_string()),
}),
}
}
60 changes: 58 additions & 2 deletions src/eth/rpc/types/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,62 @@ use stratus_macros::ErrorCode;
use crate::eth::rpc::BlockFilter;
use crate::eth::types::ErrorCode;

/// Errors that can occur while decoding a raw transaction.
#[derive(Debug, thiserror::Error)]
pub enum TransactionDecodeError {
#[error("missing field: {0}")]
MissingField(&'static str),

#[error("invalid to field")]
InvalidTo,

#[error("failed to recover signer")]
SignerRecovery,

#[error("unsupported transaction type")]
UnsupportedType,

#[error("typed transaction has extra fields")]
ExtraFields,

#[error("invalid transaction type byte")]
InvalidTypeByte,

#[error("empty transaction bytes")]
EmptyBytes,

#[error("legacy transaction type is not typed")]
LegacyNotTyped,

#[error("invalid legacy v value")]
InvalidLegacyV,

#[error("rlp decode error: {0}")]
RlpError(String),

#[error("{0}")]
Custom(String),
}

impl From<TransactionDecodeError> for alloy_rlp::Error {
fn from(value: TransactionDecodeError) -> Self {
let message = match value {
TransactionDecodeError::MissingField(_) => "missing field",
TransactionDecodeError::InvalidTo => "invalid to field",
TransactionDecodeError::SignerRecovery => "failed to recover signer",
TransactionDecodeError::UnsupportedType => "unsupported transaction type",
TransactionDecodeError::ExtraFields => "typed transaction has extra fields",
TransactionDecodeError::InvalidTypeByte => "invalid transaction type byte",
TransactionDecodeError::EmptyBytes => "empty transaction bytes",
TransactionDecodeError::LegacyNotTyped => "legacy transaction type is not typed",
TransactionDecodeError::InvalidLegacyV => "invalid legacy v value",
TransactionDecodeError::RlpError(_) => "rlp decode error",
TransactionDecodeError::Custom(_) => "failed to decode transaction",
};
alloy_rlp::Error::Custom(message)
}
}

#[derive(Debug, thiserror::Error, strum::EnumProperty, strum::IntoStaticStr, ErrorCode)]
#[major_error_code = 1000]
pub enum RpcError {
Expand Down Expand Up @@ -38,9 +94,9 @@ pub enum RpcError {
#[error_code = 7]
SubscriptionLimit { max: u32 },

#[error("failed to decode transaction RLP data.")]
#[error("failed to decode transaction RLP data: {decode_error}")]
#[error_code = 8]
TransactionInvalid { decode_error: String },
TransactionInvalid { decode_error: TransactionDecodeError },

#[error("miner mode param is invalid.")]
#[error_code = 9]
Expand Down
1 change: 1 addition & 0 deletions src/eth/rpc/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod timestamp_filter;
pub use block_filter::BlockFilter;
pub use error::MulticallError;
pub use error::RpcError;
pub use error::TransactionDecodeError;
pub use log_filter::LogFilter;
pub use log_filter_input::LogFilterInput;
pub use log_filter_input::LogFilterInputTopic;
Expand Down
2 changes: 1 addition & 1 deletion src/eth/types/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl StratusError {
Self::RPC(RpcError::ClientBlocked { client }) => to_json_value(client),

// Transaction
Self::RPC(RpcError::TransactionInvalid { decode_error }) => to_json_value(decode_error),
Self::RPC(RpcError::TransactionInvalid { decode_error }) => to_json_value(decode_error.to_string()),
Self::Executor(ExecutorError::EvmFailed(e)) => JsonValue::String(e.to_string()),
Self::Executor(ExecutorError::RevertedCall { output }) => to_json_value(output),
Self::Executor(ExecutorError::RevertedCallWithReason { reason }) => to_json_value(reason),
Expand Down
26 changes: 25 additions & 1 deletion src/eth/types/primitives/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,25 @@ use fake::Faker;
use hex_literal::hex;

use crate::alias::RevmAddress;
use crate::eth::rpc::TransactionDecodeError;
use crate::eth::types::LogTopic;

/// Address of an Ethereum account (wallet or contract).
#[derive(DebugAsJson, Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
#[derive(
DebugAsJson,
Clone,
Copy,
Default,
Eq,
PartialEq,
PartialOrd,
Ord,
Hash,
serde::Serialize,
serde::Deserialize,
alloy_rlp::RlpDecodableWrapper,
alloy_rlp::RlpEncodableWrapper,
)]
pub struct Address(pub FixedBytes<20>);

impl Address {
Expand Down Expand Up @@ -109,6 +124,15 @@ impl TryFrom<Vec<u8>> for Address {
}
}

impl TryFrom<&[u8]> for Address {
type Error = TransactionDecodeError;

fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let array = <[u8; 20]>::try_from(value).map_err(|_| TransactionDecodeError::InvalidTo)?;
Ok(Self(FixedBytes::from(array)))
}
}

// -----------------------------------------------------------------------------
// Conversions: Self -> Other
// -----------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/eth/types/primitives/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use display_json::DebugAsJson;
use crate::alias::RevmBytes;
use crate::alias::RevmOutput;

#[derive(DebugAsJson, Clone, Default, Eq, PartialEq)]
#[derive(DebugAsJson, Clone, Default, Eq, PartialEq, alloy_rlp::RlpDecodableWrapper, alloy_rlp::RlpEncodableWrapper)]
pub struct Bytes(pub bytes::Bytes);

impl Display for Bytes {
Expand Down
4 changes: 3 additions & 1 deletion src/eth/types/primitives/chain_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use fake::Faker;

use crate::ext::RuintExt;

#[derive(DebugAsJson, derive_more::Display, Clone, Copy, Default, Eq, PartialEq, serde::Serialize)]
#[derive(
DebugAsJson, derive_more::Display, Clone, Copy, Default, Eq, PartialEq, serde::Serialize, alloy_rlp::RlpDecodableWrapper, alloy_rlp::RlpEncodableWrapper,
)]
#[cfg_attr(test, derive(serde::Deserialize))]
pub struct ChainId(pub U64);

Expand Down
15 changes: 14 additions & 1 deletion src/eth/types/primitives/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,20 @@ use revm::context::result::ResultGas;

use crate::ext::RuintExt;

#[derive(DebugAsJson, derive_more::Display, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, derive_more::Add, derive_more::AddAssign)]
#[derive(
DebugAsJson,
derive_more::Display,
Clone,
Copy,
Default,
PartialEq,
Eq,
serde::Serialize,
derive_more::Add,
derive_more::AddAssign,
alloy_rlp::RlpDecodableWrapper,
alloy_rlp::RlpEncodableWrapper,
)]
#[serde(transparent)]
#[cfg_attr(test, derive(serde::Deserialize))]
pub struct Gas(U64);
Expand Down
14 changes: 13 additions & 1 deletion src/eth/types/primitives/nonce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ use fake::Faker;

use crate::ext::RuintExt;

#[derive(DebugAsJson, derive_more::Display, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[derive(
DebugAsJson,
derive_more::Display,
Clone,
Copy,
Default,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
alloy_rlp::RlpDecodableWrapper,
alloy_rlp::RlpEncodableWrapper,
)]
pub struct Nonce(U64);

impl Nonce {
Expand Down
17 changes: 16 additions & 1 deletion src/eth/types/primitives/wei.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,22 @@ use fake::Dummy;
use fake::Faker;

/// Native token amount in wei.
#[derive(DebugAsJson, derive_more::Display, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq, derive_more::Sub, serde::Serialize, serde::Deserialize)]
#[derive(
DebugAsJson,
derive_more::Display,
Clone,
Copy,
Default,
PartialOrd,
Ord,
PartialEq,
Eq,
derive_more::Sub,
serde::Serialize,
serde::Deserialize,
alloy_rlp::RlpDecodableWrapper,
alloy_rlp::RlpEncodableWrapper,
)]
pub struct Wei(pub U256);

impl Wei {
Expand Down
Loading
Loading