mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: use alloy Signature type (#10758)
Co-authored-by: Emilia Hane <elsaemiliaevahane@gmail.com>
This commit is contained in:
@ -421,7 +421,7 @@ revm-primitives = { version = "9.0.2", features = [
|
||||
# eth
|
||||
alloy-chains = "0.1.32"
|
||||
alloy-dyn-abi = "0.8.0"
|
||||
alloy-primitives = { version = "0.8.0", default-features = false }
|
||||
alloy-primitives = { version = "0.8.3", default-features = false }
|
||||
alloy-rlp = "0.3.4"
|
||||
alloy-sol-types = "0.8.0"
|
||||
alloy-trie = { version = "0.5", default-features = false }
|
||||
|
||||
@ -1571,7 +1571,7 @@ mod tests {
|
||||
max_fee_per_gas: EIP1559_INITIAL_BASE_FEE as u128,
|
||||
..Default::default()
|
||||
}),
|
||||
Signature::default(),
|
||||
Signature::test_signature(),
|
||||
)
|
||||
.with_signer(signer)
|
||||
};
|
||||
|
||||
@ -13,7 +13,7 @@ use reth_primitives::{
|
||||
constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH},
|
||||
proofs::{calculate_receipt_root, calculate_transaction_root, calculate_withdrawals_root},
|
||||
Header, Receipt, Receipts, Requests, SealedBlock, SealedBlockWithSenders, SealedHeader,
|
||||
Signature, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip1559,
|
||||
Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip1559,
|
||||
};
|
||||
use reth_trie::{root::state_root_unhashed, updates::TrieUpdates, HashedPostState};
|
||||
use revm::{db::BundleState, primitives::AccountInfo};
|
||||
@ -98,15 +98,8 @@ impl TestBlockBuilder {
|
||||
let signature_hash = tx.signature_hash();
|
||||
let signature = self.signer_pk.sign_hash_sync(&signature_hash).unwrap();
|
||||
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
tx,
|
||||
Signature {
|
||||
r: signature.r(),
|
||||
s: signature.s(),
|
||||
odd_y_parity: signature.v().y_parity(),
|
||||
},
|
||||
)
|
||||
.with_signer(self.signer)
|
||||
TransactionSigned::from_transaction_and_signature(tx, signature)
|
||||
.with_signer(self.signer)
|
||||
};
|
||||
|
||||
let num_txs = rng.gen_range(0..5);
|
||||
|
||||
@ -303,7 +303,7 @@ pub fn validate_against_parent_4844(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_primitives::{
|
||||
hex_literal::hex, Address, BlockHash, BlockNumber, Bytes, Sealable, U256,
|
||||
hex_literal::hex, Address, BlockHash, BlockNumber, Bytes, Parity, Sealable, U256,
|
||||
};
|
||||
use mockall::mock;
|
||||
use rand::Rng;
|
||||
@ -430,7 +430,7 @@ mod tests {
|
||||
blob_versioned_hashes: std::iter::repeat_with(|| rng.gen()).take(num_blobs).collect(),
|
||||
});
|
||||
|
||||
let signature = Signature { odd_y_parity: true, r: U256::default(), s: U256::default() };
|
||||
let signature = Signature::new(U256::default(), U256::default(), Parity::Parity(true));
|
||||
|
||||
TransactionSigned::from_transaction_and_signature(request, signature)
|
||||
}
|
||||
|
||||
@ -115,7 +115,8 @@ mod tests {
|
||||
use alloy_primitives::{hex, TxKind, U256};
|
||||
use alloy_rlp::{Decodable, Encodable};
|
||||
use reth_primitives::{
|
||||
BlockHashOrNumber, Header, Signature, Transaction, TransactionSigned, TxLegacy,
|
||||
alloy_primitives::Parity, BlockHashOrNumber, Header, Signature, Transaction,
|
||||
TransactionSigned, TxLegacy,
|
||||
};
|
||||
use std::str::FromStr;
|
||||
|
||||
@ -370,12 +371,11 @@ mod tests {
|
||||
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
|
||||
value: U256::from(0x200u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
|
||||
s: U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
|
||||
}
|
||||
}), Signature::new(
|
||||
U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
|
||||
U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
|
||||
Parity::Parity(false),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(Transaction::Legacy(TxLegacy {
|
||||
chain_id: Some(1),
|
||||
@ -385,11 +385,11 @@ mod tests {
|
||||
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
|
||||
value: U256::from(0x2d9u64),
|
||||
input: Default::default(),
|
||||
}), Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||
s: U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||
},
|
||||
}), Signature::new(
|
||||
U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||
U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||
Parity::Parity(false),
|
||||
),
|
||||
),
|
||||
],
|
||||
ommers: vec![
|
||||
@ -445,11 +445,11 @@ mod tests {
|
||||
value: U256::from(0x200u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
|
||||
s: U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
|
||||
}
|
||||
Signature::new(
|
||||
U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
|
||||
U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
|
||||
Parity::Eip155(37),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -461,11 +461,11 @@ mod tests {
|
||||
value: U256::from(0x2d9u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||
s: U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||
}
|
||||
Signature::new(
|
||||
U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||
U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||
Parity::Eip155(37),
|
||||
),
|
||||
),
|
||||
],
|
||||
ommers: vec![
|
||||
|
||||
@ -81,7 +81,8 @@ mod tests {
|
||||
use alloy_rlp::{Decodable, Encodable};
|
||||
use reth_chainspec::MIN_TRANSACTION_GAS;
|
||||
use reth_primitives::{
|
||||
PooledTransactionsElement, Signature, Transaction, TransactionSigned, TxEip1559, TxLegacy,
|
||||
alloy_primitives::Parity, PooledTransactionsElement, Signature, Transaction,
|
||||
TransactionSigned, TxEip1559, TxLegacy,
|
||||
};
|
||||
use std::str::FromStr;
|
||||
|
||||
@ -134,17 +135,17 @@ mod tests {
|
||||
value: U256::from(0x200u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Parity(false),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -156,17 +157,17 @@ mod tests {
|
||||
value: U256::from(0x2d9u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Parity(false),
|
||||
),
|
||||
),
|
||||
];
|
||||
let message: Vec<PooledTransactionsElement> = txs
|
||||
@ -200,17 +201,17 @@ mod tests {
|
||||
value: U256::from(0x200u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Eip155(37),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -222,17 +223,17 @@ mod tests {
|
||||
value: U256::from(0x2d9u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Eip155(37),
|
||||
),
|
||||
),
|
||||
];
|
||||
let message: Vec<PooledTransactionsElement> = txs
|
||||
@ -267,17 +268,17 @@ mod tests {
|
||||
value: U256::from(1234u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: true,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0x35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Eip155(44),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Eip1559(TxEip1559 {
|
||||
@ -291,17 +292,17 @@ mod tests {
|
||||
input: Default::default(),
|
||||
access_list: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: true,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0x59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Parity(true),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -313,17 +314,17 @@ mod tests {
|
||||
value: U256::from(1000000000000000u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0xce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Eip155(43),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -335,17 +336,17 @@ mod tests {
|
||||
value: U256::from(693361000000000u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0xe24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Eip155(43),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -357,17 +358,17 @@ mod tests {
|
||||
value: U256::from(1000000000000000u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Eip155(43),
|
||||
),
|
||||
),
|
||||
];
|
||||
let message: Vec<PooledTransactionsElement> = txs
|
||||
@ -406,17 +407,17 @@ mod tests {
|
||||
value: U256::from(1234u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: true,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0x35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Parity(true),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Eip1559(TxEip1559 {
|
||||
@ -430,17 +431,17 @@ mod tests {
|
||||
input: Default::default(),
|
||||
access_list: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: true,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0x59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Parity(true),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -452,17 +453,17 @@ mod tests {
|
||||
value: U256::from(1000000000000000u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0xce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Parity(false),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -474,17 +475,17 @@ mod tests {
|
||||
value: U256::from(693361000000000u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0xe24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Parity(false),
|
||||
),
|
||||
),
|
||||
TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Legacy(TxLegacy {
|
||||
@ -496,17 +497,17 @@ mod tests {
|
||||
value: U256::from(1000000000000000u64),
|
||||
input: Default::default(),
|
||||
}),
|
||||
Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str(
|
||||
Signature::new(
|
||||
U256::from_str(
|
||||
"0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
Parity::Parity(false),
|
||||
),
|
||||
),
|
||||
];
|
||||
let message: Vec<PooledTransactionsElement> = txs
|
||||
|
||||
@ -133,7 +133,7 @@ impl From<EthVersion> for &'static str {
|
||||
/// RLPx `p2p` protocol version
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
|
||||
#[add_arbitrary_tests(rlp)]
|
||||
pub enum ProtocolVersion {
|
||||
/// `p2p` version 4
|
||||
|
||||
@ -28,7 +28,7 @@ async fn test_large_tx_req() {
|
||||
|
||||
let ts = TransactionSigned {
|
||||
hash: Default::default(),
|
||||
signature: Signature::default(),
|
||||
signature: Signature::test_signature(),
|
||||
transaction: tx.clone().into(),
|
||||
};
|
||||
tx.set_hash(ts.recalculate_hash());
|
||||
|
||||
@ -16,7 +16,8 @@ use reth_network_p2p::{
|
||||
headers::client::{HeadersClient, HeadersRequest},
|
||||
};
|
||||
use reth_primitives::{
|
||||
Block, BlockBody, Header, Signature, Transaction, TransactionSigned, TxEip2930,
|
||||
alloy_primitives::Parity, Block, BlockBody, Header, Signature, Transaction, TransactionSigned,
|
||||
TxEip2930,
|
||||
};
|
||||
use reth_provider::test_utils::MockEthProvider;
|
||||
|
||||
@ -32,7 +33,7 @@ pub fn rng_transaction(rng: &mut impl rand::RngCore) -> TransactionSigned {
|
||||
input: Bytes::from(vec![1, 2]),
|
||||
access_list: Default::default(),
|
||||
});
|
||||
let signature = Signature { odd_y_parity: true, r: U256::default(), s: U256::default() };
|
||||
let signature = Signature::new(U256::default(), U256::default(), Parity::Parity(true));
|
||||
|
||||
TransactionSigned::from_transaction_and_signature(request, signature)
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ use futures::StreamExt;
|
||||
use rand::thread_rng;
|
||||
use reth_network::{test_utils::Testnet, NetworkEvent, NetworkEventListenerProvider};
|
||||
use reth_network_api::PeersInfo;
|
||||
use reth_primitives::{TransactionSigned, TxLegacy};
|
||||
use reth_primitives::{Signature, TransactionSigned, TxLegacy};
|
||||
use reth_provider::test_utils::{ExtendedAccount, MockEthProvider};
|
||||
use reth_transaction_pool::{test_utils::TransactionGenerator, PoolTransaction, TransactionPool};
|
||||
|
||||
@ -131,7 +131,10 @@ async fn test_sending_invalid_transactions() {
|
||||
value: Default::default(),
|
||||
input: Default::default(),
|
||||
};
|
||||
let tx = TransactionSigned::from_transaction_and_signature(tx.into(), Default::default());
|
||||
let tx = TransactionSigned::from_transaction_and_signature(
|
||||
tx.into(),
|
||||
Signature::test_signature(),
|
||||
);
|
||||
peer0.network().send_transactions(*peer1.peer_id(), vec![Arc::new(tx)]);
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ mod dev;
|
||||
mod op;
|
||||
mod op_sepolia;
|
||||
|
||||
use alloy_primitives::{Parity, Signature, U256};
|
||||
pub use base::BASE_MAINNET;
|
||||
pub use base_sepolia::BASE_SEPOLIA;
|
||||
pub use dev::OP_DEV;
|
||||
@ -32,6 +33,12 @@ pub struct OpChainSpec {
|
||||
pub inner: ChainSpec,
|
||||
}
|
||||
|
||||
/// Returns the signature for the optimism deposit transactions, which don't include a
|
||||
/// signature.
|
||||
pub fn optimism_deposit_tx_signature() -> Signature {
|
||||
Signature::new(U256::ZERO, U256::ZERO, Parity::Parity(false))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloy_genesis::Genesis;
|
||||
|
||||
@ -530,6 +530,7 @@ mod tests {
|
||||
use crate::OpChainSpec;
|
||||
use alloy_primitives::{b256, Address, StorageKey, StorageValue};
|
||||
use reth_chainspec::{ChainSpecBuilder, MIN_TRANSACTION_GAS};
|
||||
use reth_optimism_chainspec::optimism_deposit_tx_signature;
|
||||
use reth_primitives::{
|
||||
Account, Block, Signature, Transaction, TransactionSigned, TxEip1559, BASE_MAINNET,
|
||||
};
|
||||
@ -607,7 +608,7 @@ mod tests {
|
||||
to: addr.into(),
|
||||
..Default::default()
|
||||
}),
|
||||
Signature::default(),
|
||||
Signature::test_signature(),
|
||||
);
|
||||
|
||||
let tx_deposit = TransactionSigned::from_transaction_and_signature(
|
||||
@ -617,7 +618,7 @@ mod tests {
|
||||
gas_limit: MIN_TRANSACTION_GAS as u128,
|
||||
..Default::default()
|
||||
}),
|
||||
Signature::default(),
|
||||
Signature::test_signature(),
|
||||
);
|
||||
|
||||
let provider = executor_provider(chain_spec);
|
||||
@ -691,7 +692,7 @@ mod tests {
|
||||
to: addr.into(),
|
||||
..Default::default()
|
||||
}),
|
||||
Signature::default(),
|
||||
Signature::test_signature(),
|
||||
);
|
||||
|
||||
let tx_deposit = TransactionSigned::from_transaction_and_signature(
|
||||
@ -701,7 +702,7 @@ mod tests {
|
||||
gas_limit: MIN_TRANSACTION_GAS as u128,
|
||||
..Default::default()
|
||||
}),
|
||||
Signature::optimism_deposit_tx_signature(),
|
||||
optimism_deposit_tx_signature(),
|
||||
);
|
||||
|
||||
let provider = executor_provider(chain_spec);
|
||||
|
||||
@ -262,7 +262,7 @@ mod tests {
|
||||
is_system_transaction: false,
|
||||
input: Default::default(),
|
||||
});
|
||||
let signature = Signature::default();
|
||||
let signature = Signature::test_signature();
|
||||
let signed_tx = TransactionSigned::from_transaction_and_signature(deposit_tx, signature);
|
||||
let signed_recovered =
|
||||
TransactionSignedEcRecovered::from_signed_transaction(signed_tx, signer);
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::{
|
||||
TxEip4844, TxLegacy, TxType,
|
||||
};
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use alloy_primitives::TxKind;
|
||||
use alloy_primitives::{Parity, TxKind};
|
||||
use alloy_rlp::Error as RlpError;
|
||||
use alloy_serde::WithOtherFields;
|
||||
use op_alloy_rpc_types as _;
|
||||
@ -219,27 +219,32 @@ impl TryFrom<WithOtherFields<alloy_rpc_types::Transaction>> for TransactionSigne
|
||||
|
||||
let signature = tx.signature.ok_or(ConversionError::MissingSignature)?;
|
||||
let transaction: Transaction = tx.try_into()?;
|
||||
let y_parity = if let Some(y_parity) = signature.y_parity {
|
||||
y_parity.0
|
||||
} else {
|
||||
match transaction.tx_type() {
|
||||
// If the transaction type is Legacy, adjust the v component of the
|
||||
// signature according to the Ethereum specification
|
||||
TxType::Legacy => {
|
||||
extract_chain_id(signature.v.to())
|
||||
.map_err(|_| ConversionError::InvalidSignature)?
|
||||
.0
|
||||
}
|
||||
_ => !signature.v.is_zero(),
|
||||
}
|
||||
};
|
||||
|
||||
let mut parity = Parity::Parity(y_parity);
|
||||
|
||||
if matches!(transaction.tx_type(), TxType::Legacy) {
|
||||
if let Some(chain_id) = transaction.chain_id() {
|
||||
parity = parity.with_chain_id(chain_id)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self::from_transaction_and_signature(
|
||||
transaction.clone(),
|
||||
Signature {
|
||||
r: signature.r,
|
||||
s: signature.s,
|
||||
odd_y_parity: if let Some(y_parity) = signature.y_parity {
|
||||
y_parity.0
|
||||
} else {
|
||||
match transaction.tx_type() {
|
||||
// If the transaction type is Legacy, adjust the v component of the
|
||||
// signature according to the Ethereum specification
|
||||
TxType::Legacy => {
|
||||
extract_chain_id(signature.v.to())
|
||||
.map_err(|_| ConversionError::InvalidSignature)?
|
||||
.0
|
||||
}
|
||||
_ => !signature.v.is_zero(),
|
||||
}
|
||||
},
|
||||
},
|
||||
transaction,
|
||||
Signature::new(signature.r, signature.s, parity),
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -256,22 +261,6 @@ impl TryFrom<WithOtherFields<alloy_rpc_types::Transaction>> for TransactionSigne
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<alloy_rpc_types::Signature> for Signature {
|
||||
type Error = alloy_rpc_types::ConversionError;
|
||||
|
||||
fn try_from(signature: alloy_rpc_types::Signature) -> Result<Self, Self::Error> {
|
||||
use alloy_rpc_types::ConversionError;
|
||||
|
||||
let odd_y_parity = if let Some(y_parity) = signature.y_parity {
|
||||
y_parity.0
|
||||
} else {
|
||||
extract_chain_id(signature.v.to()).map_err(|_| ConversionError::InvalidSignature)?.0
|
||||
};
|
||||
|
||||
Ok(Self { r: signature.r, s: signature.s, odd_y_parity })
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<WithOtherFields<alloy_rpc_types::Transaction>> for TransactionSignedNoHash {
|
||||
type Error = alloy_rpc_types::ConversionError;
|
||||
|
||||
|
||||
@ -112,7 +112,7 @@ pub use c_kzg as kzg;
|
||||
/// Optimism specific re-exports
|
||||
#[cfg(feature = "optimism")]
|
||||
mod optimism {
|
||||
pub use crate::transaction::{TxDeposit, DEPOSIT_TX_TYPE_ID};
|
||||
pub use crate::transaction::{optimism_deposit_tx_signature, TxDeposit, DEPOSIT_TX_TYPE_ID};
|
||||
pub use reth_optimism_chainspec::{BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA};
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use alloy_consensus::SignableTransaction;
|
||||
use alloy_primitives::Parity;
|
||||
use alloy_rlp::{
|
||||
Decodable, Encodable, Error as RlpError, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE,
|
||||
};
|
||||
@ -15,6 +16,7 @@ use derive_more::{AsRef, Deref};
|
||||
use once_cell::sync::Lazy;
|
||||
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use signature::{decode_with_eip155_chain_id, with_eip155_parity};
|
||||
|
||||
pub use access_list::{AccessList, AccessListItem, AccessListResult};
|
||||
|
||||
@ -32,7 +34,9 @@ pub use sidecar::BlobTransactionValidationError;
|
||||
pub use sidecar::{BlobTransaction, BlobTransactionSidecar};
|
||||
|
||||
pub use compat::FillTxEnv;
|
||||
pub use signature::{extract_chain_id, Signature};
|
||||
pub use signature::{
|
||||
extract_chain_id, legacy_parity, recover_signer, recover_signer_unchecked, Signature,
|
||||
};
|
||||
pub use tx_type::{
|
||||
TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID,
|
||||
LEGACY_TX_TYPE_ID,
|
||||
@ -53,6 +57,8 @@ mod variant;
|
||||
#[cfg(feature = "optimism")]
|
||||
pub use op_alloy_consensus::TxDeposit;
|
||||
#[cfg(feature = "optimism")]
|
||||
pub use reth_optimism_chainspec::optimism_deposit_tx_signature;
|
||||
#[cfg(feature = "optimism")]
|
||||
pub use tx_type::DEPOSIT_TX_TYPE_ID;
|
||||
#[cfg(any(test, feature = "reth-codec"))]
|
||||
use tx_type::{
|
||||
@ -136,7 +142,7 @@ pub enum Transaction {
|
||||
#[cfg(any(test, feature = "arbitrary"))]
|
||||
impl<'a> arbitrary::Arbitrary<'a> for Transaction {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
Ok(match TxType::arbitrary(u)? {
|
||||
let mut tx = match TxType::arbitrary(u)? {
|
||||
TxType::Legacy => {
|
||||
let mut tx = TxLegacy::arbitrary(u)?;
|
||||
tx.gas_limit = (tx.gas_limit as u64).into();
|
||||
@ -169,7 +175,14 @@ impl<'a> arbitrary::Arbitrary<'a> for Transaction {
|
||||
tx.gas_limit = (tx.gas_limit as u64).into();
|
||||
Self::Deposit(tx)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
// Otherwise we might overflow when calculating `v` on `recalculate_hash`
|
||||
if let Some(chain_id) = tx.chain_id() {
|
||||
tx.set_chain_id(chain_id % (u64::MAX / 2 - 36));
|
||||
}
|
||||
|
||||
Ok(tx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -529,30 +542,20 @@ impl Transaction {
|
||||
Self::Legacy(legacy_tx) => {
|
||||
// do nothing w/ with_header
|
||||
legacy_tx.encode_with_signature_fields(
|
||||
&signature.as_signature_with_eip155_parity(legacy_tx.chain_id),
|
||||
&with_eip155_parity(signature, legacy_tx.chain_id),
|
||||
out,
|
||||
)
|
||||
}
|
||||
Self::Eip2930(access_list_tx) => access_list_tx.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
with_header,
|
||||
),
|
||||
Self::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
with_header,
|
||||
),
|
||||
Self::Eip4844(blob_tx) => blob_tx.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
with_header,
|
||||
),
|
||||
Self::Eip7702(set_code_tx) => set_code_tx.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
with_header,
|
||||
),
|
||||
Self::Eip2930(access_list_tx) => {
|
||||
access_list_tx.encode_with_signature(signature, out, with_header)
|
||||
}
|
||||
Self::Eip1559(dynamic_fee_tx) => {
|
||||
dynamic_fee_tx.encode_with_signature(signature, out, with_header)
|
||||
}
|
||||
Self::Eip4844(blob_tx) => blob_tx.encode_with_signature(signature, out, with_header),
|
||||
Self::Eip7702(set_code_tx) => {
|
||||
set_code_tx.encode_with_signature(signature, out, with_header)
|
||||
}
|
||||
#[cfg(feature = "optimism")]
|
||||
Self::Deposit(deposit_tx) => deposit_tx.encode_inner(out, with_header),
|
||||
}
|
||||
@ -828,8 +831,7 @@ impl Encodable for Transaction {
|
||||
/// Signed transaction without its Hash. Used type for inserting into the DB.
|
||||
///
|
||||
/// This can by converted to [`TransactionSigned`] by calling [`TransactionSignedNoHash::hash`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Serialize, Deserialize)]
|
||||
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
|
||||
pub struct TransactionSignedNoHash {
|
||||
/// The transaction signature values
|
||||
@ -862,7 +864,7 @@ impl TransactionSignedNoHash {
|
||||
}
|
||||
|
||||
let signature_hash = self.signature_hash();
|
||||
self.signature.recover_signer(signature_hash)
|
||||
recover_signer(&self.signature, signature_hash)
|
||||
}
|
||||
|
||||
/// Recover signer from signature and hash _without ensuring that the signature has a low `s`
|
||||
@ -872,7 +874,7 @@ impl TransactionSignedNoHash {
|
||||
/// buffer before use.**
|
||||
///
|
||||
/// Returns `None` if the transaction's signature is invalid, see also
|
||||
/// [`Signature::recover_signer_unchecked`].
|
||||
/// [`recover_signer_unchecked`].
|
||||
///
|
||||
/// # Optimism
|
||||
///
|
||||
@ -894,12 +896,12 @@ impl TransactionSignedNoHash {
|
||||
// transactions with an empty signature
|
||||
//
|
||||
// NOTE: this is very hacky and only relevant for op-mainnet pre bedrock
|
||||
if self.is_legacy() && self.signature == Signature::optimism_deposit_tx_signature() {
|
||||
if self.is_legacy() && self.signature == optimism_deposit_tx_signature() {
|
||||
return Some(Address::ZERO)
|
||||
}
|
||||
}
|
||||
|
||||
self.signature.recover_signer_unchecked(keccak256(buffer))
|
||||
recover_signer_unchecked(&self.signature, keccak256(buffer))
|
||||
}
|
||||
|
||||
/// Converts into a transaction type with its hash: [`TransactionSigned`].
|
||||
@ -927,6 +929,21 @@ impl TransactionSignedNoHash {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TransactionSignedNoHash {
|
||||
fn default() -> Self {
|
||||
Self { signature: Signature::test_signature(), transaction: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "arbitrary"))]
|
||||
impl<'a> arbitrary::Arbitrary<'a> for TransactionSignedNoHash {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
let tx_signed = TransactionSigned::arbitrary(u)?;
|
||||
|
||||
Ok(Self { signature: tx_signed.signature, transaction: tx_signed.transaction })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "reth-codec"))]
|
||||
impl reth_codecs::Compact for TransactionSignedNoHash {
|
||||
fn to_compact<B>(&self, buf: &mut B) -> usize
|
||||
@ -967,7 +984,7 @@ impl reth_codecs::Compact for TransactionSignedNoHash {
|
||||
let bitflags = buf.get_u8() as usize;
|
||||
|
||||
let sig_bit = bitflags & 1;
|
||||
let (signature, buf) = Signature::from_compact(buf, sig_bit);
|
||||
let (mut signature, buf) = Signature::from_compact(buf, sig_bit);
|
||||
|
||||
let zstd_bit = bitflags >> 3;
|
||||
let (transaction, buf) = if zstd_bit != 0 {
|
||||
@ -987,6 +1004,10 @@ impl reth_codecs::Compact for TransactionSignedNoHash {
|
||||
Transaction::from_compact(buf, transaction_type)
|
||||
};
|
||||
|
||||
if matches!(transaction, Transaction::Legacy(_)) {
|
||||
signature = signature.with_parity(legacy_parity(&signature, transaction.chain_id()))
|
||||
}
|
||||
|
||||
(Self { signature, transaction }, buf)
|
||||
}
|
||||
}
|
||||
@ -1005,7 +1026,7 @@ impl From<TransactionSigned> for TransactionSignedNoHash {
|
||||
|
||||
/// Signed transaction.
|
||||
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Default, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Serialize, Deserialize)]
|
||||
pub struct TransactionSigned {
|
||||
/// Transaction hash
|
||||
pub hash: TxHash,
|
||||
@ -1017,6 +1038,16 @@ pub struct TransactionSigned {
|
||||
pub transaction: Transaction,
|
||||
}
|
||||
|
||||
impl Default for TransactionSigned {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hash: Default::default(),
|
||||
signature: Signature::test_signature(),
|
||||
transaction: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Self> for TransactionSigned {
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
@ -1043,7 +1074,7 @@ impl TransactionSigned {
|
||||
|
||||
/// Recover signer from signature and hash.
|
||||
///
|
||||
/// Returns `None` if the transaction's signature is invalid following [EIP-2](https://eips.ethereum.org/EIPS/eip-2), see also [`Signature::recover_signer`].
|
||||
/// Returns `None` if the transaction's signature is invalid following [EIP-2](https://eips.ethereum.org/EIPS/eip-2), see also [`recover_signer`].
|
||||
///
|
||||
/// Note:
|
||||
///
|
||||
@ -1058,14 +1089,14 @@ impl TransactionSigned {
|
||||
return Some(from)
|
||||
}
|
||||
let signature_hash = self.signature_hash();
|
||||
self.signature.recover_signer(signature_hash)
|
||||
recover_signer(&self.signature, signature_hash)
|
||||
}
|
||||
|
||||
/// Recover signer from signature and hash _without ensuring that the signature has a low `s`
|
||||
/// value_.
|
||||
///
|
||||
/// Returns `None` if the transaction's signature is invalid, see also
|
||||
/// [`Signature::recover_signer_unchecked`].
|
||||
/// [`recover_signer_unchecked`].
|
||||
pub fn recover_signer_unchecked(&self) -> Option<Address> {
|
||||
// Optimism's Deposit transaction does not have a signature. Directly return the
|
||||
// `from` address.
|
||||
@ -1074,7 +1105,7 @@ impl TransactionSigned {
|
||||
return Some(from)
|
||||
}
|
||||
let signature_hash = self.signature_hash();
|
||||
self.signature.recover_signer_unchecked(signature_hash)
|
||||
recover_signer_unchecked(&self.signature, signature_hash)
|
||||
}
|
||||
|
||||
/// Recovers a list of signers from a transaction list iterator.
|
||||
@ -1192,24 +1223,20 @@ impl TransactionSigned {
|
||||
pub(crate) fn payload_len_inner(&self) -> usize {
|
||||
match &self.transaction {
|
||||
Transaction::Legacy(legacy_tx) => legacy_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_eip155_parity(legacy_tx.chain_id),
|
||||
),
|
||||
Transaction::Eip2930(access_list_tx) => access_list_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
true,
|
||||
),
|
||||
Transaction::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
true,
|
||||
),
|
||||
Transaction::Eip4844(blob_tx) => blob_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
true,
|
||||
),
|
||||
Transaction::Eip7702(set_code_tx) => set_code_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
true,
|
||||
&with_eip155_parity(&self.signature, legacy_tx.chain_id),
|
||||
),
|
||||
Transaction::Eip2930(access_list_tx) => {
|
||||
access_list_tx.encoded_len_with_signature(&self.signature, true)
|
||||
}
|
||||
Transaction::Eip1559(dynamic_fee_tx) => {
|
||||
dynamic_fee_tx.encoded_len_with_signature(&self.signature, true)
|
||||
}
|
||||
Transaction::Eip4844(blob_tx) => {
|
||||
blob_tx.encoded_len_with_signature(&self.signature, true)
|
||||
}
|
||||
Transaction::Eip7702(set_code_tx) => {
|
||||
set_code_tx.encoded_len_with_signature(&self.signature, true)
|
||||
}
|
||||
#[cfg(feature = "optimism")]
|
||||
Transaction::Deposit(deposit_tx) => deposit_tx.encoded_len(true),
|
||||
}
|
||||
@ -1235,7 +1262,7 @@ impl TransactionSigned {
|
||||
/// Calculate a heuristic for the in-memory size of the [`TransactionSigned`].
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize {
|
||||
mem::size_of::<TxHash>() + self.transaction.size() + self.signature.size()
|
||||
mem::size_of::<TxHash>() + self.transaction.size() + mem::size_of::<Signature>()
|
||||
}
|
||||
|
||||
/// Decodes legacy transaction from the data buffer into a tuple.
|
||||
@ -1268,7 +1295,7 @@ impl TransactionSigned {
|
||||
input: Decodable::decode(data)?,
|
||||
chain_id: None,
|
||||
};
|
||||
let (signature, extracted_id) = Signature::decode_with_eip155_chain_id(data)?;
|
||||
let (signature, extracted_id) = decode_with_eip155_chain_id(data)?;
|
||||
transaction.chain_id = extracted_id;
|
||||
|
||||
// check the new length, compared to the original length and the header length
|
||||
@ -1343,15 +1370,19 @@ impl TransactionSigned {
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
let signature = Signature::decode(data)?;
|
||||
let signature = Signature::decode_rlp_vrs(data)?;
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
let signature = if tx_type == TxType::Deposit {
|
||||
Signature::optimism_deposit_tx_signature()
|
||||
optimism_deposit_tx_signature()
|
||||
} else {
|
||||
Signature::decode(data)?
|
||||
Signature::decode_rlp_vrs(data)?
|
||||
};
|
||||
|
||||
if !matches!(signature.v(), Parity::Parity(_)) {
|
||||
return Err(alloy_rlp::Error::Custom("invalid parity for typed transaction"));
|
||||
}
|
||||
|
||||
let bytes_consumed = remaining_len - data.len();
|
||||
if bytes_consumed != header.payload_length {
|
||||
return Err(RlpError::UnexpectedLength)
|
||||
@ -1404,24 +1435,20 @@ impl TransactionSigned {
|
||||
// method computes the payload len without a RLP header
|
||||
match &self.transaction {
|
||||
Transaction::Legacy(legacy_tx) => legacy_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_eip155_parity(legacy_tx.chain_id),
|
||||
),
|
||||
Transaction::Eip2930(access_list_tx) => access_list_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
),
|
||||
Transaction::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
),
|
||||
Transaction::Eip4844(blob_tx) => blob_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
),
|
||||
Transaction::Eip7702(set_code_tx) => set_code_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
&with_eip155_parity(&self.signature, legacy_tx.chain_id),
|
||||
),
|
||||
Transaction::Eip2930(access_list_tx) => {
|
||||
access_list_tx.encoded_len_with_signature(&self.signature, false)
|
||||
}
|
||||
Transaction::Eip1559(dynamic_fee_tx) => {
|
||||
dynamic_fee_tx.encoded_len_with_signature(&self.signature, false)
|
||||
}
|
||||
Transaction::Eip4844(blob_tx) => {
|
||||
blob_tx.encoded_len_with_signature(&self.signature, false)
|
||||
}
|
||||
Transaction::Eip7702(set_code_tx) => {
|
||||
set_code_tx.encoded_len_with_signature(&self.signature, false)
|
||||
}
|
||||
#[cfg(feature = "optimism")]
|
||||
Transaction::Deposit(deposit_tx) => deposit_tx.encoded_len(false),
|
||||
}
|
||||
@ -1516,11 +1543,19 @@ impl Decodable for TransactionSigned {
|
||||
#[cfg(any(test, feature = "arbitrary"))]
|
||||
impl<'a> arbitrary::Arbitrary<'a> for TransactionSigned {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
#[allow(unused_mut)]
|
||||
let mut transaction = Transaction::arbitrary(u)?;
|
||||
if let Some(chain_id) = transaction.chain_id() {
|
||||
// Otherwise we might overflow when calculating `v` on `recalculate_hash`
|
||||
transaction.set_chain_id(chain_id % (u64::MAX / 2 - 36));
|
||||
}
|
||||
let mut signature = Signature::arbitrary(u)?;
|
||||
|
||||
signature = if matches!(transaction, Transaction::Legacy(_)) {
|
||||
if let Some(chain_id) = transaction.chain_id() {
|
||||
signature.with_chain_id(chain_id)
|
||||
} else {
|
||||
signature.with_parity(alloy_primitives::Parity::NonEip155(bool::arbitrary(u)?))
|
||||
}
|
||||
} else {
|
||||
signature.with_parity_bool()
|
||||
};
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
// Both `Some(0)` and `None` values are encoded as empty string byte. This introduces
|
||||
@ -1532,21 +1567,16 @@ impl<'a> arbitrary::Arbitrary<'a> for TransactionSigned {
|
||||
}
|
||||
}
|
||||
|
||||
let signature = Signature::arbitrary(u)?;
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
let signature = if transaction.is_deposit() {
|
||||
Signature::optimism_deposit_tx_signature()
|
||||
} else {
|
||||
signature
|
||||
};
|
||||
let signature =
|
||||
if transaction.is_deposit() { optimism_deposit_tx_signature() } else { signature };
|
||||
|
||||
Ok(Self::from_transaction_and_signature(transaction, signature))
|
||||
}
|
||||
}
|
||||
|
||||
/// Signed transaction with recovered signer.
|
||||
#[derive(Debug, Clone, PartialEq, Hash, Eq, AsRef, Deref, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Hash, Eq, AsRef, Deref)]
|
||||
pub struct TransactionSignedEcRecovered {
|
||||
/// Signer of the transaction
|
||||
signer: Address,
|
||||
@ -1679,7 +1709,7 @@ mod tests {
|
||||
Address, Bytes, Transaction, TransactionSigned, TransactionSignedEcRecovered,
|
||||
TransactionSignedNoHash, B256, U256,
|
||||
};
|
||||
use alloy_primitives::{address, b256, bytes};
|
||||
use alloy_primitives::{address, b256, bytes, Parity};
|
||||
use alloy_rlp::{Decodable, Encodable, Error as RlpError};
|
||||
use reth_chainspec::MIN_TRANSACTION_GAS;
|
||||
use reth_codecs::Compact;
|
||||
@ -1782,13 +1812,13 @@ mod tests {
|
||||
value: U256::from(1000000000000000u64),
|
||||
input: Bytes::default(),
|
||||
});
|
||||
let signature = Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae")
|
||||
let signature = Signature::new(
|
||||
U256::from_str("0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18")
|
||||
U256::from_str("0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18")
|
||||
.unwrap(),
|
||||
};
|
||||
Parity::Eip155(43),
|
||||
);
|
||||
let hash = b256!("a517b206d2223278f860ea017d3626cacad4f52ff51030dc9a96b432f17f8d34");
|
||||
test_decode_and_encode(&bytes, transaction, signature, Some(hash));
|
||||
|
||||
@ -1802,13 +1832,13 @@ mod tests {
|
||||
value: U256::from(693361000000000u64),
|
||||
input: Default::default(),
|
||||
});
|
||||
let signature = Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0xe24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a")
|
||||
let signature = Signature::new(
|
||||
U256::from_str("0xe24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da")
|
||||
U256::from_str("0x5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da")
|
||||
.unwrap(),
|
||||
};
|
||||
Parity::Eip155(43),
|
||||
);
|
||||
test_decode_and_encode(&bytes, transaction, signature, None);
|
||||
|
||||
let bytes = hex!("f86b0384773594008398968094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba0ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071a03ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88");
|
||||
@ -1821,13 +1851,13 @@ mod tests {
|
||||
value: U256::from(1000000000000000u64),
|
||||
input: Bytes::default(),
|
||||
});
|
||||
let signature = Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0xce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071")
|
||||
let signature = Signature::new(
|
||||
U256::from_str("0xce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88")
|
||||
U256::from_str("0x3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88")
|
||||
.unwrap(),
|
||||
};
|
||||
Parity::Eip155(43),
|
||||
);
|
||||
test_decode_and_encode(&bytes, transaction, signature, None);
|
||||
|
||||
let bytes = hex!("b87502f872041a8459682f008459682f0d8252089461815774383099e24810ab832a5b2a5425c154d58829a2241af62c000080c001a059e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafda0016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469");
|
||||
@ -1842,13 +1872,13 @@ mod tests {
|
||||
input: Default::default(),
|
||||
access_list: Default::default(),
|
||||
});
|
||||
let signature = Signature {
|
||||
odd_y_parity: true,
|
||||
r: U256::from_str("0x59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd")
|
||||
let signature = Signature::new(
|
||||
U256::from_str("0x59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469")
|
||||
U256::from_str("0x016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469")
|
||||
.unwrap(),
|
||||
};
|
||||
Parity::Parity(true),
|
||||
);
|
||||
test_decode_and_encode(&bytes, transaction, signature, None);
|
||||
|
||||
let bytes = hex!("f8650f84832156008287fb94cf7f9e66af820a19257a2108375b180b0ec491678204d2802ca035b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981a0612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860");
|
||||
@ -1861,13 +1891,13 @@ mod tests {
|
||||
value: U256::from(1234),
|
||||
input: Bytes::default(),
|
||||
});
|
||||
let signature = Signature {
|
||||
odd_y_parity: true,
|
||||
r: U256::from_str("0x35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981")
|
||||
let signature = Signature::new(
|
||||
U256::from_str("0x35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860")
|
||||
U256::from_str("0x612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860")
|
||||
.unwrap(),
|
||||
};
|
||||
Parity::Eip155(44),
|
||||
);
|
||||
test_decode_and_encode(&bytes, transaction, signature, None);
|
||||
}
|
||||
|
||||
@ -2025,13 +2055,13 @@ mod tests {
|
||||
fn transaction_signed_no_hash_zstd_codec() {
|
||||
// will use same signature everywhere.
|
||||
// We don't need signature to match tx, just decoded to the same signature
|
||||
let signature = Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae")
|
||||
let signature = Signature::new(
|
||||
U256::from_str("0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18")
|
||||
U256::from_str("0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18")
|
||||
.unwrap(),
|
||||
};
|
||||
Parity::Eip155(43),
|
||||
);
|
||||
|
||||
let inputs: Vec<Vec<u8>> = vec![
|
||||
vec![],
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
//! Defines the types for blob transactions, legacy, and other EIP-2718 transactions included in a
|
||||
//! response to `GetPooledTransactions`.
|
||||
|
||||
use super::{error::TransactionConversionError, TxEip7702};
|
||||
use super::{
|
||||
error::TransactionConversionError,
|
||||
signature::{recover_signer, with_eip155_parity},
|
||||
TxEip7702,
|
||||
};
|
||||
use crate::{
|
||||
Address, BlobTransaction, BlobTransactionSidecar, Bytes, Signature, Transaction,
|
||||
TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxEip4844, TxHash,
|
||||
@ -161,7 +165,7 @@ impl PooledTransactionsElement {
|
||||
///
|
||||
/// Returns `None` if the transaction's signature is invalid, see also [`Self::recover_signer`].
|
||||
pub fn recover_signer(&self) -> Option<Address> {
|
||||
self.signature().recover_signer(self.signature_hash())
|
||||
recover_signer(self.signature(), self.signature_hash())
|
||||
}
|
||||
|
||||
/// Tries to recover signer and return [`PooledTransactionsElementEcRecovered`].
|
||||
@ -304,30 +308,22 @@ impl PooledTransactionsElement {
|
||||
match self {
|
||||
Self::Legacy { transaction, signature, .. } => {
|
||||
// method computes the payload len with a RLP header
|
||||
transaction.encoded_len_with_signature(
|
||||
&signature.as_signature_with_eip155_parity(transaction.chain_id),
|
||||
)
|
||||
transaction.encoded_len_with_signature(&with_eip155_parity(
|
||||
signature,
|
||||
transaction.chain_id,
|
||||
))
|
||||
}
|
||||
Self::Eip2930 { transaction, signature, .. } => {
|
||||
// method computes the payload len without a RLP header
|
||||
transaction.encoded_len_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
)
|
||||
transaction.encoded_len_with_signature(signature, false)
|
||||
}
|
||||
Self::Eip1559 { transaction, signature, .. } => {
|
||||
// method computes the payload len without a RLP header
|
||||
transaction.encoded_len_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
)
|
||||
transaction.encoded_len_with_signature(signature, false)
|
||||
}
|
||||
Self::Eip7702 { transaction, signature, .. } => {
|
||||
// method computes the payload len without a RLP header
|
||||
transaction.encoded_len_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
)
|
||||
transaction.encoded_len_with_signature(signature, false)
|
||||
}
|
||||
Self::BlobTransaction(blob_tx) => {
|
||||
// the encoding does not use a header, so we set `with_header` to false
|
||||
@ -363,24 +359,18 @@ impl PooledTransactionsElement {
|
||||
match self {
|
||||
Self::Legacy { transaction, signature, .. } => transaction
|
||||
.encode_with_signature_fields(
|
||||
&signature.as_signature_with_eip155_parity(transaction.chain_id),
|
||||
&with_eip155_parity(signature, transaction.chain_id),
|
||||
out,
|
||||
),
|
||||
Self::Eip2930 { transaction, signature, .. } => transaction.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
false,
|
||||
),
|
||||
Self::Eip1559 { transaction, signature, .. } => transaction.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
false,
|
||||
),
|
||||
Self::Eip7702 { transaction, signature, .. } => transaction.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
false,
|
||||
),
|
||||
Self::Eip2930 { transaction, signature, .. } => {
|
||||
transaction.encode_with_signature(signature, out, false)
|
||||
}
|
||||
Self::Eip1559 { transaction, signature, .. } => {
|
||||
transaction.encode_with_signature(signature, out, false)
|
||||
}
|
||||
Self::Eip7702 { transaction, signature, .. } => {
|
||||
transaction.encode_with_signature(signature, out, false)
|
||||
}
|
||||
Self::BlobTransaction(blob_tx) => {
|
||||
// The inner encoding is used with `with_header` set to true, making the final
|
||||
// encoding:
|
||||
@ -502,32 +492,20 @@ impl Encodable for PooledTransactionsElement {
|
||||
match self {
|
||||
Self::Legacy { transaction, signature, .. } => transaction
|
||||
.encode_with_signature_fields(
|
||||
&signature.as_signature_with_eip155_parity(transaction.chain_id),
|
||||
&with_eip155_parity(signature, transaction.chain_id),
|
||||
out,
|
||||
),
|
||||
Self::Eip2930 { transaction, signature, .. } => {
|
||||
// encodes with string header
|
||||
transaction.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
true,
|
||||
)
|
||||
transaction.encode_with_signature(signature, out, true)
|
||||
}
|
||||
Self::Eip1559 { transaction, signature, .. } => {
|
||||
// encodes with string header
|
||||
transaction.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
true,
|
||||
)
|
||||
transaction.encode_with_signature(signature, out, true)
|
||||
}
|
||||
Self::Eip7702 { transaction, signature, .. } => {
|
||||
// encodes with string header
|
||||
transaction.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
true,
|
||||
)
|
||||
transaction.encode_with_signature(signature, out, true)
|
||||
}
|
||||
Self::BlobTransaction(blob_tx) => {
|
||||
// The inner encoding is used with `with_header` set to true, making the final
|
||||
@ -542,24 +520,22 @@ impl Encodable for PooledTransactionsElement {
|
||||
match self {
|
||||
Self::Legacy { transaction, signature, .. } => {
|
||||
// method computes the payload len with a RLP header
|
||||
transaction.encoded_len_with_signature(
|
||||
&signature.as_signature_with_eip155_parity(transaction.chain_id),
|
||||
)
|
||||
transaction.encoded_len_with_signature(&with_eip155_parity(
|
||||
signature,
|
||||
transaction.chain_id,
|
||||
))
|
||||
}
|
||||
Self::Eip2930 { transaction, signature, .. } => {
|
||||
// method computes the payload len with a RLP header
|
||||
transaction
|
||||
.encoded_len_with_signature(&signature.as_signature_with_boolean_parity(), true)
|
||||
transaction.encoded_len_with_signature(signature, true)
|
||||
}
|
||||
Self::Eip1559 { transaction, signature, .. } => {
|
||||
// method computes the payload len with a RLP header
|
||||
transaction
|
||||
.encoded_len_with_signature(&signature.as_signature_with_boolean_parity(), true)
|
||||
transaction.encoded_len_with_signature(signature, true)
|
||||
}
|
||||
Self::Eip7702 { transaction, signature, .. } => {
|
||||
// method computes the payload len with a RLP header
|
||||
transaction
|
||||
.encoded_len_with_signature(&signature.as_signature_with_boolean_parity(), true)
|
||||
transaction.encoded_len_with_signature(signature, true)
|
||||
}
|
||||
Self::BlobTransaction(blob_tx) => {
|
||||
// the encoding uses a header, so we set `with_header` to true
|
||||
|
||||
@ -20,7 +20,7 @@ use alloc::vec::Vec;
|
||||
///
|
||||
/// This is defined in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#networking) as an element
|
||||
/// of a `PooledTransactions` response.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BlobTransaction {
|
||||
/// The transaction hash.
|
||||
pub hash: TxHash,
|
||||
@ -114,8 +114,7 @@ impl BlobTransaction {
|
||||
/// Note: this should be used only when implementing other RLP encoding methods, and does not
|
||||
/// represent the full RLP encoding of the blob transaction.
|
||||
pub(crate) fn encode_inner(&self, out: &mut dyn bytes::BufMut) {
|
||||
self.transaction
|
||||
.encode_with_signature_fields(&self.signature.as_signature_with_boolean_parity(), out);
|
||||
self.transaction.encode_with_signature_fields(&self.signature, out);
|
||||
}
|
||||
|
||||
/// Outputs the length of the RLP encoding of the blob transaction, including the tx type byte,
|
||||
@ -156,7 +155,7 @@ impl BlobTransaction {
|
||||
// its list header.
|
||||
let tx_header = Header {
|
||||
list: true,
|
||||
payload_length: self.transaction.tx.fields_len() + self.signature.payload_len(),
|
||||
payload_length: self.transaction.tx.fields_len() + self.signature.rlp_vrs_len(),
|
||||
};
|
||||
|
||||
let tx_length = tx_header.length() + tx_header.payload_length;
|
||||
@ -212,7 +211,7 @@ impl BlobTransaction {
|
||||
let transaction = TxEip4844::decode_fields(data)?;
|
||||
|
||||
// signature
|
||||
let signature = Signature::decode(data)?;
|
||||
let signature = Signature::decode_rlp_vrs(data)?;
|
||||
|
||||
// the inner header only decodes the transaction and signature, so we check the length here
|
||||
let inner_consumed = inner_remaining_len - data.len();
|
||||
@ -240,11 +239,7 @@ impl BlobTransaction {
|
||||
// Instead, we use `encode_with_signature`, which RLP encodes the transaction with a
|
||||
// signature for hashing without a header. We then hash the result.
|
||||
let mut buf = Vec::new();
|
||||
transaction.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
&mut buf,
|
||||
false,
|
||||
);
|
||||
transaction.encode_with_signature(&signature, &mut buf, false);
|
||||
let hash = keccak256(&buf);
|
||||
|
||||
// the outer header is for the entire transaction, so we check the length here
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
use crate::{transaction::util::secp256k1, Address, B256, U256};
|
||||
use alloy_consensus::EncodableSignature;
|
||||
use alloy_primitives::{Bytes, Parity};
|
||||
use alloy_rlp::{Decodable, Encodable, Error as RlpError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(test)]
|
||||
use reth_codecs::Compact;
|
||||
use alloy_primitives::Parity;
|
||||
use alloy_rlp::{Decodable, Error as RlpError};
|
||||
|
||||
pub use alloy_primitives::Signature;
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
use reth_optimism_chainspec::optimism_deposit_tx_signature;
|
||||
|
||||
/// The order of the secp256k1 curve, divided by two. Signatures that should be checked according
|
||||
/// to EIP-2 should have an S value less than or equal to this.
|
||||
@ -18,194 +17,82 @@ const SECP256K1N_HALF: U256 = U256::from_be_bytes([
|
||||
0x5D, 0x57, 0x6E, 0x73, 0x57, 0xA4, 0x50, 0x1D, 0xDF, 0xE9, 0x2F, 0x46, 0x68, 0x1B, 0x20, 0xA0,
|
||||
]);
|
||||
|
||||
/// r, s: Values corresponding to the signature of the
|
||||
/// transaction and used to determine the sender of
|
||||
/// the transaction; formally Tr and Ts. This is expanded in Appendix F of yellow paper.
|
||||
///
|
||||
/// This type is unaware of the chain id, and thus shouldn't be used when encoding or decoding
|
||||
/// legacy transactions. Use `SignatureWithParity` instead.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
|
||||
pub struct Signature {
|
||||
/// The R field of the signature; the point on the curve.
|
||||
pub r: U256,
|
||||
/// The S field of the signature; the point on the curve.
|
||||
pub s: U256,
|
||||
/// yParity: Signature Y parity; formally Ty
|
||||
///
|
||||
/// WARNING: if it's deprecated in favor of `alloy_primitives::Signature` be sure that parity
|
||||
/// storage deser matches.
|
||||
pub odd_y_parity: bool,
|
||||
}
|
||||
pub(crate) fn decode_with_eip155_chain_id(
|
||||
buf: &mut &[u8],
|
||||
) -> alloy_rlp::Result<(Signature, Option<u64>)> {
|
||||
let v: Parity = Decodable::decode(buf)?;
|
||||
let r: U256 = Decodable::decode(buf)?;
|
||||
let s: U256 = Decodable::decode(buf)?;
|
||||
|
||||
#[cfg(any(test, feature = "reth-codec"))]
|
||||
impl reth_codecs::Compact for Signature {
|
||||
fn to_compact<B>(&self, buf: &mut B) -> usize
|
||||
where
|
||||
B: bytes::BufMut + AsMut<[u8]>,
|
||||
{
|
||||
buf.put_slice(&self.r.as_le_bytes());
|
||||
buf.put_slice(&self.s.as_le_bytes());
|
||||
self.odd_y_parity as usize
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
if matches!(v, Parity::Parity(_)) {
|
||||
return Err(alloy_rlp::Error::Custom("invalid parity for legacy transaction"));
|
||||
}
|
||||
|
||||
fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) {
|
||||
use bytes::Buf;
|
||||
assert!(buf.len() >= 64);
|
||||
let r = U256::from_le_slice(&buf[0..32]);
|
||||
let s = U256::from_le_slice(&buf[32..64]);
|
||||
buf.advance(64);
|
||||
(Self { r, s, odd_y_parity: identifier != 0 }, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// Decodes the `v`, `r`, `s` values without a RLP header.
|
||||
/// This will return a chain ID if the `v` value is [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) compatible.
|
||||
pub(crate) fn decode_with_eip155_chain_id(
|
||||
buf: &mut &[u8],
|
||||
) -> alloy_rlp::Result<(Self, Option<u64>)> {
|
||||
let v = u64::decode(buf)?;
|
||||
let r: U256 = Decodable::decode(buf)?;
|
||||
let s: U256 = Decodable::decode(buf)?;
|
||||
|
||||
if v < 35 {
|
||||
// non-EIP-155 legacy scheme, v = 27 for even y-parity, v = 28 for odd y-parity
|
||||
if v != 27 && v != 28 {
|
||||
#[cfg(feature = "optimism")]
|
||||
// pre bedrock system transactions were sent from the zero address as legacy
|
||||
// transactions with an empty signature
|
||||
//
|
||||
// NOTE: this is very hacky and only relevant for op-mainnet pre bedrock
|
||||
if v == 0 && r.is_zero() && s.is_zero() {
|
||||
return Ok((Self { r, s, odd_y_parity: false }, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (odd_y_parity, chain_id) = extract_chain_id(v)?;
|
||||
Ok((Self { r, s, odd_y_parity }, chain_id))
|
||||
}
|
||||
|
||||
/// Output the length of the signature without the length of the RLP header
|
||||
pub fn payload_len(&self) -> usize {
|
||||
self.odd_y_parity.length() + self.r.length() + self.s.length()
|
||||
}
|
||||
|
||||
/// Encode the `odd_y_parity`, `r`, `s` values without a RLP header.
|
||||
pub fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
|
||||
self.odd_y_parity.encode(out);
|
||||
self.r.encode(out);
|
||||
self.s.encode(out);
|
||||
}
|
||||
|
||||
/// Decodes the `odd_y_parity`, `r`, `s` values without a RLP header.
|
||||
pub fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
|
||||
Ok(Self {
|
||||
odd_y_parity: Decodable::decode(buf)?,
|
||||
r: Decodable::decode(buf)?,
|
||||
s: Decodable::decode(buf)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Recover signer from message hash, _without ensuring that the signature has a low `s`
|
||||
/// value_.
|
||||
///
|
||||
/// Using this for signature validation will succeed, even if the signature is malleable or not
|
||||
/// compliant with EIP-2. This is provided for compatibility with old signatures which have
|
||||
/// large `s` values.
|
||||
pub fn recover_signer_unchecked(&self, hash: B256) -> Option<Address> {
|
||||
let mut sig: [u8; 65] = [0; 65];
|
||||
|
||||
sig[0..32].copy_from_slice(&self.r.to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&self.s.to_be_bytes::<32>());
|
||||
sig[64] = self.odd_y_parity as u8;
|
||||
|
||||
// NOTE: we are removing error from underlying crypto library as it will restrain primitive
|
||||
// errors and we care only if recovery is passing or not.
|
||||
secp256k1::recover_signer_unchecked(&sig, &hash.0).ok()
|
||||
}
|
||||
|
||||
/// Recover signer address from message hash. This ensures that the signature S value is
|
||||
/// greater than `secp256k1n / 2`, as specified in
|
||||
/// [EIP-2](https://eips.ethereum.org/EIPS/eip-2).
|
||||
///
|
||||
/// If the S value is too large, then this will return `None`
|
||||
pub fn recover_signer(&self, hash: B256) -> Option<Address> {
|
||||
if self.s > SECP256K1N_HALF {
|
||||
return None
|
||||
}
|
||||
|
||||
self.recover_signer_unchecked(hash)
|
||||
}
|
||||
|
||||
/// Turn this signature into its byte
|
||||
/// (hex) representation.
|
||||
pub fn to_bytes(&self) -> [u8; 65] {
|
||||
let mut sig = [0u8; 65];
|
||||
sig[..32].copy_from_slice(&self.r.to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&self.s.to_be_bytes::<32>());
|
||||
let v = u8::from(self.odd_y_parity) + 27;
|
||||
sig[64] = v;
|
||||
sig
|
||||
}
|
||||
|
||||
/// Turn this signature into its hex-encoded representation.
|
||||
pub fn to_hex_bytes(&self) -> Bytes {
|
||||
self.to_bytes().into()
|
||||
}
|
||||
|
||||
/// Calculates a heuristic for the in-memory size of the [Signature].
|
||||
#[inline]
|
||||
pub const fn size(&self) -> usize {
|
||||
core::mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
/// Returns [Parity] value based on `chain_id` for legacy transaction signature.
|
||||
#[allow(clippy::missing_const_for_fn)]
|
||||
pub fn legacy_parity(&self, chain_id: Option<u64>) -> Parity {
|
||||
if let Some(chain_id) = chain_id {
|
||||
Parity::Parity(self.odd_y_parity).with_chain_id(chain_id)
|
||||
} else {
|
||||
#[cfg(feature = "optimism")]
|
||||
// pre bedrock system transactions were sent from the zero address as legacy
|
||||
// transactions with an empty signature
|
||||
//
|
||||
// NOTE: this is very hacky and only relevant for op-mainnet pre bedrock
|
||||
if *self == Self::optimism_deposit_tx_signature() {
|
||||
return Parity::Parity(false)
|
||||
}
|
||||
Parity::NonEip155(self.odd_y_parity)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a signature with the given chain ID applied to the `v` value.
|
||||
pub(crate) fn as_signature_with_eip155_parity(
|
||||
&self,
|
||||
chain_id: Option<u64>,
|
||||
) -> SignatureWithParity {
|
||||
SignatureWithParity::new(self.r, self.s, self.legacy_parity(chain_id))
|
||||
}
|
||||
|
||||
/// Returns a signature with a boolean parity flag. This is useful when we want to encode
|
||||
/// the `v` value as 0 or 1.
|
||||
pub(crate) const fn as_signature_with_boolean_parity(&self) -> SignatureWithParity {
|
||||
SignatureWithParity::new(self.r, self.s, Parity::Parity(self.odd_y_parity))
|
||||
}
|
||||
|
||||
/// Returns the signature for the optimism deposit transactions, which don't include a
|
||||
/// signature.
|
||||
#[cfg(feature = "optimism")]
|
||||
pub const fn optimism_deposit_tx_signature() -> Self {
|
||||
Self { r: U256::ZERO, s: U256::ZERO, odd_y_parity: false }
|
||||
// pre bedrock system transactions were sent from the zero address as legacy
|
||||
// transactions with an empty signature
|
||||
//
|
||||
// NOTE: this is very hacky and only relevant for op-mainnet pre bedrock
|
||||
if matches!(v, Parity::Parity(false)) && r.is_zero() && s.is_zero() {
|
||||
return Ok((Signature::new(r, s, Parity::Parity(false)), None))
|
||||
}
|
||||
|
||||
Ok((Signature::new(r, s, v), v.chain_id()))
|
||||
}
|
||||
|
||||
/// Recover signer from message hash, _without ensuring that the signature has a low `s`
|
||||
/// value_.
|
||||
///
|
||||
/// Using this for signature validation will succeed, even if the signature is malleable or not
|
||||
/// compliant with EIP-2. This is provided for compatibility with old signatures which have
|
||||
/// large `s` values.
|
||||
pub fn recover_signer_unchecked(signature: &Signature, hash: B256) -> Option<Address> {
|
||||
let mut sig: [u8; 65] = [0; 65];
|
||||
|
||||
sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
|
||||
sig[64] = signature.v().y_parity_byte();
|
||||
|
||||
// NOTE: we are removing error from underlying crypto library as it will restrain primitive
|
||||
// errors and we care only if recovery is passing or not.
|
||||
secp256k1::recover_signer_unchecked(&sig, &hash.0).ok()
|
||||
}
|
||||
|
||||
/// Recover signer address from message hash. This ensures that the signature S value is
|
||||
/// greater than `secp256k1n / 2`, as specified in
|
||||
/// [EIP-2](https://eips.ethereum.org/EIPS/eip-2).
|
||||
///
|
||||
/// If the S value is too large, then this will return `None`
|
||||
pub fn recover_signer(signature: &Signature, hash: B256) -> Option<Address> {
|
||||
if signature.s() > SECP256K1N_HALF {
|
||||
return None
|
||||
}
|
||||
|
||||
recover_signer_unchecked(signature, hash)
|
||||
}
|
||||
|
||||
/// Returns [Parity] value based on `chain_id` for legacy transaction signature.
|
||||
#[allow(clippy::missing_const_for_fn)]
|
||||
pub fn legacy_parity(signature: &Signature, chain_id: Option<u64>) -> Parity {
|
||||
if let Some(chain_id) = chain_id {
|
||||
Parity::Parity(signature.v().y_parity()).with_chain_id(chain_id)
|
||||
} else {
|
||||
#[cfg(feature = "optimism")]
|
||||
// pre bedrock system transactions were sent from the zero address as legacy
|
||||
// transactions with an empty signature
|
||||
//
|
||||
// NOTE: this is very hacky and only relevant for op-mainnet pre bedrock
|
||||
if *signature == optimism_deposit_tx_signature() {
|
||||
return Parity::Parity(false)
|
||||
}
|
||||
Parity::NonEip155(signature.v().y_parity())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<alloy_primitives::Signature> for Signature {
|
||||
fn from(value: alloy_primitives::Signature) -> Self {
|
||||
Self { r: value.r(), s: value.s(), odd_y_parity: value.v().y_parity() }
|
||||
}
|
||||
/// Returns a signature with the given chain ID applied to the `v` value.
|
||||
pub(crate) fn with_eip155_parity(signature: &Signature, chain_id: Option<u64>) -> Signature {
|
||||
Signature::new(signature.r(), signature.s(), legacy_parity(signature, chain_id))
|
||||
}
|
||||
|
||||
/// Outputs (`odd_y_parity`, `chain_id`) from the `v` value.
|
||||
@ -226,144 +113,51 @@ pub const fn extract_chain_id(v: u64) -> alloy_rlp::Result<(bool, Option<u64>)>
|
||||
}
|
||||
}
|
||||
|
||||
/// A signature with full parity included.
|
||||
// TODO: replace by alloy Signature when there will be an easy way to instantiate them.
|
||||
pub(crate) struct SignatureWithParity {
|
||||
/// The R field of the signature; the point on the curve.
|
||||
r: U256,
|
||||
/// The S field of the signature; the point on the curve.
|
||||
s: U256,
|
||||
/// Signature parity
|
||||
parity: Parity,
|
||||
}
|
||||
|
||||
impl SignatureWithParity {
|
||||
/// Creates a new [`SignatureWithParity`].
|
||||
pub(crate) const fn new(r: U256, s: U256, parity: Parity) -> Self {
|
||||
Self { r, s, parity }
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodableSignature for SignatureWithParity {
|
||||
fn from_rs_and_parity<
|
||||
P: TryInto<Parity, Error = E>,
|
||||
E: Into<alloy_primitives::SignatureError>,
|
||||
>(
|
||||
r: U256,
|
||||
s: U256,
|
||||
parity: P,
|
||||
) -> Result<Self, alloy_primitives::SignatureError> {
|
||||
Ok(Self { r, s, parity: parity.try_into().map_err(Into::into)? })
|
||||
}
|
||||
|
||||
fn r(&self) -> U256 {
|
||||
self.r
|
||||
}
|
||||
|
||||
fn s(&self) -> U256 {
|
||||
self.s
|
||||
}
|
||||
|
||||
fn v(&self) -> Parity {
|
||||
self.parity
|
||||
}
|
||||
|
||||
fn with_parity<T: Into<Parity>>(self, parity: T) -> Self {
|
||||
Self { r: self.r, s: self.s, parity: parity.into() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{hex, transaction::signature::SECP256K1N_HALF, Address, Signature, B256, U256};
|
||||
use alloy_primitives::{hex::FromHex, Bytes, Parity};
|
||||
use crate::{
|
||||
hex,
|
||||
transaction::signature::{
|
||||
legacy_parity, recover_signer, recover_signer_unchecked, SECP256K1N_HALF,
|
||||
},
|
||||
Address, Signature, B256, U256,
|
||||
};
|
||||
use alloy_primitives::Parity;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn test_legacy_parity() {
|
||||
// Select 1 as an arbitrary nonzero value for R and S, as v() always returns 0 for (0, 0).
|
||||
let signature = Signature { r: U256::from(1), s: U256::from(1), odd_y_parity: false };
|
||||
assert_eq!(Parity::NonEip155(false), signature.legacy_parity(None));
|
||||
assert_eq!(Parity::Eip155(37), signature.legacy_parity(Some(1)));
|
||||
let signature = Signature::new(U256::from(1), U256::from(1), Parity::Parity(false));
|
||||
assert_eq!(Parity::NonEip155(false), legacy_parity(&signature, None));
|
||||
assert_eq!(Parity::Eip155(37), legacy_parity(&signature, Some(1)));
|
||||
|
||||
let signature = Signature { r: U256::from(1), s: U256::from(1), odd_y_parity: true };
|
||||
assert_eq!(Parity::NonEip155(true), signature.legacy_parity(None));
|
||||
assert_eq!(Parity::Eip155(38), signature.legacy_parity(Some(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_payload_len() {
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: false };
|
||||
assert_eq!(3, signature.payload_len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_and_decode() {
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: false };
|
||||
|
||||
let mut encoded = Vec::new();
|
||||
signature.encode(&mut encoded);
|
||||
assert_eq!(encoded.len(), signature.payload_len());
|
||||
let decoded = Signature::decode(&mut &*encoded).unwrap();
|
||||
assert_eq!(signature, decoded);
|
||||
let signature = Signature::new(U256::from(1), U256::from(1), Parity::Parity(true));
|
||||
assert_eq!(Parity::NonEip155(true), legacy_parity(&signature, None));
|
||||
assert_eq!(Parity::Eip155(38), legacy_parity(&signature, Some(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_recover_signer() {
|
||||
let signature = Signature {
|
||||
r: U256::from_str(
|
||||
let signature = Signature::new(
|
||||
U256::from_str(
|
||||
"18515461264373351373200002665853028612451056578545711640558177340181847433846",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"46948507304638947509940763649030358759909902576025900602547168820602576006531",
|
||||
)
|
||||
.unwrap(),
|
||||
odd_y_parity: false,
|
||||
};
|
||||
Parity::Parity(false),
|
||||
);
|
||||
let hash =
|
||||
B256::from_str("daf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53")
|
||||
.unwrap();
|
||||
let signer = signature.recover_signer(hash).unwrap();
|
||||
let signer = recover_signer(&signature, hash).unwrap();
|
||||
let expected = Address::from_str("0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f").unwrap();
|
||||
assert_eq!(expected, signer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ensure_size_equals_sum_of_fields() {
|
||||
let signature = Signature {
|
||||
r: U256::from_str(
|
||||
"18515461264373351373200002665853028612451056578545711640558177340181847433846",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
"46948507304638947509940763649030358759909902576025900602547168820602576006531",
|
||||
)
|
||||
.unwrap(),
|
||||
odd_y_parity: false,
|
||||
};
|
||||
|
||||
assert!(signature.size() >= 65);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_hex_bytes() {
|
||||
let signature = Signature {
|
||||
r: U256::from_str(
|
||||
"18515461264373351373200002665853028612451056578545711640558177340181847433846",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
"46948507304638947509940763649030358759909902576025900602547168820602576006531",
|
||||
)
|
||||
.unwrap(),
|
||||
odd_y_parity: false,
|
||||
};
|
||||
|
||||
let expected = Bytes::from_hex("0x28ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa63627667cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d831b").unwrap();
|
||||
assert_eq!(signature.to_hex_bytes(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eip_2_reject_high_s_value() {
|
||||
// This pre-homestead transaction has a high `s` value and should be rejected by the
|
||||
@ -376,13 +170,13 @@ mod tests {
|
||||
let signature = tx.signature();
|
||||
|
||||
// make sure we know it's greater than SECP256K1N_HALF
|
||||
assert!(signature.s > SECP256K1N_HALF);
|
||||
assert!(signature.s() > SECP256K1N_HALF);
|
||||
|
||||
// recover signer, expect failure
|
||||
let hash = tx.hash();
|
||||
assert!(signature.recover_signer(hash).is_none());
|
||||
assert!(recover_signer(signature, hash).is_none());
|
||||
|
||||
// use unchecked, ensure it succeeds (the signature is valid if not for EIP-2)
|
||||
assert!(signature.recover_signer_unchecked(hash).is_some());
|
||||
assert!(recover_signer_unchecked(signature, hash).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ mod impl_secp256k1 {
|
||||
ecdsa::{RecoverableSignature, RecoveryId},
|
||||
Message, PublicKey, SecretKey, SECP256K1,
|
||||
};
|
||||
use alloy_primitives::Parity;
|
||||
use revm_primitives::U256;
|
||||
|
||||
/// Recovers the address of the sender using secp256k1 pubkey recovery.
|
||||
@ -43,11 +44,11 @@ mod impl_secp256k1 {
|
||||
let s = SECP256K1.sign_ecdsa_recoverable(&Message::from_digest(message.0), &sec);
|
||||
let (rec_id, data) = s.serialize_compact();
|
||||
|
||||
let signature = Signature {
|
||||
r: U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"),
|
||||
s: U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"),
|
||||
odd_y_parity: rec_id.to_i32() != 0,
|
||||
};
|
||||
let signature = Signature::new(
|
||||
U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"),
|
||||
U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"),
|
||||
Parity::Parity(rec_id.to_i32() != 0),
|
||||
);
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
@ -65,6 +66,7 @@ mod impl_secp256k1 {
|
||||
mod impl_k256 {
|
||||
use super::*;
|
||||
use crate::keccak256;
|
||||
use alloy_primitives::Parity;
|
||||
pub(crate) use k256::ecdsa::Error;
|
||||
use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey};
|
||||
use revm_primitives::U256;
|
||||
@ -98,11 +100,11 @@ mod impl_k256 {
|
||||
let (sig, rec_id) = sec.sign_prehash_recoverable(&message.0)?;
|
||||
let (r, s) = sig.split_bytes();
|
||||
|
||||
let signature = Signature {
|
||||
r: U256::try_from_be_slice(&r).expect("The slice has at most 32 bytes"),
|
||||
s: U256::try_from_be_slice(&s).expect("The slice has at most 32 bytes"),
|
||||
odd_y_parity: rec_id.is_y_odd(),
|
||||
};
|
||||
let signature = Signature::new(
|
||||
U256::try_from_be_slice(&r).expect("The slice has at most 32 bytes"),
|
||||
U256::try_from_be_slice(&s).expect("The slice has at most 32 bytes"),
|
||||
Parity::Parity(rec_id.is_y_odd()),
|
||||
);
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
@ -131,9 +133,9 @@ mod tests {
|
||||
sign_message(B256::from_slice(&secret.secret_bytes()[..]), hash).expect("sign message");
|
||||
|
||||
let mut sig: [u8; 65] = [0; 65];
|
||||
sig[0..32].copy_from_slice(&signature.r.to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&signature.s.to_be_bytes::<32>());
|
||||
sig[64] = signature.odd_y_parity as u8;
|
||||
sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
|
||||
sig[64] = signature.v().y_parity_byte();
|
||||
|
||||
assert_eq!(recover_signer_unchecked(&sig, &hash), Ok(signer));
|
||||
}
|
||||
@ -191,16 +193,16 @@ mod tests {
|
||||
|
||||
let mut sig: [u8; 65] = [0; 65];
|
||||
|
||||
sig[0..32].copy_from_slice(&secp256k1_signature.r.to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&secp256k1_signature.s.to_be_bytes::<32>());
|
||||
sig[64] = secp256k1_signature.odd_y_parity as u8;
|
||||
sig[0..32].copy_from_slice(&secp256k1_signature.r().to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&secp256k1_signature.s().to_be_bytes::<32>());
|
||||
sig[64] = secp256k1_signature.v().y_parity_byte();
|
||||
let secp256k1_recovered =
|
||||
impl_secp256k1::recover_signer_unchecked(&sig, &hash).expect("secp256k1 recover");
|
||||
assert_eq!(secp256k1_recovered, secp256k1_signer);
|
||||
|
||||
sig[0..32].copy_from_slice(&k256_signature.r.to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&k256_signature.s.to_be_bytes::<32>());
|
||||
sig[64] = k256_signature.odd_y_parity as u8;
|
||||
sig[0..32].copy_from_slice(&k256_signature.r().to_be_bytes::<32>());
|
||||
sig[32..64].copy_from_slice(&k256_signature.s().to_be_bytes::<32>());
|
||||
sig[64] = k256_signature.v().y_parity_byte();
|
||||
let k256_recovered =
|
||||
impl_k256::recover_signer_unchecked(&sig, &hash).expect("k256 recover");
|
||||
assert_eq!(k256_recovered, k256_signer);
|
||||
|
||||
@ -580,7 +580,8 @@ pub trait EthTransactions: LoadTransaction {
|
||||
.sign(account, &message)
|
||||
.await
|
||||
.map_err(Self::Error::from_eth_err)?
|
||||
.to_hex_bytes())
|
||||
.as_bytes()
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -590,7 +591,8 @@ pub trait EthTransactions: LoadTransaction {
|
||||
.find_signer(&account)?
|
||||
.sign_typed_data(account, data)
|
||||
.map_err(Self::Error::from_eth_err)?
|
||||
.to_hex_bytes())
|
||||
.as_bytes()
|
||||
.into())
|
||||
}
|
||||
|
||||
/// Returns the signer for the given account, if found in configured signers.
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
//! Utilities for serving `eth_simulateV1`
|
||||
|
||||
use alloy_consensus::{TxEip4844Variant, TxType, TypedTransaction};
|
||||
use alloy_primitives::Parity;
|
||||
use alloy_rpc_types::{
|
||||
simulate::{SimCallResult, SimulateError, SimulatedBlock},
|
||||
Block, BlockTransactionsKind,
|
||||
@ -134,7 +135,7 @@ where
|
||||
|
||||
// Create an empty signature for the transaction.
|
||||
let signature =
|
||||
Signature { odd_y_parity: false, r: Default::default(), s: Default::default() };
|
||||
Signature::new(Default::default(), Default::default(), Parity::Parity(false));
|
||||
|
||||
let tx = match tx {
|
||||
TypedTransaction::Legacy(tx) => {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use alloy_primitives::U256;
|
||||
use alloy_rpc_types::{Parity, Signature};
|
||||
use reth_primitives::{Signature as PrimitiveSignature, TxType};
|
||||
use reth_primitives::{transaction::legacy_parity, Signature as PrimitiveSignature, TxType};
|
||||
|
||||
/// Creates a new rpc signature from a legacy [primitive
|
||||
/// signature](reth_primitives::Signature), using the give chain id to compute the signature's
|
||||
@ -12,9 +12,9 @@ pub fn from_legacy_primitive_signature(
|
||||
chain_id: Option<u64>,
|
||||
) -> Signature {
|
||||
Signature {
|
||||
r: signature.r,
|
||||
s: signature.s,
|
||||
v: U256::from(signature.legacy_parity(chain_id).to_u64()),
|
||||
r: signature.r(),
|
||||
s: signature.s(),
|
||||
v: U256::from(legacy_parity(&signature, chain_id).to_u64()),
|
||||
y_parity: None,
|
||||
}
|
||||
}
|
||||
@ -24,10 +24,10 @@ pub fn from_legacy_primitive_signature(
|
||||
/// the signature's `odd_y_parity`.
|
||||
pub fn from_typed_primitive_signature(signature: PrimitiveSignature) -> Signature {
|
||||
Signature {
|
||||
r: signature.r,
|
||||
s: signature.s,
|
||||
v: U256::from(signature.odd_y_parity as u8),
|
||||
y_parity: Some(Parity(signature.odd_y_parity)),
|
||||
r: signature.r(),
|
||||
s: signature.s(),
|
||||
v: U256::from(signature.v().y_parity_byte()),
|
||||
y_parity: Some(Parity(signature.v().y_parity())),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -103,7 +103,7 @@ impl EthSigner for DevSigner {
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use alloy_primitives::U256;
|
||||
use alloy_primitives::{Parity, U256};
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -185,19 +185,19 @@ 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 expected = Signature {
|
||||
r: U256::from_str_radix(
|
||||
let expected = Signature::new(
|
||||
U256::from_str_radix(
|
||||
"5318aee9942b84885761bb20e768372b76e7ee454fc4d39b59ce07338d15a06c",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str_radix(
|
||||
U256::from_str_radix(
|
||||
"5e585a2f4882ec3228a9303244798b47a9102e4be72f48159d890c73e4511d79",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
odd_y_parity: false,
|
||||
};
|
||||
Parity::Parity(false),
|
||||
);
|
||||
assert_eq!(sig, expected)
|
||||
}
|
||||
|
||||
@ -206,19 +206,19 @@ mod tests {
|
||||
let message = b"Test message";
|
||||
let signer = build_signer();
|
||||
let sig = signer.sign(Address::default(), message).await.unwrap();
|
||||
let expected = Signature {
|
||||
r: U256::from_str_radix(
|
||||
let expected = Signature::new(
|
||||
U256::from_str_radix(
|
||||
"54313da7432e4058b8d22491b2e7dbb19c7186c35c24155bec0820a8a2bfe0c1",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str_radix(
|
||||
U256::from_str_radix(
|
||||
"687250f11a3d4435004c04a4cb60e846bc27997271d67f21c6c8170f17a25e10",
|
||||
16,
|
||||
)
|
||||
.unwrap(),
|
||||
odd_y_parity: true,
|
||||
};
|
||||
Parity::Parity(true),
|
||||
);
|
||||
assert_eq!(sig, expected)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ mod genesis_account;
|
||||
mod header;
|
||||
mod log;
|
||||
mod request;
|
||||
mod signature;
|
||||
mod transaction;
|
||||
mod trie;
|
||||
mod txkind;
|
||||
|
||||
23
crates/storage/codecs/src/alloy/signature.rs
Normal file
23
crates/storage/codecs/src/alloy/signature.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use alloy_primitives::{Parity, Signature, U256};
|
||||
|
||||
use crate::Compact;
|
||||
|
||||
impl Compact for Signature {
|
||||
fn to_compact<B>(&self, buf: &mut B) -> usize
|
||||
where
|
||||
B: bytes::BufMut + AsMut<[u8]>,
|
||||
{
|
||||
buf.put_slice(&self.r().as_le_bytes());
|
||||
buf.put_slice(&self.s().as_le_bytes());
|
||||
self.v().y_parity() as usize
|
||||
}
|
||||
|
||||
fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) {
|
||||
use bytes::Buf;
|
||||
assert!(buf.len() >= 64);
|
||||
let r = U256::from_le_slice(&buf[0..32]);
|
||||
let s = U256::from_le_slice(&buf[32..64]);
|
||||
buf.advance(64);
|
||||
(Self::new(r, s, Parity::Parity(identifier != 0)), buf)
|
||||
}
|
||||
}
|
||||
@ -1,15 +1,14 @@
|
||||
//! Dummy blocks and data for tests
|
||||
use crate::{DatabaseProviderRW, ExecutionOutcome};
|
||||
use alloy_primitives::{
|
||||
b256, hex_literal::hex, Address, BlockNumber, Bytes, Log, TxKind, B256, U256,
|
||||
b256, hex_literal::hex, Address, BlockNumber, Bytes, Log, Parity, Sealable, TxKind, B256, U256,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_db::tables;
|
||||
use reth_db_api::{database::Database, models::StoredBlockBodyIndices};
|
||||
use reth_primitives::{
|
||||
alloy_primitives, alloy_primitives::Sealable, Account, Header, Receipt, Requests, SealedBlock,
|
||||
SealedBlockWithSenders, SealedHeader, Signature, Transaction, TransactionSigned, TxLegacy,
|
||||
TxType, Withdrawal, Withdrawals,
|
||||
Account, Header, Receipt, Requests, SealedBlock, SealedBlockWithSenders, SealedHeader,
|
||||
Signature, Transaction, TransactionSigned, TxLegacy, TxType, Withdrawal, Withdrawals,
|
||||
};
|
||||
use reth_trie::root::{state_root_unhashed, storage_root_unhashed};
|
||||
use revm::{
|
||||
@ -90,17 +89,17 @@ pub(crate) static TEST_BLOCK: Lazy<SealedBlock> = Lazy::new(|| SealedBlock {
|
||||
),
|
||||
body: vec![TransactionSigned {
|
||||
hash: hex!("3541dd1d17e76adeb25dcf2b0a9b60a1669219502e58dcf26a2beafbfb550397").into(),
|
||||
signature: Signature {
|
||||
r: U256::from_str(
|
||||
signature: Signature::new(
|
||||
U256::from_str(
|
||||
"51983300959770368863831494747186777928121405155922056726144551509338672451120",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"29056683545955299640297374067888344259176096769870751649153779895496107008675",
|
||||
)
|
||||
.unwrap(),
|
||||
odd_y_parity: false,
|
||||
},
|
||||
Parity::NonEip155(false),
|
||||
),
|
||||
transaction: Transaction::Legacy(TxLegacy {
|
||||
gas_price: 10,
|
||||
gas_limit: 400_000,
|
||||
|
||||
@ -893,7 +893,7 @@ impl From<MockTransaction> for TransactionSignedEcRecovered {
|
||||
fn from(tx: MockTransaction) -> Self {
|
||||
let signed_tx = TransactionSigned {
|
||||
hash: *tx.hash(),
|
||||
signature: Signature::default(),
|
||||
signature: Signature::test_signature(),
|
||||
transaction: tx.clone().into(),
|
||||
};
|
||||
|
||||
|
||||
@ -1443,7 +1443,7 @@ mod tests {
|
||||
value: U256::from(100),
|
||||
..Default::default()
|
||||
});
|
||||
let signature = Signature::default();
|
||||
let signature = Signature::test_signature();
|
||||
let signed_tx = TransactionSigned::from_transaction_and_signature(tx, signature);
|
||||
let transaction =
|
||||
TransactionSignedEcRecovered::from_signed_transaction(signed_tx, Default::default());
|
||||
@ -1465,7 +1465,7 @@ mod tests {
|
||||
value: U256::from(100),
|
||||
..Default::default()
|
||||
});
|
||||
let signature = Signature::default();
|
||||
let signature = Signature::test_signature();
|
||||
let signed_tx = TransactionSigned::from_transaction_and_signature(tx, signature);
|
||||
let transaction =
|
||||
TransactionSignedEcRecovered::from_signed_transaction(signed_tx, Default::default());
|
||||
@ -1487,7 +1487,7 @@ mod tests {
|
||||
value: U256::from(100),
|
||||
..Default::default()
|
||||
});
|
||||
let signature = Signature::default();
|
||||
let signature = Signature::test_signature();
|
||||
let signed_tx = TransactionSigned::from_transaction_and_signature(tx, signature);
|
||||
let transaction =
|
||||
TransactionSignedEcRecovered::from_signed_transaction(signed_tx, Default::default());
|
||||
@ -1511,7 +1511,7 @@ mod tests {
|
||||
blob_versioned_hashes: vec![B256::default()],
|
||||
..Default::default()
|
||||
});
|
||||
let signature = Signature::default();
|
||||
let signature = Signature::test_signature();
|
||||
let signed_tx = TransactionSigned::from_transaction_and_signature(tx, signature);
|
||||
let transaction =
|
||||
TransactionSignedEcRecovered::from_signed_transaction(signed_tx, Default::default());
|
||||
@ -1535,7 +1535,7 @@ mod tests {
|
||||
value: U256::from(100),
|
||||
..Default::default()
|
||||
});
|
||||
let signature = Signature::default();
|
||||
let signature = Signature::test_signature();
|
||||
let signed_tx = TransactionSigned::from_transaction_and_signature(tx, signature);
|
||||
let transaction =
|
||||
TransactionSignedEcRecovered::from_signed_transaction(signed_tx, Default::default());
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
use alloy_eips::{
|
||||
eip6110::DepositRequest, eip7002::WithdrawalRequest, eip7251::ConsolidationRequest,
|
||||
};
|
||||
use alloy_primitives::{Address, BlockNumber, Bytes, Sealable, TxKind, B256, U256};
|
||||
use alloy_primitives::{Address, BlockNumber, Bytes, Parity, Sealable, TxKind, B256, U256};
|
||||
pub use rand::Rng;
|
||||
use rand::{
|
||||
distributions::uniform::SampleRange, rngs::StdRng, seq::SliceRandom, thread_rng, SeedableRng,
|
||||
@ -138,8 +138,17 @@ pub fn sign_tx_with_random_key_pair<R: Rng>(rng: &mut R, tx: Transaction) -> Tra
|
||||
|
||||
/// Signs the [Transaction] with the given key pair.
|
||||
pub fn sign_tx_with_key_pair(key_pair: Keypair, tx: Transaction) -> TransactionSigned {
|
||||
let signature =
|
||||
let mut signature =
|
||||
sign_message(B256::from_slice(&key_pair.secret_bytes()[..]), tx.signature_hash()).unwrap();
|
||||
|
||||
if matches!(tx, Transaction::Legacy(_)) {
|
||||
signature = if let Some(chain_id) = tx.chain_id() {
|
||||
signature.with_chain_id(chain_id)
|
||||
} else {
|
||||
signature.with_parity(Parity::NonEip155(signature.v().y_parity()))
|
||||
}
|
||||
}
|
||||
|
||||
TransactionSigned::from_transaction_and_signature(tx, signature)
|
||||
}
|
||||
|
||||
@ -475,6 +484,7 @@ pub fn random_request<R: Rng>(rng: &mut R) -> Request {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_primitives::Parity;
|
||||
use reth_primitives::{hex, public_key_to_address, AccessList, Signature, TxEip1559};
|
||||
use std::str::FromStr;
|
||||
|
||||
@ -539,17 +549,17 @@ mod tests {
|
||||
.unwrap();
|
||||
let signature = sign_message(secret, hash).unwrap();
|
||||
|
||||
let expected = Signature {
|
||||
r: U256::from_str(
|
||||
let expected = Signature::new(
|
||||
U256::from_str(
|
||||
"18515461264373351373200002665853028612451056578545711640558177340181847433846",
|
||||
)
|
||||
.unwrap(),
|
||||
s: U256::from_str(
|
||||
U256::from_str(
|
||||
"46948507304638947509940763649030358759909902576025900602547168820602576006531",
|
||||
)
|
||||
.unwrap(),
|
||||
odd_y_parity: false,
|
||||
};
|
||||
Parity::Parity(false),
|
||||
);
|
||||
assert_eq!(expected, signature);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user