From 161fe0d957952d8182ea1b283e0afaa7beef97e0 Mon Sep 17 00:00:00 2001 From: "Kim, JinSan" Date: Thu, 19 Jan 2023 02:48:52 +0900 Subject: [PATCH] test: signature & transaction w/ EIP155 (#914) --- .../interfaces/src/test_utils/generators.rs | 47 +++++++++ crates/primitives/src/transaction/mod.rs | 13 ++- .../primitives/src/transaction/signature.rs | 95 ++++++++++++++++++- 3 files changed, 150 insertions(+), 5 deletions(-) diff --git a/crates/interfaces/src/test_utils/generators.rs b/crates/interfaces/src/test_utils/generators.rs index 3e8ed597eb..8624478f5c 100644 --- a/crates/interfaces/src/test_utils/generators.rs +++ b/crates/interfaces/src/test_utils/generators.rs @@ -166,6 +166,8 @@ pub fn random_block_range( #[cfg(test)] mod test { + use std::str::FromStr; + use super::*; use hex_literal::hex; use reth_primitives::{keccak256, AccessList, Address, TransactionKind, TxEip1559}; @@ -204,4 +206,49 @@ mod test { assert_eq!(recovered, expected); } } + + #[test] + fn test_sign_eip_155() { + // reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#example + let transaction = Transaction::Legacy(TxLegacy { + chain_id: Some(1), + nonce: 9, + gas_price: 20 * 10_u128.pow(9), + gas_limit: 21000, + to: TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()), + value: 10_u128.pow(18), + input: Bytes::default(), + }); + + // TODO resolve dependency issue + // let mut encoded = BytesMut::new(); + // transaction.encode(&mut encoded); + // let expected = + // hex!("ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080"); + // assert_eq!(expected, encoded.as_ref()); + + let hash = transaction.signature_hash(); + let expected = + H256::from_str("daf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53") + .unwrap(); + assert_eq!(expected, hash); + + let secret = + H256::from_str("4646464646464646464646464646464646464646464646464646464646464646") + .unwrap(); + let signature = sign_message(secret, hash).unwrap(); + + let expected = Signature { + r: U256::from_str( + "18515461264373351373200002665853028612451056578545711640558177340181847433846", + ) + .unwrap(), + s: U256::from_str( + "46948507304638947509940763649030358759909902576025900602547168820602576006531", + ) + .unwrap(), + odd_y_parity: false, + }; + assert_eq!(expected, signature); + } } diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index df42605790..90efeedf0a 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -627,9 +627,7 @@ impl Decodable for TransactionSigned { // For eip2728 types transaction header is not used inside hash let original_encoding = *buf; - let tx_type = *buf - .first() - .ok_or(DecodeError::Custom("typed tx cannot be decoded from an empty slice"))?; + let tx_type = *buf.first().ok_or(DecodeError::InputTooShort)?; buf.advance(1); // decode the list header for the rest of the transaction let header = Header::decode(buf)?; @@ -897,9 +895,16 @@ mod tests { }; use bytes::BytesMut; use ethers_core::utils::hex; - use reth_rlp::{Decodable, Encodable}; + use reth_rlp::{Decodable, DecodeError, Encodable}; use std::str::FromStr; + #[test] + fn test_decode_empty_typed_tx() { + let input = [0x80u8]; + let res = TransactionSigned::decode(&mut &input[..]).unwrap_err(); + assert_eq!(DecodeError::InputTooShort, res); + } + #[test] fn test_decode_create() { // tests that a contract creation tx encodes and decodes properly diff --git a/crates/primitives/src/transaction/signature.rs b/crates/primitives/src/transaction/signature.rs index 431c50a541..7366b5111e 100644 --- a/crates/primitives/src/transaction/signature.rs +++ b/crates/primitives/src/transaction/signature.rs @@ -16,7 +16,6 @@ pub struct Signature { pub odd_y_parity: bool, } -#[allow(dead_code)] impl Signature { /// Encode the `v`, `r`, `s` values without a RLP header. /// Encodes the `v` value using the legacy scheme without EIP-155. @@ -81,3 +80,97 @@ impl Signature { secp256k1::recover(&sig, hash.as_fixed_bytes()).ok() } } + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use bytes::BytesMut; + + use crate::{Address, Signature, H256, U256}; + + #[test] + fn test_encode_inner_legacy() { + 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]); + + 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]); + } + + #[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() { + 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(); + 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(); + assert_eq!(signature, decoded); + assert_eq!(Some(1), chain_id); + } + + #[test] + fn test_recover_signer() { + let signature = Signature { + r: U256::from_str( + "18515461264373351373200002665853028612451056578545711640558177340181847433846", + ) + .unwrap(), + s: U256::from_str( + "46948507304638947509940763649030358759909902576025900602547168820602576006531", + ) + .unwrap(), + odd_y_parity: false, + }; + let hash = + H256::from_str("daf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53") + .unwrap(); + let signer = signature.recover_signer(hash).unwrap(); + let expected = Address::from_str("0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f").unwrap(); + assert_eq!(expected, signer); + } +}