diff --git a/.github/assets/check_no_std.sh b/.github/assets/check_no_std.sh index f19e39ddac9..2b06c2e40b9 100755 --- a/.github/assets/check_no_std.sh +++ b/.github/assets/check_no_std.sh @@ -3,7 +3,9 @@ set -eo pipefail # TODO no_std_packages=( -# reth-codecs + reth-codecs + reth-primitives-traits +# reth-primitives # reth-consensus # reth-db # reth-errors @@ -11,13 +13,11 @@ no_std_packages=( # reth-evm # reth-evm-ethereum # reth-network-peers -# reth-primitives -# reth-primitives-traits # reth-revm ) for package in "${no_std_packages[@]}"; do - cmd="cargo +stable build -p $package --target riscv32imac-unknown-none-elf --no-default-features" + cmd="cargo +stable build -p $package --target wasm32-wasi --no-default-features" if [ -n "$CI" ]; then echo "::group::$cmd" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d0329aefc89..8c9bea516ab 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -52,7 +52,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: - target: riscv32imac-unknown-none-elf + target: wasm32-wasi - uses: taiki-e/install-action@cargo-hack - uses: Swatinem/rust-cache@v2 with: diff --git a/Cargo.lock b/Cargo.lock index 8d62a42cb3e..d7a35449564 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8044,6 +8044,7 @@ dependencies = [ "c-kzg", "criterion", "derive_more", + "k256", "modular-bitfield", "nybbles", "once_cell", diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml index 638cdccc613..9dd993cf0f7 100644 --- a/crates/primitives-traits/Cargo.toml +++ b/crates/primitives-traits/Cargo.toml @@ -27,7 +27,7 @@ revm-primitives = { workspace = true, features = ["serde"] } # misc thiserror-no-std = { workspace = true, default-features = false } roaring = "0.10.2" -byteorder = "1" +byteorder = { version = "1", default-features = false } # required by reth-codecs modular-bitfield.workspace = true diff --git a/crates/primitives-traits/src/constants/gas_units.rs b/crates/primitives-traits/src/constants/gas_units.rs index 0af0d2c24ce..cba13e67f6c 100644 --- a/crates/primitives-traits/src/constants/gas_units.rs +++ b/crates/primitives-traits/src/constants/gas_units.rs @@ -1,4 +1,7 @@ -use std::time::Duration; +#[cfg(not(feature = "std"))] +use alloc::{format, string::String}; + +use core::time::Duration; /// Represents one Kilogas, or `1_000` gas. pub const KILOGAS: u64 = 1_000; diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs index b7a42d9c7b5..be0d5f772f7 100644 --- a/crates/primitives-traits/src/lib.rs +++ b/crates/primitives-traits/src/lib.rs @@ -9,6 +9,9 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(not(feature = "std"))] +extern crate alloc; + #[cfg(feature = "alloy-compat")] mod alloy_compat; diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 1e37184ab85..3e6f66dfefa 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -33,7 +33,8 @@ secp256k1 = { workspace = true, features = [ "global-context", "recovery", "rand", -] } +], optional = true } +k256 = { version = "0.13.3", default-features = false, features = ["ecdsa"] } # for eip-4844 c-kzg = { workspace = true, features = ["serde"], optional = true } @@ -83,8 +84,9 @@ pprof = { workspace = true, features = [ ] } secp256k1.workspace = true + [features] -default = ["c-kzg", "zstd-codec", "alloy-compat", "std"] +default = ["c-kzg", "zstd-codec", "alloy-compat", "std", "secp256k1"] asm-keccak = ["alloy-primitives/asm-keccak"] arbitrary = [ "reth-primitives-traits/arbitrary", @@ -98,6 +100,7 @@ arbitrary = [ "dep:proptest", "zstd-codec", ] +secp256k1 = ["dep:secp256k1"] c-kzg = ["dep:c-kzg", "revm-primitives/c-kzg", "dep:tempfile", "alloy-eips/kzg"] zstd-codec = ["dep:zstd"] optimism = [ diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 29154d591e8..d8550d7417a 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -64,7 +64,6 @@ pub use transaction::{ pub use transaction::BlobTransactionValidationError; pub use transaction::{ - util::secp256k1::{public_key_to_address, recover_signer_unchecked, sign_message}, AccessList, AccessListItem, IntoRecoveredTransaction, InvalidTransactionError, Signature, Transaction, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TryFromRecoveredTransaction, TxEip1559, TxEip2930, TxEip4844, @@ -72,6 +71,16 @@ pub use transaction::{ LEGACY_TX_TYPE_ID, }; +#[cfg(feature = "secp256k1")] +pub use transaction::util::secp256k1::{ + public_key_to_address, recover_signer_unchecked, sign_message, +}; + +#[cfg(not(feature = "secp256k1"))] +pub use transaction::util::secp256k1::recover_signer_unchecked; + +use k256 as _; + // Re-exports pub use self::ruint::UintTryTo; pub use alloy_primitives::{ diff --git a/crates/primitives/src/transaction/eip1559.rs b/crates/primitives/src/transaction/eip1559.rs index cce6f0ca22f..748040a3817 100644 --- a/crates/primitives/src/transaction/eip1559.rs +++ b/crates/primitives/src/transaction/eip1559.rs @@ -2,6 +2,10 @@ use super::access_list::AccessList; use crate::{keccak256, Bytes, ChainId, Signature, TxKind, TxType, B256, U256}; use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use core::mem; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + use reth_codecs::{main_codec, Compact}; /// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). diff --git a/crates/primitives/src/transaction/eip2930.rs b/crates/primitives/src/transaction/eip2930.rs index ebaa12785c1..69caa6a1d37 100644 --- a/crates/primitives/src/transaction/eip2930.rs +++ b/crates/primitives/src/transaction/eip2930.rs @@ -4,6 +4,9 @@ use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use core::mem; use reth_codecs::{main_codec, Compact}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// Transaction with an [`AccessList`] ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)). #[main_codec] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] diff --git a/crates/primitives/src/transaction/legacy.rs b/crates/primitives/src/transaction/legacy.rs index 09b661cf799..5d99570032b 100644 --- a/crates/primitives/src/transaction/legacy.rs +++ b/crates/primitives/src/transaction/legacy.rs @@ -3,6 +3,9 @@ use alloy_rlp::{length_of_length, Encodable, Header}; use core::mem; use reth_codecs::{main_codec, Compact}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// Legacy transaction. #[main_codec] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] diff --git a/crates/primitives/src/transaction/util.rs b/crates/primitives/src/transaction/util.rs index b4a2db7f6b5..40e0ef5661f 100644 --- a/crates/primitives/src/transaction/util.rs +++ b/crates/primitives/src/transaction/util.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "secp256k1")] pub(crate) mod secp256k1 { use super::*; use crate::{keccak256, Address, Signature}; @@ -47,6 +48,43 @@ pub(crate) mod secp256k1 { } } +#[cfg(not(feature = "secp256k1"))] +pub(crate) mod secp256k1 { + use super::*; + use crate::{keccak256, Address}; + pub(crate) use ::k256::ecdsa::Error; + use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; + + /// Recovers the address of the sender using secp256k1 pubkey recovery. + /// + /// Converts the public key into an ethereum address by hashing the public key with keccak256. + /// + /// This does not ensure that the `s` value in the signature is low, and _just_ wraps the + /// underlying secp256k1 library. + pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result
{ + let mut signature = Signature::from_slice(&sig[0..64])?; + let mut recid = sig[64]; + + // normalize signature and flip recovery id if needed. + if let Some(sig_normalized) = signature.normalize_s() { + signature = sig_normalized; + recid ^= 1; + } + let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid"); + + // recover key + let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &signature, recid)?; + Ok(public_key_to_address(recovered_key)) + } + + /// Converts a public key into an ethereum address by hashing the encoded public key with + /// keccak256. + fn public_key_to_address(public: VerifyingKey) -> Address { + let hash = keccak256(&public.to_encoded_point(/* compress = */ false).as_bytes()[1..]); + Address::from_slice(&hash[12..]) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/storage/codecs/src/lib.rs b/crates/storage/codecs/src/lib.rs index bea26090deb..b22c5d32d72 100644 --- a/crates/storage/codecs/src/lib.rs +++ b/crates/storage/codecs/src/lib.rs @@ -19,6 +19,12 @@ pub use reth_codecs_derive::*; +#[cfg(not(feature = "std"))] +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + use alloy_primitives::{Address, Bloom, Bytes, FixedBytes, U256}; use bytes::Buf;