Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add recovered wrapper type and eth pool conversions #4267

Merged
merged 3 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ pub use transaction::{
util::secp256k1::{public_key_to_address, recover_signer, sign_message},
AccessList, AccessListItem, AccessListWithGasUsed, BlobTransaction, BlobTransactionSidecar,
FromRecoveredTransaction, IntoRecoveredTransaction, InvalidTransactionError,
PooledTransactionsElement, Signature, Transaction, TransactionKind, TransactionMeta,
TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxEip1559, TxEip2930,
TxEip4844, TxLegacy, TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID,
LEGACY_TX_TYPE_ID,
PooledTransactionsElement, PooledTransactionsElementEcRecovered, Signature, Transaction,
TransactionKind, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered,
TransactionSignedNoHash, TxEip1559, TxEip2930, TxEip4844, TxLegacy, TxType, EIP1559_TX_TYPE_ID,
EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID,
};
pub use withdrawal::Withdrawal;

Expand Down
25 changes: 24 additions & 1 deletion crates/primitives/src/transaction/eip1559.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::access_list::AccessList;
use crate::{Bytes, ChainId, Signature, TransactionKind, TxType};
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256};
use bytes::BytesMut;
use reth_codecs::{main_codec, Compact};
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header};
use std::mem;
Expand Down Expand Up @@ -188,6 +189,28 @@ impl TxEip1559 {
self.access_list.size() + // access_list
self.input.len() // input
}

/// Encodes the legacy transaction in RLP for signing.
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
out.put_u8(self.tx_type() as u8);
Header { list: true, payload_length: self.fields_len() }.encode(out);
self.encode_fields(out);
}

/// Outputs the length of the signature RLP encoding for the transaction.
pub(crate) fn payload_len_for_signature(&self) -> usize {
let payload_length = self.fields_len();
// 'transaction type byte length' + 'header length' + 'payload length'
1 + length_of_length(payload_length) + payload_length
}

/// Outputs the signature hash of the transaction by first encoding without a signature, then
/// hashing.
pub(crate) fn signature_hash(&self) -> H256 {
let mut buf = BytesMut::with_capacity(self.payload_len_for_signature());
self.encode_for_signing(&mut buf);
keccak256(&buf)
}
}

#[cfg(test)]
Expand Down
25 changes: 24 additions & 1 deletion crates/primitives/src/transaction/eip2930.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::access_list::AccessList;
use crate::{Bytes, ChainId, Signature, TransactionKind, TxType};
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256};
use bytes::BytesMut;
use reth_codecs::{main_codec, Compact};
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header};
use std::mem;
Expand Down Expand Up @@ -153,6 +154,28 @@ impl TxEip2930 {
pub(crate) fn tx_type(&self) -> TxType {
TxType::EIP2930
}

/// Encodes the legacy transaction in RLP for signing.
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
out.put_u8(self.tx_type() as u8);
Header { list: true, payload_length: self.fields_len() }.encode(out);
self.encode_fields(out);
}

/// Outputs the length of the signature RLP encoding for the transaction.
pub(crate) fn payload_len_for_signature(&self) -> usize {
let payload_length = self.fields_len();
// 'transaction type byte length' + 'header length' + 'payload length'
1 + length_of_length(payload_length) + payload_length
}

/// Outputs the signature hash of the transaction by first encoding without a signature, then
/// hashing.
pub(crate) fn signature_hash(&self) -> H256 {
let mut buf = BytesMut::with_capacity(self.payload_len_for_signature());
self.encode_for_signing(&mut buf);
keccak256(&buf)
}
}

#[cfg(test)]
Expand Down
23 changes: 23 additions & 0 deletions crates/primitives/src/transaction/eip4844.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
kzg_to_versioned_hash, Bytes, ChainId, Signature, Transaction, TransactionKind,
TransactionSigned, TxHash, TxType, EIP4844_TX_TYPE_ID, H256,
};
use bytes::BytesMut;
use reth_codecs::{main_codec, Compact};
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -226,6 +227,28 @@ impl TxEip4844 {
pub(crate) fn tx_type(&self) -> TxType {
TxType::EIP4844
}

/// Encodes the legacy transaction in RLP for signing.
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
out.put_u8(self.tx_type() as u8);
Header { list: true, payload_length: self.fields_len() }.encode(out);
self.encode_fields(out);
}

