feat(rpc): Replace TypedTransactionType (#11089)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Jennifer
2024-09-25 13:34:58 +02:00
committed by GitHub
parent 466f21acfa
commit 5d2867f2c5
13 changed files with 93 additions and 413 deletions

11
Cargo.lock generated
View File

@ -494,7 +494,6 @@ dependencies = [
"alloy-rlp",
"alloy-serde",
"alloy-sol-types",
"arbitrary",
"cfg-if",
"derive_more",
"hashbrown 0.14.5",
@ -8404,6 +8403,7 @@ dependencies = [
name = "reth-rpc"
version = "1.0.7"
dependencies = [
"alloy-consensus",
"alloy-dyn-abi",
"alloy-genesis",
"alloy-network",
@ -8417,6 +8417,8 @@ dependencies = [
"alloy-rpc-types-trace",
"alloy-rpc-types-txpool",
"alloy-serde",
"alloy-signer",
"alloy-signer-local",
"async-trait",
"derive_more",
"futures",
@ -8446,7 +8448,6 @@ dependencies = [
"reth-rpc-eth-api",
"reth-rpc-eth-types",
"reth-rpc-server-types",
"reth-rpc-types",
"reth-rpc-types-compat",
"reth-tasks",
"reth-testing-utils",
@ -8455,7 +8456,6 @@ dependencies = [
"revm",
"revm-inspectors",
"revm-primitives",
"secp256k1",
"serde",
"serde_json",
"thiserror",
@ -8628,7 +8628,6 @@ dependencies = [
"reth-revm",
"reth-rpc-eth-types",
"reth-rpc-server-types",
"reth-rpc-types",
"reth-rpc-types-compat",
"reth-tasks",
"reth-transaction-pool",
@ -8718,12 +8717,8 @@ dependencies = [
name = "reth-rpc-types"
version = "1.0.7"
dependencies = [
"alloy-primitives",
"alloy-rpc-types",
"alloy-rpc-types-engine",
"arbitrary",
"jsonrpsee-types",
"rand 0.8.5",
]
[[package]]

View File

@ -21,7 +21,6 @@ reth-evm.workspace = true
reth-primitives.workspace = true
reth-provider.workspace = true
reth-revm.workspace = true
reth-rpc-types.workspace = true
reth-rpc-types-compat.workspace = true
reth-tasks = { workspace = true, features = ["rayon"] }
reth-transaction-pool.workspace = true

View File

@ -1,13 +1,12 @@
//! An abstraction over ethereum signers.
use std::result;
use alloy_dyn_abi::TypedData;
use alloy_primitives::Address;
use alloy_rpc_types_eth::TransactionRequest;
use dyn_clone::DynClone;
use reth_primitives::{Signature, TransactionSigned};
use reth_rpc_eth_types::SignError;
use reth_rpc_types::TypedTransactionRequest;
use std::result;
/// Result returned by [`EthSigner`] methods.
pub type Result<T> = result::Result<T, SignError>;
@ -27,9 +26,9 @@ pub trait EthSigner: Send + Sync + DynClone {
async fn sign(&self, address: Address, message: &[u8]) -> Result<Signature>;
/// signs a transaction request using the given account in request
fn sign_transaction(
async fn sign_transaction(
&self,
request: TypedTransactionRequest,
request: TransactionRequest,
address: &Address,
) -> Result<TransactionSigned>;

View File

@ -2,7 +2,8 @@
//! network.
use alloy_dyn_abi::TypedData;
use alloy_primitives::{Address, Bytes, TxHash, TxKind, B256, U256};
use alloy_network::TransactionBuilder;
use alloy_primitives::{Address, Bytes, TxHash, B256};
use alloy_rpc_types::{BlockNumberOrTag, TransactionInfo};
use alloy_rpc_types_eth::transaction::TransactionRequest;
use futures::Future;
@ -14,13 +15,6 @@ use reth_rpc_eth_types::{
utils::{binary_search, recover_raw_transaction},
EthApiError, EthStateCache, SignError, TransactionSource,
};
use reth_rpc_types::{
transaction::{
EIP1559TransactionRequest, EIP2930TransactionRequest, EIP4844TransactionRequest,
LegacyTransactionRequest,
},
TypedTransactionRequest,
};
use reth_rpc_types_compat::transaction::{from_recovered, from_recovered_with_block_context};
use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool};
@ -369,172 +363,14 @@ pub trait EthTransactions: LoadTransaction {
}
let chain_id = self.chain_id();
request.chain_id = Some(chain_id.to::<u64>());
let estimated_gas =
self.estimate_gas_at(request.clone(), BlockId::pending(), None).await?;
let gas_limit = estimated_gas;
request.set_gas_limit(gas_limit.to::<u128>());
let TransactionRequest {
to,
gas_price,
max_fee_per_gas,
max_priority_fee_per_gas,
gas,
value,
input: data,
nonce,
mut access_list,
max_fee_per_blob_gas,
blob_versioned_hashes,
sidecar,
..
} = request;
// todo: remove this inlining after https://github.com/alloy-rs/alloy/pull/183#issuecomment-1928161285
let transaction = match (
gas_price,
max_fee_per_gas,
access_list.take(),
max_fee_per_blob_gas,
blob_versioned_hashes,
sidecar,
) {
// legacy transaction
// gas price required
(Some(_), None, None, None, None, None) => {
Some(TypedTransactionRequest::Legacy(LegacyTransactionRequest {
nonce: nonce.unwrap_or_default(),
gas_price: U256::from(gas_price.unwrap_or_default()),
gas_limit: U256::from(gas.unwrap_or_default()),
value: value.unwrap_or_default(),
input: data.into_input().unwrap_or_default(),
kind: to.unwrap_or(TxKind::Create),
chain_id: None,
}))
}
// EIP2930
// if only accesslist is set, and no eip1599 fees
(_, None, Some(access_list), None, None, None) => {
Some(TypedTransactionRequest::EIP2930(EIP2930TransactionRequest {
nonce: nonce.unwrap_or_default(),
gas_price: U256::from(gas_price.unwrap_or_default()),
gas_limit: U256::from(gas.unwrap_or_default()),
value: value.unwrap_or_default(),
input: data.into_input().unwrap_or_default(),
kind: to.unwrap_or(TxKind::Create),
chain_id: 0,
access_list,
}))
}
// EIP1559
// if 4844 fields missing
// gas_price, max_fee_per_gas, access_list, max_fee_per_blob_gas,
// blob_versioned_hashes, sidecar,
(None, _, _, None, None, None) => {
// Empty fields fall back to the canonical transaction schema.
Some(TypedTransactionRequest::EIP1559(EIP1559TransactionRequest {
nonce: nonce.unwrap_or_default(),
max_fee_per_gas: U256::from(max_fee_per_gas.unwrap_or_default()),
max_priority_fee_per_gas: U256::from(
max_priority_fee_per_gas.unwrap_or_default(),
),
gas_limit: U256::from(gas.unwrap_or_default()),
value: value.unwrap_or_default(),
input: data.into_input().unwrap_or_default(),
kind: to.unwrap_or(TxKind::Create),
chain_id: 0,
access_list: access_list.unwrap_or_default(),
}))
}
// EIP4884
// all blob fields required
(
None,
_,
_,
Some(max_fee_per_blob_gas),
Some(blob_versioned_hashes),
Some(sidecar),
) => {
// As per the EIP, we follow the same semantics as EIP-1559.
Some(TypedTransactionRequest::EIP4844(EIP4844TransactionRequest {
chain_id: 0,
nonce: nonce.unwrap_or_default(),
max_priority_fee_per_gas: U256::from(
max_priority_fee_per_gas.unwrap_or_default(),
),
max_fee_per_gas: U256::from(max_fee_per_gas.unwrap_or_default()),
gas_limit: U256::from(gas.unwrap_or_default()),
value: value.unwrap_or_default(),
input: data.into_input().unwrap_or_default(),
to: match to {
Some(TxKind::Call(to)) => to,
_ => Address::default(),
},
access_list: access_list.unwrap_or_default(),
// eip-4844 specific.
max_fee_per_blob_gas: U256::from(max_fee_per_blob_gas),
blob_versioned_hashes,
sidecar,
}))
}
_ => None,
};
let transaction = match transaction {
Some(TypedTransactionRequest::Legacy(mut req)) => {
req.chain_id = Some(chain_id.to());
req.gas_limit = gas_limit.saturating_to();
req.gas_price = self.legacy_gas_price(gas_price.map(U256::from)).await?;
TypedTransactionRequest::Legacy(req)
}
Some(TypedTransactionRequest::EIP2930(mut req)) => {
req.chain_id = chain_id.to();
req.gas_limit = gas_limit.saturating_to();
req.gas_price = self.legacy_gas_price(gas_price.map(U256::from)).await?;
TypedTransactionRequest::EIP2930(req)
}
Some(TypedTransactionRequest::EIP1559(mut req)) => {
let (max_fee_per_gas, max_priority_fee_per_gas) = self
.eip1559_fees(
max_fee_per_gas.map(U256::from),
max_priority_fee_per_gas.map(U256::from),
)
.await?;
req.chain_id = chain_id.to();
req.gas_limit = gas_limit.saturating_to();
req.max_fee_per_gas = max_fee_per_gas.saturating_to();
req.max_priority_fee_per_gas = max_priority_fee_per_gas.saturating_to();
TypedTransactionRequest::EIP1559(req)
}
Some(TypedTransactionRequest::EIP4844(mut req)) => {
let (max_fee_per_gas, max_priority_fee_per_gas) = self
.eip1559_fees(
max_fee_per_gas.map(U256::from),
max_priority_fee_per_gas.map(U256::from),
)
.await?;
req.max_fee_per_gas = max_fee_per_gas;
req.max_priority_fee_per_gas = max_priority_fee_per_gas;
req.max_fee_per_blob_gas =
self.eip4844_blob_fee(max_fee_per_blob_gas.map(U256::from)).await?;
req.chain_id = chain_id.to();
req.gas_limit = gas_limit;
TypedTransactionRequest::EIP4844(req)
}
None => return Err(EthApiError::ConflictingFeeFieldsInRequest.into()),
};
let signed_tx = self.sign_request(&from, transaction)?;
let signed_tx = self.sign_request(&from, request).await?;
let recovered =
signed_tx.into_ecrecovered().ok_or(EthApiError::InvalidTransactionSignature)?;
@ -555,17 +391,20 @@ pub trait EthTransactions: LoadTransaction {
fn sign_request(
&self,
from: &Address,
request: TypedTransactionRequest,
) -> Result<TransactionSigned, Self::Error> {
for signer in self.signers().read().iter() {
if signer.is_signer_for(from) {
return match signer.sign_transaction(request, from) {
Ok(tx) => Ok(tx),
Err(e) => Err(e.into_eth_err()),
txn: TransactionRequest,
) -> impl Future<Output = Result<TransactionSigned, Self::Error>> + Send {
async move {
let signers: Vec<_> = self.signers().read().iter().cloned().collect();
for signer in signers {
if signer.is_signer_for(from) {
return match signer.sign_transaction(txn, from).await {
Ok(tx) => Ok(tx),
Err(e) => Err(e.into_eth_err()),
}
}
}
Err(EthApiError::InvalidTransactionSignature.into())
}
Err(EthApiError::InvalidTransactionSignature.into())
}
/// Signs given message. Returns the signature.

View File

@ -1,11 +1,7 @@
//! Compatibility functions for rpc `Transaction` type.
mod signature;
mod typed;
pub use signature::*;
pub use typed::*;
use std::fmt;
use alloy_rpc_types::{

View File

@ -1,58 +0,0 @@
/// Converts a typed transaction request into a primitive transaction.
///
/// Returns `None` if any of the following are true:
/// - `nonce` is greater than [`u64::MAX`]
/// - `gas_limit` is greater than [`u64::MAX`]
/// - `value` is greater than [`u128::MAX`]
pub fn to_primitive_transaction(
tx_request: reth_rpc_types::TypedTransactionRequest,
) -> Option<reth_primitives::Transaction> {
use reth_primitives::{Transaction, TxEip1559, TxEip2930, TxEip4844, TxLegacy};
use reth_rpc_types::TypedTransactionRequest;
Some(match tx_request {
TypedTransactionRequest::Legacy(tx) => Transaction::Legacy(TxLegacy {
chain_id: tx.chain_id,
nonce: tx.nonce,
gas_price: tx.gas_price.to(),
gas_limit: tx.gas_limit.try_into().ok()?,
to: tx.kind,
value: tx.value,
input: tx.input,
}),
TypedTransactionRequest::EIP2930(tx) => Transaction::Eip2930(TxEip2930 {
chain_id: tx.chain_id,
nonce: tx.nonce,
gas_price: tx.gas_price.to(),
gas_limit: tx.gas_limit.try_into().ok()?,
to: tx.kind,
value: tx.value,
input: tx.input,
access_list: tx.access_list,
}),
TypedTransactionRequest::EIP1559(tx) => Transaction::Eip1559(TxEip1559 {
chain_id: tx.chain_id,
nonce: tx.nonce,
max_fee_per_gas: tx.max_fee_per_gas.to(),
gas_limit: tx.gas_limit.try_into().ok()?,
to: tx.kind,
value: tx.value,
input: tx.input,
access_list: tx.access_list,
max_priority_fee_per_gas: tx.max_priority_fee_per_gas.to(),
}),
TypedTransactionRequest::EIP4844(tx) => Transaction::Eip4844(TxEip4844 {
chain_id: tx.chain_id,
nonce: tx.nonce,
gas_limit: tx.gas_limit.to(),
max_fee_per_gas: tx.max_fee_per_gas.to(),
max_priority_fee_per_gas: tx.max_priority_fee_per_gas.to(),
to: tx.to,
value: tx.value,
access_list: tx.access_list,
blob_versioned_hashes: tx.blob_versioned_hashes,
max_fee_per_blob_gas: tx.max_fee_per_blob_gas.to(),
input: tx.input,
}),
})
}

View File

@ -14,25 +14,17 @@ workspace = true
[dependencies]
# ethereum
alloy-primitives = { workspace = true, features = ["rand", "rlp", "serde"] }
alloy-rpc-types.workspace = true
alloy-rpc-types-engine = { workspace = true, features = ["std", "serde", "jsonrpsee-types"], optional = true }
# misc
jsonrpsee-types = { workspace = true, optional = true }
[dev-dependencies]
# misc
alloy-primitives = { workspace = true, features = ["rand", "rlp", "serde", "arbitrary"] }
arbitrary = { workspace = true, features = ["derive"] }
rand.workspace = true
[features]
default = ["jsonrpsee-types"]
jsonrpsee-types = [
"dep:jsonrpsee-types",
"dep:alloy-rpc-types-engine",
"alloy-rpc-types/jsonrpsee-types",
"alloy-rpc-types-engine/jsonrpsee-types",
]
arbitrary = ["alloy-primitives/arbitrary", "alloy-rpc-types/arbitrary"]
]

View File

@ -1,7 +1,6 @@
//! Ethereum related types
pub(crate) mod error;
pub mod transaction;
// re-export
#[cfg(feature = "jsonrpsee-types")]

View File

@ -1,3 +0,0 @@
//! RPC types for transactions
mod typed;
pub use typed::*;

View File

@ -1,113 +0,0 @@
use alloy_primitives::{Address, Bytes, TxKind, B256, U256};
use alloy_rpc_types::{AccessList, BlobTransactionSidecar};
/// Container type for various Ethereum transaction requests
///
/// Its variants correspond to specific allowed transactions:
/// 1. Legacy (pre-EIP2718) [`LegacyTransactionRequest`]
/// 2. EIP2930 (state access lists) [`EIP2930TransactionRequest`]
/// 3. EIP1559 [`EIP1559TransactionRequest`]
/// 4. EIP4844 [`EIP4844TransactionRequest`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TypedTransactionRequest {
/// Represents a Legacy (pre-EIP2718) transaction request
Legacy(LegacyTransactionRequest),
/// Represents an EIP2930 (state access lists) transaction request
EIP2930(EIP2930TransactionRequest),
/// Represents an EIP1559 transaction request
EIP1559(EIP1559TransactionRequest),
/// Represents an EIP4844 transaction request
EIP4844(EIP4844TransactionRequest),
}
/// Represents a legacy transaction request
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LegacyTransactionRequest {
/// The nonce of the transaction
pub nonce: u64,
/// The gas price for the transaction
pub gas_price: U256,
/// The gas limit for the transaction
pub gas_limit: U256,
/// The kind of transaction (e.g., Call, Create)
pub kind: TxKind,
/// The value of the transaction
pub value: U256,
/// The input data for the transaction
pub input: Bytes,
/// The optional chain ID for the transaction
pub chain_id: Option<u64>,
}
/// Represents an EIP-2930 transaction request
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EIP2930TransactionRequest {
/// The chain ID for the transaction
pub chain_id: u64,
/// The nonce of the transaction
pub nonce: u64,
/// The gas price for the transaction
pub gas_price: U256,
/// The gas limit for the transaction
pub gas_limit: U256,
/// The kind of transaction (e.g., Call, Create)
pub kind: TxKind,
/// The value of the transaction
pub value: U256,
/// The input data for the transaction
pub input: Bytes,
/// The access list for the transaction
pub access_list: AccessList,
}
/// Represents an EIP-1559 transaction request
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EIP1559TransactionRequest {
/// The chain ID for the transaction
pub chain_id: u64,
/// The nonce of the transaction
pub nonce: u64,
/// The maximum priority fee per gas for the transaction
pub max_priority_fee_per_gas: U256,
/// The maximum fee per gas for the transaction
pub max_fee_per_gas: U256,
/// The gas limit for the transaction
pub gas_limit: U256,
/// The kind of transaction (e.g., Call, Create)
pub kind: TxKind,
/// The value of the transaction
pub value: U256,
/// The input data for the transaction
pub input: Bytes,
/// The access list for the transaction
pub access_list: AccessList,
}
/// Represents an EIP-4844 transaction request
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EIP4844TransactionRequest {
/// The chain ID for the transaction
pub chain_id: u64,
/// The nonce of the transaction
pub nonce: u64,
/// The maximum priority fee per gas for the transaction
pub max_priority_fee_per_gas: U256,
/// The maximum fee per gas for the transaction
pub max_fee_per_gas: U256,
/// The gas limit for the transaction
pub gas_limit: U256,
/// The recipient of the transaction
pub to: Address,
/// The value of the transaction
pub value: U256,
/// The input data for the transaction
pub input: Bytes,
/// The access list for the transaction
pub access_list: AccessList,
/// The maximum fee per blob gas for the transaction
pub max_fee_per_blob_gas: U256,
/// Versioned hashes associated with the transaction
pub blob_versioned_hashes: Vec<B256>,
/// Sidecar information for the transaction
pub sidecar: BlobTransactionSidecar,
}

View File

@ -15,7 +15,6 @@ mod eth;
// Ethereum specific rpc types related to typed transaction requests and the engine API.
#[cfg(feature = "jsonrpsee-types")]
pub use eth::error::ToRpcError;
pub use eth::transaction::{self, TypedTransactionRequest};
#[cfg(feature = "jsonrpsee-types")]
pub use eth::{
engine,

View File

@ -17,7 +17,6 @@ reth-chainspec.workspace = true
reth-primitives = { workspace = true, features = ["secp256k1"] }
reth-rpc-api.workspace = true
reth-rpc-eth-api.workspace = true
reth-rpc-types.workspace = true
reth-errors.workspace = true
reth-provider.workspace = true
reth-transaction-pool.workspace = true
@ -37,13 +36,16 @@ reth-network-types.workspace = true
reth-trie.workspace = true
# ethereum
alloy-consensus.workspace = true
alloy-signer.workspace = true
alloy-signer-local.workspace = true
alloy-dyn-abi.workspace = true
alloy-genesis.workspace = true
alloy-network.workspace = true
alloy-primitives.workspace = true
alloy-rlp.workspace = true
alloy-rpc-types.workspace = true
alloy-rpc-types-eth.workspace = true
alloy-rpc-types-eth = { workspace = true, features = ["jsonrpsee-types"] }
alloy-rpc-types-debug.workspace = true
alloy-rpc-types-trace.workspace = true
alloy-rpc-types-mev.workspace = true
@ -56,7 +58,6 @@ revm = { workspace = true, features = [
"optional_no_base_fee",
] }
revm-primitives = { workspace = true, features = ["serde"] }
secp256k1.workspace = true
# rpc
jsonrpsee.workspace = true

View File

@ -2,16 +2,17 @@
use std::collections::HashMap;
use crate::EthApi;
use alloy_consensus::TxEnvelope;
use alloy_dyn_abi::TypedData;
use alloy_network::{eip2718::Encodable2718, EthereumWallet, TransactionBuilder};
use alloy_primitives::{eip191_hash_message, Address, B256};
use reth_primitives::{sign_message, Signature, TransactionSigned};
use alloy_rpc_types_eth::TransactionRequest;
use alloy_signer::SignerSync;
use alloy_signer_local::PrivateKeySigner;
use reth_primitives::{Signature, TransactionSigned};
use reth_rpc_eth_api::helpers::{signer::Result, AddDevSigners, EthSigner};
use reth_rpc_eth_types::SignError;
use reth_rpc_types::TypedTransactionRequest;
use reth_rpc_types_compat::transaction::to_primitive_transaction;
use secp256k1::SecretKey;
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> AddDevSigners
for EthApi<Provider, Pool, Network, EvmConfig>
@ -25,7 +26,7 @@ impl<Provider, Pool, Network, EvmConfig> AddDevSigners
#[derive(Debug, Clone)]
pub struct DevSigner {
addresses: Vec<Address>,
accounts: HashMap<Address, SecretKey>,
accounts: HashMap<Address, PrivateKeySigner>,
}
#[allow(dead_code)]
@ -41,23 +42,23 @@ impl DevSigner {
pub fn random_signers(num: u32) -> Vec<Box<dyn EthSigner + 'static>> {
let mut signers = Vec::new();
for _ in 0..num {
let (sk, pk) = secp256k1::generate_keypair(&mut rand::thread_rng());
let sk = PrivateKeySigner::random_with(&mut rand::thread_rng());
let address = reth_primitives::public_key_to_address(pk);
let address = sk.address();
let addresses = vec![address];
let accounts = HashMap::from([(address, sk)]);
signers.push(Box::new(Self { addresses, accounts }) as Box<dyn EthSigner>);
}
signers
}
fn get_key(&self, account: Address) -> Result<&SecretKey> {
fn get_key(&self, account: Address) -> Result<&PrivateKeySigner> {
self.accounts.get(&account).ok_or(SignError::NoAccount)
}
fn sign_hash(&self, hash: B256, account: Address) -> Result<Signature> {
let secret = self.get_key(account)?;
let signature = sign_message(B256::from_slice(secret.as_ref()), hash);
let signature = self.get_key(account)?.sign_hash_sync(&hash);
signature.map_err(|_| SignError::CouldNotSign)
}
}
@ -79,18 +80,25 @@ impl EthSigner for DevSigner {
self.sign_hash(hash, address)
}
fn sign_transaction(
async fn sign_transaction(
&self,
request: TypedTransactionRequest,
request: TransactionRequest,
address: &Address,
) -> Result<TransactionSigned> {
// convert to primitive transaction
let transaction =
to_primitive_transaction(request).ok_or(SignError::InvalidTransactionRequest)?;
let tx_signature_hash = transaction.signature_hash();
let signature = self.sign_hash(tx_signature_hash, *address)?;
// create local signer wallet from signing key
let signer = self.accounts.get(address).ok_or(SignError::NoAccount)?.clone();
let wallet = EthereumWallet::from(signer);
Ok(TransactionSigned::from_transaction_and_signature(transaction, signature))
// build and sign transaction with signer
let txn_envelope: TxEnvelope =
request.build(&wallet).await.map_err(|_| SignError::InvalidTransactionRequest)?;
// decode transaction into signed transaction type
let encoded = txn_envelope.encoded_2718();
let txn_signed = TransactionSigned::decode_enveloped(&mut encoded.as_ref())
.map_err(|_| SignError::InvalidTransactionRequest)?;
Ok(txn_signed)
}
fn sign_typed_data(&self, address: Address, payload: &TypedData) -> Result<Signature> {
@ -101,18 +109,18 @@ impl EthSigner for DevSigner {
#[cfg(test)]
mod tests {
use std::str::FromStr;
use alloy_primitives::{Parity, U256};
use alloy_primitives::{Bytes, Parity, U256};
use alloy_rpc_types_eth::TransactionInput;
use revm_primitives::TxKind;
use super::*;
fn build_signer() -> DevSigner {
let addresses = vec![];
let secret =
SecretKey::from_str("4646464646464646464646464646464646464646464646464646464646464646")
.unwrap();
let accounts = HashMap::from([(Address::default(), secret)]);
let signer: PrivateKeySigner =
"4646464646464646464646464646464646464646464646464646464646464646".parse().unwrap();
let address = signer.address();
let accounts = HashMap::from([(address, signer)]);
let addresses = vec![address];
DevSigner { addresses, accounts }
}
@ -184,7 +192,8 @@ mod tests {
}"#;
let data: TypedData = serde_json::from_str(eip_712_example).unwrap();
let signer = build_signer();
let sig = signer.sign_typed_data(Address::default(), &data).unwrap();
let from = *signer.addresses.first().unwrap();
let sig = signer.sign_typed_data(from, &data).unwrap();
let expected = Signature::new(
U256::from_str_radix(
"5318aee9942b84885761bb20e768372b76e7ee454fc4d39b59ce07338d15a06c",
@ -205,7 +214,8 @@ mod tests {
async fn test_signer() {
let message = b"Test message";
let signer = build_signer();
let sig = signer.sign(Address::default(), message).await.unwrap();
let from = *signer.addresses.first().unwrap();
let sig = signer.sign(from, message).await.unwrap();
let expected = Signature::new(
U256::from_str_radix(
"54313da7432e4058b8d22491b2e7dbb19c7186c35c24155bec0820a8a2bfe0c1",
@ -221,4 +231,29 @@ mod tests {
);
assert_eq!(sig, expected)
}
#[tokio::test]
async fn test_sign_transaction() {
let message = b"Test message";
let signer = build_signer();
let from = *signer.addresses.first().unwrap();
let request = TransactionRequest {
chain_id: Some(1u64),
from: Some(from),
to: Some(TxKind::Create),
gas: Some(1000u128),
gas_price: Some(1000u128),
value: Some(U256::from(1000)),
input: TransactionInput {
data: Some(Bytes::from(message.to_vec())),
input: Some(Bytes::from(message.to_vec())),
},
nonce: Some(0u64),
..Default::default()
};
let txn_signed = signer.sign_transaction(request, &from).await;
assert!(txn_signed.is_ok());
assert_eq!(Bytes::from(message.to_vec()), txn_signed.unwrap().input().0);
}
}