mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
chore(primitives): revise signature interface and transaction encode (#928)
Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
@@ -269,25 +269,6 @@ impl Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes individual transaction fields into the desired buffer, without a RLP header.
|
||||
pub(crate) fn encode_inner(&self, out: &mut dyn bytes::BufMut) {
|
||||
match self {
|
||||
Transaction::Legacy { .. } => self.encode_fields(out),
|
||||
Transaction::Eip2930 { .. } => {
|
||||
out.put_u8(1);
|
||||
let list_header = Header { list: true, payload_length: self.fields_len() };
|
||||
list_header.encode(out);
|
||||
self.encode_fields(out);
|
||||
}
|
||||
Transaction::Eip1559 { .. } => {
|
||||
out.put_u8(2);
|
||||
let list_header = Header { list: true, payload_length: self.fields_len() };
|
||||
list_header.encode(out);
|
||||
self.encode_fields(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
@@ -315,21 +296,6 @@ impl Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
/// Outputs the length of the transaction payload without the length of the RLP header or
|
||||
/// eip155 fields.
|
||||
pub(crate) fn payload_len(&self) -> usize {
|
||||
match self {
|
||||
Transaction::Legacy { .. } => self.fields_len(),
|
||||
_ => {
|
||||
let mut len = self.fields_len();
|
||||
// add list header length
|
||||
len += length_of_length(len);
|
||||
// add transaction type byte length
|
||||
len + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
@@ -466,26 +432,32 @@ impl Transaction {
|
||||
/// intended for signing.
|
||||
impl Encodable for Transaction {
|
||||
fn length(&self) -> usize {
|
||||
// TODO: fix
|
||||
let len = self.payload_len();
|
||||
len + length_of_length(len)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode(&self, out: &mut dyn bytes::BufMut) {
|
||||
match self {
|
||||
Transaction::Legacy { .. } => {
|
||||
let header = Header {
|
||||
list: true,
|
||||
payload_length: self.payload_len() + self.eip155_fields_len(),
|
||||
};
|
||||
header.encode(out);
|
||||
self.encode_inner(out);
|
||||
Header { list: true, payload_length: self.fields_len() + self.eip155_fields_len() }
|
||||
.encode(out);
|
||||
self.encode_fields(out);
|
||||
self.encode_eip155_fields(out);
|
||||
}
|
||||
Transaction::Eip2930 { .. } => {
|
||||
self.encode_inner(out);
|
||||
}
|
||||
Transaction::Eip1559 { .. } => {
|
||||
self.encode_inner(out);
|
||||
_ => {
|
||||
out.put_u8(self.tx_type() as u8);
|
||||
Header { list: true, payload_length: self.fields_len() }.encode(out);
|
||||
self.encode_fields(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -607,10 +579,7 @@ impl Encodable for TransactionSigned {
|
||||
}
|
||||
|
||||
fn length(&self) -> usize {
|
||||
let len = self.payload_len();
|
||||
|
||||
// add the length of the RLP header
|
||||
len + length_of_length(len)
|
||||
self.payload_len_inner()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,11 +630,7 @@ impl Decodable for TransactionSigned {
|
||||
_ => return Err(DecodeError::Custom("unsupported typed transaction type")),
|
||||
};
|
||||
|
||||
let signature = Signature {
|
||||
odd_y_parity: Decodable::decode(buf)?,
|
||||
r: Decodable::decode(buf)?,
|
||||
s: Decodable::decode(buf)?,
|
||||
};
|
||||
let signature = Signature::decode(buf)?;
|
||||
|
||||
let hash = keccak256(&original_encoding[..first_header.payload_length]);
|
||||
let signed = TransactionSigned { transaction, hash, signature };
|
||||
@@ -680,7 +645,7 @@ impl Decodable for TransactionSigned {
|
||||
input: Bytes(Decodable::decode(buf)?),
|
||||
chain_id: None,
|
||||
});
|
||||
let (signature, extracted_id) = Signature::decode_eip155_inner(buf)?;
|
||||
let (signature, extracted_id) = Signature::decode_with_eip155_chain_id(buf)?;
|
||||
if let Some(id) = extracted_id {
|
||||
transaction.set_chain_id(id);
|
||||
}
|
||||
@@ -727,42 +692,50 @@ impl TransactionSigned {
|
||||
/// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating
|
||||
/// hash that for eip2728 does not require rlp header
|
||||
pub(crate) fn encode_inner(&self, out: &mut dyn bytes::BufMut, with_header: bool) {
|
||||
if let Transaction::Legacy(TxLegacy { chain_id, .. }) = self.transaction {
|
||||
let header = Header { list: true, payload_length: self.payload_len() };
|
||||
header.encode(out);
|
||||
self.transaction.encode_fields(out);
|
||||
|
||||
if let Some(id) = chain_id {
|
||||
self.signature.encode_eip155_inner(out, id);
|
||||
} else {
|
||||
// if the transaction has no chain id then it is a pre-EIP-155 transaction
|
||||
self.signature.encode_inner_legacy(out);
|
||||
}
|
||||
} else {
|
||||
if with_header {
|
||||
let header = Header { list: false, payload_length: self.payload_len() };
|
||||
match self.transaction {
|
||||
Transaction::Legacy(TxLegacy { chain_id, .. }) => {
|
||||
// do nothing w/ with_header
|
||||
let payload_length = self.transaction.fields_len() +
|
||||
self.signature.payload_len_with_eip155_chain_id(chain_id);
|
||||
let header = Header { list: true, payload_length };
|
||||
header.encode(out);
|
||||
self.transaction.encode_fields(out);
|
||||
self.signature.encode_with_eip155_chain_id(out, chain_id);
|
||||
}
|
||||
match self.transaction {
|
||||
Transaction::Eip2930 { .. } => {
|
||||
out.put_u8(1);
|
||||
let list_header = Header { list: true, payload_length: self.inner_tx_len() };
|
||||
list_header.encode(out);
|
||||
}
|
||||
Transaction::Eip1559 { .. } => {
|
||||
out.put_u8(2);
|
||||
let list_header = Header { list: true, payload_length: self.inner_tx_len() };
|
||||
list_header.encode(out);
|
||||
}
|
||||
Transaction::Legacy { .. } => {
|
||||
unreachable!("Legacy transaction should be handled above")
|
||||
_ => {
|
||||
let payload_length = self.transaction.fields_len() + self.signature.payload_len();
|
||||
if with_header {
|
||||
Header {
|
||||
list: false,
|
||||
payload_length: 1 + length_of_length(payload_length) + payload_length,
|
||||
}
|
||||
.encode(out);
|
||||
}
|
||||
out.put_u8(self.transaction.tx_type() as u8);
|
||||
let header = Header { list: true, payload_length };
|
||||
header.encode(out);
|
||||
self.transaction.encode_fields(out);
|
||||
self.signature.encode(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.transaction.encode_fields(out);
|
||||
self.signature.odd_y_parity.encode(out);
|
||||
self.signature.r.encode(out);
|
||||
self.signature.s.encode(out);
|
||||
/// Output the length of the encode_inner(out, true). Note to assume that `with_header` is only
|
||||
/// `true`.
|
||||
pub(crate) fn payload_len_inner(&self) -> usize {
|
||||
match self.transaction {
|
||||
Transaction::Legacy(TxLegacy { chain_id, .. }) => {
|
||||
let payload_length = self.transaction.fields_len() +
|
||||
self.signature.payload_len_with_eip155_chain_id(chain_id);
|
||||
// 'header length' + 'payload length'
|
||||
length_of_length(payload_length) + payload_length
|
||||
}
|
||||
_ => {
|
||||
let payload_length = self.transaction.fields_len() + self.signature.payload_len();
|
||||
// 'transaction type byte length' + 'header length' + 'payload length'
|
||||
let len = 1 + length_of_length(payload_length) + payload_length;
|
||||
length_of_length(len) + len
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,37 +754,6 @@ impl TransactionSigned {
|
||||
initial_tx.hash = initial_tx.recalculate_hash();
|
||||
initial_tx
|
||||
}
|
||||
|
||||
/// Output the length of the inner transaction and signature fields.
|
||||
pub(crate) fn inner_tx_len(&self) -> usize {
|
||||
let mut len = self.transaction.fields_len();
|
||||
if let Transaction::Legacy(TxLegacy { chain_id, .. }) = self.transaction {
|
||||
if let Some(id) = chain_id {
|
||||
len += self.signature.eip155_payload_len(id);
|
||||
} else {
|
||||
// if the transaction has no chain id then it is a pre-EIP-155 transaction
|
||||
len += self.signature.payload_len_legacy();
|
||||
}
|
||||
} else {
|
||||
len += self.signature.odd_y_parity.length();
|
||||
len += self.signature.r.length();
|
||||
len += self.signature.s.length();
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
/// Output the length of the signed transaction's rlp payload without a rlp header.
|
||||
pub(crate) fn payload_len(&self) -> usize {
|
||||
let mut len = self.inner_tx_len();
|
||||
if let Transaction::Legacy { .. } = self.transaction {
|
||||
len
|
||||
} else {
|
||||
// length of the list header
|
||||
len += Header { list: true, payload_length: len }.length();
|
||||
// add type byte
|
||||
len + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Signed transaction with recovered signer.
|
||||
@@ -923,6 +865,7 @@ mod tests {
|
||||
|
||||
let mut encoded = BytesMut::new();
|
||||
tx.encode(&mut encoded);
|
||||
assert_eq!(encoded.len(), tx.length());
|
||||
|
||||
let decoded = TransactionSigned::decode(&mut &*encoded).unwrap();
|
||||
assert_eq!(decoded, tx);
|
||||
@@ -934,7 +877,14 @@ mod tests {
|
||||
let tx_bytes =
|
||||
hex::decode("b901f202f901ee05228459682f008459682f11830209bf8080b90195608060405234801561001057600080fd5b50610175806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80630c49c36c14610030575b600080fd5b61003861004e565b604051610045919061011d565b60405180910390f35b60606020600052600f6020527f68656c6c6f2073746174656d696e64000000000000000000000000000000000060405260406000f35b600081519050919050565b600082825260208201905092915050565b60005b838110156100be5780820151818401526020810190506100a3565b838111156100cd576000848401525b50505050565b6000601f19601f8301169050919050565b60006100ef82610084565b6100f9818561008f565b93506101098185602086016100a0565b610112816100d3565b840191505092915050565b6000602082019050818103600083015261013781846100e4565b90509291505056fea264697066735822122051449585839a4ea5ac23cae4552ef8a96b64ff59d0668f76bfac3796b2bdbb3664736f6c63430008090033c080a0136ebffaa8fc8b9fda9124de9ccb0b1f64e90fbd44251b4c4ac2501e60b104f9a07eb2999eec6d185ef57e91ed099afb0a926c5b536f0155dd67e537c7476e1471")
|
||||
.unwrap();
|
||||
let _decoded = TransactionSigned::decode(&mut &tx_bytes[..]).unwrap();
|
||||
|
||||
let decoded = TransactionSigned::decode(&mut &tx_bytes[..]).unwrap();
|
||||
assert_eq!(tx_bytes.len(), decoded.length());
|
||||
|
||||
let mut encoded = BytesMut::new();
|
||||
decoded.encode(&mut encoded);
|
||||
|
||||
assert_eq!(tx_bytes, encoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -956,6 +906,7 @@ mod tests {
|
||||
|
||||
let mut encoded = BytesMut::new();
|
||||
tx.encode(&mut encoded);
|
||||
assert_eq!(encoded.len(), tx.length());
|
||||
|
||||
let decoded = TransactionSigned::decode(&mut &*encoded).unwrap();
|
||||
assert_eq!(decoded, tx);
|
||||
@@ -975,8 +926,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn decode_multiple_network_txs() {
|
||||
let bytes_first = &mut &hex::decode("f86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18").unwrap()[..];
|
||||
let expected_request = Transaction::Legacy(TxLegacy {
|
||||
let bytes = hex::decode("f86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18").unwrap();
|
||||
let transaction = Transaction::Legacy(TxLegacy {
|
||||
chain_id: Some(4u64),
|
||||
nonce: 2,
|
||||
gas_price: 1000000000,
|
||||
@@ -987,24 +938,20 @@ mod tests {
|
||||
value: 1000000000000000,
|
||||
input: Bytes::default(),
|
||||
});
|
||||
let expected_signature = Signature {
|
||||
let signature = Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18")
|
||||
.unwrap(),
|
||||
};
|
||||
let expected =
|
||||
TransactionSigned::from_transaction_and_signature(expected_request, expected_signature);
|
||||
assert_eq!(expected, TransactionSigned::decode(bytes_first).unwrap());
|
||||
assert_eq!(
|
||||
expected.hash,
|
||||
let hash =
|
||||
H256::from_str("0xa517b206d2223278f860ea017d3626cacad4f52ff51030dc9a96b432f17f8d34")
|
||||
.unwrap()
|
||||
);
|
||||
.ok();
|
||||
test_decode_and_encode(bytes, transaction, signature, hash);
|
||||
|
||||
let bytes_second = &mut &hex::decode("f86b01843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac3960468702769bb01b2a00802ba0e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0aa05406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da").unwrap()[..];
|
||||
let expected_request = Transaction::Legacy(TxLegacy {
|
||||
let bytes = hex::decode("f86b01843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac3960468702769bb01b2a00802ba0e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0aa05406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da").unwrap();
|
||||
let transaction = Transaction::Legacy(TxLegacy {
|
||||
chain_id: Some(4),
|
||||
nonce: 1u64,
|
||||
gas_price: 1000000000,
|
||||
@@ -1015,20 +962,17 @@ mod tests {
|
||||
value: 693361000000000u64.into(),
|
||||
input: Default::default(),
|
||||
});
|
||||
let expected_signature = Signature {
|
||||
let signature = Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0xe24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da")
|
||||
.unwrap(),
|
||||
};
|
||||
test_decode_and_encode(bytes, transaction, signature, None);
|
||||
|
||||
let expected =
|
||||
TransactionSigned::from_transaction_and_signature(expected_request, expected_signature);
|
||||
assert_eq!(expected, TransactionSigned::decode(bytes_second).unwrap());
|
||||
|
||||
let bytes_third = &mut &hex::decode("f86b0384773594008398968094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba0ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071a03ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88").unwrap()[..];
|
||||
let expected_request = Transaction::Legacy(TxLegacy {
|
||||
let bytes = hex::decode("f86b0384773594008398968094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba0ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071a03ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88").unwrap();
|
||||
let transaction = Transaction::Legacy(TxLegacy {
|
||||
chain_id: Some(4),
|
||||
nonce: 3,
|
||||
gas_price: 2000000000,
|
||||
@@ -1039,21 +983,17 @@ mod tests {
|
||||
value: 1000000000000000u64.into(),
|
||||
input: Bytes::default(),
|
||||
});
|
||||
|
||||
let expected_signature = Signature {
|
||||
let signature = Signature {
|
||||
odd_y_parity: false,
|
||||
r: U256::from_str("0xce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88")
|
||||
.unwrap(),
|
||||
};
|
||||
test_decode_and_encode(bytes, transaction, signature, None);
|
||||
|
||||
let expected =
|
||||
TransactionSigned::from_transaction_and_signature(expected_request, expected_signature);
|
||||
assert_eq!(expected, TransactionSigned::decode(bytes_third).unwrap());
|
||||
|
||||
let bytes_fourth = &mut &hex::decode("b87502f872041a8459682f008459682f0d8252089461815774383099e24810ab832a5b2a5425c154d58829a2241af62c000080c001a059e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafda0016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469").unwrap()[..];
|
||||
let expected = Transaction::Eip1559(TxEip1559 {
|
||||
let bytes = hex::decode("b87502f872041a8459682f008459682f0d8252089461815774383099e24810ab832a5b2a5425c154d58829a2241af62c000080c001a059e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafda0016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469").unwrap();
|
||||
let transaction = Transaction::Eip1559(TxEip1559 {
|
||||
chain_id: 4,
|
||||
nonce: 26,
|
||||
max_priority_fee_per_gas: 1500000000,
|
||||
@@ -1066,21 +1006,17 @@ mod tests {
|
||||
input: Default::default(),
|
||||
access_list: Default::default(),
|
||||
});
|
||||
|
||||
let expected_signature = Signature {
|
||||
let signature = Signature {
|
||||
odd_y_parity: true,
|
||||
r: U256::from_str("0x59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd")
|
||||
.unwrap(),
|
||||
s: U256::from_str("0x016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469")
|
||||
.unwrap(),
|
||||
};
|
||||
test_decode_and_encode(bytes, transaction, signature, None);
|
||||
|
||||
let expected =
|
||||
TransactionSigned::from_transaction_and_signature(expected, expected_signature);
|
||||
assert_eq!(expected, TransactionSigned::decode(bytes_fourth).unwrap());
|
||||
|
||||
let bytes_fifth = &mut &hex::decode("f8650f84832156008287fb94cf7f9e66af820a19257a2108375b180b0ec491678204d2802ca035b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981a0612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860").unwrap()[..];
|
||||
let expected = Transaction::Legacy(TxLegacy {
|
||||
let bytes = hex::decode("f8650f84832156008287fb94cf7f9e66af820a19257a2108375b180b0ec491678204d2802ca035b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981a0612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860").unwrap();
|
||||
let transaction = Transaction::Legacy(TxLegacy {
|
||||
chain_id: Some(4),
|
||||
nonce: 15,
|
||||
gas_price: 2200000000,
|
||||
@@ -1098,9 +1034,27 @@ mod tests {
|
||||
s: U256::from_str("0x612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860")
|
||||
.unwrap(),
|
||||
};
|
||||
test_decode_and_encode(bytes, transaction, signature, None);
|
||||
}
|
||||
|
||||
let expected = TransactionSigned::from_transaction_and_signature(expected, signature);
|
||||
assert_eq!(expected, TransactionSigned::decode(bytes_fifth).unwrap());
|
||||
fn test_decode_and_encode(
|
||||
bytes: Vec<u8>,
|
||||
transaction: Transaction,
|
||||
signature: Signature,
|
||||
hash: Option<H256>,
|
||||
) {
|
||||
let expected = TransactionSigned::from_transaction_and_signature(transaction, signature);
|
||||
if let Some(hash) = hash {
|
||||
assert_eq!(hash, expected.hash);
|
||||
}
|
||||
assert_eq!(bytes.len(), expected.length());
|
||||
|
||||
let decoded = TransactionSigned::decode(&mut &bytes[..]).unwrap();
|
||||
assert_eq!(expected, decoded);
|
||||
|
||||
let mut encoded = BytesMut::new();
|
||||
expected.encode(&mut encoded);
|
||||
assert_eq!(bytes, encoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -17,41 +17,40 @@ pub struct Signature {
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// Encode the `v`, `r`, `s` values without a RLP header.
|
||||
/// Encodes the `v` value using the legacy scheme without EIP-155.
|
||||
pub(crate) fn encode_inner_legacy(&self, out: &mut dyn reth_rlp::BufMut) {
|
||||
(self.odd_y_parity as u8 + 27).encode(out);
|
||||
self.r.encode(out);
|
||||
self.s.encode(out);
|
||||
}
|
||||
|
||||
/// Output the length of the signature without the length of the RLP header, using the legacy
|
||||
/// scheme without EIP-155.
|
||||
pub(crate) fn payload_len_legacy(&self) -> usize {
|
||||
(self.odd_y_parity as u8 + 27).length() + self.r.length() + self.s.length()
|
||||
/// scheme with EIP-155 support depends on chain_id.
|
||||
pub(crate) fn payload_len_with_eip155_chain_id(&self, chain_id: Option<u64>) -> usize {
|
||||
self.v(chain_id).length() + self.r.length() + self.s.length()
|
||||
}
|
||||
|
||||
/// Encode the `v`, `r`, `s` values without a RLP header.
|
||||
/// Encodes the `v` value with EIP-155 support, using the specified chain ID.
|
||||
pub(crate) fn encode_eip155_inner(&self, out: &mut dyn reth_rlp::BufMut, chain_id: u64) {
|
||||
// EIP-155: v = {0, 1} + CHAIN_ID * 2 + 35
|
||||
let v = chain_id * 2 + 35 + self.odd_y_parity as u64;
|
||||
v.encode(out);
|
||||
/// Encodes the `v` value using the legacy scheme with EIP-155 support depends on chain_id.
|
||||
pub(crate) fn encode_with_eip155_chain_id(
|
||||
&self,
|
||||
out: &mut dyn reth_rlp::BufMut,
|
||||
chain_id: Option<u64>,
|
||||
) {
|
||||
self.v(chain_id).encode(out);
|
||||
self.r.encode(out);
|
||||
self.s.encode(out);
|
||||
}
|
||||
|
||||
/// Output the length of the signature without the length of the RLP header, with EIP-155
|
||||
/// support.
|
||||
pub(crate) fn eip155_payload_len(&self, chain_id: u64) -> usize {
|
||||
// EIP-155: v = {0, 1} + CHAIN_ID * 2 + 35
|
||||
let v = chain_id * 2 + 35 + self.odd_y_parity as u64;
|
||||
v.length() + self.r.length() + self.s.length()
|
||||
/// Output the `v` of the signature depends on chain_id
|
||||
#[inline]
|
||||
fn v(&self, chain_id: Option<u64>) -> u64 {
|
||||
if let Some(chain_id) = chain_id {
|
||||
// EIP-155: v = {0, 1} + CHAIN_ID * 2 + 35
|
||||
self.odd_y_parity as u64 + chain_id * 2 + 35
|
||||
} else {
|
||||
self.odd_y_parity as u64 + 27
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes the `v`, `r`, `s` values without a RLP header.
|
||||
/// This will return a chain ID if the `v` value is EIP-155 compatible.
|
||||
pub(crate) fn decode_eip155_inner(buf: &mut &[u8]) -> Result<(Self, Option<u64>), DecodeError> {
|
||||
pub(crate) fn decode_with_eip155_chain_id(
|
||||
buf: &mut &[u8],
|
||||
) -> Result<(Self, Option<u64>), DecodeError> {
|
||||
let v = u64::decode(buf)?;
|
||||
let r = Decodable::decode(buf)?;
|
||||
let s = Decodable::decode(buf)?;
|
||||
@@ -67,6 +66,27 @@ impl Signature {
|
||||
}
|
||||
}
|
||||
|
||||
/// Output the length of the signature without the length of the RLP header
|
||||
pub(crate) 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(crate) fn encode(&self, out: &mut dyn reth_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(crate) fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError> {
|
||||
Ok(Signature {
|
||||
odd_y_parity: Decodable::decode(buf)?,
|
||||
r: Decodable::decode(buf)?,
|
||||
s: Decodable::decode(buf)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Recover signature from hash.
|
||||
pub(crate) fn recover_signer(&self, hash: H256) -> Option<Address> {
|
||||
let mut sig: [u8; 65] = [0; 65];
|
||||
@@ -90,69 +110,61 @@ mod tests {
|
||||
use crate::{Address, Signature, H256, U256};
|
||||
|
||||
#[test]
|
||||
fn test_encode_inner_legacy() {
|
||||
fn test_payload_len_with_eip155_chain_id() {
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: false };
|
||||
let mut encoded = BytesMut::new();
|
||||
signature.encode_inner_legacy(&mut encoded);
|
||||
let expected = 27u8;
|
||||
assert_eq!(expected, encoded.as_ref()[0]);
|
||||
|
||||
assert_eq!(3, signature.payload_len_with_eip155_chain_id(None));
|
||||
assert_eq!(3, signature.payload_len_with_eip155_chain_id(Some(1)));
|
||||
assert_eq!(4, signature.payload_len_with_eip155_chain_id(Some(47)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_v() {
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: false };
|
||||
assert_eq!(27, signature.v(None));
|
||||
assert_eq!(37, signature.v(Some(1)));
|
||||
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: true };
|
||||
let mut encoded = BytesMut::new();
|
||||
signature.encode_inner_legacy(&mut encoded);
|
||||
let expected = 28u8;
|
||||
assert_eq!(expected, encoded.as_ref()[0]);
|
||||
assert_eq!(28, signature.v(None));
|
||||
assert_eq!(38, signature.v(Some(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_payload_len_legacy() {
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: false };
|
||||
let len = signature.payload_len_legacy();
|
||||
assert_eq!(3, len);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_eip155_inner() {
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: false };
|
||||
let mut encoded = BytesMut::new();
|
||||
signature.encode_eip155_inner(&mut encoded, 1);
|
||||
let expected = 37u8;
|
||||
assert_eq!(expected, encoded.as_ref()[0]);
|
||||
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: true };
|
||||
let mut encoded = BytesMut::new();
|
||||
signature.encode_eip155_inner(&mut encoded, 1);
|
||||
let expected = 38u8;
|
||||
assert_eq!(expected, encoded.as_ref()[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eip155_payload_len() {
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: false };
|
||||
let len = signature.eip155_payload_len(1);
|
||||
assert_eq!(3, len);
|
||||
|
||||
let len = signature.eip155_payload_len(47);
|
||||
assert_eq!(4, len);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode_eip155_inner() {
|
||||
fn test_encode_and_decode_with_eip155_chain_id() {
|
||||
let signature = Signature { r: U256::default(), s: U256::default(), odd_y_parity: false };
|
||||
|
||||
let mut encoded = BytesMut::new();
|
||||
signature.encode_inner_legacy(&mut encoded);
|
||||
let (decoded, chain_id) = Signature::decode_eip155_inner(&mut &*encoded).unwrap();
|
||||
signature.encode_with_eip155_chain_id(&mut encoded, None);
|
||||
assert_eq!(encoded.len(), signature.payload_len_with_eip155_chain_id(None));
|
||||
let (decoded, chain_id) = Signature::decode_with_eip155_chain_id(&mut &*encoded).unwrap();
|
||||
assert_eq!(signature, decoded);
|
||||
assert_eq!(None, chain_id);
|
||||
|
||||
let mut encoded = BytesMut::new();
|
||||
signature.encode_eip155_inner(&mut encoded, 1);
|
||||
let (decoded, chain_id) = Signature::decode_eip155_inner(&mut &*encoded).unwrap();
|
||||
signature.encode_with_eip155_chain_id(&mut encoded, Some(1));
|
||||
assert_eq!(encoded.len(), signature.payload_len_with_eip155_chain_id(Some(1)));
|
||||
let (decoded, chain_id) = Signature::decode_with_eip155_chain_id(&mut &*encoded).unwrap();
|
||||
assert_eq!(signature, decoded);
|
||||
assert_eq!(Some(1), chain_id);
|
||||
}
|
||||
|
||||
#[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 = BytesMut::new();
|
||||
signature.encode(&mut encoded);
|
||||
assert_eq!(encoded.len(), signature.payload_len());
|
||||
let decoded = Signature::decode(&mut &*encoded).unwrap();
|
||||
assert_eq!(signature, decoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_recover_signer() {
|
||||
let signature = Signature {
|
||||
|
||||
Reference in New Issue
Block a user