/// Outputs the length of the signature RLP encoding for the transaction.
pub(crate) fn payload_len_for_signature(&self) -> usize {
let payload_length = self.fields_len();
// 'transaction type byte length' + 'header length' + 'payload length'
1 + length_of_length(payload_length) + payload_length
}

/// Outputs the signature hash of the transaction by first encoding without a signature, then
/// hashing.
pub(crate) fn signature_hash(&self) -> H256 {
let mut buf = BytesMut::with_capacity(self.payload_len_for_signature());
self.encode_for_signing(&mut buf);
keccak256(&buf)
}
}

/// An error that can occur when validating a [BlobTransaction].
Expand Down
56 changes: 55 additions & 1 deletion crates/primitives/src/transaction/legacy.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{Bytes, ChainId, Signature, TransactionKind, TxType};
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256};
use bytes::BytesMut;
use reth_codecs::{main_codec, Compact};
use reth_rlp::{length_of_length, Encodable, Header};
use std::mem;
Expand Down Expand Up @@ -105,6 +106,59 @@ impl TxLegacy {
pub(crate) fn tx_type(&self) -> TxType {
TxType::Legacy
}

/// Encodes EIP-155 arguments into the desired buffer. Only encodes values for legacy
/// transactions.
pub(crate) fn encode_eip155_fields(&self, out: &mut dyn bytes::BufMut) {
// if this is a legacy transaction without a chain ID, it must be pre-EIP-155
// and does not need to encode the chain ID for the signature hash encoding
if let Some(id) = self.chain_id {
// EIP-155 encodes the chain ID and two zeroes
id.encode(out);
0x00u8.encode(out);
0x00u8.encode(out);
}
}

/// Outputs the length of EIP-155 fields. Only outputs a non-zero value for EIP-155 legacy
/// transactions.
pub(crate) fn eip155_fields_len(&self) -> usize {
if let Some(id) = self.chain_id {
// EIP-155 encodes the chain ID and two zeroes, so we add 2 to the length of the chain
// ID to get the length of all 3 fields
// len(chain_id) + (0x00) + (0x00)
id.length() + 2
} else {
// this is either a pre-EIP-155 legacy transaction or a typed transaction
0
}
}

/// Encodes the legacy transaction in RLP for signing, including the EIP-155 fields if possible.
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
Header { list: true, payload_length: self.fields_len() + self.eip155_fields_len() }
.encode(out);
self.encode_fields(out);
self.encode_eip155_fields(out);
}

/// Outputs the length of the signature RLP encoding for the transaction, including the length
/// of the EIP-155 fields if possible.
pub(crate) fn payload_len_for_signature(&self) -> usize {
let payload_length = self.fields_len() + self.eip155_fields_len();
// 'header length' + 'payload length'
length_of_length(payload_length) + payload_length
}

/// Outputs the signature hash of the transaction by first encoding without a signature, then
/// hashing.
///
/// See [Self::encode_for_signing] for more information on the encoding format.
pub(crate) fn signature_hash(&self) -> H256 {
let mut buf = BytesMut::with_capacity(self.payload_len_for_signature());
self.encode_for_signing(&mut buf);
keccak256(&buf)
}
}

#[cfg(test)]
Expand Down
96 changes: 22 additions & 74 deletions crates/primitives/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ pub use meta::TransactionMeta;
use once_cell::sync::Lazy;
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use reth_codecs::{add_arbitrary_tests, derive_arbitrary, Compact};
use reth_rlp::{
length_of_length, Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE,
};
use reth_rlp::{Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE};
use serde::{Deserialize, Serialize};
pub use signature::Signature;
use std::mem;
Expand All @@ -24,7 +22,7 @@ pub use eip1559::TxEip1559;
pub use eip2930::TxEip2930;
pub use eip4844::{BlobTransaction, BlobTransactionSidecar, TxEip4844};
pub use legacy::TxLegacy;
pub use pooled::PooledTransactionsElement;
pub use pooled::{PooledTransactionsElement, PooledTransactionsElementEcRecovered};

mod access_list;
mod eip1559;
Expand Down Expand Up @@ -100,9 +98,12 @@ impl Transaction {
/// Heavy operation that return signature hash over rlp encoded transaction.
/// It is only for signature signing or signer recovery.
pub fn signature_hash(&self) -> H256 {
let mut buf = BytesMut::new();
self.encode(&mut buf);
keccak256(&buf)
match self {
Transaction::Legacy(tx) => tx.signature_hash(),
Transaction::Eip2930(tx) => tx.signature_hash(),
Transaction::Eip1559(tx) => tx.signature_hash(),
Transaction::Eip4844(tx) => tx.signature_hash(),
}
}

/// Get chain_id.
Expand Down Expand Up @@ -316,54 +317,6 @@ impl Transaction {
}
}

/// Encodes EIP-155 arguments into the desired buffer. Only encodes values for legacy
/// transactions.
pub(crate) fn encode_eip155_fields(&self, out: &mut dyn bytes::BufMut) {
// if this is a legacy transaction without a chain ID, it must be pre-EIP-155
// and does not need to encode the chain ID for the signature hash encoding
if let Transaction::Legacy(TxLegacy { chain_id: Some(id), .. }) = self {
// EIP-155 encodes the chain ID and two zeroes
id.encode(out);
0x00u8.encode(out);
0x00u8.encode(out);
}
}

/// Outputs the length of EIP-155 fields. Only outputs a non-zero value for EIP-155 legacy
/// transactions.
pub(crate) fn eip155_fields_len(&self) -> usize {
if let Transaction::Legacy(TxLegacy { chain_id: Some(id), .. }) = self {
// EIP-155 encodes the chain ID and two zeroes, so we add 2 to the length of the chain
// ID to get the length of all 3 fields
// len(chain_id) + (0x00) + (0x00)
id.length() + 2
} else {
// this is either a pre-EIP-155 legacy transaction or a typed transaction
0
}
}

/// Outputs the length of the transaction's fields, without a RLP header or length of the
/// eip155 fields.
pub(crate) fn fields_len(&self) -> usize {
match self {
Transaction::Legacy(legacy_tx) => legacy_tx.fields_len(),
Transaction::Eip2930(access_list_tx) => access_list_tx.fields_len(),
Transaction::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.fields_len(),
Transaction::Eip4844(blob_tx) => blob_tx.fields_len(),
}
}

/// Encodes only the transaction's fields into the desired buffer, without a RLP header.
pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) {
match self {
Transaction::Legacy(legacy_tx) => legacy_tx.encode_fields(out),
Transaction::Eip2930(access_list_tx) => access_list_tx.encode_fields(out),
Transaction::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.encode_fields(out),
Transaction::Eip4844(blob_tx) => blob_tx.encode_fields(out),
}
}

/// This encodes the transaction _without_ the signature, and is only suitable for creating a
/// hash intended for signing.
pub fn encode_without_signature(&self, out: &mut dyn bytes::BufMut) {
Expand Down Expand Up @@ -496,32 +449,27 @@ impl Default for Transaction {
impl Encodable for Transaction {
fn encode(&self, out: &mut dyn bytes::BufMut) {
match self {
Transaction::Legacy { .. } => {
Header { list: true, payload_length: self.fields_len() + self.eip155_fields_len() }
.encode(out);
self.encode_fields(out);
self.encode_eip155_fields(out);
Transaction::Legacy(legacy_tx) => {
legacy_tx.encode_for_signing(out);
}
_ => {
out.put_u8(self.tx_type() as u8);
Header { list: true, payload_length: self.fields_len() }.encode(out);
self.encode_fields(out);
Transaction::Eip2930(access_list_tx) => {
access_list_tx.encode_for_signing(out);
}
Transaction::Eip1559(dynamic_fee_tx) => {
dynamic_fee_tx.encode_for_signing(out);
}
Transaction::Eip4844(blob_tx) => {
blob_tx.encode_for_signing(out);
}
}
}

fn length(&self) -> usize {
match self {
Transaction::Legacy { .. } => {
let payload_length = self.fields_len() + self.eip155_fields_len();
// 'header length' + 'payload length'
length_of_length(payload_length) + payload_length
}
_ => {
let payload_length = self.fields_len();
// 'transaction type byte length' + 'header length' + 'payload length'
1 + length_of_length(payload_length) + payload_length
}
Transaction::Legacy(legacy_tx) => legacy_tx.payload_len_for_signature(),
Transaction::Eip2930(access_list_tx) => access_list_tx.payload_len_for_signature(),
Transaction::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.payload_len_for_signature(),
Transaction::Eip4844(blob_tx) => blob_tx.payload_len_for_signature(),
}
}
}
Expand Down
Loading
Loading