From 8bfcf60e0c72b84bb95f630d02d6f4a89c926d48 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 15:18:55 +0500 Subject: [PATCH 01/27] add typed tx with eip2930 and eip1559 support --- ethcore/transaction/src/transaction.rs | 620 +++++++++++------- .../transaction/src/transaction/eip1559.rs | 191 ++++++ .../transaction/src/transaction/eip2930.rs | 241 +++++++ ethcore/transaction/src/transaction/legacy.rs | 190 ++++++ 4 files changed, 1011 insertions(+), 231 deletions(-) create mode 100644 ethcore/transaction/src/transaction/eip1559.rs create mode 100644 ethcore/transaction/src/transaction/eip2930.rs create mode 100644 ethcore/transaction/src/transaction/legacy.rs diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 43f1a389b10..10349b1ab53 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -1,3 +1,5 @@ +// This source is derived from Parity code +// // Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. @@ -16,21 +18,32 @@ //! Transaction data structure. -use std::ops::Deref; -use ethereum_types::{H256, H160, Address, U256}; use error; -use ethkey::{self, recover, Signature, Secret, Public, public_to_address}; +use ethereum_types::{Address, H160, H256, U256}; +use ethkey::{self, public_to_address, recover, Public, Secret, Signature}; use hash::keccak; -use rlp::{self, RlpStream, Rlp, DecoderError, Encodable}; +use rlp::{self, DecoderError, Rlp, RlpStream}; +use std::convert::TryInto; +use std::ops::Deref; + +mod legacy; +use self::legacy::{LegacyTransaction, UnverifiedLegacyTransaction}; +mod eip2930; +use self::eip2930::{Eip2930Transaction, UnverifiedEip2930Transaction, EIP2930_TX_TYPE}; +mod eip1559; +use self::eip1559::{Eip1559Transaction, UnverifiedEip1559Transaction, EIP1559_TX_TYPE}; -type Bytes = Vec; type BlockNumber = u64; +type Bytes = Vec; /// Fake address for unsigned transactions as defined by EIP-86. pub const UNSIGNED_SENDER: Address = H160([0xff; 20]); /// System sender address for internal state updates. -pub const SYSTEM_ADDRESS: Address = H160([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xfe]); +pub const SYSTEM_ADDRESS: Address = H160([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, +]); /// Transaction action type. #[derive(Debug, Clone, PartialEq, Eq)] @@ -43,7 +56,9 @@ pub enum Action { } impl Default for Action { - fn default() -> Action { Action::Create } + fn default() -> Action { + Action::Create + } } impl rlp::Decodable for Action { @@ -74,110 +89,97 @@ pub enum Condition { Timestamp(u64), } -/// Replay protection logic for v part of transaction's signature -pub mod signature { - /// Adds chain id into v - pub fn add_chain_replay_protection(v: u64, chain_id: Option) -> u64 { - v + if let Some(n) = chain_id { 35 + n * 2 } else { 27 } - } - - /// Returns refined v - /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. - pub fn check_replay_protection(v: u64) -> u8 { - match v { - v if v == 27 => 0, - v if v == 28 => 1, - v if v > 36 => ((v - 1) % 2) as u8, - _ => 4 - } - } -} +/// Methods common for all tx versions +pub trait TransactionShared { + fn nonce(&self) -> U256; + + fn action(&self) -> &Action; + + fn value(&self) -> U256; + + fn data(&self) -> &Bytes; -/// A set of information describing an externally-originating message call -/// or contract creation operation. -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct Transaction { - /// Nonce. - pub nonce: U256, - /// Gas price. - pub gas_price: U256, - /// Gas paid up front for transaction execution. - pub gas: U256, - /// Action, can be either call or contract create. - pub action: Action, - /// Transfered value. - pub value: U256, - /// Transaction data. - pub data: Bytes, + fn message_hash(&self, chain_id: Option) -> H256; } -impl Transaction { - /// Append object with a without signature into RLP stream - pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, chain_id: Option) { - s.begin_list(if chain_id.is_none() { 6 } else { 9 }); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - if let Some(n) = chain_id { - s.append(&n); - s.append(&0u8); - s.append(&0u8); - } +/// Methods common all signed tx versions +pub trait SignedTransactionShared { + fn compute_hash(mut self) -> Self + where + Self: rlp::Encodable + Sized, + { + let hash = keccak(&*self.rlp_bytes()); + self.set_hash(hash); + self } + + fn set_hash(&mut self, hash: H256); } -impl Transaction { +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum TransactionWrapper { + Legacy(LegacyTransaction), + Eip2930(Eip2930Transaction), + Eip1559(Eip1559Transaction), +} + +impl TransactionWrapper { /// The message hash of the transaction. - pub fn hash(&self, chain_id: Option) -> H256 { - let mut stream = RlpStream::new(); - self.rlp_append_unsigned_transaction(&mut stream, chain_id); - keccak(stream.as_raw()) + pub fn message_hash(&self, chain_id: Option) -> H256 { + match self { + TransactionWrapper::Legacy(tx) => tx.message_hash(chain_id), + TransactionWrapper::Eip2930(tx) => tx.message_hash(None), + TransactionWrapper::Eip1559(tx) => tx.message_hash(None), + } } /// Signs the transaction as coming from `sender`. pub fn sign(self, secret: &Secret, chain_id: Option) -> SignedTransaction { - let sig = ::ethkey::sign(secret, &self.hash(chain_id)) + let sig = ::ethkey::sign(secret, &self.message_hash(chain_id)) .expect("data is valid and context has signing capabilities; qed"); SignedTransaction::new(self.with_signature(sig, chain_id)) .expect("secret is valid so it's recoverable") } - /// Signs the transaction with signature. - pub fn with_signature(self, sig: Signature, chain_id: Option) -> UnverifiedTransaction { - UnverifiedTransaction { - unsigned: self, - r: sig.r().into(), - s: sig.s().into(), - v: signature::add_chain_replay_protection(sig.v() as u64, chain_id), - hash: H256::from_low_u64_ne(0), - }.compute_hash() + /// Add signature to the transaction. + fn with_signature(self, sig: Signature, chain_id: Option) -> UnverifiedTransactionWrapper { + UnverifiedTransactionWrapper::new( + self, + sig.r().into(), + sig.s().into(), + sig.v() as u64, + chain_id, + H256::from_low_u64_ne(0), + ) + .compute_hash() } /// Useful for test incorrectly signed transactions. #[cfg(test)] - pub fn invalid_sign(self) -> UnverifiedTransaction { - UnverifiedTransaction { - unsigned: self, - r: U256::one(), - s: U256::one(), - v: 0, - hash: H256::from_low_u64_ne(0), - }.compute_hash() + pub fn invalid_sign(self) -> UnverifiedTransactionWrapper { + UnverifiedTransactionWrapper::new( + self, + U256::one(), + U256::one(), + 0, + None, + H256::from_low_u64_ne(0), + ) + .compute_hash() } /// Specify the sender; this won't survive the serialize/deserialize process, but can be cloned. pub fn fake_sign(self, from: Address) -> SignedTransaction { SignedTransaction { - transaction: UnverifiedTransaction { - unsigned: self, - r: U256::one(), - s: U256::one(), - v: 0, - hash: H256::from_low_u64_ne(0), - }.compute_hash(), + transaction: UnverifiedTransactionWrapper::new( + self, + U256::one(), + U256::one(), + 0, + None, + H256::from_low_u64_ne(0), + ) + .compute_hash(), sender: from, public: None, } @@ -186,120 +188,140 @@ impl Transaction { /// Add EIP-86 compatible empty signature. pub fn null_sign(self, chain_id: u64) -> SignedTransaction { SignedTransaction { - transaction: UnverifiedTransaction { - unsigned: self, - r: U256::zero(), - s: U256::zero(), - v: chain_id, - hash: H256::from_low_u64_ne(0), - }.compute_hash(), + transaction: UnverifiedTransactionWrapper::new( + self, + U256::zero(), + U256::zero(), + chain_id, + None, + H256::from_low_u64_ne(0), + ) + .compute_hash(), sender: UNSIGNED_SENDER, public: None, } } } -/// Signed transaction information without verified signature. #[derive(Debug, Clone, Eq, PartialEq)] -pub struct UnverifiedTransaction { - /// Plain Transaction. - pub unsigned: Transaction, - /// The V field of the signature; the LS bit described which half of the curve our point falls - /// in. The MS bits describe which chain this transaction is for. If 27/28, its for all chains. - pub v: u64, - /// The R field of the signature; helps describe the point on the curve. - pub r: U256, - /// The S field of the signature; helps describe the point on the curve. - pub s: U256, - /// Hash of the transaction - pub hash: H256, -} - -impl Deref for UnverifiedTransaction { - type Target = Transaction; - - fn deref(&self) -> &Self::Target { - &self.unsigned - } +pub enum UnverifiedTransactionWrapper { + Legacy(UnverifiedLegacyTransaction), + Eip2930(UnverifiedEip2930Transaction), + Eip1559(UnverifiedEip1559Transaction), } -impl rlp::Decodable for UnverifiedTransaction { +impl rlp::Decodable for UnverifiedTransactionWrapper { fn decode(d: &Rlp) -> Result { - if d.item_count()? != 9 { - return Err(DecoderError::RlpIncorrectListLen); + if is_typed_transaction(d) { + // first byte is tx version + match d.as_raw()[0] { + EIP2930_TX_TYPE => Ok(UnverifiedTransactionWrapper::Eip2930( + UnverifiedEip2930Transaction::decode(d)?, + )), + EIP1559_TX_TYPE => Ok(UnverifiedTransactionWrapper::Eip1559( + UnverifiedEip1559Transaction::decode(d)?, + )), + _ => Err(DecoderError::Custom("unsupported tx version")), + } + } else { + Ok(UnverifiedTransactionWrapper::Legacy(UnverifiedLegacyTransaction::decode(d)?)) } - let hash = keccak(d.as_raw()); - Ok(UnverifiedTransaction { - unsigned: Transaction { - nonce: d.val_at(0)?, - gas_price: d.val_at(1)?, - gas: d.val_at(2)?, - action: d.val_at(3)?, - value: d.val_at(4)?, - data: d.val_at(5)?, - }, - v: d.val_at(6)?, - r: d.val_at(7)?, - s: d.val_at(8)?, - hash: hash, - }) } } -impl rlp::Encodable for UnverifiedTransaction { - fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_sealed_transaction(s) } -} - -impl UnverifiedTransaction { - /// Used to compute hash of created transactions - fn compute_hash(mut self) -> UnverifiedTransaction { - let hash = keccak(&*self.rlp_bytes()); - self.hash = hash; - self +impl UnverifiedTransactionWrapper { + fn new( + tx: TransactionWrapper, + r: U256, + s: U256, + v: u64, + chain_id: Option, + hash: H256, + ) -> Self { + match tx { + TransactionWrapper::Legacy(unsigned) => { + UnverifiedTransactionWrapper::Legacy(UnverifiedLegacyTransaction { + unsigned, + r, + s, + network_v: UnverifiedLegacyTransaction::to_network_v(v, chain_id), + hash, + }) + } + TransactionWrapper::Eip2930(unsigned) => { + UnverifiedTransactionWrapper::Eip2930(UnverifiedEip2930Transaction { + unsigned, + r, + s, + v: v.try_into().unwrap(), + hash, + }) + } + TransactionWrapper::Eip1559(unsigned) => { + UnverifiedTransactionWrapper::Eip1559(UnverifiedEip1559Transaction { + unsigned, + r, + s, + v: v.try_into().unwrap(), + hash, + }) + } + } } - /// Checks is signature is empty. - pub fn is_unsigned(&self) -> bool { - self.r.is_zero() && self.s.is_zero() + fn compute_hash(self) -> UnverifiedTransactionWrapper { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => { + UnverifiedTransactionWrapper::Legacy(tx.compute_hash()) + } + UnverifiedTransactionWrapper::Eip2930(tx) => { + UnverifiedTransactionWrapper::Eip2930(tx.compute_hash()) + } + UnverifiedTransactionWrapper::Eip1559(tx) => { + UnverifiedTransactionWrapper::Eip1559(tx.compute_hash()) + } + } } /// Append object with a signature into RLP stream fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { - s.begin_list(9); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - s.append(&self.v); - s.append(&self.r); - s.append(&self.s); + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.rlp_append_sealed_transaction(s), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.rlp_append_sealed_transaction(s), + UnverifiedTransactionWrapper::Eip1559(tx) => tx.rlp_append_sealed_transaction(s), + }; } - /// Reference to unsigned part of this transaction. - pub fn as_unsigned(&self) -> &Transaction { - &self.unsigned + pub fn unsigned(&self) -> &dyn TransactionShared { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &dyn TransactionShared, + UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &dyn TransactionShared, + UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &dyn TransactionShared, + } } - pub fn standard_v(&self) -> u8 { signature::check_replay_protection(self.v) } - - /// The `v` value that appears in the RLP. - pub fn original_v(&self) -> u64 { self.v } + /// Add eip155 fix to signature v, for legacy tx + pub fn standard_v(&self) -> u8 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.standard_v(), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.standard_v(), + UnverifiedTransactionWrapper::Eip1559(tx) => tx.standard_v(), + } + } /// The chain ID, or `None` if this is a global transaction. - pub fn chain_id(&self) -> Option { - match self.v { - v if self.is_unsigned() => Some(v), - v if v > 36 => Some((v - 35) / 2), + pub fn chain_id_from_v(&self) -> Option { + match self.v() { + v if self.is_unsigned() => Some(v), // v is chain_id for null signer by eip-86 (TODO: is this supported?) + v if v > 36 => Some((v - 35) / 2), // encoded by eip-155 _ => None, } } /// Construct a signature object from the sig. pub fn signature(&self) -> Signature { - let r = h256_from_u256(self.r); - let s = h256_from_u256(self.s); + let r = h256_from_u256(self.r()); + let s = h256_from_u256(self.s()); Signature::from_rsv(&r, &s, self.standard_v()) } @@ -312,35 +334,49 @@ impl UnverifiedTransaction { } } - /// Get the hash of this transaction (keccak of the RLP). - pub fn hash(&self) -> H256 { - self.hash + /// Checks is signature is empty. + pub(crate) fn is_unsigned(&self) -> bool { + self.r().is_zero() && self.s().is_zero() } /// Recovers the public key of the sender. pub fn recover_public(&self) -> Result { - Ok(recover(&self.signature(), &self.unsigned.hash(self.chain_id()))?) + Ok(recover(&self.signature(), &self.unsigned().message_hash(self.chain_id_from_v()))?) } /// Do basic validation, checking for valid signature and minimum gas, // TODO: consider use in block validation. #[cfg(feature = "json-tests")] - pub fn validate(self, schedule: &Schedule, require_low: bool, allow_chain_id_of_one: bool, allow_empty_signature: bool) - -> Result - { + pub fn validate( + self, + schedule: &Schedule, + require_low: bool, + allow_chain_id_of_one: bool, + allow_empty_signature: bool, + ) -> Result { let chain_id = if allow_chain_id_of_one { Some(1) } else { None }; self.verify_basic(require_low, chain_id, allow_empty_signature)?; if !allow_empty_signature || !self.is_unsigned() { self.recover_public()?; } if self.gas < U256::from(self.gas_required(&schedule)) { - return Err(error::Error::InvalidGasLimit(::unexpected::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}).into()) + return Err(error::Error::InvalidGasLimit(::unexpected::OutOfBounds { + min: Some(U256::from(self.gas_required(&schedule))), + max: None, + found: self.gas, + }) + .into()); } Ok(self) } /// Verify basic signature params. Does not attempt sender recovery. - pub fn verify_basic(&self, check_low_s: bool, chain_id: Option, allow_empty_signature: bool) -> Result<(), error::Error> { + pub fn verify_basic( + &self, + check_low_s: bool, + chain_id: Option, + allow_empty_signature: bool, + ) -> Result<(), error::Error> { if check_low_s && !(allow_empty_signature && self.is_unsigned()) { self.check_low_s()?; } @@ -348,39 +384,81 @@ impl UnverifiedTransaction { if !allow_empty_signature && self.is_unsigned() { return Err(ethkey::Error::InvalidSignature.into()); } - // EIP-86: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. - if allow_empty_signature && self.is_unsigned() && !(self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero()) { - return Err(ethkey::Error::InvalidSignature.into()) + + if allow_empty_signature && self.is_unsigned() && self.validate_empty_sig() { + return Err(ethkey::Error::InvalidSignature.into()); } - match (self.chain_id(), chain_id) { - (None, _) => {}, - (Some(n), Some(m)) if n == m => {}, + match (self.chain_id_from_v(), chain_id) { + (None, _) => {} + (Some(n), Some(m)) if n == m => {} _ => return Err(error::Error::InvalidChainId), }; Ok(()) } + + /// validate tx with empty signature + fn validate_empty_sig(&self) -> bool { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.validate_eip86(), + UnverifiedTransactionWrapper::Eip2930(_tx) => true, // TODO: what is it for eip2930? + UnverifiedTransactionWrapper::Eip1559(_tx) => true, // TODO: what is it for eip1559? + } + } + + fn r(&self) -> U256 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.r, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.r, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.r, + } + } + fn s(&self) -> U256 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.s, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.s, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.s, + } + } + fn v(&self) -> u64 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.network_v, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.v as u64, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.v as u64, + } + } + + /// Get the hash of this transaction (keccak of the RLP). + pub fn tx_hash(&self) -> H256 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.hash, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.hash, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.hash, + } + } } /// A `UnverifiedTransaction` with successfully recovered `sender`. #[derive(Debug, Clone, Eq, PartialEq)] pub struct SignedTransaction { - pub transaction: UnverifiedTransaction, + pub transaction: UnverifiedTransactionWrapper, pub sender: Address, pub public: Option, } impl rlp::Encodable for SignedTransaction { - fn rlp_append(&self, s: &mut RlpStream) { self.transaction.rlp_append_sealed_transaction(s) } + fn rlp_append(&self, s: &mut RlpStream) { + self.transaction.rlp_append_sealed_transaction(s) + } } impl Deref for SignedTransaction { - type Target = UnverifiedTransaction; + type Target = UnverifiedTransactionWrapper; fn deref(&self) -> &Self::Target { &self.transaction } } -impl From for UnverifiedTransaction { +impl From for UnverifiedTransactionWrapper { fn from(tx: SignedTransaction) -> Self { tx.transaction } @@ -388,7 +466,7 @@ impl From for UnverifiedTransaction { impl SignedTransaction { /// Try to verify transaction and recover sender. - pub fn new(transaction: UnverifiedTransaction) -> Result { + pub fn new(transaction: UnverifiedTransactionWrapper) -> Result { if transaction.is_unsigned() { Ok(SignedTransaction { transaction: transaction, @@ -422,7 +500,7 @@ impl SignedTransaction { } /// Deconstructs this transaction back into `UnverifiedTransaction` - pub fn deconstruct(self) -> (UnverifiedTransaction, Address, Option) { + pub fn deconstruct(self) -> (UnverifiedTransactionWrapper, Address, Option) { (self.transaction, self.sender, self.public) } } @@ -431,7 +509,7 @@ impl SignedTransaction { #[derive(Debug, Clone, PartialEq, Eq)] pub struct LocalizedTransaction { /// Signed part. - pub signed: UnverifiedTransaction, + pub signed: UnverifiedTransactionWrapper, /// Block number. pub block_number: BlockNumber, /// Block hash. @@ -460,7 +538,7 @@ impl LocalizedTransaction { } impl Deref for LocalizedTransaction { - type Target = UnverifiedTransaction; + type Target = UnverifiedTransactionWrapper; fn deref(&self) -> &Self::Target { &self.signed @@ -489,15 +567,14 @@ impl PendingTransaction { impl Deref for PendingTransaction { type Target = SignedTransaction; - fn deref(&self) -> &SignedTransaction { &self.transaction } + fn deref(&self) -> &SignedTransaction { + &self.transaction + } } impl From for PendingTransaction { fn from(t: SignedTransaction) -> Self { - PendingTransaction { - transaction: t, - condition: None, - } + PendingTransaction { transaction: t, condition: None } } } @@ -509,82 +586,106 @@ fn h256_from_u256(num: U256) -> H256 { H256::from(bytes) } +/// Returns true if serialized tx has type as in eip-2718 +fn is_typed_transaction(d: &Rlp) -> bool { + !d.is_list() && d.as_raw().len() > 0 && d.as_raw()[0] < 0x7f +} + #[cfg(test)] mod tests { use super::*; use ethereum_types::U256; - use hash::keccak; use ethkey::KeyPair; + use hash::keccak; use std::str::FromStr; #[test] - fn sender_test() { + fn legacy_sender_test() { let bytes: Vec = ::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap(); - let t: UnverifiedTransaction = rlp::decode(&bytes).expect("decoding UnverifiedTransaction failed"); - assert_eq!(t.data, b""); - assert_eq!(t.gas, U256::from(0x5208u64)); - assert_eq!(t.gas_price, U256::from(0x01u64)); - assert_eq!(t.nonce, U256::from(0x00u64)); - if let Action::Call(ref to) = t.action { - let expected = Address::from_str("095e7baea6a6c7c4c2dfeb977efac326af552d87").unwrap(); - assert_eq!(*to, expected); - } else { panic!(); } - assert_eq!(t.value, U256::from(0x0au64)); - let expected = Address::from_str("0f65fe9276bc9a24ae7083ae28e2660ef72df99e").unwrap(); - assert_eq!(public_to_address(&t.recover_public().unwrap()), expected); - assert_eq!(t.chain_id(), None); + let t: UnverifiedTransactionWrapper = + rlp::decode(&bytes).expect("decoding UnverifiedTransaction failed"); + if let UnverifiedTransactionWrapper::Legacy(legacy_tx) = t.clone() { + assert_eq!(legacy_tx.data, b""); + assert_eq!(legacy_tx.gas, U256::from(0x5208u64)); + assert_eq!(legacy_tx.gas_price, U256::from(0x01u64)); + assert_eq!(legacy_tx.nonce, U256::from(0x00u64)); + if let Action::Call(ref to) = legacy_tx.action { + let expected = + Address::from_str("095e7baea6a6c7c4c2dfeb977efac326af552d87").unwrap(); + assert_eq!(*to, expected); + } else { + panic!(); + } + assert_eq!(legacy_tx.value, U256::from(0x0au64)); + let expected = Address::from_str("0f65fe9276bc9a24ae7083ae28e2660ef72df99e").unwrap(); + assert_eq!(public_to_address(&t.recover_public().unwrap()), expected); + assert_eq!(t.chain_id_from_v(), None); + } else { + panic!("invalid tx ver"); + } } #[test] - fn signing() { - let key = KeyPair::from_secret_slice(&[128, 148, 101, 177, 125, 10, 77, 219, 62, 76, 105, 232, 242, 60, 44, 171, 173, 134, 143, 81, 248, 190, 213, 199, 101, 173, 29, 101, 22, 195, 48, 111]).unwrap(); - let t = Transaction { + fn legacy_signing() { + let key = KeyPair::from_secret_slice(&[ + 128, 148, 101, 177, 125, 10, 77, 219, 62, 76, 105, 232, 242, 60, 44, 171, 173, 134, + 143, 81, 248, 190, 213, 199, 101, 173, 29, 101, 22, 195, 48, 111, + ]) + .unwrap(); + let t = TransactionWrapper::Legacy(LegacyTransaction { action: Action::Create, nonce: U256::from(42), gas_price: U256::from(3000), gas: U256::from(50_000), value: U256::from(1), - data: b"Hello!".to_vec() - }.sign(&key.secret(), None); + data: b"Hello!".to_vec(), + }) + .sign(&key.secret(), None); assert_eq!(Address::from(keccak(key.public())), t.sender()); - assert_eq!(t.chain_id(), None); + assert_eq!(t.chain_id_from_v(), None); } #[test] - fn fake_signing() { - let t = Transaction { + fn legacy_fake_signing() { + let t = TransactionWrapper::Legacy(LegacyTransaction { action: Action::Create, nonce: U256::from(42), gas_price: U256::from(3000), gas: U256::from(50_000), value: U256::from(1), - data: b"Hello!".to_vec() - }.fake_sign(Address::from_low_u64_ne(0x69)); + data: b"Hello!".to_vec(), + }) + .fake_sign(Address::from_low_u64_ne(0x69)); assert_eq!(Address::from_low_u64_ne(0x69), t.sender()); - assert_eq!(t.chain_id(), None); + assert_eq!(t.chain_id_from_v(), None); let t = t.clone(); assert_eq!(Address::from_low_u64_ne(0x69), t.sender()); - assert_eq!(t.chain_id(), None); + assert_eq!(t.chain_id_from_v(), None); } #[test] - fn should_recover_from_chain_specific_signing() { - let key = KeyPair::from_secret_slice(&[128, 148, 101, 177, 125, 10, 77, 219, 62, 76, 105, 232, 242, 60, 44, 171, 173, 134, 143, 81, 248, 190, 213, 199, 101, 173, 29, 101, 22, 195, 48, 111]).unwrap(); - let t = Transaction { + fn legacy_should_recover_from_chain_specific_signing() { + let key = KeyPair::from_secret_slice(&[ + 128, 148, 101, 177, 125, 10, 77, 219, 62, 76, 105, 232, 242, 60, 44, 171, 173, 134, + 143, 81, 248, 190, 213, 199, 101, 173, 29, 101, 22, 195, 48, 111, + ]) + .unwrap(); + let t = TransactionWrapper::Legacy(LegacyTransaction { action: Action::Create, nonce: U256::from(42), gas_price: U256::from(3000), gas: U256::from(50_000), value: U256::from(1), - data: b"Hello!".to_vec() - }.sign(&key.secret(), Some(69)); + data: b"Hello!".to_vec(), + }) + .sign(&key.secret(), Some(69)); assert_eq!(Address::from(keccak(key.public())), t.sender()); - assert_eq!(t.chain_id(), Some(69)); + assert_eq!(t.chain_id_from_v(), Some(69)); } #[test] - fn should_agree_with_vitalik() { + fn legacy_should_agree_with_vitalik() { use rustc_hex::FromHex; let test_vector = |tx_data: &str, address: &'static str| { @@ -594,7 +695,7 @@ mod tests { let expected = Address::from_str(address).unwrap(); assert_eq!(signed.sender(), expected); - println!("chainid: {:?}", signed.chain_id()); + println!("chainid_from_v: {:?}", signed.chain_id_from_v()); }; test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"); @@ -608,4 +709,61 @@ mod tests { test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029"); test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"); } + + #[test] + fn tx_type_1_parse_tx() { + use rustc_hex::FromHex; + + let test_vector = |tx_data: &str, address: &'static str, hash: &'static str| { + let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); + let unverified = rlp::decode(&bytes).expect("decoding tx data failed"); + let signed = SignedTransaction::new(unverified).unwrap(); + + let expected_addr = Address::from_str(address).unwrap(); + assert_eq!(signed.sender(), expected_addr); + let expected_hash = H256::from_str(hash).unwrap(); + let unverified_tx = signed.transaction.clone().compute_hash(); + assert_eq!(unverified_tx.tx_hash(), expected_hash); + + if let UnverifiedTransactionWrapper::Eip2930(tx) = signed.transaction { + println!("chainid: {:?}", tx.chain_id); + } else { + panic!("expected tx type 1 (eip-2930)"); + } + }; + // type 1, empty access list + test_vector("01f87201830180058504375e83908307a120942f3e89bb84705085dd2afc1f00ca5f823ff7f6088801aaaf118d612c0080c080a04f08e11860459e944e28a39193b76cc2ca0566bea40c086160f6c44ce43dd6fca07333d8b6c872a4d599cb4027c9129941c2691f09ce1cbea361a827bc30e78e54", "0x264bd8291fAE1D75DB2c5F573b07faA6715997B5", "0xe9b033c089745a1b70003586e8a1fbdb59d407c5943f00193d5c562194042524"); + } + + #[test] + fn eip1559_parse_tx() { + use rustc_hex::FromHex; + + let test_vector = |tx_data: &str, address: &'static str, hash: &'static str| { + let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); + let unverified = rlp::decode(&bytes).expect("decoding tx data failed"); + let signed = SignedTransaction::new(unverified).unwrap(); + + let expected_addr = Address::from_str(address).unwrap(); + assert_eq!(signed.sender(), expected_addr); + let expected_hash = H256::from_str(hash).unwrap(); + let unverified_tx = signed.transaction.clone().compute_hash(); + assert_eq!(unverified_tx.tx_hash(), expected_hash); + + if let UnverifiedTransactionWrapper::Eip1559(tx) = signed.transaction { + println!("chainid: {:?}", tx.chain_id); + } else { + panic!("expected tx type 2 (eip-1559)"); + } + }; + + // simple transfer eth tx + test_vector("02f8710103830f42408518ad0849c4825208941749b8eccc622d81600ab7fa322a17b99def83d2876b803d5ccd438580c001a08303e62f4d7779b09ab9daeaef868a8ad3bc937b435a60e8cc432d224bd8b1fba0520ae4b5906f3978ff413eef4131c1d246b15eb676a19324ce9ad23ac48aa987", + "0xfAe06Df909Df46f3b1649c9b11e150F14E9B83B0", + "0x9903f6398f118dfc04b95ed6c00e55237eb204986590593d13e2f9ce47716ed9"); + // tx with data and access list + test_vector("02f907670183180a51808507a6a2c507830917af946b75d8af000000e20b7a7ddf000ba900b4009a8080b89c0c8ee819c10e1f20df3a8c2ac93a62d7fba719fa777026c02d337617b02998480049642110b712c1fd7261bc074105e9e44676c68fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22710f2fe5250fe5318b03d536566b02998ffffc076c4ffff93001a6cd7c3a21bda7cf6a0cd5d5e8d10ab55d8ba58257813a239ca819d9510a73c424485f89ea52839fdb30640eb7dd7e0078e12fb0a4eac742df9065df89b94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f884a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8a093f4f2109c73365b91270de71d7ce61b41cfceb94f27f26e2b6e30142ea529e5a0af9987888ab75f8cdc0eee179dff704e6c0a13b462f58aac23ab8eb77f3d71cda0176d9f00066af884810a42c67ff9a8c1374be6135e1ee85edb8c9cf021f1fdd5f8dd94da7cf6a0cd5d5e8d10ab55d8ba58257813a239caf8c6a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000af8bc94993864e43caa7f7f12953ad6feb1d1ca635b875ff8a5a00000000000000000000000000000000000000000000000000000000000000003a0d93f987b59bbb5780fe5994c7112f10657809cae45c627a319f962c40235428ca0a6eabb9b2c010ec47045c52eb64682c8a09fe52a8605fef87ee312fa6817bde7a01f31c723d1f4395a6dac2d34827bb7577589384735f0df95b73389f4d27d8769a06e89d460fefb1c8f5b2b8f2e9609ee9a4ef3f9b7ff014be959a86fabed2b4af8f87a949ce9704b1993ff308f1815e0fd44b0dffee2d0dcf863a06d0cc4c200c8af0ffd8b254bae44f07d6bc5c15ac854d2a3dbf761299ffa9c56a0101ed5680b1cfc12bfd6f2c99ee49abcf5d75b12223f9040664d083b09f1c7d7a00000000000000000000000000000000000000000000000000000000000000002f8dd94424485f89ea52839fdb30640eb7dd7e0078e12fbf8c6a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000af9026a9419c10e1f20df3a8c2ac93a62d7fba719fa777026f90252a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000008a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896737a02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2ca057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f78a02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2da057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f76a00000000000000000000000000000000000000000000000000000000000000002a0c0d1c00078410fd0164580b0bad93d8a579580d06cf45fc2696a823498097b8aa02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2aa02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2ba057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f75a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896738a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896739a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e989673aa057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f77f8599449642110b712c1fd7261bc074105e9e44676c68ff842a0b39e9ba92c3c47c76d4f70e3bc9c3270ab78d2592718d377c8f5433a34d3470aa05f19933e8ecba477d24413f29da8dd3035e36ca249de114bc98ea28d251d02b580a0a00d83a12835ab9653ee11077d5dd310a424dd67885445f5319207e7a5a2ae15a059c4642a2ac77f31d88de1a4e0f70eb220be8a8219943c3af9cf9c71e3143ebd", + "0xae2Fc483527B8EF99EB5D9B44875F005ba1FaE13", + "0x256c91a7934b7584c1f8f28a6b3b8cacf13419637532896fc1e1119aa7fa32ba"); + } } diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs new file mode 100644 index 00000000000..c8bfad4e2aa --- /dev/null +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -0,0 +1,191 @@ +// This source is derived from Parity code +// +//! Eip 1559 transaction encoding/decoding and specific checks + +use super::eip2930::AccessList; +use super::SignedTransactionShared; +use super::{Action, Bytes, TransactionShared}; +use ethereum_types::{H256, U256}; +use hash::keccak; +use rlp::{self, DecoderError, Rlp, RlpStream}; +use std::{convert::TryInto, ops::Deref}; + +pub const EIP1559_TX_TYPE: u8 = 2; + +/// A set of information describing an externally-originating message call +/// or contract creation operation. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct Eip1559Transaction { + /// Simple replay attack protection + pub chain_id: u64, + /// Nonce. + pub nonce: U256, + /// Max fee per gas. + pub max_fee_per_gas: U256, + /// Max priority fee per gas. + pub max_priority_fee_per_gas: U256, + /// Gas paid up front for transaction execution. + pub gas: U256, + /// Action, can be either call or contract create. + pub action: Action, + /// Transfered value. + pub value: U256, + /// Transaction data. + pub data: Bytes, + /// Access list. + pub access_list: AccessList, +} + +impl Eip1559Transaction { + const fn payload_length(&self) -> usize { + 9 + } + + /// Append object with a without signature into RLP stream + fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { + s.append(&EIP1559_TX_TYPE); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.max_priority_fee_per_gas); + s.append(&self.max_fee_per_gas); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + } +} + +impl TransactionShared for Eip1559Transaction { + fn nonce(&self) -> U256 { + self.nonce + } + fn action(&self) -> &Action { + &self.action + } + fn value(&self) -> U256 { + self.value + } + fn data(&self) -> &Bytes { + &self.data + } + /// The message hash of the transaction. + fn message_hash(&self, _chain_id: Option) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream); + keccak(stream.as_raw()) + } +} + +impl rlp::Decodable for Eip1559Transaction { + fn decode(d: &Rlp) -> Result { + if d.as_raw().len() < 2 { + return Err(DecoderError::RlpIsTooShort); + } + let version: u8 = d.as_raw()[0]; + if version != EIP1559_TX_TYPE { + return Err(DecoderError::Custom("bad tx version")); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(Eip1559Transaction { + chain_id: list.val_at(0)?, + nonce: list.val_at(1)?, + max_priority_fee_per_gas: list.val_at(2)?, + max_fee_per_gas: list.val_at(3)?, + gas: list.val_at(4)?, + action: list.val_at(5)?, + value: list.val_at(6)?, + data: list.val_at(7)?, + access_list: list.val_at(8)?, + }) + } +} + +/// Signed transaction information without verified signature. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UnverifiedEip1559Transaction { + /// Plain Transaction. + pub unsigned: Eip1559Transaction, + /// The V field of the signature + pub v: u64, + /// The R field of the signature; helps describe the point on the curve. + pub r: U256, + /// The S field of the signature; helps describe the point on the curve. + pub s: U256, + /// Hash of the transaction + pub hash: H256, +} + +impl Deref for UnverifiedEip1559Transaction { + type Target = Eip1559Transaction; + + fn deref(&self) -> &Self::Target { + &self.unsigned + } +} + +impl rlp::Decodable for UnverifiedEip1559Transaction { + fn decode(d: &Rlp) -> Result { + let unsigned = Eip1559Transaction::decode(d)?; + let hash = keccak(d.as_raw()); + let offset = unsigned.payload_length(); + if d.as_raw().len() < 1 { + return Err(DecoderError::RlpIsTooShort); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(UnverifiedEip1559Transaction { + unsigned, + v: list.val_at(offset)?, + r: list.val_at(offset + 1)?, + s: list.val_at(offset + 2)?, + hash, + }) + } +} + +impl rlp::Encodable for UnverifiedEip1559Transaction { + fn rlp_append(&self, s: &mut RlpStream) { + self.rlp_append_sealed_transaction(s) + } +} + +impl SignedTransactionShared for UnverifiedEip1559Transaction { + fn set_hash(&mut self, hash: H256) { + self.hash = hash; + } +} + +impl UnverifiedEip1559Transaction { + /// tx list item count + fn payload_length(&self) -> usize { + self.unsigned.payload_length() + 3 + } + + /// Append object with a signature into RLP stream + pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + s.append(&EIP1559_TX_TYPE); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.max_priority_fee_per_gas); + s.append(&self.max_fee_per_gas); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + s.append(&self.v); + s.append(&self.r); + s.append(&self.s); + } + + pub fn standard_v(&self) -> u8 { + self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns + } + + // EIP-86 or newer: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. + pub(crate) fn _validate_empty_sig(&self) -> bool { + true // TODO fix for eip1559 + } +} diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs new file mode 100644 index 00000000000..beb38b8adf7 --- /dev/null +++ b/ethcore/transaction/src/transaction/eip2930.rs @@ -0,0 +1,241 @@ +// This source is derived from Parity code +// +//! Eip 2930 transaction encoding/decoding and specific checks + +use super::{Action, Bytes, TransactionShared}; +use crate::SignedTransactionShared; +use ethereum_types::{Address, H256, U256}; +use hash::keccak; +use rlp::{self, DecoderError, Rlp, RlpStream}; +use std::{convert::TryInto, ops::Deref}; + +pub const EIP2930_TX_TYPE: u8 = 1; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +pub struct AccessListItem { + /// Account addresses that would be loaded at the start of execution + pub address: Address, + /// Keys of storage that would be loaded at the start of execution + pub storage_keys: Vec, +} + +impl rlp::Decodable for AccessListItem { + fn decode(d: &Rlp) -> Result { + let address = Address::decode(&d.at(0)?)?; + let keys_rlp = d.at(1)?; + let mut storage_keys: Vec = vec![]; + for i in 0..keys_rlp.item_count()? { + storage_keys.push(H256::decode(&keys_rlp.at(i)?)?); + } + Ok(AccessListItem { address, storage_keys }) + } +} + +impl rlp::Encodable for AccessListItem { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.address); + + s.begin_list(self.storage_keys.len()); + for i in 0..self.storage_keys.len() { + s.append(&self.storage_keys[i]); + } + } +} + +/// AccessList as defined in EIP-2930 +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +pub struct AccessList(pub Vec); + +impl rlp::Decodable for AccessList { + fn decode(d: &Rlp) -> Result { + let mut items: Vec = vec![]; + for i in 0..d.item_count()? { + let item = AccessListItem::decode(&d.at(i)?)?; + items.push(item); + } + Ok(AccessList(items)) + } +} + +impl rlp::Encodable for AccessList { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(self.0.len()); + for i in 0..self.0.len() { + s.append(&self.0[i]); + } + } +} + +/// A set of information describing an externally-originating message call +/// or contract creation operation. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct Eip2930Transaction { + /// Simple replay attack protection + pub chain_id: u64, + /// Nonce. + pub nonce: U256, + /// Gas price. + pub gas_price: U256, + /// Gas paid up front for transaction execution. + pub gas: U256, + /// Action, can be either call or contract create. + pub action: Action, + /// Transfered value. + pub value: U256, + /// Transaction data. + pub data: Bytes, + /// Access list. + pub access_list: AccessList, +} + +impl Eip2930Transaction { + const fn payload_length(&self) -> usize { + 8 + } + + /// Append object with a without signature into RLP stream + fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { + s.append(&EIP2930_TX_TYPE); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + } +} + +impl TransactionShared for Eip2930Transaction { + fn nonce(&self) -> U256 { + self.nonce + } + fn action(&self) -> &Action { + &self.action + } + fn value(&self) -> U256 { + self.value + } + fn data(&self) -> &Bytes { + &self.data + } + /// The message hash of the transaction. + fn message_hash(&self, _chain_id: Option) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream); + keccak(stream.as_raw()) + } +} + +impl rlp::Decodable for Eip2930Transaction { + fn decode(d: &Rlp) -> Result { + if d.as_raw().len() < 2 { + return Err(DecoderError::RlpIsTooShort); + } + let version: u8 = d.as_raw()[0]; + if version != EIP2930_TX_TYPE { + return Err(DecoderError::Custom("bad tx version")); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(Eip2930Transaction { + chain_id: list.val_at(0)?, + nonce: list.val_at(1)?, + gas_price: list.val_at(2)?, + gas: list.val_at(3)?, + action: list.val_at(4)?, + value: list.val_at(5)?, + data: list.val_at(6)?, + access_list: list.val_at(7)?, + }) + } +} + +/// Signed transaction information without verified signature. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UnverifiedEip2930Transaction { + /// Plain Transaction. + pub unsigned: Eip2930Transaction, + /// The V field of the signature + pub v: u64, + /// The R field of the signature; helps describe the point on the curve. + pub r: U256, + /// The S field of the signature; helps describe the point on the curve. + pub s: U256, + /// Hash of the transaction + pub hash: H256, +} + +impl Deref for UnverifiedEip2930Transaction { + type Target = Eip2930Transaction; + + fn deref(&self) -> &Self::Target { + &self.unsigned + } +} + +impl rlp::Decodable for UnverifiedEip2930Transaction { + fn decode(d: &Rlp) -> Result { + let unsigned = Eip2930Transaction::decode(d)?; + let hash = keccak(d.as_raw()); + let offset = unsigned.payload_length(); + if d.as_raw().len() < 1 { + return Err(DecoderError::RlpIsTooShort); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(UnverifiedEip2930Transaction { + unsigned, + v: list.val_at(offset)?, + r: list.val_at(offset + 1)?, + s: list.val_at(offset + 2)?, + hash, + }) + } +} + +impl rlp::Encodable for UnverifiedEip2930Transaction { + fn rlp_append(&self, s: &mut RlpStream) { + self.rlp_append_sealed_transaction(s) + } +} + +impl SignedTransactionShared for UnverifiedEip2930Transaction { + fn set_hash(&mut self, hash: H256) { + self.hash = hash; + } +} + +impl UnverifiedEip2930Transaction { + /// tx list item count + fn payload_length(&self) -> usize { + self.unsigned.payload_length() + 3 + } + + /// Append object with a signature into RLP stream + pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + s.append(&EIP2930_TX_TYPE); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + s.append(&self.v); + s.append(&self.r); + s.append(&self.s); + } + + pub fn standard_v(&self) -> u8 { + self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns + } + + // EIP-86 or newer: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. + pub(crate) fn _validate_empty_sig(&self) -> bool { + true // TODO fix for eip2930 + } +} diff --git a/ethcore/transaction/src/transaction/legacy.rs b/ethcore/transaction/src/transaction/legacy.rs new file mode 100644 index 00000000000..1450ff1c2c8 --- /dev/null +++ b/ethcore/transaction/src/transaction/legacy.rs @@ -0,0 +1,190 @@ +// This source is derived from Parity code +// +//! Legacy transaction encoding/decoding and specific checks + +use super::{Action, Bytes, TransactionShared}; +use crate::SignedTransactionShared; +use ethereum_types::{H256, U256}; +use hash::keccak; +use rlp::{self, DecoderError, Rlp, RlpStream}; +use std::ops::Deref; + +/// A set of information describing an externally-originating message call +/// or contract creation operation. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct LegacyTransaction { + /// Nonce. + pub nonce: U256, + /// Gas price. + pub gas_price: U256, + /// Gas paid up front for transaction execution. + pub gas: U256, + /// Action, can be either call or contract create. + pub action: Action, + /// Transfered value. + pub value: U256, + /// Transaction data. + pub data: Bytes, +} + +impl LegacyTransaction { + /// tx list item count + fn payload_length(chain_id: Option) -> usize { + if chain_id.is_none() { + 6 + } else { + 9 + } + } + + /// Append object with a without signature into RLP stream + fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, chain_id: Option) { + s.begin_list(Self::payload_length(chain_id)); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + if let Some(n) = chain_id { + s.append(&n); + s.append(&0u8); + s.append(&0u8); + } + } +} + +impl TransactionShared for LegacyTransaction { + fn nonce(&self) -> U256 { + self.nonce + } + fn action(&self) -> &Action { + &self.action + } + fn value(&self) -> U256 { + self.value + } + fn data(&self) -> &Bytes { + &self.data + } + /// The message hash of the transaction. + fn message_hash(&self, chain_id: Option) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream, chain_id); + keccak(stream.as_raw()) + } +} + +impl rlp::Decodable for LegacyTransaction { + fn decode(d: &Rlp) -> Result { + Ok(LegacyTransaction { + nonce: d.val_at(0)?, + gas_price: d.val_at(1)?, + gas: d.val_at(2)?, + action: d.val_at(3)?, + value: d.val_at(4)?, + data: d.val_at(5)?, + }) + } +} + +/// Signed transaction information without verified signature. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UnverifiedLegacyTransaction { + /// Plain Transaction. + pub unsigned: LegacyTransaction, + /// The V field of the signature; the LS bit described which half of the curve our point falls + /// in. The MS bits describe which chain this transaction is for. If 27/28, its for all chains. + /// normally fixed with chain_id for Eip155 + pub network_v: u64, + /// The R field of the signature; helps describe the point on the curve. + pub r: U256, + /// The S field of the signature; helps describe the point on the curve. + pub s: U256, + /// Hash of the transaction + pub hash: H256, +} + +impl Deref for UnverifiedLegacyTransaction { + type Target = LegacyTransaction; + + fn deref(&self) -> &Self::Target { + &self.unsigned + } +} + +impl rlp::Decodable for UnverifiedLegacyTransaction { + fn decode(d: &Rlp) -> Result { + if d.item_count()? != 9 { + return Err(DecoderError::RlpIncorrectListLen); + } + let hash = keccak(d.as_raw()); + Ok(UnverifiedLegacyTransaction { + unsigned: LegacyTransaction::decode(d)?, + network_v: d.val_at(6)?, + r: d.val_at(7)?, + s: d.val_at(8)?, + hash, + }) + } +} + +impl rlp::Encodable for UnverifiedLegacyTransaction { + fn rlp_append(&self, s: &mut RlpStream) { + self.rlp_append_sealed_transaction(s) + } +} + +impl SignedTransactionShared for UnverifiedLegacyTransaction { + fn set_hash(&mut self, hash: H256) { + self.hash = hash; + } +} + +impl UnverifiedLegacyTransaction { + /// Append object with a signature into RLP stream + pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + s.begin_list(9); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.network_v); + s.append(&self.r); + s.append(&self.s); + } + + pub fn standard_v(&self) -> u8 { + eip155_methods::check_replay_protection(self.network_v) + } + + pub fn to_network_v(v: u64, chain_id: Option) -> u64 { + eip155_methods::add_chain_replay_protection(v, chain_id) + } + + // EIP-86: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. + pub(crate) fn validate_eip86(&self) -> bool { + self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero() + } +} + +/// Replay protection logic for v part of transaction's signature +pub mod eip155_methods { + /// Adds chain id into v + pub fn add_chain_replay_protection(v: u64, chain_id: Option) -> u64 { + v + if let Some(n) = chain_id { 35 + n * 2 } else { 27 } + } + + /// Returns refined v + /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. + pub fn check_replay_protection(v: u64) -> u8 { + match v { + v if v == 27 => 0, + v if v == 28 => 1, + v if v > 36 => ((v - 1) % 2) as u8, + _ => 4, + } + } +} From e7a82b1165851a54bbd7b37a0afe4b5e5ed12e68 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 15:19:24 +0500 Subject: [PATCH 02/27] fix fmt --- ethcore/transaction/src/error.rs | 27 ++++++++++++++++----------- ethcore/transaction/src/lib.rs | 2 +- rustfmt.toml | 9 --------- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index 0efd18ae6b3..b22a7d236f3 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::{fmt, error}; +use std::{error, fmt}; use ethereum_types::U256; use ethkey; @@ -101,22 +101,27 @@ impl fmt::Display for Error { Old => "No longer valid".into(), TooCheapToReplace => "Gas price too low to replace".into(), LimitReached => "Transaction limit reached".into(), - InsufficientGasPrice { minimal, got } => - format!("Insufficient gas price. Min={}, Given={}", minimal, got), - InsufficientGas { minimal, got } => - format!("Insufficient gas. Min={}, Given={}", minimal, got), - InsufficientBalance { balance, cost } => - format!("Insufficient balance for transaction. Balance={}, Cost={}", - balance, cost), - GasLimitExceeded { limit, got } => - format!("Gas limit exceeded. Limit={}, Given={}", limit, got), + InsufficientGasPrice { minimal, got } => { + format!("Insufficient gas price. Min={}, Given={}", minimal, got) + } + InsufficientGas { minimal, got } => { + format!("Insufficient gas. Min={}, Given={}", minimal, got) + } + InsufficientBalance { balance, cost } => { + format!("Insufficient balance for transaction. Balance={}, Cost={}", balance, cost) + } + GasLimitExceeded { limit, got } => { + format!("Gas limit exceeded. Limit={}, Given={}", limit, got) + } InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err), SenderBanned => "Sender is temporarily banned.".into(), RecipientBanned => "Recipient is temporarily banned.".into(), CodeBanned => "Contract code is temporarily banned.".into(), InvalidChainId => "Transaction of this chain ID is not allowed on this chain.".into(), InvalidSignature(ref err) => format!("Transaction has invalid signature: {}.", err), - NotAllowed => "Sender does not have permissions to execute this type of transction".into(), + NotAllowed => { + "Sender does not have permissions to execute this type of transction".into() + } TooBig => "Transaction too big".into(), InvalidRlp(ref err) => format!("Transaction has invalid RLP structure: {}.", err), }; diff --git a/ethcore/transaction/src/lib.rs b/ethcore/transaction/src/lib.rs index 3f3576c4619..76b85ac225e 100644 --- a/ethcore/transaction/src/lib.rs +++ b/ethcore/transaction/src/lib.rs @@ -20,8 +20,8 @@ extern crate ethereum_types; extern crate ethkey; extern crate keccak_hash as hash; extern crate rlp; -extern crate unexpected; extern crate rustc_hex; +extern crate unexpected; mod error; mod transaction; diff --git a/rustfmt.toml b/rustfmt.toml index 16016b1b2af..9601de2e1e1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,16 +1,7 @@ -verbose=false max_width=100 -comment_width=100 tab_spaces=4 fn_call_width=100 struct_lit_width=32 -fn_call_style="Visual" single_line_if_else_max_width=100 -trailing_comma="Vertical" -chain_indent="Visual" -chain_one_line_max=100 reorder_imports=true -format_strings=false hard_tabs=true -wrap_match_arms=false -error_on_line_overflow=false \ No newline at end of file From 3157990e83842c686f25daf444528659ef6fb370 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 15:33:39 +0500 Subject: [PATCH 03/27] add pub for tx types imports --- ethcore/transaction/src/transaction.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 10349b1ab53..06148ca89d1 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -27,11 +27,11 @@ use std::convert::TryInto; use std::ops::Deref; mod legacy; -use self::legacy::{LegacyTransaction, UnverifiedLegacyTransaction}; +pub use self::legacy::{LegacyTransaction, UnverifiedLegacyTransaction}; mod eip2930; -use self::eip2930::{Eip2930Transaction, UnverifiedEip2930Transaction, EIP2930_TX_TYPE}; +pub use self::eip2930::{Eip2930Transaction, UnverifiedEip2930Transaction, EIP2930_TX_TYPE}; mod eip1559; -use self::eip1559::{Eip1559Transaction, UnverifiedEip1559Transaction, EIP1559_TX_TYPE}; +pub use self::eip1559::{Eip1559Transaction, UnverifiedEip1559Transaction, EIP1559_TX_TYPE}; type BlockNumber = u64; type Bytes = Vec; From 811c10561255d6647d0e5af9a3106253b6a6634f Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 16:13:58 +0500 Subject: [PATCH 04/27] add unsigned() to SignedTransaction --- ethcore/transaction/src/transaction.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 06148ca89d1..ca2f31e3674 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -484,6 +484,14 @@ impl SignedTransaction { } } + pub fn unsigned(&self) -> &dyn TransactionShared { + match &self.transaction { + UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &dyn TransactionShared, + UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &dyn TransactionShared, + UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &dyn TransactionShared, + } + } + /// Returns transaction sender. pub fn sender(&self) -> Address { self.sender From cea75e261c443b21c5b07ef8c0b8f73586639bb2 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 18:25:23 +0500 Subject: [PATCH 05/27] add Send to ret type --- ethcore/transaction/src/transaction.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index ca2f31e3674..4afb979d208 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -89,6 +89,8 @@ pub enum Condition { Timestamp(u64), } +type TransactionSharedRet = dyn TransactionShared + Send + 'static; + /// Methods common for all tx versions pub trait TransactionShared { fn nonce(&self) -> U256; @@ -292,11 +294,11 @@ impl UnverifiedTransactionWrapper { }; } - pub fn unsigned(&self) -> &dyn TransactionShared { + pub fn unsigned(&self) -> &TransactionSharedRet { match self { - UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &dyn TransactionShared, - UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &dyn TransactionShared, - UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &dyn TransactionShared, + UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, } } @@ -484,11 +486,11 @@ impl SignedTransaction { } } - pub fn unsigned(&self) -> &dyn TransactionShared { + pub fn unsigned(&self) -> &TransactionSharedRet { match &self.transaction { - UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &dyn TransactionShared, - UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &dyn TransactionShared, - UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &dyn TransactionShared, + UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, } } From 93c99205210e5b661c953d92a253a5566545e039 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 18:47:31 +0500 Subject: [PATCH 06/27] add Sync to ret --- ethcore/transaction/src/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 4afb979d208..b9b41db1f8c 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -89,7 +89,7 @@ pub enum Condition { Timestamp(u64), } -type TransactionSharedRet = dyn TransactionShared + Send + 'static; +type TransactionSharedRet = dyn TransactionShared + Send + Sync + 'static; /// Methods common for all tx versions pub trait TransactionShared { From de10dc6a176960e2a237369c8b9d86da623131ca Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 21:18:27 +0500 Subject: [PATCH 07/27] add unsigned tx builder --- ethcore/transaction/src/transaction.rs | 2 + .../src/transaction/tx_builders.rs | 82 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 ethcore/transaction/src/transaction/tx_builders.rs diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index b9b41db1f8c..fb6b3b2111c 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -27,6 +27,8 @@ use std::convert::TryInto; use std::ops::Deref; mod legacy; +pub mod tx_builders; +pub use self::tx_builders::TransactionWrapperBuilder; pub use self::legacy::{LegacyTransaction, UnverifiedLegacyTransaction}; mod eip2930; pub use self::eip2930::{Eip2930Transaction, UnverifiedEip2930Transaction, EIP2930_TX_TYPE}; diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs new file mode 100644 index 00000000000..7466f5513bb --- /dev/null +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -0,0 +1,82 @@ +//! Transaction builders + +use super::{Bytes, eip2930::AccessList, Action, TransactionWrapper, U256, Eip1559Transaction, LegacyTransaction}; + +pub enum TxBuilderError { + NoGasDetailsSet, +} + +pub struct TransactionWrapperBuilder { + chain_id: Option, + nonce: U256, + gas_price: Option, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + gas: U256, + action: Action, + value: U256, + data: Bytes, + access_list: Option, +} + +impl TransactionWrapperBuilder { + pub fn new(nonce: U256, gas: U256, action: Action, value: U256, data: Bytes) -> Self { + Self { + chain_id: None, + nonce, + gas, + gas_price: None, + max_fee_per_gas: None, + max_priority_fee_per_gas: None, + action, + value, + data, + access_list: None, + } + } + + pub fn with_gas_price(mut self, gas_price: U256) -> Self { + self.gas_price = Some(gas_price); + self + } + + pub fn with_priority_fee_per_gas(mut self, max_fee_per_gas: U256, max_priority_fee_per_gas: U256) -> Self { + self.max_fee_per_gas = Some(max_fee_per_gas); + self.max_priority_fee_per_gas = Some(max_priority_fee_per_gas); + self + } + + pub fn with_access_list(mut self, access_list: AccessList) -> Self { + self.access_list = Some(access_list); + self + } + + pub fn build(self) -> Result { + if let Some(gas_price) = self.gas_price { + Ok(TransactionWrapper::Legacy(LegacyTransaction { + nonce: self.nonce, + gas_price, + gas: self.gas, + action: self.action, + value: self.value, + data: self.data, + })) + + } else if let (Some(max_fee_per_gas), Some(max_priority_fee_per_gas), Some(chain_id)) = + (self.max_fee_per_gas, self.max_priority_fee_per_gas, self.chain_id) { + Ok(TransactionWrapper::Eip1559(Eip1559Transaction { + chain_id, + nonce: self.nonce, + max_fee_per_gas, + max_priority_fee_per_gas, + gas: self.gas, + action: self.action, + value: self.value, + data: self.data, + access_list: if let Some(access_list) = self.access_list { access_list } else { AccessList::default() }, + })) + } else { + Err(TxBuilderError::NoGasDetailsSet) + } + } +} \ No newline at end of file From 8254b533014ff80e28aa8cd280daddc69cd8060c Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 21:23:36 +0500 Subject: [PATCH 08/27] remove eip2930 tx type (supposed won't be used) --- ethcore/transaction/src/transaction.rs | 58 +---- .../transaction/src/transaction/eip1559.rs | 59 ++++- .../transaction/src/transaction/eip2930.rs | 241 ------------------ .../src/transaction/tx_builders.rs | 2 +- 4 files changed, 61 insertions(+), 299 deletions(-) delete mode 100644 ethcore/transaction/src/transaction/eip2930.rs diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index fb6b3b2111c..3e75c8705db 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -26,12 +26,12 @@ use rlp::{self, DecoderError, Rlp, RlpStream}; use std::convert::TryInto; use std::ops::Deref; -mod legacy; pub mod tx_builders; pub use self::tx_builders::TransactionWrapperBuilder; + +mod legacy; pub use self::legacy::{LegacyTransaction, UnverifiedLegacyTransaction}; -mod eip2930; -pub use self::eip2930::{Eip2930Transaction, UnverifiedEip2930Transaction, EIP2930_TX_TYPE}; + mod eip1559; pub use self::eip1559::{Eip1559Transaction, UnverifiedEip1559Transaction, EIP1559_TX_TYPE}; @@ -123,7 +123,6 @@ pub trait SignedTransactionShared { #[derive(Debug, Clone, Eq, PartialEq)] pub enum TransactionWrapper { Legacy(LegacyTransaction), - Eip2930(Eip2930Transaction), Eip1559(Eip1559Transaction), } @@ -132,7 +131,6 @@ impl TransactionWrapper { pub fn message_hash(&self, chain_id: Option) -> H256 { match self { TransactionWrapper::Legacy(tx) => tx.message_hash(chain_id), - TransactionWrapper::Eip2930(tx) => tx.message_hash(None), TransactionWrapper::Eip1559(tx) => tx.message_hash(None), } } @@ -210,7 +208,6 @@ impl TransactionWrapper { #[derive(Debug, Clone, Eq, PartialEq)] pub enum UnverifiedTransactionWrapper { Legacy(UnverifiedLegacyTransaction), - Eip2930(UnverifiedEip2930Transaction), Eip1559(UnverifiedEip1559Transaction), } @@ -219,9 +216,6 @@ impl rlp::Decodable for UnverifiedTransactionWrapper { if is_typed_transaction(d) { // first byte is tx version match d.as_raw()[0] { - EIP2930_TX_TYPE => Ok(UnverifiedTransactionWrapper::Eip2930( - UnverifiedEip2930Transaction::decode(d)?, - )), EIP1559_TX_TYPE => Ok(UnverifiedTransactionWrapper::Eip1559( UnverifiedEip1559Transaction::decode(d)?, )), @@ -252,15 +246,6 @@ impl UnverifiedTransactionWrapper { hash, }) } - TransactionWrapper::Eip2930(unsigned) => { - UnverifiedTransactionWrapper::Eip2930(UnverifiedEip2930Transaction { - unsigned, - r, - s, - v: v.try_into().unwrap(), - hash, - }) - } TransactionWrapper::Eip1559(unsigned) => { UnverifiedTransactionWrapper::Eip1559(UnverifiedEip1559Transaction { unsigned, @@ -278,9 +263,6 @@ impl UnverifiedTransactionWrapper { UnverifiedTransactionWrapper::Legacy(tx) => { UnverifiedTransactionWrapper::Legacy(tx.compute_hash()) } - UnverifiedTransactionWrapper::Eip2930(tx) => { - UnverifiedTransactionWrapper::Eip2930(tx.compute_hash()) - } UnverifiedTransactionWrapper::Eip1559(tx) => { UnverifiedTransactionWrapper::Eip1559(tx.compute_hash()) } @@ -291,7 +273,6 @@ impl UnverifiedTransactionWrapper { fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.rlp_append_sealed_transaction(s), - UnverifiedTransactionWrapper::Eip2930(tx) => tx.rlp_append_sealed_transaction(s), UnverifiedTransactionWrapper::Eip1559(tx) => tx.rlp_append_sealed_transaction(s), }; } @@ -299,7 +280,6 @@ impl UnverifiedTransactionWrapper { pub fn unsigned(&self) -> &TransactionSharedRet { match self { UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, } } @@ -308,7 +288,6 @@ impl UnverifiedTransactionWrapper { pub fn standard_v(&self) -> u8 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.standard_v(), - UnverifiedTransactionWrapper::Eip2930(tx) => tx.standard_v(), UnverifiedTransactionWrapper::Eip1559(tx) => tx.standard_v(), } } @@ -404,7 +383,6 @@ impl UnverifiedTransactionWrapper { fn validate_empty_sig(&self) -> bool { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.validate_eip86(), - UnverifiedTransactionWrapper::Eip2930(_tx) => true, // TODO: what is it for eip2930? UnverifiedTransactionWrapper::Eip1559(_tx) => true, // TODO: what is it for eip1559? } } @@ -412,21 +390,18 @@ impl UnverifiedTransactionWrapper { fn r(&self) -> U256 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.r, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.r, UnverifiedTransactionWrapper::Eip1559(tx) => tx.r, } } fn s(&self) -> U256 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.s, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.s, UnverifiedTransactionWrapper::Eip1559(tx) => tx.s, } } fn v(&self) -> u64 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.network_v, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.v as u64, UnverifiedTransactionWrapper::Eip1559(tx) => tx.v as u64, } } @@ -435,7 +410,6 @@ impl UnverifiedTransactionWrapper { pub fn tx_hash(&self) -> H256 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.hash, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.hash, UnverifiedTransactionWrapper::Eip1559(tx) => tx.hash, } } @@ -491,7 +465,6 @@ impl SignedTransaction { pub fn unsigned(&self) -> &TransactionSharedRet { match &self.transaction { UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, } } @@ -722,31 +695,6 @@ mod tests { test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"); } - #[test] - fn tx_type_1_parse_tx() { - use rustc_hex::FromHex; - - let test_vector = |tx_data: &str, address: &'static str, hash: &'static str| { - let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); - let unverified = rlp::decode(&bytes).expect("decoding tx data failed"); - let signed = SignedTransaction::new(unverified).unwrap(); - - let expected_addr = Address::from_str(address).unwrap(); - assert_eq!(signed.sender(), expected_addr); - let expected_hash = H256::from_str(hash).unwrap(); - let unverified_tx = signed.transaction.clone().compute_hash(); - assert_eq!(unverified_tx.tx_hash(), expected_hash); - - if let UnverifiedTransactionWrapper::Eip2930(tx) = signed.transaction { - println!("chainid: {:?}", tx.chain_id); - } else { - panic!("expected tx type 1 (eip-2930)"); - } - }; - // type 1, empty access list - test_vector("01f87201830180058504375e83908307a120942f3e89bb84705085dd2afc1f00ca5f823ff7f6088801aaaf118d612c0080c080a04f08e11860459e944e28a39193b76cc2ca0566bea40c086160f6c44ce43dd6fca07333d8b6c872a4d599cb4027c9129941c2691f09ce1cbea361a827bc30e78e54", "0x264bd8291fAE1D75DB2c5F573b07faA6715997B5", "0xe9b033c089745a1b70003586e8a1fbdb59d407c5943f00193d5c562194042524"); - } - #[test] fn eip1559_parse_tx() { use rustc_hex::FromHex; diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs index c8bfad4e2aa..860869af949 100644 --- a/ethcore/transaction/src/transaction/eip1559.rs +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -2,9 +2,8 @@ // //! Eip 1559 transaction encoding/decoding and specific checks -use super::eip2930::AccessList; use super::SignedTransactionShared; -use super::{Action, Bytes, TransactionShared}; +use super::{Address, Action, Bytes, TransactionShared}; use ethereum_types::{H256, U256}; use hash::keccak; use rlp::{self, DecoderError, Rlp, RlpStream}; @@ -12,6 +11,62 @@ use std::{convert::TryInto, ops::Deref}; pub const EIP1559_TX_TYPE: u8 = 2; +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +pub struct AccessListItem { + /// Account addresses that would be loaded at the start of execution + pub address: Address, + /// Keys of storage that would be loaded at the start of execution + pub storage_keys: Vec, +} + +impl rlp::Decodable for AccessListItem { + fn decode(d: &Rlp) -> Result { + let address = Address::decode(&d.at(0)?)?; + let keys_rlp = d.at(1)?; + let mut storage_keys: Vec = vec![]; + for i in 0..keys_rlp.item_count()? { + storage_keys.push(H256::decode(&keys_rlp.at(i)?)?); + } + Ok(AccessListItem { address, storage_keys }) + } +} + +impl rlp::Encodable for AccessListItem { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.address); + + s.begin_list(self.storage_keys.len()); + for i in 0..self.storage_keys.len() { + s.append(&self.storage_keys[i]); + } + } +} + +/// AccessList as defined in EIP-2930 +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +pub struct AccessList(pub Vec); + +impl rlp::Decodable for AccessList { + fn decode(d: &Rlp) -> Result { + let mut items: Vec = vec![]; + for i in 0..d.item_count()? { + let item = AccessListItem::decode(&d.at(i)?)?; + items.push(item); + } + Ok(AccessList(items)) + } +} + +impl rlp::Encodable for AccessList { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(self.0.len()); + for i in 0..self.0.len() { + s.append(&self.0[i]); + } + } +} + /// A set of information describing an externally-originating message call /// or contract creation operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs deleted file mode 100644 index beb38b8adf7..00000000000 --- a/ethcore/transaction/src/transaction/eip2930.rs +++ /dev/null @@ -1,241 +0,0 @@ -// This source is derived from Parity code -// -//! Eip 2930 transaction encoding/decoding and specific checks - -use super::{Action, Bytes, TransactionShared}; -use crate::SignedTransactionShared; -use ethereum_types::{Address, H256, U256}; -use hash::keccak; -use rlp::{self, DecoderError, Rlp, RlpStream}; -use std::{convert::TryInto, ops::Deref}; - -pub const EIP2930_TX_TYPE: u8 = 1; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] -pub struct AccessListItem { - /// Account addresses that would be loaded at the start of execution - pub address: Address, - /// Keys of storage that would be loaded at the start of execution - pub storage_keys: Vec, -} - -impl rlp::Decodable for AccessListItem { - fn decode(d: &Rlp) -> Result { - let address = Address::decode(&d.at(0)?)?; - let keys_rlp = d.at(1)?; - let mut storage_keys: Vec = vec![]; - for i in 0..keys_rlp.item_count()? { - storage_keys.push(H256::decode(&keys_rlp.at(i)?)?); - } - Ok(AccessListItem { address, storage_keys }) - } -} - -impl rlp::Encodable for AccessListItem { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.address); - - s.begin_list(self.storage_keys.len()); - for i in 0..self.storage_keys.len() { - s.append(&self.storage_keys[i]); - } - } -} - -/// AccessList as defined in EIP-2930 -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] -pub struct AccessList(pub Vec); - -impl rlp::Decodable for AccessList { - fn decode(d: &Rlp) -> Result { - let mut items: Vec = vec![]; - for i in 0..d.item_count()? { - let item = AccessListItem::decode(&d.at(i)?)?; - items.push(item); - } - Ok(AccessList(items)) - } -} - -impl rlp::Encodable for AccessList { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(self.0.len()); - for i in 0..self.0.len() { - s.append(&self.0[i]); - } - } -} - -/// A set of information describing an externally-originating message call -/// or contract creation operation. -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct Eip2930Transaction { - /// Simple replay attack protection - pub chain_id: u64, - /// Nonce. - pub nonce: U256, - /// Gas price. - pub gas_price: U256, - /// Gas paid up front for transaction execution. - pub gas: U256, - /// Action, can be either call or contract create. - pub action: Action, - /// Transfered value. - pub value: U256, - /// Transaction data. - pub data: Bytes, - /// Access list. - pub access_list: AccessList, -} - -impl Eip2930Transaction { - const fn payload_length(&self) -> usize { - 8 - } - - /// Append object with a without signature into RLP stream - fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { - s.append(&EIP2930_TX_TYPE); - s.begin_list(self.payload_length()); - s.append(&self.chain_id); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - s.append(&self.access_list); - } -} - -impl TransactionShared for Eip2930Transaction { - fn nonce(&self) -> U256 { - self.nonce - } - fn action(&self) -> &Action { - &self.action - } - fn value(&self) -> U256 { - self.value - } - fn data(&self) -> &Bytes { - &self.data - } - /// The message hash of the transaction. - fn message_hash(&self, _chain_id: Option) -> H256 { - let mut stream = RlpStream::new(); - self.rlp_append_unsigned_transaction(&mut stream); - keccak(stream.as_raw()) - } -} - -impl rlp::Decodable for Eip2930Transaction { - fn decode(d: &Rlp) -> Result { - if d.as_raw().len() < 2 { - return Err(DecoderError::RlpIsTooShort); - } - let version: u8 = d.as_raw()[0]; - if version != EIP2930_TX_TYPE { - return Err(DecoderError::Custom("bad tx version")); - } - let list = Rlp::new(&d.as_raw()[1..]); - Ok(Eip2930Transaction { - chain_id: list.val_at(0)?, - nonce: list.val_at(1)?, - gas_price: list.val_at(2)?, - gas: list.val_at(3)?, - action: list.val_at(4)?, - value: list.val_at(5)?, - data: list.val_at(6)?, - access_list: list.val_at(7)?, - }) - } -} - -/// Signed transaction information without verified signature. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct UnverifiedEip2930Transaction { - /// Plain Transaction. - pub unsigned: Eip2930Transaction, - /// The V field of the signature - pub v: u64, - /// The R field of the signature; helps describe the point on the curve. - pub r: U256, - /// The S field of the signature; helps describe the point on the curve. - pub s: U256, - /// Hash of the transaction - pub hash: H256, -} - -impl Deref for UnverifiedEip2930Transaction { - type Target = Eip2930Transaction; - - fn deref(&self) -> &Self::Target { - &self.unsigned - } -} - -impl rlp::Decodable for UnverifiedEip2930Transaction { - fn decode(d: &Rlp) -> Result { - let unsigned = Eip2930Transaction::decode(d)?; - let hash = keccak(d.as_raw()); - let offset = unsigned.payload_length(); - if d.as_raw().len() < 1 { - return Err(DecoderError::RlpIsTooShort); - } - let list = Rlp::new(&d.as_raw()[1..]); - Ok(UnverifiedEip2930Transaction { - unsigned, - v: list.val_at(offset)?, - r: list.val_at(offset + 1)?, - s: list.val_at(offset + 2)?, - hash, - }) - } -} - -impl rlp::Encodable for UnverifiedEip2930Transaction { - fn rlp_append(&self, s: &mut RlpStream) { - self.rlp_append_sealed_transaction(s) - } -} - -impl SignedTransactionShared for UnverifiedEip2930Transaction { - fn set_hash(&mut self, hash: H256) { - self.hash = hash; - } -} - -impl UnverifiedEip2930Transaction { - /// tx list item count - fn payload_length(&self) -> usize { - self.unsigned.payload_length() + 3 - } - - /// Append object with a signature into RLP stream - pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { - s.append(&EIP2930_TX_TYPE); - s.begin_list(self.payload_length()); - s.append(&self.chain_id); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - s.append(&self.access_list); - s.append(&self.v); - s.append(&self.r); - s.append(&self.s); - } - - pub fn standard_v(&self) -> u8 { - self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns - } - - // EIP-86 or newer: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. - pub(crate) fn _validate_empty_sig(&self) -> bool { - true // TODO fix for eip2930 - } -} diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs index 7466f5513bb..7e43d0c85e1 100644 --- a/ethcore/transaction/src/transaction/tx_builders.rs +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -1,6 +1,6 @@ //! Transaction builders -use super::{Bytes, eip2930::AccessList, Action, TransactionWrapper, U256, Eip1559Transaction, LegacyTransaction}; +use super::{Bytes, eip1559::AccessList, Action, TransactionWrapper, U256, Eip1559Transaction, LegacyTransaction}; pub enum TxBuilderError { NoGasDetailsSet, From c2d6a335abd0cbfd0e343b2e642a666f99935f3d Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 21:45:14 +0500 Subject: [PATCH 09/27] add debug to tx builder error --- ethcore/transaction/src/transaction/tx_builders.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs index 7e43d0c85e1..a2729d1301f 100644 --- a/ethcore/transaction/src/transaction/tx_builders.rs +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -2,8 +2,10 @@ use super::{Bytes, eip1559::AccessList, Action, TransactionWrapper, U256, Eip1559Transaction, LegacyTransaction}; +#[derive(Debug, PartialEq, Clone)] pub enum TxBuilderError { - NoGasDetailsSet, + /// No gas price or pricority fee per gas set + NoGasPriceSet, } pub struct TransactionWrapperBuilder { @@ -76,7 +78,7 @@ impl TransactionWrapperBuilder { access_list: if let Some(access_list) = self.access_list { access_list } else { AccessList::default() }, })) } else { - Err(TxBuilderError::NoGasDetailsSet) + Err(TxBuilderError::NoGasPriceSet) } } } \ No newline at end of file From 6f9ab8a418cf9c2accc7330a28cd74c415ea5840 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 4 Mar 2024 21:45:42 +0500 Subject: [PATCH 10/27] fix fmt --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index e69de29bb2d..8b137891791 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1 @@ + From cfcb4c28a39e6cdeeda6b6b9e8f2cc27278fafbd Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 5 Mar 2024 12:41:19 +0500 Subject: [PATCH 11/27] add with_chain_id --- .../transaction/src/transaction/tx_builders.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs index a2729d1301f..71e95ac1985 100644 --- a/ethcore/transaction/src/transaction/tx_builders.rs +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -4,8 +4,10 @@ use super::{Bytes, eip1559::AccessList, Action, TransactionWrapper, U256, Eip155 #[derive(Debug, PartialEq, Clone)] pub enum TxBuilderError { - /// No gas price or pricority fee per gas set + /// No gas price or priority fee per gas set NoGasPriceSet, + /// Chain_id must be set for tx type >= 1 + NoChainIdSet, } pub struct TransactionWrapperBuilder { @@ -37,6 +39,11 @@ impl TransactionWrapperBuilder { } } + pub fn with_chain_id(mut self, chain_id: u64) -> Self { + self.chain_id = Some(chain_id); + self + } + pub fn with_gas_price(mut self, gas_price: U256) -> Self { self.gas_price = Some(gas_price); self @@ -78,7 +85,11 @@ impl TransactionWrapperBuilder { access_list: if let Some(access_list) = self.access_list { access_list } else { AccessList::default() }, })) } else { - Err(TxBuilderError::NoGasPriceSet) + if !matches!(self.chain_id, Some(_chain_id)) { + Err(TxBuilderError::NoChainIdSet) + } else { + Err(TxBuilderError::NoGasPriceSet) + } } } } \ No newline at end of file From ea2690a7057f433bf2105d9f545b207526dbdbeb Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 5 Mar 2024 14:02:18 +0500 Subject: [PATCH 12/27] add Display for TxBuilderError --- ethcore/transaction/src/transaction/tx_builders.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs index 71e95ac1985..b1112d53940 100644 --- a/ethcore/transaction/src/transaction/tx_builders.rs +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -1,15 +1,25 @@ //! Transaction builders - +use std::fmt; use super::{Bytes, eip1559::AccessList, Action, TransactionWrapper, U256, Eip1559Transaction, LegacyTransaction}; #[derive(Debug, PartialEq, Clone)] pub enum TxBuilderError { /// No gas price or priority fee per gas set NoGasPriceSet, - /// Chain_id must be set for tx type >= 1 + /// Chain id must be set for tx type >= 1 NoChainIdSet, } +impl fmt::Display for TxBuilderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let msg: String = match *self { + TxBuilderError::NoGasPriceSet => "No gas price or priority fee per gas set".into(), + TxBuilderError::NoChainIdSet => "Chain id must be set".into(), + }; + f.write_fmt(format_args!("Transaction builder error ({})", msg)) + } +} + pub struct TransactionWrapperBuilder { chain_id: Option, nonce: U256, From b0aa2939be0a2ee120cf3c0ab559f8ef36ef1e71 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 23 Mar 2024 17:00:35 +0500 Subject: [PATCH 13/27] disable eip-86 code --- ethcore/transaction/src/transaction.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 3e75c8705db..6a79ad74fb9 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -381,11 +381,13 @@ impl UnverifiedTransactionWrapper { /// validate tx with empty signature fn validate_empty_sig(&self) -> bool { + /* looks like EIP-86 is not actual match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.validate_eip86(), - UnverifiedTransactionWrapper::Eip1559(_tx) => true, // TODO: what is it for eip1559? - } - } + UnverifiedTransactionWrapper::Eip1559(_tx) => true, + } */ + false + } fn r(&self) -> U256 { match self { From b426feac9e58a288d2394202400fd534a7132740 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 23 Mar 2024 17:09:32 +0500 Subject: [PATCH 14/27] remove more eip-86 unused code --- ethcore/transaction/src/transaction.rs | 6 +----- ethcore/transaction/src/transaction/eip1559.rs | 5 ----- ethcore/transaction/src/transaction/legacy.rs | 5 ----- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 6a79ad74fb9..7eefd4fa8d3 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -381,11 +381,7 @@ impl UnverifiedTransactionWrapper { /// validate tx with empty signature fn validate_empty_sig(&self) -> bool { - /* looks like EIP-86 is not actual - match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.validate_eip86(), - UnverifiedTransactionWrapper::Eip1559(_tx) => true, - } */ + // Note: EIP-86 code was removed false } diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs index 860869af949..5389e755360 100644 --- a/ethcore/transaction/src/transaction/eip1559.rs +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -238,9 +238,4 @@ impl UnverifiedEip1559Transaction { pub fn standard_v(&self) -> u8 { self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns } - - // EIP-86 or newer: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. - pub(crate) fn _validate_empty_sig(&self) -> bool { - true // TODO fix for eip1559 - } } diff --git a/ethcore/transaction/src/transaction/legacy.rs b/ethcore/transaction/src/transaction/legacy.rs index 1450ff1c2c8..aeac2e39b23 100644 --- a/ethcore/transaction/src/transaction/legacy.rs +++ b/ethcore/transaction/src/transaction/legacy.rs @@ -163,11 +163,6 @@ impl UnverifiedLegacyTransaction { pub fn to_network_v(v: u64, chain_id: Option) -> u64 { eip155_methods::add_chain_replay_protection(v, chain_id) } - - // EIP-86: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. - pub(crate) fn validate_eip86(&self) -> bool { - self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero() - } } /// Replay protection logic for v part of transaction's signature From 78000fabd9a03e3087667053692a340439dde2d6 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 24 Mar 2024 19:59:39 +0500 Subject: [PATCH 15/27] restored tx type 1 eip2930 support, added TxType enum --- ethcore/transaction/src/transaction.rs | 89 ++++++- .../transaction/src/transaction/eip1559.rs | 67 +---- .../transaction/src/transaction/eip2930.rs | 239 ++++++++++++++++++ .../src/transaction/tx_builders.rs | 188 ++++++++------ 4 files changed, 438 insertions(+), 145 deletions(-) create mode 100644 ethcore/transaction/src/transaction/eip2930.rs diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 7eefd4fa8d3..b91f299440e 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -26,18 +26,38 @@ use rlp::{self, DecoderError, Rlp, RlpStream}; use std::convert::TryInto; use std::ops::Deref; -pub mod tx_builders; -pub use self::tx_builders::TransactionWrapperBuilder; - mod legacy; +pub mod tx_builders; pub use self::legacy::{LegacyTransaction, UnverifiedLegacyTransaction}; - +pub use self::tx_builders::TransactionWrapperBuilder; +mod eip2930; +pub use self::eip2930::{ + AccessList, AccessListItem, Eip2930Transaction, UnverifiedEip2930Transaction, +}; mod eip1559; -pub use self::eip1559::{Eip1559Transaction, UnverifiedEip1559Transaction, EIP1559_TX_TYPE}; +pub use self::eip1559::{Eip1559Transaction, UnverifiedEip1559Transaction}; type BlockNumber = u64; type Bytes = Vec; +#[derive(PartialEq)] +pub enum TxType { + Legacy, + Type1 = 1, + Type2 = 2, + Invalid, +} + +impl From for TxType { + fn from(v: u8) -> Self { + match v { + 1 => TxType::Type1, + 2 => TxType::Type2, + _ => TxType::Invalid, + } + } +} + /// Fake address for unsigned transactions as defined by EIP-86. pub const UNSIGNED_SENDER: Address = H160([0xff; 20]); @@ -123,6 +143,7 @@ pub trait SignedTransactionShared { #[derive(Debug, Clone, Eq, PartialEq)] pub enum TransactionWrapper { Legacy(LegacyTransaction), + Eip2930(Eip2930Transaction), Eip1559(Eip1559Transaction), } @@ -131,6 +152,7 @@ impl TransactionWrapper { pub fn message_hash(&self, chain_id: Option) -> H256 { match self { TransactionWrapper::Legacy(tx) => tx.message_hash(chain_id), + TransactionWrapper::Eip2930(tx) => tx.message_hash(None), TransactionWrapper::Eip1559(tx) => tx.message_hash(None), } } @@ -208,6 +230,7 @@ impl TransactionWrapper { #[derive(Debug, Clone, Eq, PartialEq)] pub enum UnverifiedTransactionWrapper { Legacy(UnverifiedLegacyTransaction), + Eip2930(UnverifiedEip2930Transaction), Eip1559(UnverifiedEip1559Transaction), } @@ -215,8 +238,11 @@ impl rlp::Decodable for UnverifiedTransactionWrapper { fn decode(d: &Rlp) -> Result { if is_typed_transaction(d) { // first byte is tx version - match d.as_raw()[0] { - EIP1559_TX_TYPE => Ok(UnverifiedTransactionWrapper::Eip1559( + match TxType::from(d.as_raw()[0]) { + TxType::Type1 => Ok(UnverifiedTransactionWrapper::Eip2930( + UnverifiedEip2930Transaction::decode(d)?, + )), + TxType::Type2 => Ok(UnverifiedTransactionWrapper::Eip1559( UnverifiedEip1559Transaction::decode(d)?, )), _ => Err(DecoderError::Custom("unsupported tx version")), @@ -246,6 +272,15 @@ impl UnverifiedTransactionWrapper { hash, }) } + TransactionWrapper::Eip2930(unsigned) => { + UnverifiedTransactionWrapper::Eip2930(UnverifiedEip2930Transaction { + unsigned, + r, + s, + v: v.try_into().unwrap(), + hash, + }) + } TransactionWrapper::Eip1559(unsigned) => { UnverifiedTransactionWrapper::Eip1559(UnverifiedEip1559Transaction { unsigned, @@ -263,6 +298,9 @@ impl UnverifiedTransactionWrapper { UnverifiedTransactionWrapper::Legacy(tx) => { UnverifiedTransactionWrapper::Legacy(tx.compute_hash()) } + UnverifiedTransactionWrapper::Eip2930(tx) => { + UnverifiedTransactionWrapper::Eip2930(tx.compute_hash()) + } UnverifiedTransactionWrapper::Eip1559(tx) => { UnverifiedTransactionWrapper::Eip1559(tx.compute_hash()) } @@ -273,6 +311,7 @@ impl UnverifiedTransactionWrapper { fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.rlp_append_sealed_transaction(s), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.rlp_append_sealed_transaction(s), UnverifiedTransactionWrapper::Eip1559(tx) => tx.rlp_append_sealed_transaction(s), }; } @@ -280,6 +319,7 @@ impl UnverifiedTransactionWrapper { pub fn unsigned(&self) -> &TransactionSharedRet { match self { UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, } } @@ -288,6 +328,7 @@ impl UnverifiedTransactionWrapper { pub fn standard_v(&self) -> u8 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.standard_v(), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.standard_v(), UnverifiedTransactionWrapper::Eip1559(tx) => tx.standard_v(), } } @@ -381,25 +422,28 @@ impl UnverifiedTransactionWrapper { /// validate tx with empty signature fn validate_empty_sig(&self) -> bool { - // Note: EIP-86 code was removed + // Note: EIP-86 code was removed false - } + } fn r(&self) -> U256 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.r, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.r, UnverifiedTransactionWrapper::Eip1559(tx) => tx.r, } } fn s(&self) -> U256 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.s, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.s, UnverifiedTransactionWrapper::Eip1559(tx) => tx.s, } } fn v(&self) -> u64 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.network_v, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.v as u64, UnverifiedTransactionWrapper::Eip1559(tx) => tx.v as u64, } } @@ -408,6 +452,7 @@ impl UnverifiedTransactionWrapper { pub fn tx_hash(&self) -> H256 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.hash, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.hash, UnverifiedTransactionWrapper::Eip1559(tx) => tx.hash, } } @@ -463,6 +508,7 @@ impl SignedTransaction { pub fn unsigned(&self) -> &TransactionSharedRet { match &self.transaction { UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, } } @@ -693,6 +739,31 @@ mod tests { test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"); } + #[test] + fn tx_type_1_parse_tx() { + use rustc_hex::FromHex; + + let test_vector = |tx_data: &str, address: &'static str, hash: &'static str| { + let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); + let unverified = rlp::decode(&bytes).expect("decoding tx data failed"); + let signed = SignedTransaction::new(unverified).unwrap(); + + let expected_addr = Address::from_str(address).unwrap(); + assert_eq!(signed.sender(), expected_addr); + let expected_hash = H256::from_str(hash).unwrap(); + let unverified_tx = signed.transaction.clone().compute_hash(); + assert_eq!(unverified_tx.tx_hash(), expected_hash); + + if let UnverifiedTransactionWrapper::Eip2930(tx) = signed.transaction { + println!("chainid: {:?}", tx.chain_id); + } else { + panic!("expected tx type 1 (eip-2930)"); + } + }; + // type 1, empty access list + test_vector("01f87201830180058504375e83908307a120942f3e89bb84705085dd2afc1f00ca5f823ff7f6088801aaaf118d612c0080c080a04f08e11860459e944e28a39193b76cc2ca0566bea40c086160f6c44ce43dd6fca07333d8b6c872a4d599cb4027c9129941c2691f09ce1cbea361a827bc30e78e54", "0x264bd8291fAE1D75DB2c5F573b07faA6715997B5", "0xe9b033c089745a1b70003586e8a1fbdb59d407c5943f00193d5c562194042524"); + } + #[test] fn eip1559_parse_tx() { use rustc_hex::FromHex; diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs index 5389e755360..9f9fbb3ce21 100644 --- a/ethcore/transaction/src/transaction/eip1559.rs +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -2,71 +2,14 @@ // //! Eip 1559 transaction encoding/decoding and specific checks +use super::AccessList; use super::SignedTransactionShared; -use super::{Address, Action, Bytes, TransactionShared}; +use super::{Action, Bytes, TransactionShared, TxType}; use ethereum_types::{H256, U256}; use hash::keccak; use rlp::{self, DecoderError, Rlp, RlpStream}; use std::{convert::TryInto, ops::Deref}; -pub const EIP1559_TX_TYPE: u8 = 2; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] -pub struct AccessListItem { - /// Account addresses that would be loaded at the start of execution - pub address: Address, - /// Keys of storage that would be loaded at the start of execution - pub storage_keys: Vec, -} - -impl rlp::Decodable for AccessListItem { - fn decode(d: &Rlp) -> Result { - let address = Address::decode(&d.at(0)?)?; - let keys_rlp = d.at(1)?; - let mut storage_keys: Vec = vec![]; - for i in 0..keys_rlp.item_count()? { - storage_keys.push(H256::decode(&keys_rlp.at(i)?)?); - } - Ok(AccessListItem { address, storage_keys }) - } -} - -impl rlp::Encodable for AccessListItem { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.address); - - s.begin_list(self.storage_keys.len()); - for i in 0..self.storage_keys.len() { - s.append(&self.storage_keys[i]); - } - } -} - -/// AccessList as defined in EIP-2930 -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] -pub struct AccessList(pub Vec); - -impl rlp::Decodable for AccessList { - fn decode(d: &Rlp) -> Result { - let mut items: Vec = vec![]; - for i in 0..d.item_count()? { - let item = AccessListItem::decode(&d.at(i)?)?; - items.push(item); - } - Ok(AccessList(items)) - } -} - -impl rlp::Encodable for AccessList { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(self.0.len()); - for i in 0..self.0.len() { - s.append(&self.0[i]); - } - } -} - /// A set of information describing an externally-originating message call /// or contract creation operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] @@ -98,7 +41,7 @@ impl Eip1559Transaction { /// Append object with a without signature into RLP stream fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { - s.append(&EIP1559_TX_TYPE); + s.append(&(TxType::Type2 as u8)); s.begin_list(self.payload_length()); s.append(&self.chain_id); s.append(&self.nonce); @@ -139,7 +82,7 @@ impl rlp::Decodable for Eip1559Transaction { return Err(DecoderError::RlpIsTooShort); } let version: u8 = d.as_raw()[0]; - if version != EIP1559_TX_TYPE { + if TxType::from(version) != TxType::Type2 { return Err(DecoderError::Custom("bad tx version")); } let list = Rlp::new(&d.as_raw()[1..]); @@ -219,7 +162,7 @@ impl UnverifiedEip1559Transaction { /// Append object with a signature into RLP stream pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { - s.append(&EIP1559_TX_TYPE); + s.append(&(TxType::Type2 as u8)); s.begin_list(self.payload_length()); s.append(&self.chain_id); s.append(&self.nonce); diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs new file mode 100644 index 00000000000..61356a4387e --- /dev/null +++ b/ethcore/transaction/src/transaction/eip2930.rs @@ -0,0 +1,239 @@ +// This source is derived from Parity code +// +//! Eip 2930 transaction encoding/decoding and specific checks + +use super::{Action, Bytes, TransactionShared, TxType}; +use crate::SignedTransactionShared; +use ethereum_types::{Address, H256, U256}; +use hash::keccak; +use rlp::{self, DecoderError, Rlp, RlpStream}; +use std::{convert::TryInto, ops::Deref}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +pub struct AccessListItem { + /// Account addresses that would be loaded at the start of execution + pub address: Address, + /// Keys of storage that would be loaded at the start of execution + pub storage_keys: Vec, +} + +impl rlp::Decodable for AccessListItem { + fn decode(d: &Rlp) -> Result { + let address = Address::decode(&d.at(0)?)?; + let keys_rlp = d.at(1)?; + let mut storage_keys: Vec = vec![]; + for i in 0..keys_rlp.item_count()? { + storage_keys.push(H256::decode(&keys_rlp.at(i)?)?); + } + Ok(AccessListItem { address, storage_keys }) + } +} + +impl rlp::Encodable for AccessListItem { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.address); + + s.begin_list(self.storage_keys.len()); + for i in 0..self.storage_keys.len() { + s.append(&self.storage_keys[i]); + } + } +} + +/// AccessList as defined in EIP-2930 +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +pub struct AccessList(pub Vec); + +impl rlp::Decodable for AccessList { + fn decode(d: &Rlp) -> Result { + let mut items: Vec = vec![]; + for i in 0..d.item_count()? { + let item = AccessListItem::decode(&d.at(i)?)?; + items.push(item); + } + Ok(AccessList(items)) + } +} + +impl rlp::Encodable for AccessList { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(self.0.len()); + for i in 0..self.0.len() { + s.append(&self.0[i]); + } + } +} + +/// A set of information describing an externally-originating message call +/// or contract creation operation. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct Eip2930Transaction { + /// Simple replay attack protection + pub chain_id: u64, + /// Nonce. + pub nonce: U256, + /// Gas price. + pub gas_price: U256, + /// Gas paid up front for transaction execution. + pub gas: U256, + /// Action, can be either call or contract create. + pub action: Action, + /// Transfered value. + pub value: U256, + /// Transaction data. + pub data: Bytes, + /// Access list. + pub access_list: AccessList, +} + +impl Eip2930Transaction { + const fn payload_length(&self) -> usize { + 8 + } + + /// Append object with a without signature into RLP stream + fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { + s.append(&(TxType::Type1 as u8)); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + } +} + +impl TransactionShared for Eip2930Transaction { + fn nonce(&self) -> U256 { + self.nonce + } + fn action(&self) -> &Action { + &self.action + } + fn value(&self) -> U256 { + self.value + } + fn data(&self) -> &Bytes { + &self.data + } + /// The message hash of the transaction. + fn message_hash(&self, _chain_id: Option) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream); + keccak(stream.as_raw()) + } +} + +impl rlp::Decodable for Eip2930Transaction { + fn decode(d: &Rlp) -> Result { + if d.as_raw().len() < 2 { + return Err(DecoderError::RlpIsTooShort); + } + let version: u8 = d.as_raw()[0]; + if TxType::from(version) != TxType::Type1 { + return Err(DecoderError::Custom("bad tx version")); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(Eip2930Transaction { + chain_id: list.val_at(0)?, + nonce: list.val_at(1)?, + gas_price: list.val_at(2)?, + gas: list.val_at(3)?, + action: list.val_at(4)?, + value: list.val_at(5)?, + data: list.val_at(6)?, + access_list: list.val_at(7)?, + }) + } +} + +/// Signed transaction information without verified signature. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UnverifiedEip2930Transaction { + /// Plain Transaction. + pub unsigned: Eip2930Transaction, + /// The V field of the signature + pub v: u64, + /// The R field of the signature; helps describe the point on the curve. + pub r: U256, + /// The S field of the signature; helps describe the point on the curve. + pub s: U256, + /// Hash of the transaction + pub hash: H256, +} + +impl Deref for UnverifiedEip2930Transaction { + type Target = Eip2930Transaction; + + fn deref(&self) -> &Self::Target { + &self.unsigned + } +} + +impl rlp::Decodable for UnverifiedEip2930Transaction { + fn decode(d: &Rlp) -> Result { + let unsigned = Eip2930Transaction::decode(d)?; + let hash = keccak(d.as_raw()); + let offset = unsigned.payload_length(); + if d.as_raw().len() < 1 { + return Err(DecoderError::RlpIsTooShort); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(UnverifiedEip2930Transaction { + unsigned, + v: list.val_at(offset)?, + r: list.val_at(offset + 1)?, + s: list.val_at(offset + 2)?, + hash, + }) + } +} + +impl rlp::Encodable for UnverifiedEip2930Transaction { + fn rlp_append(&self, s: &mut RlpStream) { + self.rlp_append_sealed_transaction(s) + } +} + +impl SignedTransactionShared for UnverifiedEip2930Transaction { + fn set_hash(&mut self, hash: H256) { + self.hash = hash; + } +} + +impl UnverifiedEip2930Transaction { + /// tx list item count + fn payload_length(&self) -> usize { + self.unsigned.payload_length() + 3 + } + + /// Append object with a signature into RLP stream + pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + s.append(&(TxType::Type1 as u8)); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + s.append(&self.v); + s.append(&self.r); + s.append(&self.s); + } + + pub fn standard_v(&self) -> u8 { + self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns + } + + // EIP-86 or newer: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. + pub(crate) fn _validate_empty_sig(&self) -> bool { + true // TODO fix for eip2930 + } +} diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs index b1112d53940..af6123af3dc 100644 --- a/ethcore/transaction/src/transaction/tx_builders.rs +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -1,29 +1,39 @@ //! Transaction builders +use super::{ + AccessList, Action, Bytes, Eip1559Transaction, Eip2930Transaction, LegacyTransaction, + TransactionWrapper, TxType, U256, +}; use std::fmt; -use super::{Bytes, eip1559::AccessList, Action, TransactionWrapper, U256, Eip1559Transaction, LegacyTransaction}; #[derive(Debug, PartialEq, Clone)] pub enum TxBuilderError { - /// No gas price or priority fee per gas set - NoGasPriceSet, - /// Chain id must be set for tx type >= 1 - NoChainIdSet, + /// Invalid tx type + InvalidTxType, + /// No gas price + NoGasPriceSet, + /// No max gas fee or priority fee set + NoFeePerGasSet, + /// Chain id must be set for tx type >= 1 + NoChainIdSet, } impl fmt::Display for TxBuilderError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let msg: String = match *self { - TxBuilderError::NoGasPriceSet => "No gas price or priority fee per gas set".into(), + TxBuilderError::InvalidTxType => "Invalid transaction type set".into(), + TxBuilderError::NoGasPriceSet => "No gas price set".into(), + TxBuilderError::NoFeePerGasSet => "No gas fee or priority fee per gas set".into(), TxBuilderError::NoChainIdSet => "Chain id must be set".into(), - }; - f.write_fmt(format_args!("Transaction builder error ({})", msg)) - } + }; + f.write_fmt(format_args!("Transaction builder error ({})", msg)) + } } pub struct TransactionWrapperBuilder { + tx_type: TxType, chain_id: Option, nonce: U256, - gas_price: Option, + gas_price: Option, max_fee_per_gas: Option, max_priority_fee_per_gas: Option, gas: U256, @@ -34,72 +44,102 @@ pub struct TransactionWrapperBuilder { } impl TransactionWrapperBuilder { - pub fn new(nonce: U256, gas: U256, action: Action, value: U256, data: Bytes) -> Self { - Self { - chain_id: None, - nonce, - gas, - gas_price: None, - max_fee_per_gas: None, - max_priority_fee_per_gas: None, - action, - value, - data, - access_list: None, - } - } + pub fn new( + tx_type: TxType, + nonce: U256, + gas: U256, + action: Action, + value: U256, + data: Bytes, + ) -> Self { + Self { + tx_type, + chain_id: None, + nonce, + gas, + gas_price: None, + max_fee_per_gas: None, + max_priority_fee_per_gas: None, + action, + value, + data, + access_list: None, + } + } - pub fn with_chain_id(mut self, chain_id: u64) -> Self { - self.chain_id = Some(chain_id); - self - } + pub fn with_chain_id(mut self, chain_id: u64) -> Self { + self.chain_id = Some(chain_id); + self + } - pub fn with_gas_price(mut self, gas_price: U256) -> Self { - self.gas_price = Some(gas_price); - self - } + pub fn with_gas_price(mut self, gas_price: U256) -> Self { + self.gas_price = Some(gas_price); + self + } - pub fn with_priority_fee_per_gas(mut self, max_fee_per_gas: U256, max_priority_fee_per_gas: U256) -> Self { - self.max_fee_per_gas = Some(max_fee_per_gas); - self.max_priority_fee_per_gas = Some(max_priority_fee_per_gas); - self - } + pub fn with_priority_fee_per_gas( + mut self, + max_fee_per_gas: U256, + max_priority_fee_per_gas: U256, + ) -> Self { + self.max_fee_per_gas = Some(max_fee_per_gas); + self.max_priority_fee_per_gas = Some(max_priority_fee_per_gas); + self + } - pub fn with_access_list(mut self, access_list: AccessList) -> Self { - self.access_list = Some(access_list); - self - } + pub fn with_access_list(mut self, access_list: AccessList) -> Self { + self.access_list = Some(access_list); + self + } - pub fn build(self) -> Result { - if let Some(gas_price) = self.gas_price { - Ok(TransactionWrapper::Legacy(LegacyTransaction { - nonce: self.nonce, - gas_price, - gas: self.gas, - action: self.action, - value: self.value, - data: self.data, - })) - - } else if let (Some(max_fee_per_gas), Some(max_priority_fee_per_gas), Some(chain_id)) = - (self.max_fee_per_gas, self.max_priority_fee_per_gas, self.chain_id) { - Ok(TransactionWrapper::Eip1559(Eip1559Transaction { - chain_id, - nonce: self.nonce, - max_fee_per_gas, - max_priority_fee_per_gas, - gas: self.gas, - action: self.action, - value: self.value, - data: self.data, - access_list: if let Some(access_list) = self.access_list { access_list } else { AccessList::default() }, - })) - } else { - if !matches!(self.chain_id, Some(_chain_id)) { - Err(TxBuilderError::NoChainIdSet) - } else { - Err(TxBuilderError::NoGasPriceSet) - } - } - } -} \ No newline at end of file + pub fn build(self) -> Result { + match self.tx_type { + TxType::Legacy => Ok(TransactionWrapper::Legacy(LegacyTransaction { + nonce: self.nonce, + gas_price: self + .gas_price + .ok_or_else(|| TxBuilderError::NoGasPriceSet)?, + gas: self.gas, + action: self.action, + value: self.value, + data: self.data, + })), + TxType::Type1 => Ok(TransactionWrapper::Eip2930(Eip2930Transaction { + chain_id: self.chain_id.ok_or_else(|| TxBuilderError::NoChainIdSet)?, + nonce: self.nonce, + gas_price: self + .gas_price + .ok_or_else(|| TxBuilderError::NoGasPriceSet)?, + gas: self.gas, + action: self.action, + value: self.value, + data: self.data, + access_list: if let Some(access_list) = self.access_list { + access_list + } else { + AccessList::default() + }, + })), + TxType::Type2 => Ok(TransactionWrapper::Eip1559(Eip1559Transaction { + chain_id: self.chain_id.ok_or_else(|| TxBuilderError::NoChainIdSet)?, + nonce: self.nonce, + max_fee_per_gas: self + .max_fee_per_gas + .ok_or_else(|| TxBuilderError::NoFeePerGasSet)?, + max_priority_fee_per_gas: self + .max_priority_fee_per_gas + .ok_or_else(|| TxBuilderError::NoFeePerGasSet)?, + gas: self.gas, + action: self.action, + value: self.value, + data: self.data, + access_list: if let Some(access_list) = self.access_list { + access_list + } else { + AccessList::default() + }, + })), + TxType::Invalid => Err(TxBuilderError::InvalidTxType), + } + } +} From d56017e6f94b52c1783cd0ba6973308ce9d8186f Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 29 Mar 2024 14:53:35 +0500 Subject: [PATCH 16/27] fix toolchain and cargo fmt notes --- ethcore/transaction/Cargo.toml | 1 + ethcore/transaction/src/error.rs | 189 ++- ethcore/transaction/src/transaction.rs | 1233 ++++++++--------- .../transaction/src/transaction/eip1559.rs | 250 ++-- .../transaction/src/transaction/eip2930.rs | 328 +++-- ethcore/transaction/src/transaction/legacy.rs | 254 ++-- .../src/transaction/tx_builders.rs | 231 ++- rust-toolchain | 1 - rust-toolchain.toml | 3 + rustfmt.toml | 56 +- 10 files changed, 1237 insertions(+), 1309 deletions(-) delete mode 100644 rust-toolchain create mode 100644 rust-toolchain.toml diff --git a/ethcore/transaction/Cargo.toml b/ethcore/transaction/Cargo.toml index 1377b14fc06..58d278c5e47 100644 --- a/ethcore/transaction/Cargo.toml +++ b/ethcore/transaction/Cargo.toml @@ -3,6 +3,7 @@ name = "ethcore-transaction" description = "Transaction type" version = "0.1.0" authors = ["Parity Technologies "] +edition = "2018" [dependencies] ethkey = { path = "../../ethkey" } diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index b22a7d236f3..5c090846902 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -24,114 +24,109 @@ use unexpected::OutOfBounds; #[derive(Debug, PartialEq, Clone)] /// Errors concerning transaction processing. pub enum Error { - /// Transaction is already imported to the queue - AlreadyImported, - /// Transaction is not valid anymore (state already has higher nonce) - Old, - /// Transaction has too low fee - /// (there is already a transaction with the same sender-nonce but higher gas price) - TooCheapToReplace, - /// Transaction was not imported to the queue because limit has been reached. - LimitReached, - /// Transaction's gas price is below threshold. - InsufficientGasPrice { - /// Minimal expected gas price - minimal: U256, - /// Transaction gas price - got: U256, - }, - /// Transaction's gas is below currently set minimal gas requirement. - InsufficientGas { - /// Minimal expected gas - minimal: U256, - /// Transaction gas - got: U256, - }, - /// Sender doesn't have enough funds to pay for this transaction - InsufficientBalance { - /// Senders balance - balance: U256, - /// Transaction cost - cost: U256, - }, - /// Transactions gas is higher then current gas limit - GasLimitExceeded { - /// Current gas limit - limit: U256, - /// Declared transaction gas - got: U256, - }, - /// Transaction's gas limit (aka gas) is invalid. - InvalidGasLimit(OutOfBounds), - /// Transaction sender is banned. - SenderBanned, - /// Transaction receipient is banned. - RecipientBanned, - /// Contract creation code is banned. - CodeBanned, - /// Invalid chain ID given. - InvalidChainId, - /// Not enough permissions given by permission contract. - NotAllowed, - /// Signature error - InvalidSignature(String), - /// Transaction too big - TooBig, - /// Invalid RLP encoding - InvalidRlp(String), + /// Transaction is already imported to the queue + AlreadyImported, + /// Transaction is not valid anymore (state already has higher nonce) + Old, + /// Transaction has too low fee + /// (there is already a transaction with the same sender-nonce but higher gas price) + TooCheapToReplace, + /// Transaction was not imported to the queue because limit has been reached. + LimitReached, + /// Transaction's gas price is below threshold. + InsufficientGasPrice { + /// Minimal expected gas price + minimal: U256, + /// Transaction gas price + got: U256, + }, + /// Transaction's gas is below currently set minimal gas requirement. + InsufficientGas { + /// Minimal expected gas + minimal: U256, + /// Transaction gas + got: U256, + }, + /// Sender doesn't have enough funds to pay for this transaction + InsufficientBalance { + /// Senders balance + balance: U256, + /// Transaction cost + cost: U256, + }, + /// Transactions gas is higher then current gas limit + GasLimitExceeded { + /// Current gas limit + limit: U256, + /// Declared transaction gas + got: U256, + }, + /// Transaction's gas limit (aka gas) is invalid. + InvalidGasLimit(OutOfBounds), + /// Transaction sender is banned. + SenderBanned, + /// Transaction receipient is banned. + RecipientBanned, + /// Contract creation code is banned. + CodeBanned, + /// Invalid chain ID given. + InvalidChainId, + /// Not enough permissions given by permission contract. + NotAllowed, + /// Signature error + InvalidSignature(String), + /// Transaction too big + TooBig, + /// Invalid RLP encoding + InvalidRlp(String), } impl From for Error { - fn from(err: ethkey::Error) -> Self { - Error::InvalidSignature(format!("{}", err)) - } + fn from(err: ethkey::Error) -> Self { Error::InvalidSignature(format!("{}", err)) } } impl From for Error { - fn from(err: rlp::DecoderError) -> Self { - Error::InvalidRlp(format!("{}", err)) - } + fn from(err: rlp::DecoderError) -> Self { Error::InvalidRlp(format!("{}", err)) } } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::Error::*; - let msg = match *self { - AlreadyImported => "Already imported".into(), - Old => "No longer valid".into(), - TooCheapToReplace => "Gas price too low to replace".into(), - LimitReached => "Transaction limit reached".into(), - InsufficientGasPrice { minimal, got } => { - format!("Insufficient gas price. Min={}, Given={}", minimal, got) - } - InsufficientGas { minimal, got } => { - format!("Insufficient gas. Min={}, Given={}", minimal, got) - } - InsufficientBalance { balance, cost } => { - format!("Insufficient balance for transaction. Balance={}, Cost={}", balance, cost) - } - GasLimitExceeded { limit, got } => { - format!("Gas limit exceeded. Limit={}, Given={}", limit, got) - } - InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err), - SenderBanned => "Sender is temporarily banned.".into(), - RecipientBanned => "Recipient is temporarily banned.".into(), - CodeBanned => "Contract code is temporarily banned.".into(), - InvalidChainId => "Transaction of this chain ID is not allowed on this chain.".into(), - InvalidSignature(ref err) => format!("Transaction has invalid signature: {}.", err), - NotAllowed => { - "Sender does not have permissions to execute this type of transction".into() - } - TooBig => "Transaction too big".into(), - InvalidRlp(ref err) => format!("Transaction has invalid RLP structure: {}.", err), - }; + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Error::*; + let msg = match *self { + AlreadyImported => "Already imported".into(), + Old => "No longer valid".into(), + TooCheapToReplace => "Gas price too low to replace".into(), + LimitReached => "Transaction limit reached".into(), + InsufficientGasPrice { minimal, got } => { + format!("Insufficient gas price. Min={}, Given={}", minimal, got) + }, + InsufficientGas { minimal, got } => { + format!("Insufficient gas. Min={}, Given={}", minimal, got) + }, + InsufficientBalance { balance, cost } => { + format!( + "Insufficient balance for transaction. Balance={}, Cost={}", + balance, cost + ) + }, + GasLimitExceeded { limit, got } => { + format!("Gas limit exceeded. Limit={}, Given={}", limit, got) + }, + InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err), + SenderBanned => "Sender is temporarily banned.".into(), + RecipientBanned => "Recipient is temporarily banned.".into(), + CodeBanned => "Contract code is temporarily banned.".into(), + InvalidChainId => "Transaction of this chain ID is not allowed on this chain.".into(), + InvalidSignature(ref err) => format!("Transaction has invalid signature: {}.", err), + NotAllowed => "Sender does not have permissions to execute this type of transction".into(), + TooBig => "Transaction too big".into(), + InvalidRlp(ref err) => format!("Transaction has invalid RLP structure: {}.", err), + }; - f.write_fmt(format_args!("Transaction error ({})", msg)) - } + f.write_fmt(format_args!("Transaction error ({})", msg)) + } } impl error::Error for Error { - fn description(&self) -> &str { - "Transaction error" - } + fn description(&self) -> &str { "Transaction error" } } diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index b91f299440e..0486e22de12 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -18,7 +18,7 @@ //! Transaction data structure. -use error; +use crate::error; use ethereum_types::{Address, H160, H256, U256}; use ethkey::{self, public_to_address, recover, Public, Secret, Signature}; use hash::keccak; @@ -31,9 +31,7 @@ pub mod tx_builders; pub use self::legacy::{LegacyTransaction, UnverifiedLegacyTransaction}; pub use self::tx_builders::TransactionWrapperBuilder; mod eip2930; -pub use self::eip2930::{ - AccessList, AccessListItem, Eip2930Transaction, UnverifiedEip2930Transaction, -}; +pub use self::eip2930::{AccessList, AccessListItem, Eip2930Transaction, UnverifiedEip2930Transaction}; mod eip1559; pub use self::eip1559::{Eip1559Transaction, UnverifiedEip1559Transaction}; @@ -42,20 +40,20 @@ type Bytes = Vec; #[derive(PartialEq)] pub enum TxType { - Legacy, - Type1 = 1, - Type2 = 2, - Invalid, + Legacy, + Type1 = 1, + Type2 = 2, + Invalid, } impl From for TxType { - fn from(v: u8) -> Self { - match v { - 1 => TxType::Type1, - 2 => TxType::Type2, - _ => TxType::Invalid, - } - } + fn from(v: u8) -> Self { + match v { + 1 => TxType::Type1, + 2 => TxType::Type2, + _ => TxType::Invalid, + } + } } /// Fake address for unsigned transactions as defined by EIP-86. @@ -63,736 +61,697 @@ pub const UNSIGNED_SENDER: Address = H160([0xff; 20]); /// System sender address for internal state updates. pub const SYSTEM_ADDRESS: Address = H160([ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, ]); /// Transaction action type. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Action { - /// Create creates new contract. - Create, - /// Calls contract at given address. - /// In the case of a transfer, this is the receiver's address.' - Call(Address), + /// Create creates new contract. + Create, + /// Calls contract at given address. + /// In the case of a transfer, this is the receiver's address.' + Call(Address), } impl Default for Action { - fn default() -> Action { - Action::Create - } + fn default() -> Action { Action::Create } } impl rlp::Decodable for Action { - fn decode(rlp: &Rlp) -> Result { - if rlp.is_empty() { - Ok(Action::Create) - } else { - Ok(Action::Call(rlp.as_val()?)) - } - } + fn decode(rlp: &Rlp) -> Result { + if rlp.is_empty() { + Ok(Action::Create) + } else { + Ok(Action::Call(rlp.as_val()?)) + } + } } impl rlp::Encodable for Action { - fn rlp_append(&self, s: &mut RlpStream) { - match *self { - Action::Create => s.append_internal(&""), - Action::Call(ref addr) => s.append_internal(addr), - }; - } + fn rlp_append(&self, s: &mut RlpStream) { + match *self { + Action::Create => s.append_internal(&""), + Action::Call(ref addr) => s.append_internal(addr), + }; + } } /// Transaction activation condition. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Condition { - /// Valid at this block number or later. - Number(BlockNumber), - /// Valid at this unix time or later. - Timestamp(u64), + /// Valid at this block number or later. + Number(BlockNumber), + /// Valid at this unix time or later. + Timestamp(u64), } type TransactionSharedRet = dyn TransactionShared + Send + Sync + 'static; /// Methods common for all tx versions pub trait TransactionShared { - fn nonce(&self) -> U256; + fn nonce(&self) -> U256; - fn action(&self) -> &Action; + fn action(&self) -> &Action; - fn value(&self) -> U256; + fn value(&self) -> U256; - fn data(&self) -> &Bytes; + fn data(&self) -> &Bytes; - fn message_hash(&self, chain_id: Option) -> H256; + fn message_hash(&self, chain_id: Option) -> H256; } /// Methods common all signed tx versions pub trait SignedTransactionShared { - fn compute_hash(mut self) -> Self - where - Self: rlp::Encodable + Sized, - { - let hash = keccak(&*self.rlp_bytes()); - self.set_hash(hash); - self - } - - fn set_hash(&mut self, hash: H256); + fn compute_hash(mut self) -> Self + where + Self: rlp::Encodable + Sized, + { + let hash = keccak(&*self.rlp_bytes()); + self.set_hash(hash); + self + } + + fn set_hash(&mut self, hash: H256); } #[derive(Debug, Clone, Eq, PartialEq)] pub enum TransactionWrapper { - Legacy(LegacyTransaction), - Eip2930(Eip2930Transaction), - Eip1559(Eip1559Transaction), + Legacy(LegacyTransaction), + Eip2930(Eip2930Transaction), + Eip1559(Eip1559Transaction), } impl TransactionWrapper { - /// The message hash of the transaction. - pub fn message_hash(&self, chain_id: Option) -> H256 { - match self { - TransactionWrapper::Legacy(tx) => tx.message_hash(chain_id), - TransactionWrapper::Eip2930(tx) => tx.message_hash(None), - TransactionWrapper::Eip1559(tx) => tx.message_hash(None), - } - } - - /// Signs the transaction as coming from `sender`. - pub fn sign(self, secret: &Secret, chain_id: Option) -> SignedTransaction { - let sig = ::ethkey::sign(secret, &self.message_hash(chain_id)) - .expect("data is valid and context has signing capabilities; qed"); - SignedTransaction::new(self.with_signature(sig, chain_id)) - .expect("secret is valid so it's recoverable") - } - - /// Add signature to the transaction. - fn with_signature(self, sig: Signature, chain_id: Option) -> UnverifiedTransactionWrapper { - UnverifiedTransactionWrapper::new( - self, - sig.r().into(), - sig.s().into(), - sig.v() as u64, - chain_id, - H256::from_low_u64_ne(0), - ) - .compute_hash() - } - - /// Useful for test incorrectly signed transactions. - #[cfg(test)] - pub fn invalid_sign(self) -> UnverifiedTransactionWrapper { - UnverifiedTransactionWrapper::new( - self, - U256::one(), - U256::one(), - 0, - None, - H256::from_low_u64_ne(0), - ) - .compute_hash() - } - - /// Specify the sender; this won't survive the serialize/deserialize process, but can be cloned. - pub fn fake_sign(self, from: Address) -> SignedTransaction { - SignedTransaction { - transaction: UnverifiedTransactionWrapper::new( - self, - U256::one(), - U256::one(), - 0, - None, - H256::from_low_u64_ne(0), - ) - .compute_hash(), - sender: from, - public: None, - } - } - - /// Add EIP-86 compatible empty signature. - pub fn null_sign(self, chain_id: u64) -> SignedTransaction { - SignedTransaction { - transaction: UnverifiedTransactionWrapper::new( - self, - U256::zero(), - U256::zero(), - chain_id, - None, - H256::from_low_u64_ne(0), - ) - .compute_hash(), - sender: UNSIGNED_SENDER, - public: None, - } - } + /// The message hash of the transaction. + pub fn message_hash(&self, chain_id: Option) -> H256 { + match self { + TransactionWrapper::Legacy(tx) => tx.message_hash(chain_id), + TransactionWrapper::Eip2930(tx) => tx.message_hash(None), + TransactionWrapper::Eip1559(tx) => tx.message_hash(None), + } + } + + /// Signs the transaction as coming from `sender`. + pub fn sign(self, secret: &Secret, chain_id: Option) -> SignedTransaction { + let sig = ::ethkey::sign(secret, &self.message_hash(chain_id)) + .expect("data is valid and context has signing capabilities; qed"); + SignedTransaction::new(self.with_signature(sig, chain_id)).expect("secret is valid so it's recoverable") + } + + /// Add signature to the transaction. + fn with_signature(self, sig: Signature, chain_id: Option) -> UnverifiedTransactionWrapper { + UnverifiedTransactionWrapper::new( + self, + sig.r().into(), + sig.s().into(), + sig.v() as u64, + chain_id, + H256::from_low_u64_ne(0), + ) + .compute_hash() + } + + /// Useful for test incorrectly signed transactions. + #[cfg(test)] + pub fn invalid_sign(self) -> UnverifiedTransactionWrapper { + UnverifiedTransactionWrapper::new(self, U256::one(), U256::one(), 0, None, H256::from_low_u64_ne(0)) + .compute_hash() + } + + /// Specify the sender; this won't survive the serialize/deserialize process, but can be cloned. + pub fn fake_sign(self, from: Address) -> SignedTransaction { + SignedTransaction { + transaction: UnverifiedTransactionWrapper::new( + self, + U256::one(), + U256::one(), + 0, + None, + H256::from_low_u64_ne(0), + ) + .compute_hash(), + sender: from, + public: None, + } + } + + /// Add EIP-86 compatible empty signature. + pub fn null_sign(self, chain_id: u64) -> SignedTransaction { + SignedTransaction { + transaction: UnverifiedTransactionWrapper::new( + self, + U256::zero(), + U256::zero(), + chain_id, + None, + H256::from_low_u64_ne(0), + ) + .compute_hash(), + sender: UNSIGNED_SENDER, + public: None, + } + } } #[derive(Debug, Clone, Eq, PartialEq)] pub enum UnverifiedTransactionWrapper { - Legacy(UnverifiedLegacyTransaction), - Eip2930(UnverifiedEip2930Transaction), - Eip1559(UnverifiedEip1559Transaction), + Legacy(UnverifiedLegacyTransaction), + Eip2930(UnverifiedEip2930Transaction), + Eip1559(UnverifiedEip1559Transaction), } impl rlp::Decodable for UnverifiedTransactionWrapper { - fn decode(d: &Rlp) -> Result { - if is_typed_transaction(d) { - // first byte is tx version - match TxType::from(d.as_raw()[0]) { - TxType::Type1 => Ok(UnverifiedTransactionWrapper::Eip2930( - UnverifiedEip2930Transaction::decode(d)?, - )), - TxType::Type2 => Ok(UnverifiedTransactionWrapper::Eip1559( - UnverifiedEip1559Transaction::decode(d)?, - )), - _ => Err(DecoderError::Custom("unsupported tx version")), - } - } else { - Ok(UnverifiedTransactionWrapper::Legacy(UnverifiedLegacyTransaction::decode(d)?)) - } - } + fn decode(d: &Rlp) -> Result { + if is_typed_transaction(d) { + // first byte is tx version + match TxType::from(d.as_raw()[0]) { + TxType::Type1 => Ok(UnverifiedTransactionWrapper::Eip2930( + UnverifiedEip2930Transaction::decode(d)?, + )), + TxType::Type2 => Ok(UnverifiedTransactionWrapper::Eip1559( + UnverifiedEip1559Transaction::decode(d)?, + )), + _ => Err(DecoderError::Custom("unsupported tx version")), + } + } else { + Ok(UnverifiedTransactionWrapper::Legacy( + UnverifiedLegacyTransaction::decode(d)?, + )) + } + } } impl UnverifiedTransactionWrapper { - fn new( - tx: TransactionWrapper, - r: U256, - s: U256, - v: u64, - chain_id: Option, - hash: H256, - ) -> Self { - match tx { - TransactionWrapper::Legacy(unsigned) => { - UnverifiedTransactionWrapper::Legacy(UnverifiedLegacyTransaction { - unsigned, - r, - s, - network_v: UnverifiedLegacyTransaction::to_network_v(v, chain_id), - hash, - }) - } - TransactionWrapper::Eip2930(unsigned) => { - UnverifiedTransactionWrapper::Eip2930(UnverifiedEip2930Transaction { - unsigned, - r, - s, - v: v.try_into().unwrap(), - hash, - }) - } - TransactionWrapper::Eip1559(unsigned) => { - UnverifiedTransactionWrapper::Eip1559(UnverifiedEip1559Transaction { - unsigned, - r, - s, - v: v.try_into().unwrap(), - hash, - }) - } - } - } - - fn compute_hash(self) -> UnverifiedTransactionWrapper { - match self { - UnverifiedTransactionWrapper::Legacy(tx) => { - UnverifiedTransactionWrapper::Legacy(tx.compute_hash()) - } - UnverifiedTransactionWrapper::Eip2930(tx) => { - UnverifiedTransactionWrapper::Eip2930(tx.compute_hash()) - } - UnverifiedTransactionWrapper::Eip1559(tx) => { - UnverifiedTransactionWrapper::Eip1559(tx.compute_hash()) - } - } - } - - /// Append object with a signature into RLP stream - fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { - match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.rlp_append_sealed_transaction(s), - UnverifiedTransactionWrapper::Eip2930(tx) => tx.rlp_append_sealed_transaction(s), - UnverifiedTransactionWrapper::Eip1559(tx) => tx.rlp_append_sealed_transaction(s), - }; - } - - pub fn unsigned(&self) -> &TransactionSharedRet { - match self { - UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, - } - } - - /// Add eip155 fix to signature v, for legacy tx - pub fn standard_v(&self) -> u8 { - match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.standard_v(), - UnverifiedTransactionWrapper::Eip2930(tx) => tx.standard_v(), - UnverifiedTransactionWrapper::Eip1559(tx) => tx.standard_v(), - } - } - - /// The chain ID, or `None` if this is a global transaction. - pub fn chain_id_from_v(&self) -> Option { - match self.v() { - v if self.is_unsigned() => Some(v), // v is chain_id for null signer by eip-86 (TODO: is this supported?) - v if v > 36 => Some((v - 35) / 2), // encoded by eip-155 - _ => None, - } - } - - /// Construct a signature object from the sig. - pub fn signature(&self) -> Signature { - let r = h256_from_u256(self.r()); - let s = h256_from_u256(self.s()); - Signature::from_rsv(&r, &s, self.standard_v()) - } - - /// Checks whether the signature has a low 's' value. - pub fn check_low_s(&self) -> Result<(), ethkey::Error> { - if !self.signature().is_low_s() { - Err(ethkey::Error::InvalidSignature.into()) - } else { - Ok(()) - } - } - - /// Checks is signature is empty. - pub(crate) fn is_unsigned(&self) -> bool { - self.r().is_zero() && self.s().is_zero() - } - - /// Recovers the public key of the sender. - pub fn recover_public(&self) -> Result { - Ok(recover(&self.signature(), &self.unsigned().message_hash(self.chain_id_from_v()))?) - } - - /// Do basic validation, checking for valid signature and minimum gas, - // TODO: consider use in block validation. - #[cfg(feature = "json-tests")] - pub fn validate( - self, - schedule: &Schedule, - require_low: bool, - allow_chain_id_of_one: bool, - allow_empty_signature: bool, - ) -> Result { - let chain_id = if allow_chain_id_of_one { Some(1) } else { None }; - self.verify_basic(require_low, chain_id, allow_empty_signature)?; - if !allow_empty_signature || !self.is_unsigned() { - self.recover_public()?; - } - if self.gas < U256::from(self.gas_required(&schedule)) { - return Err(error::Error::InvalidGasLimit(::unexpected::OutOfBounds { - min: Some(U256::from(self.gas_required(&schedule))), - max: None, - found: self.gas, - }) - .into()); - } - Ok(self) - } - - /// Verify basic signature params. Does not attempt sender recovery. - pub fn verify_basic( - &self, - check_low_s: bool, - chain_id: Option, - allow_empty_signature: bool, - ) -> Result<(), error::Error> { - if check_low_s && !(allow_empty_signature && self.is_unsigned()) { - self.check_low_s()?; - } - // Disallow unsigned transactions in case EIP-86 is disabled. - if !allow_empty_signature && self.is_unsigned() { - return Err(ethkey::Error::InvalidSignature.into()); - } - - if allow_empty_signature && self.is_unsigned() && self.validate_empty_sig() { - return Err(ethkey::Error::InvalidSignature.into()); - } - match (self.chain_id_from_v(), chain_id) { - (None, _) => {} - (Some(n), Some(m)) if n == m => {} - _ => return Err(error::Error::InvalidChainId), - }; - Ok(()) - } - - /// validate tx with empty signature - fn validate_empty_sig(&self) -> bool { - // Note: EIP-86 code was removed - false - } - - fn r(&self) -> U256 { - match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.r, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.r, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.r, - } - } - fn s(&self) -> U256 { - match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.s, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.s, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.s, - } - } - fn v(&self) -> u64 { - match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.network_v, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.v as u64, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.v as u64, - } - } - - /// Get the hash of this transaction (keccak of the RLP). - pub fn tx_hash(&self) -> H256 { - match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.hash, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.hash, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.hash, - } - } + fn new(tx: TransactionWrapper, r: U256, s: U256, v: u64, chain_id: Option, hash: H256) -> Self { + match tx { + TransactionWrapper::Legacy(unsigned) => UnverifiedTransactionWrapper::Legacy(UnverifiedLegacyTransaction { + unsigned, + r, + s, + network_v: UnverifiedLegacyTransaction::to_network_v(v, chain_id), + hash, + }), + TransactionWrapper::Eip2930(unsigned) => { + UnverifiedTransactionWrapper::Eip2930(UnverifiedEip2930Transaction { + unsigned, + r, + s, + v: v.try_into().unwrap(), + hash, + }) + }, + TransactionWrapper::Eip1559(unsigned) => { + UnverifiedTransactionWrapper::Eip1559(UnverifiedEip1559Transaction { + unsigned, + r, + s, + v: v.try_into().unwrap(), + hash, + }) + }, + } + } + + fn compute_hash(self) -> UnverifiedTransactionWrapper { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => UnverifiedTransactionWrapper::Legacy(tx.compute_hash()), + UnverifiedTransactionWrapper::Eip2930(tx) => UnverifiedTransactionWrapper::Eip2930(tx.compute_hash()), + UnverifiedTransactionWrapper::Eip1559(tx) => UnverifiedTransactionWrapper::Eip1559(tx.compute_hash()), + } + } + + /// Append object with a signature into RLP stream + fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.rlp_append_sealed_transaction(s), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.rlp_append_sealed_transaction(s), + UnverifiedTransactionWrapper::Eip1559(tx) => tx.rlp_append_sealed_transaction(s), + }; + } + + pub fn unsigned(&self) -> &TransactionSharedRet { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, + } + } + + /// Add eip155 fix to signature v, for legacy tx + pub fn standard_v(&self) -> u8 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.standard_v(), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.standard_v(), + UnverifiedTransactionWrapper::Eip1559(tx) => tx.standard_v(), + } + } + + /// The chain ID, or `None` if this is a global transaction. + pub fn chain_id_from_v(&self) -> Option { + match self.v() { + v if self.is_unsigned() => Some(v), // v is chain_id for null signer by eip-86 (TODO: is this supported?) + v if v > 36 => Some((v - 35) / 2), // encoded by eip-155 + _ => None, + } + } + + /// Construct a signature object from the sig. + pub fn signature(&self) -> Signature { + let r = h256_from_u256(self.r()); + let s = h256_from_u256(self.s()); + Signature::from_rsv(&r, &s, self.standard_v()) + } + + /// Checks whether the signature has a low 's' value. + pub fn check_low_s(&self) -> Result<(), ethkey::Error> { + if !self.signature().is_low_s() { + Err(ethkey::Error::InvalidSignature.into()) + } else { + Ok(()) + } + } + + /// Checks is signature is empty. + pub(crate) fn is_unsigned(&self) -> bool { self.r().is_zero() && self.s().is_zero() } + + /// Recovers the public key of the sender. + pub fn recover_public(&self) -> Result { + Ok(recover( + &self.signature(), + &self.unsigned().message_hash(self.chain_id_from_v()), + )?) + } + + /// Do basic validation, checking for valid signature and minimum gas, + // TODO: consider use in block validation. + #[cfg(feature = "json-tests")] + pub fn validate( + self, + schedule: &Schedule, + require_low: bool, + allow_chain_id_of_one: bool, + allow_empty_signature: bool, + ) -> Result { + let chain_id = if allow_chain_id_of_one { Some(1) } else { None }; + self.verify_basic(require_low, chain_id, allow_empty_signature)?; + if !allow_empty_signature || !self.is_unsigned() { + self.recover_public()?; + } + if self.gas < U256::from(self.gas_required(&schedule)) { + return Err(error::Error::InvalidGasLimit(::unexpected::OutOfBounds { + min: Some(U256::from(self.gas_required(&schedule))), + max: None, + found: self.gas, + }) + .into()); + } + Ok(self) + } + + /// Verify basic signature params. Does not attempt sender recovery. + pub fn verify_basic( + &self, + check_low_s: bool, + chain_id: Option, + allow_empty_signature: bool, + ) -> Result<(), error::Error> { + if check_low_s && !(allow_empty_signature && self.is_unsigned()) { + self.check_low_s()?; + } + // Disallow unsigned transactions in case EIP-86 is disabled. + if !allow_empty_signature && self.is_unsigned() { + return Err(ethkey::Error::InvalidSignature.into()); + } + + if allow_empty_signature && self.is_unsigned() && self.validate_empty_sig() { + return Err(ethkey::Error::InvalidSignature.into()); + } + match (self.chain_id_from_v(), chain_id) { + (None, _) => {}, + (Some(n), Some(m)) if n == m => {}, + _ => return Err(error::Error::InvalidChainId), + }; + Ok(()) + } + + /// validate tx with empty signature + fn validate_empty_sig(&self) -> bool { + // Note: EIP-86 code was removed + false + } + + fn r(&self) -> U256 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.r, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.r, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.r, + } + } + fn s(&self) -> U256 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.s, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.s, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.s, + } + } + fn v(&self) -> u64 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.network_v, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.v as u64, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.v as u64, + } + } + + /// Get the hash of this transaction (keccak of the RLP). + pub fn tx_hash(&self) -> H256 { + match self { + UnverifiedTransactionWrapper::Legacy(tx) => tx.hash, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.hash, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.hash, + } + } } /// A `UnverifiedTransaction` with successfully recovered `sender`. #[derive(Debug, Clone, Eq, PartialEq)] pub struct SignedTransaction { - pub transaction: UnverifiedTransactionWrapper, - pub sender: Address, - pub public: Option, + pub transaction: UnverifiedTransactionWrapper, + pub sender: Address, + pub public: Option, } impl rlp::Encodable for SignedTransaction { - fn rlp_append(&self, s: &mut RlpStream) { - self.transaction.rlp_append_sealed_transaction(s) - } + fn rlp_append(&self, s: &mut RlpStream) { self.transaction.rlp_append_sealed_transaction(s) } } impl Deref for SignedTransaction { - type Target = UnverifiedTransactionWrapper; - fn deref(&self) -> &Self::Target { - &self.transaction - } + type Target = UnverifiedTransactionWrapper; + fn deref(&self) -> &Self::Target { &self.transaction } } impl From for UnverifiedTransactionWrapper { - fn from(tx: SignedTransaction) -> Self { - tx.transaction - } + fn from(tx: SignedTransaction) -> Self { tx.transaction } } impl SignedTransaction { - /// Try to verify transaction and recover sender. - pub fn new(transaction: UnverifiedTransactionWrapper) -> Result { - if transaction.is_unsigned() { - Ok(SignedTransaction { - transaction: transaction, - sender: UNSIGNED_SENDER, - public: None, - }) - } else { - let public = transaction.recover_public()?; - let sender = public_to_address(&public); - Ok(SignedTransaction { - transaction: transaction, - sender: sender, - public: Some(public), - }) - } - } - - pub fn unsigned(&self) -> &TransactionSharedRet { - match &self.transaction { - UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, - } - } - - /// Returns transaction sender. - pub fn sender(&self) -> Address { - self.sender - } - - /// Returns a public key of the sender. - pub fn public_key(&self) -> Option { - self.public - } - - /// Checks is signature is empty. - pub fn is_unsigned(&self) -> bool { - self.transaction.is_unsigned() - } - - /// Deconstructs this transaction back into `UnverifiedTransaction` - pub fn deconstruct(self) -> (UnverifiedTransactionWrapper, Address, Option) { - (self.transaction, self.sender, self.public) - } + /// Try to verify transaction and recover sender. + pub fn new(transaction: UnverifiedTransactionWrapper) -> Result { + if transaction.is_unsigned() { + Ok(SignedTransaction { + transaction, + sender: UNSIGNED_SENDER, + public: None, + }) + } else { + let public = transaction.recover_public()?; + let sender = public_to_address(&public); + Ok(SignedTransaction { + transaction, + sender, + public: Some(public), + }) + } + } + + pub fn unsigned(&self) -> &TransactionSharedRet { + match &self.transaction { + UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, + } + } + + /// Returns transaction sender. + pub fn sender(&self) -> Address { self.sender } + + /// Returns a public key of the sender. + pub fn public_key(&self) -> Option { self.public } + + /// Checks is signature is empty. + pub fn is_unsigned(&self) -> bool { self.transaction.is_unsigned() } + + /// Deconstructs this transaction back into `UnverifiedTransaction` + pub fn deconstruct(self) -> (UnverifiedTransactionWrapper, Address, Option) { + (self.transaction, self.sender, self.public) + } } /// Signed Transaction that is a part of canon blockchain. #[derive(Debug, Clone, PartialEq, Eq)] pub struct LocalizedTransaction { - /// Signed part. - pub signed: UnverifiedTransactionWrapper, - /// Block number. - pub block_number: BlockNumber, - /// Block hash. - pub block_hash: H256, - /// Transaction index within block. - pub transaction_index: usize, - /// Cached sender - pub cached_sender: Option
, + /// Signed part. + pub signed: UnverifiedTransactionWrapper, + /// Block number. + pub block_number: BlockNumber, + /// Block hash. + pub block_hash: H256, + /// Transaction index within block. + pub transaction_index: usize, + /// Cached sender + pub cached_sender: Option
, } impl LocalizedTransaction { - /// Returns transaction sender. - /// Panics if `LocalizedTransaction` is constructed using invalid `UnverifiedTransaction`. - pub fn sender(&mut self) -> Address { - if let Some(sender) = self.cached_sender { - return sender; - } - if self.is_unsigned() { - return UNSIGNED_SENDER.clone(); - } - let sender = public_to_address(&self.recover_public() + /// Returns transaction sender. + /// Panics if `LocalizedTransaction` is constructed using invalid `UnverifiedTransaction`. + pub fn sender(&mut self) -> Address { + if let Some(sender) = self.cached_sender { + return sender; + } + if self.is_unsigned() { + return UNSIGNED_SENDER.clone(); + } + let sender = public_to_address(&self.recover_public() .expect("LocalizedTransaction is always constructed from transaction from blockchain; Blockchain only stores verified transactions; qed")); - self.cached_sender = Some(sender); - sender - } + self.cached_sender = Some(sender); + sender + } } impl Deref for LocalizedTransaction { - type Target = UnverifiedTransactionWrapper; + type Target = UnverifiedTransactionWrapper; - fn deref(&self) -> &Self::Target { - &self.signed - } + fn deref(&self) -> &Self::Target { &self.signed } } /// Queued transaction with additional information. #[derive(Debug, Clone, PartialEq, Eq)] pub struct PendingTransaction { - /// Signed transaction data. - pub transaction: SignedTransaction, - /// To be activated at this condition. `None` for immediately. - pub condition: Option, + /// Signed transaction data. + pub transaction: SignedTransaction, + /// To be activated at this condition. `None` for immediately. + pub condition: Option, } impl PendingTransaction { - /// Create a new pending transaction from signed transaction. - pub fn new(signed: SignedTransaction, condition: Option) -> Self { - PendingTransaction { - transaction: signed, - condition: condition, - } - } + /// Create a new pending transaction from signed transaction. + pub fn new(signed: SignedTransaction, condition: Option) -> Self { + PendingTransaction { + transaction: signed, + condition, + } + } } impl Deref for PendingTransaction { - type Target = SignedTransaction; + type Target = SignedTransaction; - fn deref(&self) -> &SignedTransaction { - &self.transaction - } + fn deref(&self) -> &SignedTransaction { &self.transaction } } impl From for PendingTransaction { - fn from(t: SignedTransaction) -> Self { - PendingTransaction { transaction: t, condition: None } - } + fn from(t: SignedTransaction) -> Self { + PendingTransaction { + transaction: t, + condition: None, + } + } } /// Reproduces the same conversion as it was in the previous `ethereum-types-0.4` version: /// https://docs.rs/ethereum-types/0.4.0/src/ethereum_types/hash.rs.html#32-38 fn h256_from_u256(num: U256) -> H256 { - // `U256::to_big_endian` is used internally. - let bytes: [u8; 32] = num.into(); - H256::from(bytes) + // `U256::to_big_endian` is used internally. + let bytes: [u8; 32] = num.into(); + H256::from(bytes) } /// Returns true if serialized tx has type as in eip-2718 -fn is_typed_transaction(d: &Rlp) -> bool { - !d.is_list() && d.as_raw().len() > 0 && d.as_raw()[0] < 0x7f -} +fn is_typed_transaction(d: &Rlp) -> bool { !d.is_list() && d.as_raw().len() > 0 && d.as_raw()[0] < 0x7f } #[cfg(test)] mod tests { - use super::*; - use ethereum_types::U256; - use ethkey::KeyPair; - use hash::keccak; - use std::str::FromStr; - - #[test] - fn legacy_sender_test() { - let bytes: Vec = ::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap(); - let t: UnverifiedTransactionWrapper = - rlp::decode(&bytes).expect("decoding UnverifiedTransaction failed"); - if let UnverifiedTransactionWrapper::Legacy(legacy_tx) = t.clone() { - assert_eq!(legacy_tx.data, b""); - assert_eq!(legacy_tx.gas, U256::from(0x5208u64)); - assert_eq!(legacy_tx.gas_price, U256::from(0x01u64)); - assert_eq!(legacy_tx.nonce, U256::from(0x00u64)); - if let Action::Call(ref to) = legacy_tx.action { - let expected = - Address::from_str("095e7baea6a6c7c4c2dfeb977efac326af552d87").unwrap(); - assert_eq!(*to, expected); - } else { - panic!(); - } - assert_eq!(legacy_tx.value, U256::from(0x0au64)); - let expected = Address::from_str("0f65fe9276bc9a24ae7083ae28e2660ef72df99e").unwrap(); - assert_eq!(public_to_address(&t.recover_public().unwrap()), expected); - assert_eq!(t.chain_id_from_v(), None); - } else { - panic!("invalid tx ver"); - } - } - - #[test] - fn legacy_signing() { - let key = KeyPair::from_secret_slice(&[ - 128, 148, 101, 177, 125, 10, 77, 219, 62, 76, 105, 232, 242, 60, 44, 171, 173, 134, - 143, 81, 248, 190, 213, 199, 101, 173, 29, 101, 22, 195, 48, 111, - ]) - .unwrap(); - let t = TransactionWrapper::Legacy(LegacyTransaction { - action: Action::Create, - nonce: U256::from(42), - gas_price: U256::from(3000), - gas: U256::from(50_000), - value: U256::from(1), - data: b"Hello!".to_vec(), - }) - .sign(&key.secret(), None); - assert_eq!(Address::from(keccak(key.public())), t.sender()); - assert_eq!(t.chain_id_from_v(), None); - } - - #[test] - fn legacy_fake_signing() { - let t = TransactionWrapper::Legacy(LegacyTransaction { - action: Action::Create, - nonce: U256::from(42), - gas_price: U256::from(3000), - gas: U256::from(50_000), - value: U256::from(1), - data: b"Hello!".to_vec(), - }) - .fake_sign(Address::from_low_u64_ne(0x69)); - assert_eq!(Address::from_low_u64_ne(0x69), t.sender()); - assert_eq!(t.chain_id_from_v(), None); - - let t = t.clone(); - assert_eq!(Address::from_low_u64_ne(0x69), t.sender()); - assert_eq!(t.chain_id_from_v(), None); - } - - #[test] - fn legacy_should_recover_from_chain_specific_signing() { - let key = KeyPair::from_secret_slice(&[ - 128, 148, 101, 177, 125, 10, 77, 219, 62, 76, 105, 232, 242, 60, 44, 171, 173, 134, - 143, 81, 248, 190, 213, 199, 101, 173, 29, 101, 22, 195, 48, 111, - ]) - .unwrap(); - let t = TransactionWrapper::Legacy(LegacyTransaction { - action: Action::Create, - nonce: U256::from(42), - gas_price: U256::from(3000), - gas: U256::from(50_000), - value: U256::from(1), - data: b"Hello!".to_vec(), - }) - .sign(&key.secret(), Some(69)); - assert_eq!(Address::from(keccak(key.public())), t.sender()); - assert_eq!(t.chain_id_from_v(), Some(69)); - } - - #[test] - fn legacy_should_agree_with_vitalik() { - use rustc_hex::FromHex; - - let test_vector = |tx_data: &str, address: &'static str| { - let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); - let signed = rlp::decode(&bytes).expect("decoding tx data failed"); - let signed = SignedTransaction::new(signed).unwrap(); - - let expected = Address::from_str(address).unwrap(); - assert_eq!(signed.sender(), expected); - println!("chainid_from_v: {:?}", signed.chain_id_from_v()); - }; - - test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"); - test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112"); - test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be"); - test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0"); - test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554"); - test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4"); - test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35"); - test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332"); - test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029"); - test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"); - } - - #[test] - fn tx_type_1_parse_tx() { - use rustc_hex::FromHex; - - let test_vector = |tx_data: &str, address: &'static str, hash: &'static str| { - let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); - let unverified = rlp::decode(&bytes).expect("decoding tx data failed"); - let signed = SignedTransaction::new(unverified).unwrap(); - - let expected_addr = Address::from_str(address).unwrap(); - assert_eq!(signed.sender(), expected_addr); - let expected_hash = H256::from_str(hash).unwrap(); - let unverified_tx = signed.transaction.clone().compute_hash(); - assert_eq!(unverified_tx.tx_hash(), expected_hash); - - if let UnverifiedTransactionWrapper::Eip2930(tx) = signed.transaction { - println!("chainid: {:?}", tx.chain_id); - } else { - panic!("expected tx type 1 (eip-2930)"); - } - }; - // type 1, empty access list - test_vector("01f87201830180058504375e83908307a120942f3e89bb84705085dd2afc1f00ca5f823ff7f6088801aaaf118d612c0080c080a04f08e11860459e944e28a39193b76cc2ca0566bea40c086160f6c44ce43dd6fca07333d8b6c872a4d599cb4027c9129941c2691f09ce1cbea361a827bc30e78e54", "0x264bd8291fAE1D75DB2c5F573b07faA6715997B5", "0xe9b033c089745a1b70003586e8a1fbdb59d407c5943f00193d5c562194042524"); - } - - #[test] - fn eip1559_parse_tx() { - use rustc_hex::FromHex; - - let test_vector = |tx_data: &str, address: &'static str, hash: &'static str| { - let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); - let unverified = rlp::decode(&bytes).expect("decoding tx data failed"); - let signed = SignedTransaction::new(unverified).unwrap(); - - let expected_addr = Address::from_str(address).unwrap(); - assert_eq!(signed.sender(), expected_addr); - let expected_hash = H256::from_str(hash).unwrap(); - let unverified_tx = signed.transaction.clone().compute_hash(); - assert_eq!(unverified_tx.tx_hash(), expected_hash); - - if let UnverifiedTransactionWrapper::Eip1559(tx) = signed.transaction { - println!("chainid: {:?}", tx.chain_id); - } else { - panic!("expected tx type 2 (eip-1559)"); - } - }; - - // simple transfer eth tx - test_vector("02f8710103830f42408518ad0849c4825208941749b8eccc622d81600ab7fa322a17b99def83d2876b803d5ccd438580c001a08303e62f4d7779b09ab9daeaef868a8ad3bc937b435a60e8cc432d224bd8b1fba0520ae4b5906f3978ff413eef4131c1d246b15eb676a19324ce9ad23ac48aa987", + use super::*; + use ethereum_types::U256; + use ethkey::KeyPair; + use hash::keccak; + use std::str::FromStr; + + #[test] + fn legacy_sender_test() { + let bytes: Vec = ::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap(); + let t: UnverifiedTransactionWrapper = rlp::decode(&bytes).expect("decoding UnverifiedTransaction failed"); + if let UnverifiedTransactionWrapper::Legacy(legacy_tx) = t.clone() { + assert_eq!(legacy_tx.data, b""); + assert_eq!(legacy_tx.gas, U256::from(0x5208u64)); + assert_eq!(legacy_tx.gas_price, U256::from(0x01u64)); + assert_eq!(legacy_tx.nonce, U256::from(0x00u64)); + if let Action::Call(ref to) = legacy_tx.action { + let expected = Address::from_str("095e7baea6a6c7c4c2dfeb977efac326af552d87").unwrap(); + assert_eq!(*to, expected); + } else { + panic!(); + } + assert_eq!(legacy_tx.value, U256::from(0x0au64)); + let expected = Address::from_str("0f65fe9276bc9a24ae7083ae28e2660ef72df99e").unwrap(); + assert_eq!(public_to_address(&t.recover_public().unwrap()), expected); + assert_eq!(t.chain_id_from_v(), None); + } else { + panic!("invalid tx ver"); + } + } + + #[test] + fn legacy_signing() { + let key = KeyPair::from_secret_slice(&[ + 128, 148, 101, 177, 125, 10, 77, 219, 62, 76, 105, 232, 242, 60, 44, 171, 173, 134, 143, 81, 248, 190, 213, + 199, 101, 173, 29, 101, 22, 195, 48, 111, + ]) + .unwrap(); + let t = TransactionWrapper::Legacy(LegacyTransaction { + action: Action::Create, + nonce: U256::from(42), + gas_price: U256::from(3000), + gas: U256::from(50_000), + value: U256::from(1), + data: b"Hello!".to_vec(), + }) + .sign(&key.secret(), None); + assert_eq!(Address::from(keccak(key.public())), t.sender()); + assert_eq!(t.chain_id_from_v(), None); + } + + #[test] + fn legacy_fake_signing() { + let t = TransactionWrapper::Legacy(LegacyTransaction { + action: Action::Create, + nonce: U256::from(42), + gas_price: U256::from(3000), + gas: U256::from(50_000), + value: U256::from(1), + data: b"Hello!".to_vec(), + }) + .fake_sign(Address::from_low_u64_ne(0x69)); + assert_eq!(Address::from_low_u64_ne(0x69), t.sender()); + assert_eq!(t.chain_id_from_v(), None); + + let t = t.clone(); + assert_eq!(Address::from_low_u64_ne(0x69), t.sender()); + assert_eq!(t.chain_id_from_v(), None); + } + + #[test] + fn legacy_should_recover_from_chain_specific_signing() { + let key = KeyPair::from_secret_slice(&[ + 128, 148, 101, 177, 125, 10, 77, 219, 62, 76, 105, 232, 242, 60, 44, 171, 173, 134, 143, 81, 248, 190, 213, + 199, 101, 173, 29, 101, 22, 195, 48, 111, + ]) + .unwrap(); + let t = TransactionWrapper::Legacy(LegacyTransaction { + action: Action::Create, + nonce: U256::from(42), + gas_price: U256::from(3000), + gas: U256::from(50_000), + value: U256::from(1), + data: b"Hello!".to_vec(), + }) + .sign(&key.secret(), Some(69)); + assert_eq!(Address::from(keccak(key.public())), t.sender()); + assert_eq!(t.chain_id_from_v(), Some(69)); + } + + #[test] + fn legacy_should_agree_with_vitalik() { + use rustc_hex::FromHex; + + let test_vector = |tx_data: &str, address: &'static str| { + let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); + let signed = rlp::decode(&bytes).expect("decoding tx data failed"); + let signed = SignedTransaction::new(signed).unwrap(); + + let expected = Address::from_str(address).unwrap(); + assert_eq!(signed.sender(), expected); + println!("chainid_from_v: {:?}", signed.chain_id_from_v()); + }; + + test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"); + test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112"); + test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be"); + test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0"); + test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554"); + test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4"); + test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35"); + test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332"); + test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029"); + test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"); + } + + #[test] + fn tx_type_1_parse_tx() { + use rustc_hex::FromHex; + + let test_vector = |tx_data: &str, address: &'static str, hash: &'static str| { + let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); + let unverified = rlp::decode(&bytes).expect("decoding tx data failed"); + let signed = SignedTransaction::new(unverified).unwrap(); + + let expected_addr = Address::from_str(address).unwrap(); + assert_eq!(signed.sender(), expected_addr); + let expected_hash = H256::from_str(hash).unwrap(); + let unverified_tx = signed.transaction.clone().compute_hash(); + assert_eq!(unverified_tx.tx_hash(), expected_hash); + + if let UnverifiedTransactionWrapper::Eip2930(tx) = signed.transaction { + println!("chainid: {:?}", tx.chain_id); + } else { + panic!("expected tx type 1 (eip-2930)"); + } + }; + // type 1, empty access list + test_vector("01f87201830180058504375e83908307a120942f3e89bb84705085dd2afc1f00ca5f823ff7f6088801aaaf118d612c0080c080a04f08e11860459e944e28a39193b76cc2ca0566bea40c086160f6c44ce43dd6fca07333d8b6c872a4d599cb4027c9129941c2691f09ce1cbea361a827bc30e78e54", "0x264bd8291fAE1D75DB2c5F573b07faA6715997B5", "0xe9b033c089745a1b70003586e8a1fbdb59d407c5943f00193d5c562194042524"); + } + + #[test] + fn eip1559_parse_tx() { + use rustc_hex::FromHex; + + let test_vector = |tx_data: &str, address: &'static str, hash: &'static str| { + let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); + let unverified = rlp::decode(&bytes).expect("decoding tx data failed"); + let signed = SignedTransaction::new(unverified).unwrap(); + + let expected_addr = Address::from_str(address).unwrap(); + assert_eq!(signed.sender(), expected_addr); + let expected_hash = H256::from_str(hash).unwrap(); + let unverified_tx = signed.transaction.clone().compute_hash(); + assert_eq!(unverified_tx.tx_hash(), expected_hash); + + if let UnverifiedTransactionWrapper::Eip1559(tx) = signed.transaction { + println!("chainid: {:?}", tx.chain_id); + } else { + panic!("expected tx type 2 (eip-1559)"); + } + }; + + // simple transfer eth tx + test_vector("02f8710103830f42408518ad0849c4825208941749b8eccc622d81600ab7fa322a17b99def83d2876b803d5ccd438580c001a08303e62f4d7779b09ab9daeaef868a8ad3bc937b435a60e8cc432d224bd8b1fba0520ae4b5906f3978ff413eef4131c1d246b15eb676a19324ce9ad23ac48aa987", "0xfAe06Df909Df46f3b1649c9b11e150F14E9B83B0", "0x9903f6398f118dfc04b95ed6c00e55237eb204986590593d13e2f9ce47716ed9"); - // tx with data and access list - test_vector("02f907670183180a51808507a6a2c507830917af946b75d8af000000e20b7a7ddf000ba900b4009a8080b89c0c8ee819c10e1f20df3a8c2ac93a62d7fba719fa777026c02d337617b02998480049642110b712c1fd7261bc074105e9e44676c68fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22710f2fe5250fe5318b03d536566b02998ffffc076c4ffff93001a6cd7c3a21bda7cf6a0cd5d5e8d10ab55d8ba58257813a239ca819d9510a73c424485f89ea52839fdb30640eb7dd7e0078e12fb0a4eac742df9065df89b94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f884a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8a093f4f2109c73365b91270de71d7ce61b41cfceb94f27f26e2b6e30142ea529e5a0af9987888ab75f8cdc0eee179dff704e6c0a13b462f58aac23ab8eb77f3d71cda0176d9f00066af884810a42c67ff9a8c1374be6135e1ee85edb8c9cf021f1fdd5f8dd94da7cf6a0cd5d5e8d10ab55d8ba58257813a239caf8c6a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000af8bc94993864e43caa7f7f12953ad6feb1d1ca635b875ff8a5a00000000000000000000000000000000000000000000000000000000000000003a0d93f987b59bbb5780fe5994c7112f10657809cae45c627a319f962c40235428ca0a6eabb9b2c010ec47045c52eb64682c8a09fe52a8605fef87ee312fa6817bde7a01f31c723d1f4395a6dac2d34827bb7577589384735f0df95b73389f4d27d8769a06e89d460fefb1c8f5b2b8f2e9609ee9a4ef3f9b7ff014be959a86fabed2b4af8f87a949ce9704b1993ff308f1815e0fd44b0dffee2d0dcf863a06d0cc4c200c8af0ffd8b254bae44f07d6bc5c15ac854d2a3dbf761299ffa9c56a0101ed5680b1cfc12bfd6f2c99ee49abcf5d75b12223f9040664d083b09f1c7d7a00000000000000000000000000000000000000000000000000000000000000002f8dd94424485f89ea52839fdb30640eb7dd7e0078e12fbf8c6a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000af9026a9419c10e1f20df3a8c2ac93a62d7fba719fa777026f90252a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000008a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896737a02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2ca057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f78a02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2da057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f76a00000000000000000000000000000000000000000000000000000000000000002a0c0d1c00078410fd0164580b0bad93d8a579580d06cf45fc2696a823498097b8aa02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2aa02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2ba057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f75a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896738a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896739a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e989673aa057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f77f8599449642110b712c1fd7261bc074105e9e44676c68ff842a0b39e9ba92c3c47c76d4f70e3bc9c3270ab78d2592718d377c8f5433a34d3470aa05f19933e8ecba477d24413f29da8dd3035e36ca249de114bc98ea28d251d02b580a0a00d83a12835ab9653ee11077d5dd310a424dd67885445f5319207e7a5a2ae15a059c4642a2ac77f31d88de1a4e0f70eb220be8a8219943c3af9cf9c71e3143ebd", + // tx with data and access list + test_vector("02f907670183180a51808507a6a2c507830917af946b75d8af000000e20b7a7ddf000ba900b4009a8080b89c0c8ee819c10e1f20df3a8c2ac93a62d7fba719fa777026c02d337617b02998480049642110b712c1fd7261bc074105e9e44676c68fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22710f2fe5250fe5318b03d536566b02998ffffc076c4ffff93001a6cd7c3a21bda7cf6a0cd5d5e8d10ab55d8ba58257813a239ca819d9510a73c424485f89ea52839fdb30640eb7dd7e0078e12fb0a4eac742df9065df89b94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f884a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8a093f4f2109c73365b91270de71d7ce61b41cfceb94f27f26e2b6e30142ea529e5a0af9987888ab75f8cdc0eee179dff704e6c0a13b462f58aac23ab8eb77f3d71cda0176d9f00066af884810a42c67ff9a8c1374be6135e1ee85edb8c9cf021f1fdd5f8dd94da7cf6a0cd5d5e8d10ab55d8ba58257813a239caf8c6a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000af8bc94993864e43caa7f7f12953ad6feb1d1ca635b875ff8a5a00000000000000000000000000000000000000000000000000000000000000003a0d93f987b59bbb5780fe5994c7112f10657809cae45c627a319f962c40235428ca0a6eabb9b2c010ec47045c52eb64682c8a09fe52a8605fef87ee312fa6817bde7a01f31c723d1f4395a6dac2d34827bb7577589384735f0df95b73389f4d27d8769a06e89d460fefb1c8f5b2b8f2e9609ee9a4ef3f9b7ff014be959a86fabed2b4af8f87a949ce9704b1993ff308f1815e0fd44b0dffee2d0dcf863a06d0cc4c200c8af0ffd8b254bae44f07d6bc5c15ac854d2a3dbf761299ffa9c56a0101ed5680b1cfc12bfd6f2c99ee49abcf5d75b12223f9040664d083b09f1c7d7a00000000000000000000000000000000000000000000000000000000000000002f8dd94424485f89ea52839fdb30640eb7dd7e0078e12fbf8c6a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000af9026a9419c10e1f20df3a8c2ac93a62d7fba719fa777026f90252a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000008a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896737a02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2ca057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f78a02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2da057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f76a00000000000000000000000000000000000000000000000000000000000000002a0c0d1c00078410fd0164580b0bad93d8a579580d06cf45fc2696a823498097b8aa02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2aa02bb5540461adf3eb1d87affec4120ad02c1d3dfeb558a44a41bdb546360c8b2ba057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f75a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896738a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e9896739a07350e62d400da1aad24eb98f7ba1200460b13fa4ebaebccf69f1ec15e989673aa057e15af2cdc4ea5af6477be852d0d55b2e8b8039f955b0db7400692f43f35f77f8599449642110b712c1fd7261bc074105e9e44676c68ff842a0b39e9ba92c3c47c76d4f70e3bc9c3270ab78d2592718d377c8f5433a34d3470aa05f19933e8ecba477d24413f29da8dd3035e36ca249de114bc98ea28d251d02b580a0a00d83a12835ab9653ee11077d5dd310a424dd67885445f5319207e7a5a2ae15a059c4642a2ac77f31d88de1a4e0f70eb220be8a8219943c3af9cf9c71e3143ebd", "0xae2Fc483527B8EF99EB5D9B44875F005ba1FaE13", "0x256c91a7934b7584c1f8f28a6b3b8cacf13419637532896fc1e1119aa7fa32ba"); - } + } } diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs index 9f9fbb3ce21..ac5eef75fd6 100644 --- a/ethcore/transaction/src/transaction/eip1559.rs +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -14,171 +14,153 @@ use std::{convert::TryInto, ops::Deref}; /// or contract creation operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Eip1559Transaction { - /// Simple replay attack protection - pub chain_id: u64, - /// Nonce. - pub nonce: U256, - /// Max fee per gas. - pub max_fee_per_gas: U256, - /// Max priority fee per gas. - pub max_priority_fee_per_gas: U256, - /// Gas paid up front for transaction execution. - pub gas: U256, - /// Action, can be either call or contract create. - pub action: Action, - /// Transfered value. - pub value: U256, - /// Transaction data. - pub data: Bytes, - /// Access list. - pub access_list: AccessList, + /// Simple replay attack protection + pub chain_id: u64, + /// Nonce. + pub nonce: U256, + /// Max fee per gas. + pub max_fee_per_gas: U256, + /// Max priority fee per gas. + pub max_priority_fee_per_gas: U256, + /// Gas paid up front for transaction execution. + pub gas: U256, + /// Action, can be either call or contract create. + pub action: Action, + /// Transfered value. + pub value: U256, + /// Transaction data. + pub data: Bytes, + /// Access list. + pub access_list: AccessList, } impl Eip1559Transaction { - const fn payload_length(&self) -> usize { - 9 - } + const fn payload_length(&self) -> usize { 9 } - /// Append object with a without signature into RLP stream - fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { - s.append(&(TxType::Type2 as u8)); - s.begin_list(self.payload_length()); - s.append(&self.chain_id); - s.append(&self.nonce); - s.append(&self.max_priority_fee_per_gas); - s.append(&self.max_fee_per_gas); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - s.append(&self.access_list); - } + /// Append object with a without signature into RLP stream + fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { + s.append(&(TxType::Type2 as u8)); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.max_priority_fee_per_gas); + s.append(&self.max_fee_per_gas); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + } } impl TransactionShared for Eip1559Transaction { - fn nonce(&self) -> U256 { - self.nonce - } - fn action(&self) -> &Action { - &self.action - } - fn value(&self) -> U256 { - self.value - } - fn data(&self) -> &Bytes { - &self.data - } - /// The message hash of the transaction. - fn message_hash(&self, _chain_id: Option) -> H256 { - let mut stream = RlpStream::new(); - self.rlp_append_unsigned_transaction(&mut stream); - keccak(stream.as_raw()) - } + fn nonce(&self) -> U256 { self.nonce } + fn action(&self) -> &Action { &self.action } + fn value(&self) -> U256 { self.value } + fn data(&self) -> &Bytes { &self.data } + /// The message hash of the transaction. + fn message_hash(&self, _chain_id: Option) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream); + keccak(stream.as_raw()) + } } impl rlp::Decodable for Eip1559Transaction { - fn decode(d: &Rlp) -> Result { - if d.as_raw().len() < 2 { - return Err(DecoderError::RlpIsTooShort); - } - let version: u8 = d.as_raw()[0]; - if TxType::from(version) != TxType::Type2 { - return Err(DecoderError::Custom("bad tx version")); - } - let list = Rlp::new(&d.as_raw()[1..]); - Ok(Eip1559Transaction { - chain_id: list.val_at(0)?, - nonce: list.val_at(1)?, - max_priority_fee_per_gas: list.val_at(2)?, - max_fee_per_gas: list.val_at(3)?, - gas: list.val_at(4)?, - action: list.val_at(5)?, - value: list.val_at(6)?, - data: list.val_at(7)?, - access_list: list.val_at(8)?, - }) - } + fn decode(d: &Rlp) -> Result { + if d.as_raw().len() < 2 { + return Err(DecoderError::RlpIsTooShort); + } + let version: u8 = d.as_raw()[0]; + if TxType::from(version) != TxType::Type2 { + return Err(DecoderError::Custom("bad tx version")); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(Eip1559Transaction { + chain_id: list.val_at(0)?, + nonce: list.val_at(1)?, + max_priority_fee_per_gas: list.val_at(2)?, + max_fee_per_gas: list.val_at(3)?, + gas: list.val_at(4)?, + action: list.val_at(5)?, + value: list.val_at(6)?, + data: list.val_at(7)?, + access_list: list.val_at(8)?, + }) + } } /// Signed transaction information without verified signature. #[derive(Debug, Clone, Eq, PartialEq)] pub struct UnverifiedEip1559Transaction { - /// Plain Transaction. - pub unsigned: Eip1559Transaction, - /// The V field of the signature - pub v: u64, - /// The R field of the signature; helps describe the point on the curve. - pub r: U256, - /// The S field of the signature; helps describe the point on the curve. - pub s: U256, - /// Hash of the transaction - pub hash: H256, + /// Plain Transaction. + pub unsigned: Eip1559Transaction, + /// The V field of the signature + pub v: u64, + /// The R field of the signature; helps describe the point on the curve. + pub r: U256, + /// The S field of the signature; helps describe the point on the curve. + pub s: U256, + /// Hash of the transaction + pub hash: H256, } impl Deref for UnverifiedEip1559Transaction { - type Target = Eip1559Transaction; + type Target = Eip1559Transaction; - fn deref(&self) -> &Self::Target { - &self.unsigned - } + fn deref(&self) -> &Self::Target { &self.unsigned } } impl rlp::Decodable for UnverifiedEip1559Transaction { - fn decode(d: &Rlp) -> Result { - let unsigned = Eip1559Transaction::decode(d)?; - let hash = keccak(d.as_raw()); - let offset = unsigned.payload_length(); - if d.as_raw().len() < 1 { - return Err(DecoderError::RlpIsTooShort); - } - let list = Rlp::new(&d.as_raw()[1..]); - Ok(UnverifiedEip1559Transaction { - unsigned, - v: list.val_at(offset)?, - r: list.val_at(offset + 1)?, - s: list.val_at(offset + 2)?, - hash, - }) - } + fn decode(d: &Rlp) -> Result { + let unsigned = Eip1559Transaction::decode(d)?; + let hash = keccak(d.as_raw()); + let offset = unsigned.payload_length(); + if d.as_raw().len() < 1 { + return Err(DecoderError::RlpIsTooShort); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(UnverifiedEip1559Transaction { + unsigned, + v: list.val_at(offset)?, + r: list.val_at(offset + 1)?, + s: list.val_at(offset + 2)?, + hash, + }) + } } impl rlp::Encodable for UnverifiedEip1559Transaction { - fn rlp_append(&self, s: &mut RlpStream) { - self.rlp_append_sealed_transaction(s) - } + fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_sealed_transaction(s) } } impl SignedTransactionShared for UnverifiedEip1559Transaction { - fn set_hash(&mut self, hash: H256) { - self.hash = hash; - } + fn set_hash(&mut self, hash: H256) { self.hash = hash; } } impl UnverifiedEip1559Transaction { - /// tx list item count - fn payload_length(&self) -> usize { - self.unsigned.payload_length() + 3 - } + /// tx list item count + fn payload_length(&self) -> usize { self.unsigned.payload_length() + 3 } - /// Append object with a signature into RLP stream - pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { - s.append(&(TxType::Type2 as u8)); - s.begin_list(self.payload_length()); - s.append(&self.chain_id); - s.append(&self.nonce); - s.append(&self.max_priority_fee_per_gas); - s.append(&self.max_fee_per_gas); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - s.append(&self.access_list); - s.append(&self.v); - s.append(&self.r); - s.append(&self.s); - } + /// Append object with a signature into RLP stream + pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + s.append(&(TxType::Type2 as u8)); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.max_priority_fee_per_gas); + s.append(&self.max_fee_per_gas); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + s.append(&self.v); + s.append(&self.r); + s.append(&self.s); + } - pub fn standard_v(&self) -> u8 { - self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns - } + pub fn standard_v(&self) -> u8 { + self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns + } } diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs index 61356a4387e..a8c25244ad2 100644 --- a/ethcore/transaction/src/transaction/eip2930.rs +++ b/ethcore/transaction/src/transaction/eip2930.rs @@ -11,34 +11,34 @@ use std::{convert::TryInto, ops::Deref}; #[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] pub struct AccessListItem { - /// Account addresses that would be loaded at the start of execution - pub address: Address, - /// Keys of storage that would be loaded at the start of execution - pub storage_keys: Vec, + /// Account addresses that would be loaded at the start of execution + pub address: Address, + /// Keys of storage that would be loaded at the start of execution + pub storage_keys: Vec, } impl rlp::Decodable for AccessListItem { - fn decode(d: &Rlp) -> Result { - let address = Address::decode(&d.at(0)?)?; - let keys_rlp = d.at(1)?; - let mut storage_keys: Vec = vec![]; - for i in 0..keys_rlp.item_count()? { - storage_keys.push(H256::decode(&keys_rlp.at(i)?)?); - } - Ok(AccessListItem { address, storage_keys }) - } + fn decode(d: &Rlp) -> Result { + let address = Address::decode(&d.at(0)?)?; + let keys_rlp = d.at(1)?; + let mut storage_keys: Vec = vec![]; + for i in 0..keys_rlp.item_count()? { + storage_keys.push(H256::decode(&keys_rlp.at(i)?)?); + } + Ok(AccessListItem { address, storage_keys }) + } } impl rlp::Encodable for AccessListItem { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.address); - - s.begin_list(self.storage_keys.len()); - for i in 0..self.storage_keys.len() { - s.append(&self.storage_keys[i]); - } - } + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.address); + + s.begin_list(self.storage_keys.len()); + for i in 0..self.storage_keys.len() { + s.append(&self.storage_keys[i]); + } + } } /// AccessList as defined in EIP-2930 @@ -46,194 +46,176 @@ impl rlp::Encodable for AccessListItem { pub struct AccessList(pub Vec); impl rlp::Decodable for AccessList { - fn decode(d: &Rlp) -> Result { - let mut items: Vec = vec![]; - for i in 0..d.item_count()? { - let item = AccessListItem::decode(&d.at(i)?)?; - items.push(item); - } - Ok(AccessList(items)) - } + fn decode(d: &Rlp) -> Result { + let mut items: Vec = vec![]; + for i in 0..d.item_count()? { + let item = AccessListItem::decode(&d.at(i)?)?; + items.push(item); + } + Ok(AccessList(items)) + } } impl rlp::Encodable for AccessList { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(self.0.len()); - for i in 0..self.0.len() { - s.append(&self.0[i]); - } - } + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(self.0.len()); + for i in 0..self.0.len() { + s.append(&self.0[i]); + } + } } /// A set of information describing an externally-originating message call /// or contract creation operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Eip2930Transaction { - /// Simple replay attack protection - pub chain_id: u64, - /// Nonce. - pub nonce: U256, - /// Gas price. - pub gas_price: U256, - /// Gas paid up front for transaction execution. - pub gas: U256, - /// Action, can be either call or contract create. - pub action: Action, - /// Transfered value. - pub value: U256, - /// Transaction data. - pub data: Bytes, - /// Access list. - pub access_list: AccessList, + /// Simple replay attack protection + pub chain_id: u64, + /// Nonce. + pub nonce: U256, + /// Gas price. + pub gas_price: U256, + /// Gas paid up front for transaction execution. + pub gas: U256, + /// Action, can be either call or contract create. + pub action: Action, + /// Transfered value. + pub value: U256, + /// Transaction data. + pub data: Bytes, + /// Access list. + pub access_list: AccessList, } impl Eip2930Transaction { - const fn payload_length(&self) -> usize { - 8 - } - - /// Append object with a without signature into RLP stream - fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { - s.append(&(TxType::Type1 as u8)); - s.begin_list(self.payload_length()); - s.append(&self.chain_id); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - s.append(&self.access_list); - } + const fn payload_length(&self) -> usize { 8 } + + /// Append object with a without signature into RLP stream + fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { + s.append(&(TxType::Type1 as u8)); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + } } impl TransactionShared for Eip2930Transaction { - fn nonce(&self) -> U256 { - self.nonce - } - fn action(&self) -> &Action { - &self.action - } - fn value(&self) -> U256 { - self.value - } - fn data(&self) -> &Bytes { - &self.data - } - /// The message hash of the transaction. - fn message_hash(&self, _chain_id: Option) -> H256 { - let mut stream = RlpStream::new(); - self.rlp_append_unsigned_transaction(&mut stream); - keccak(stream.as_raw()) - } + fn nonce(&self) -> U256 { self.nonce } + fn action(&self) -> &Action { &self.action } + fn value(&self) -> U256 { self.value } + fn data(&self) -> &Bytes { &self.data } + /// The message hash of the transaction. + fn message_hash(&self, _chain_id: Option) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream); + keccak(stream.as_raw()) + } } impl rlp::Decodable for Eip2930Transaction { - fn decode(d: &Rlp) -> Result { - if d.as_raw().len() < 2 { - return Err(DecoderError::RlpIsTooShort); - } - let version: u8 = d.as_raw()[0]; - if TxType::from(version) != TxType::Type1 { - return Err(DecoderError::Custom("bad tx version")); - } - let list = Rlp::new(&d.as_raw()[1..]); - Ok(Eip2930Transaction { - chain_id: list.val_at(0)?, - nonce: list.val_at(1)?, - gas_price: list.val_at(2)?, - gas: list.val_at(3)?, - action: list.val_at(4)?, - value: list.val_at(5)?, - data: list.val_at(6)?, - access_list: list.val_at(7)?, - }) - } + fn decode(d: &Rlp) -> Result { + if d.as_raw().len() < 2 { + return Err(DecoderError::RlpIsTooShort); + } + let version: u8 = d.as_raw()[0]; + if TxType::from(version) != TxType::Type1 { + return Err(DecoderError::Custom("bad tx version")); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(Eip2930Transaction { + chain_id: list.val_at(0)?, + nonce: list.val_at(1)?, + gas_price: list.val_at(2)?, + gas: list.val_at(3)?, + action: list.val_at(4)?, + value: list.val_at(5)?, + data: list.val_at(6)?, + access_list: list.val_at(7)?, + }) + } } /// Signed transaction information without verified signature. #[derive(Debug, Clone, Eq, PartialEq)] pub struct UnverifiedEip2930Transaction { - /// Plain Transaction. - pub unsigned: Eip2930Transaction, - /// The V field of the signature - pub v: u64, - /// The R field of the signature; helps describe the point on the curve. - pub r: U256, - /// The S field of the signature; helps describe the point on the curve. - pub s: U256, - /// Hash of the transaction - pub hash: H256, + /// Plain Transaction. + pub unsigned: Eip2930Transaction, + /// The V field of the signature + pub v: u64, + /// The R field of the signature; helps describe the point on the curve. + pub r: U256, + /// The S field of the signature; helps describe the point on the curve. + pub s: U256, + /// Hash of the transaction + pub hash: H256, } impl Deref for UnverifiedEip2930Transaction { - type Target = Eip2930Transaction; + type Target = Eip2930Transaction; - fn deref(&self) -> &Self::Target { - &self.unsigned - } + fn deref(&self) -> &Self::Target { &self.unsigned } } impl rlp::Decodable for UnverifiedEip2930Transaction { - fn decode(d: &Rlp) -> Result { - let unsigned = Eip2930Transaction::decode(d)?; - let hash = keccak(d.as_raw()); - let offset = unsigned.payload_length(); - if d.as_raw().len() < 1 { - return Err(DecoderError::RlpIsTooShort); - } - let list = Rlp::new(&d.as_raw()[1..]); - Ok(UnverifiedEip2930Transaction { - unsigned, - v: list.val_at(offset)?, - r: list.val_at(offset + 1)?, - s: list.val_at(offset + 2)?, - hash, - }) - } + fn decode(d: &Rlp) -> Result { + let unsigned = Eip2930Transaction::decode(d)?; + let hash = keccak(d.as_raw()); + let offset = unsigned.payload_length(); + if d.as_raw().len() < 1 { + return Err(DecoderError::RlpIsTooShort); + } + let list = Rlp::new(&d.as_raw()[1..]); + Ok(UnverifiedEip2930Transaction { + unsigned, + v: list.val_at(offset)?, + r: list.val_at(offset + 1)?, + s: list.val_at(offset + 2)?, + hash, + }) + } } impl rlp::Encodable for UnverifiedEip2930Transaction { - fn rlp_append(&self, s: &mut RlpStream) { - self.rlp_append_sealed_transaction(s) - } + fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_sealed_transaction(s) } } impl SignedTransactionShared for UnverifiedEip2930Transaction { - fn set_hash(&mut self, hash: H256) { - self.hash = hash; - } + fn set_hash(&mut self, hash: H256) { self.hash = hash; } } impl UnverifiedEip2930Transaction { - /// tx list item count - fn payload_length(&self) -> usize { - self.unsigned.payload_length() + 3 - } - - /// Append object with a signature into RLP stream - pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { - s.append(&(TxType::Type1 as u8)); - s.begin_list(self.payload_length()); - s.append(&self.chain_id); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - s.append(&self.access_list); - s.append(&self.v); - s.append(&self.r); - s.append(&self.s); - } - - pub fn standard_v(&self) -> u8 { - self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns - } - - // EIP-86 or newer: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. - pub(crate) fn _validate_empty_sig(&self) -> bool { - true // TODO fix for eip2930 - } + /// tx list item count + fn payload_length(&self) -> usize { self.unsigned.payload_length() + 3 } + + /// Append object with a signature into RLP stream + pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + s.append(&(TxType::Type1 as u8)); + s.begin_list(self.payload_length()); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.access_list); + s.append(&self.v); + s.append(&self.r); + s.append(&self.s); + } + + pub fn standard_v(&self) -> u8 { + self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns + } + + // EIP-86 or newer: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. + pub(crate) fn _validate_empty_sig(&self) -> bool { + true // TODO fix for eip2930 + } } diff --git a/ethcore/transaction/src/transaction/legacy.rs b/ethcore/transaction/src/transaction/legacy.rs index aeac2e39b23..7cffdce943f 100644 --- a/ethcore/transaction/src/transaction/legacy.rs +++ b/ethcore/transaction/src/transaction/legacy.rs @@ -13,173 +13,157 @@ use std::ops::Deref; /// or contract creation operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct LegacyTransaction { - /// Nonce. - pub nonce: U256, - /// Gas price. - pub gas_price: U256, - /// Gas paid up front for transaction execution. - pub gas: U256, - /// Action, can be either call or contract create. - pub action: Action, - /// Transfered value. - pub value: U256, - /// Transaction data. - pub data: Bytes, + /// Nonce. + pub nonce: U256, + /// Gas price. + pub gas_price: U256, + /// Gas paid up front for transaction execution. + pub gas: U256, + /// Action, can be either call or contract create. + pub action: Action, + /// Transfered value. + pub value: U256, + /// Transaction data. + pub data: Bytes, } impl LegacyTransaction { - /// tx list item count - fn payload_length(chain_id: Option) -> usize { - if chain_id.is_none() { - 6 - } else { - 9 - } - } - - /// Append object with a without signature into RLP stream - fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, chain_id: Option) { - s.begin_list(Self::payload_length(chain_id)); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - if let Some(n) = chain_id { - s.append(&n); - s.append(&0u8); - s.append(&0u8); - } - } + /// tx list item count + fn payload_length(chain_id: Option) -> usize { + if chain_id.is_none() { + 6 + } else { + 9 + } + } + + /// Append object with a without signature into RLP stream + fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, chain_id: Option) { + s.begin_list(Self::payload_length(chain_id)); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + if let Some(n) = chain_id { + s.append(&n); + s.append(&0u8); + s.append(&0u8); + } + } } impl TransactionShared for LegacyTransaction { - fn nonce(&self) -> U256 { - self.nonce - } - fn action(&self) -> &Action { - &self.action - } - fn value(&self) -> U256 { - self.value - } - fn data(&self) -> &Bytes { - &self.data - } - /// The message hash of the transaction. - fn message_hash(&self, chain_id: Option) -> H256 { - let mut stream = RlpStream::new(); - self.rlp_append_unsigned_transaction(&mut stream, chain_id); - keccak(stream.as_raw()) - } + fn nonce(&self) -> U256 { self.nonce } + fn action(&self) -> &Action { &self.action } + fn value(&self) -> U256 { self.value } + fn data(&self) -> &Bytes { &self.data } + /// The message hash of the transaction. + fn message_hash(&self, chain_id: Option) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream, chain_id); + keccak(stream.as_raw()) + } } impl rlp::Decodable for LegacyTransaction { - fn decode(d: &Rlp) -> Result { - Ok(LegacyTransaction { - nonce: d.val_at(0)?, - gas_price: d.val_at(1)?, - gas: d.val_at(2)?, - action: d.val_at(3)?, - value: d.val_at(4)?, - data: d.val_at(5)?, - }) - } + fn decode(d: &Rlp) -> Result { + Ok(LegacyTransaction { + nonce: d.val_at(0)?, + gas_price: d.val_at(1)?, + gas: d.val_at(2)?, + action: d.val_at(3)?, + value: d.val_at(4)?, + data: d.val_at(5)?, + }) + } } /// Signed transaction information without verified signature. #[derive(Debug, Clone, Eq, PartialEq)] pub struct UnverifiedLegacyTransaction { - /// Plain Transaction. - pub unsigned: LegacyTransaction, - /// The V field of the signature; the LS bit described which half of the curve our point falls - /// in. The MS bits describe which chain this transaction is for. If 27/28, its for all chains. - /// normally fixed with chain_id for Eip155 - pub network_v: u64, - /// The R field of the signature; helps describe the point on the curve. - pub r: U256, - /// The S field of the signature; helps describe the point on the curve. - pub s: U256, - /// Hash of the transaction - pub hash: H256, + /// Plain Transaction. + pub unsigned: LegacyTransaction, + /// The V field of the signature; the LS bit described which half of the curve our point falls + /// in. The MS bits describe which chain this transaction is for. If 27/28, its for all chains. + /// normally fixed with chain_id for Eip155 + pub network_v: u64, + /// The R field of the signature; helps describe the point on the curve. + pub r: U256, + /// The S field of the signature; helps describe the point on the curve. + pub s: U256, + /// Hash of the transaction + pub hash: H256, } impl Deref for UnverifiedLegacyTransaction { - type Target = LegacyTransaction; + type Target = LegacyTransaction; - fn deref(&self) -> &Self::Target { - &self.unsigned - } + fn deref(&self) -> &Self::Target { &self.unsigned } } impl rlp::Decodable for UnverifiedLegacyTransaction { - fn decode(d: &Rlp) -> Result { - if d.item_count()? != 9 { - return Err(DecoderError::RlpIncorrectListLen); - } - let hash = keccak(d.as_raw()); - Ok(UnverifiedLegacyTransaction { - unsigned: LegacyTransaction::decode(d)?, - network_v: d.val_at(6)?, - r: d.val_at(7)?, - s: d.val_at(8)?, - hash, - }) - } + fn decode(d: &Rlp) -> Result { + if d.item_count()? != 9 { + return Err(DecoderError::RlpIncorrectListLen); + } + let hash = keccak(d.as_raw()); + Ok(UnverifiedLegacyTransaction { + unsigned: LegacyTransaction::decode(d)?, + network_v: d.val_at(6)?, + r: d.val_at(7)?, + s: d.val_at(8)?, + hash, + }) + } } impl rlp::Encodable for UnverifiedLegacyTransaction { - fn rlp_append(&self, s: &mut RlpStream) { - self.rlp_append_sealed_transaction(s) - } + fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_sealed_transaction(s) } } impl SignedTransactionShared for UnverifiedLegacyTransaction { - fn set_hash(&mut self, hash: H256) { - self.hash = hash; - } + fn set_hash(&mut self, hash: H256) { self.hash = hash; } } impl UnverifiedLegacyTransaction { - /// Append object with a signature into RLP stream - pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { - s.begin_list(9); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - s.append(&self.action); - s.append(&self.value); - s.append(&self.data); - s.append(&self.network_v); - s.append(&self.r); - s.append(&self.s); - } - - pub fn standard_v(&self) -> u8 { - eip155_methods::check_replay_protection(self.network_v) - } - - pub fn to_network_v(v: u64, chain_id: Option) -> u64 { - eip155_methods::add_chain_replay_protection(v, chain_id) - } + /// Append object with a signature into RLP stream + pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + s.begin_list(9); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + s.append(&self.action); + s.append(&self.value); + s.append(&self.data); + s.append(&self.network_v); + s.append(&self.r); + s.append(&self.s); + } + + pub fn standard_v(&self) -> u8 { eip155_methods::check_replay_protection(self.network_v) } + + pub fn to_network_v(v: u64, chain_id: Option) -> u64 { + eip155_methods::add_chain_replay_protection(v, chain_id) + } } /// Replay protection logic for v part of transaction's signature pub mod eip155_methods { - /// Adds chain id into v - pub fn add_chain_replay_protection(v: u64, chain_id: Option) -> u64 { - v + if let Some(n) = chain_id { 35 + n * 2 } else { 27 } - } - - /// Returns refined v - /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. - pub fn check_replay_protection(v: u64) -> u8 { - match v { - v if v == 27 => 0, - v if v == 28 => 1, - v if v > 36 => ((v - 1) % 2) as u8, - _ => 4, - } - } + /// Adds chain id into v + pub fn add_chain_replay_protection(v: u64, chain_id: Option) -> u64 { + v + if let Some(n) = chain_id { 35 + n * 2 } else { 27 } + } + + /// Returns refined v + /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. + pub fn check_replay_protection(v: u64) -> u8 { + match v { + v if v == 27 => 0, + v if v == 28 => 1, + v if v > 36 => ((v - 1) % 2) as u8, + _ => 4, + } + } } diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs index af6123af3dc..8f12c327411 100644 --- a/ethcore/transaction/src/transaction/tx_builders.rs +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -1,145 +1,126 @@ //! Transaction builders -use super::{ - AccessList, Action, Bytes, Eip1559Transaction, Eip2930Transaction, LegacyTransaction, - TransactionWrapper, TxType, U256, -}; +use super::{AccessList, Action, Bytes, Eip1559Transaction, Eip2930Transaction, LegacyTransaction, TransactionWrapper, + TxType, U256}; use std::fmt; #[derive(Debug, PartialEq, Clone)] pub enum TxBuilderError { - /// Invalid tx type - InvalidTxType, - /// No gas price - NoGasPriceSet, - /// No max gas fee or priority fee set - NoFeePerGasSet, - /// Chain id must be set for tx type >= 1 - NoChainIdSet, + /// Invalid tx type + InvalidTxType, + /// No gas price + NoGasPriceSet, + /// No max gas fee or priority fee set + NoFeePerGasSet, + /// Chain id must be set for tx type >= 1 + NoChainIdSet, } impl fmt::Display for TxBuilderError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let msg: String = match *self { - TxBuilderError::InvalidTxType => "Invalid transaction type set".into(), - TxBuilderError::NoGasPriceSet => "No gas price set".into(), - TxBuilderError::NoFeePerGasSet => "No gas fee or priority fee per gas set".into(), - TxBuilderError::NoChainIdSet => "Chain id must be set".into(), - }; - f.write_fmt(format_args!("Transaction builder error ({})", msg)) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let msg: String = match *self { + TxBuilderError::InvalidTxType => "Invalid transaction type set".into(), + TxBuilderError::NoGasPriceSet => "No gas price set".into(), + TxBuilderError::NoFeePerGasSet => "No gas fee or priority fee per gas set".into(), + TxBuilderError::NoChainIdSet => "Chain id must be set".into(), + }; + f.write_fmt(format_args!("Transaction builder error ({})", msg)) + } } pub struct TransactionWrapperBuilder { - tx_type: TxType, - chain_id: Option, - nonce: U256, - gas_price: Option, - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - gas: U256, - action: Action, - value: U256, - data: Bytes, - access_list: Option, + tx_type: TxType, + chain_id: Option, + nonce: U256, + gas_price: Option, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + gas: U256, + action: Action, + value: U256, + data: Bytes, + access_list: Option, } impl TransactionWrapperBuilder { - pub fn new( - tx_type: TxType, - nonce: U256, - gas: U256, - action: Action, - value: U256, - data: Bytes, - ) -> Self { - Self { - tx_type, - chain_id: None, - nonce, - gas, - gas_price: None, - max_fee_per_gas: None, - max_priority_fee_per_gas: None, - action, - value, - data, - access_list: None, - } - } + pub fn new(tx_type: TxType, nonce: U256, gas: U256, action: Action, value: U256, data: Bytes) -> Self { + Self { + tx_type, + chain_id: None, + nonce, + gas, + gas_price: None, + max_fee_per_gas: None, + max_priority_fee_per_gas: None, + action, + value, + data, + access_list: None, + } + } - pub fn with_chain_id(mut self, chain_id: u64) -> Self { - self.chain_id = Some(chain_id); - self - } + pub fn with_chain_id(mut self, chain_id: u64) -> Self { + self.chain_id = Some(chain_id); + self + } - pub fn with_gas_price(mut self, gas_price: U256) -> Self { - self.gas_price = Some(gas_price); - self - } + pub fn with_gas_price(mut self, gas_price: U256) -> Self { + self.gas_price = Some(gas_price); + self + } - pub fn with_priority_fee_per_gas( - mut self, - max_fee_per_gas: U256, - max_priority_fee_per_gas: U256, - ) -> Self { - self.max_fee_per_gas = Some(max_fee_per_gas); - self.max_priority_fee_per_gas = Some(max_priority_fee_per_gas); - self - } + pub fn with_priority_fee_per_gas(mut self, max_fee_per_gas: U256, max_priority_fee_per_gas: U256) -> Self { + self.max_fee_per_gas = Some(max_fee_per_gas); + self.max_priority_fee_per_gas = Some(max_priority_fee_per_gas); + self + } - pub fn with_access_list(mut self, access_list: AccessList) -> Self { - self.access_list = Some(access_list); - self - } + pub fn with_access_list(mut self, access_list: AccessList) -> Self { + self.access_list = Some(access_list); + self + } - pub fn build(self) -> Result { - match self.tx_type { - TxType::Legacy => Ok(TransactionWrapper::Legacy(LegacyTransaction { - nonce: self.nonce, - gas_price: self - .gas_price - .ok_or_else(|| TxBuilderError::NoGasPriceSet)?, - gas: self.gas, - action: self.action, - value: self.value, - data: self.data, - })), - TxType::Type1 => Ok(TransactionWrapper::Eip2930(Eip2930Transaction { - chain_id: self.chain_id.ok_or_else(|| TxBuilderError::NoChainIdSet)?, - nonce: self.nonce, - gas_price: self - .gas_price - .ok_or_else(|| TxBuilderError::NoGasPriceSet)?, - gas: self.gas, - action: self.action, - value: self.value, - data: self.data, - access_list: if let Some(access_list) = self.access_list { - access_list - } else { - AccessList::default() - }, - })), - TxType::Type2 => Ok(TransactionWrapper::Eip1559(Eip1559Transaction { - chain_id: self.chain_id.ok_or_else(|| TxBuilderError::NoChainIdSet)?, - nonce: self.nonce, - max_fee_per_gas: self - .max_fee_per_gas - .ok_or_else(|| TxBuilderError::NoFeePerGasSet)?, - max_priority_fee_per_gas: self - .max_priority_fee_per_gas - .ok_or_else(|| TxBuilderError::NoFeePerGasSet)?, - gas: self.gas, - action: self.action, - value: self.value, - data: self.data, - access_list: if let Some(access_list) = self.access_list { - access_list - } else { - AccessList::default() - }, - })), - TxType::Invalid => Err(TxBuilderError::InvalidTxType), - } - } + pub fn build(self) -> Result { + match self.tx_type { + TxType::Legacy => Ok(TransactionWrapper::Legacy(LegacyTransaction { + nonce: self.nonce, + gas_price: self.gas_price.ok_or_else(|| TxBuilderError::NoGasPriceSet)?, + gas: self.gas, + action: self.action, + value: self.value, + data: self.data, + })), + TxType::Type1 => Ok(TransactionWrapper::Eip2930(Eip2930Transaction { + chain_id: self.chain_id.ok_or_else(|| TxBuilderError::NoChainIdSet)?, + nonce: self.nonce, + gas_price: self.gas_price.ok_or_else(|| TxBuilderError::NoGasPriceSet)?, + gas: self.gas, + action: self.action, + value: self.value, + data: self.data, + access_list: if let Some(access_list) = self.access_list { + access_list + } else { + AccessList::default() + }, + })), + TxType::Type2 => Ok(TransactionWrapper::Eip1559(Eip1559Transaction { + chain_id: self.chain_id.ok_or_else(|| TxBuilderError::NoChainIdSet)?, + nonce: self.nonce, + max_fee_per_gas: self.max_fee_per_gas.ok_or_else(|| TxBuilderError::NoFeePerGasSet)?, + max_priority_fee_per_gas: self + .max_priority_fee_per_gas + .ok_or_else(|| TxBuilderError::NoFeePerGasSet)?, + gas: self.gas, + action: self.action, + value: self.value, + data: self.data, + access_list: if let Some(access_list) = self.access_list { + access_list + } else { + AccessList::default() + }, + })), + TxType::Invalid => Err(TxBuilderError::InvalidTxType), + } + } } diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 2bf5ad0447d..00000000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -stable diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000000..0f36ce4d603 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2022-10-29" +components = ["rustfmt", "clippy"] diff --git a/rustfmt.toml b/rustfmt.toml index 9601de2e1e1..55d1bb5ff2c 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,7 +1,49 @@ -max_width=100 -tab_spaces=4 -fn_call_width=100 -struct_lit_width=32 -single_line_if_else_max_width=100 -reorder_imports=true -hard_tabs=true +# Enable unstable features on stable and beta channels (unstable features are available by default on nightly). +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#unstable_features +unstable_features = true + +# Put single-expression functions on a single line +# Note: Unstable +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#fn_single_line +fn_single_line = true + +# Force multiline closure and match arm bodies to be wrapped in a block +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#force_multiline_blocks +force_multiline_blocks = false + +# Indent style of imports +# Note: Unstable +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#imports_indent +imports_indent = "Visual" + +# Write an item and its attribute on the same line if their combined width is below a threshold +# Note: Unstable +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#inline_attribute_width +inline_attribute_width = 65 + +# Put a trailing comma after a block based match arm (non-block arms are not affected) +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#match_block_trailing_comma +match_block_trailing_comma = true + +# Maximum width of each line. +# Default: 100 +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#max_width +max_width = 120 + +# Unix or Windows line endings +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#newline_style +newline_style = "Auto" + +# When structs, slices, arrays, and block/array-like macros are used as the last argument in an expression list, +# allow them to overflow (like blocks/closures) instead of being indented on a new line. +# Note: Unstable +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#overflow_delimited_expr +overflow_delimited_expr = true + +# Number of spaces per tab +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#tab_spaces +tab_spaces = 4 + +# Use field initialize shorthand if possible. +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#use_field_init_shorthand +use_field_init_shorthand = true From 66bee37147ac45aa2a1419676a902f7528eba273 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 29 Mar 2024 15:01:37 +0500 Subject: [PATCH 17/27] fix clippy err --- ethcore/transaction/src/error.rs | 2 -- ethcore/transaction/src/transaction.rs | 19 +++++++++---------- .../transaction/src/transaction/eip1559.rs | 2 +- .../transaction/src/transaction/eip2930.rs | 2 +- .../src/transaction/tx_builders.rs | 12 ++++++------ 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index 5c090846902..d85980c4145 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -17,8 +17,6 @@ use std::{error, fmt}; use ethereum_types::U256; -use ethkey; -use rlp; use unexpected::OutOfBounds; #[derive(Debug, PartialEq, Clone)] diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 0486e22de12..aa016e2db69 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -23,7 +23,6 @@ use ethereum_types::{Address, H160, H256, U256}; use ethkey::{self, public_to_address, recover, Public, Secret, Signature}; use hash::keccak; use rlp::{self, DecoderError, Rlp, RlpStream}; -use std::convert::TryInto; use std::ops::Deref; mod legacy; @@ -258,7 +257,7 @@ impl UnverifiedTransactionWrapper { unsigned, r, s, - v: v.try_into().unwrap(), + v, hash, }) }, @@ -267,7 +266,7 @@ impl UnverifiedTransactionWrapper { unsigned, r, s, - v: v.try_into().unwrap(), + v, hash, }) }, @@ -327,7 +326,7 @@ impl UnverifiedTransactionWrapper { /// Checks whether the signature has a low 's' value. pub fn check_low_s(&self) -> Result<(), ethkey::Error> { if !self.signature().is_low_s() { - Err(ethkey::Error::InvalidSignature.into()) + Err(ethkey::Error::InvalidSignature) } else { Ok(()) } @@ -338,10 +337,10 @@ impl UnverifiedTransactionWrapper { /// Recovers the public key of the sender. pub fn recover_public(&self) -> Result { - Ok(recover( + recover( &self.signature(), &self.unsigned().message_hash(self.chain_id_from_v()), - )?) + ) } /// Do basic validation, checking for valid signature and minimum gas, @@ -419,8 +418,8 @@ impl UnverifiedTransactionWrapper { fn v(&self) -> u64 { match self { UnverifiedTransactionWrapper::Legacy(tx) => tx.network_v, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.v as u64, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.v as u64, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.v, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.v, } } @@ -521,7 +520,7 @@ impl LocalizedTransaction { return sender; } if self.is_unsigned() { - return UNSIGNED_SENDER.clone(); + return UNSIGNED_SENDER; } let sender = public_to_address(&self.recover_public() .expect("LocalizedTransaction is always constructed from transaction from blockchain; Blockchain only stores verified transactions; qed")); @@ -579,7 +578,7 @@ fn h256_from_u256(num: U256) -> H256 { } /// Returns true if serialized tx has type as in eip-2718 -fn is_typed_transaction(d: &Rlp) -> bool { !d.is_list() && d.as_raw().len() > 0 && d.as_raw()[0] < 0x7f } +fn is_typed_transaction(d: &Rlp) -> bool { !d.is_list() && !d.as_raw().is_empty() && d.as_raw()[0] < 0x7f } #[cfg(test)] mod tests { diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs index ac5eef75fd6..d8dd2fb5d81 100644 --- a/ethcore/transaction/src/transaction/eip1559.rs +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -116,7 +116,7 @@ impl rlp::Decodable for UnverifiedEip1559Transaction { let unsigned = Eip1559Transaction::decode(d)?; let hash = keccak(d.as_raw()); let offset = unsigned.payload_length(); - if d.as_raw().len() < 1 { + if d.as_raw().is_empty() { return Err(DecoderError::RlpIsTooShort); } let list = Rlp::new(&d.as_raw()[1..]); diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs index a8c25244ad2..840ea88a37c 100644 --- a/ethcore/transaction/src/transaction/eip2930.rs +++ b/ethcore/transaction/src/transaction/eip2930.rs @@ -167,7 +167,7 @@ impl rlp::Decodable for UnverifiedEip2930Transaction { let unsigned = Eip2930Transaction::decode(d)?; let hash = keccak(d.as_raw()); let offset = unsigned.payload_length(); - if d.as_raw().len() < 1 { + if d.as_raw().is_empty() { return Err(DecoderError::RlpIsTooShort); } let list = Rlp::new(&d.as_raw()[1..]); diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs index 8f12c327411..3ebe431157f 100644 --- a/ethcore/transaction/src/transaction/tx_builders.rs +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -83,16 +83,16 @@ impl TransactionWrapperBuilder { match self.tx_type { TxType::Legacy => Ok(TransactionWrapper::Legacy(LegacyTransaction { nonce: self.nonce, - gas_price: self.gas_price.ok_or_else(|| TxBuilderError::NoGasPriceSet)?, + gas_price: self.gas_price.ok_or(TxBuilderError::NoGasPriceSet)?, gas: self.gas, action: self.action, value: self.value, data: self.data, })), TxType::Type1 => Ok(TransactionWrapper::Eip2930(Eip2930Transaction { - chain_id: self.chain_id.ok_or_else(|| TxBuilderError::NoChainIdSet)?, + chain_id: self.chain_id.ok_or(TxBuilderError::NoChainIdSet)?, nonce: self.nonce, - gas_price: self.gas_price.ok_or_else(|| TxBuilderError::NoGasPriceSet)?, + gas_price: self.gas_price.ok_or(TxBuilderError::NoGasPriceSet)?, gas: self.gas, action: self.action, value: self.value, @@ -104,12 +104,12 @@ impl TransactionWrapperBuilder { }, })), TxType::Type2 => Ok(TransactionWrapper::Eip1559(Eip1559Transaction { - chain_id: self.chain_id.ok_or_else(|| TxBuilderError::NoChainIdSet)?, + chain_id: self.chain_id.ok_or(TxBuilderError::NoChainIdSet)?, nonce: self.nonce, - max_fee_per_gas: self.max_fee_per_gas.ok_or_else(|| TxBuilderError::NoFeePerGasSet)?, + max_fee_per_gas: self.max_fee_per_gas.ok_or(TxBuilderError::NoFeePerGasSet)?, max_priority_fee_per_gas: self .max_priority_fee_per_gas - .ok_or_else(|| TxBuilderError::NoFeePerGasSet)?, + .ok_or(TxBuilderError::NoFeePerGasSet)?, gas: self.gas, action: self.action, value: self.value, From 025ebbc41affa4c217e06fc5bba5f53962ca65f6 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 29 Mar 2024 20:37:13 +0500 Subject: [PATCH 18/27] add cargo.lock to source control --- .gitignore | 2 - Cargo.lock | 711 +++++++++++++++++++++++++++++++++ ethcore/transaction/Cargo.lock | 698 ++++++++++++++++++++++++++++++++ ethkey/Cargo.lock | 672 +++++++++++++++++++++++++++++++ 4 files changed, 2081 insertions(+), 2 deletions(-) create mode 100644 Cargo.lock create mode 100644 ethcore/transaction/Cargo.lock create mode 100644 ethkey/Cargo.lock diff --git a/.gitignore b/.gitignore index 62ce30beec6..dab78134a77 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,6 @@ # Executables *.exe -Cargo.lock - # Generated by Cargo **/target/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000000..2760dfabef7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,711 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "edit-distance" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "ethbloom" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "ethcore-transaction" +version = "0.1.0" +dependencies = [ + "ethereum-types", + "ethkey", + "keccak-hash", + "rlp", + "rustc-hex", + "unexpected", +] + +[[package]] +name = "ethereum-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "ethkey" +version = "0.3.0" +dependencies = [ + "byteorder", + "edit-distance", + "ethereum-types", + "log", + "mem", + "rand 0.6.5", + "rustc-hex", + "secp256k1", + "serde", + "serde_derive", + "tiny-keccak 1.4.4", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "keccak-hash" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82bc5d5ca345b067619615f62ac6f93e7daa67eb82d080bc380ed480708ec9e3" +dependencies = [ + "primitive-types", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "mem" +version = "0.1.0" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "parity-ethereum" +version = "2.1.0" +dependencies = [ + "ethcore-transaction", + "ethkey", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.8", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "secp256k1" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +dependencies = [ + "rand 0.6.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tiny-keccak" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f11c56c1b46016bb1129db9399f905385490f3e17907e4a8430e57f9a5b979c" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unexpected" +version = "0.1.0" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[patch.unused]] +name = "ring" +version = "0.12.1" +source = "git+https://github.com/paritytech/ring#bae475e9f7ea7dd4ae671bef4b576089a9b06731" diff --git a/ethcore/transaction/Cargo.lock b/ethcore/transaction/Cargo.lock new file mode 100644 index 00000000000..b1c97a0a8e9 --- /dev/null +++ b/ethcore/transaction/Cargo.lock @@ -0,0 +1,698 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "edit-distance" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "ethbloom" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "ethcore-transaction" +version = "0.1.0" +dependencies = [ + "ethereum-types", + "ethkey", + "keccak-hash", + "rlp", + "rustc-hex", + "unexpected", +] + +[[package]] +name = "ethereum-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "ethkey" +version = "0.3.0" +dependencies = [ + "byteorder", + "edit-distance", + "ethereum-types", + "log", + "mem", + "rand 0.6.5", + "rustc-hex", + "secp256k1", + "serde", + "serde_derive", + "tiny-keccak 1.4.4", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "keccak-hash" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82bc5d5ca345b067619615f62ac6f93e7daa67eb82d080bc380ed480708ec9e3" +dependencies = [ + "primitive-types", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "mem" +version = "0.1.0" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.8", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "secp256k1" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +dependencies = [ + "rand 0.6.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tiny-keccak" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f11c56c1b46016bb1129db9399f905385490f3e17907e4a8430e57f9a5b979c" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unexpected" +version = "0.1.0" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/ethkey/Cargo.lock b/ethkey/Cargo.lock new file mode 100644 index 00000000000..df2998ad65b --- /dev/null +++ b/ethkey/Cargo.lock @@ -0,0 +1,672 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.2.0", +] + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "edit-distance" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "ethbloom" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "ethereum-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "ethkey" +version = "0.3.0" +dependencies = [ + "byteorder", + "edit-distance", + "ethereum-types", + "log", + "mem", + "rand 0.6.5", + "rustc-hex", + "secp256k1", + "serde", + "serde_derive", + "tiny-keccak 1.4.4", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "mem" +version = "0.1.0" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.8", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "secp256k1" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +dependencies = [ + "rand 0.6.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tiny-keccak" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f11c56c1b46016bb1129db9399f905385490f3e17907e4a8430e57f9a5b979c" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] From a0876b9733ba305c8ba8a589257c3d875b1837dc Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 29 Mar 2024 20:40:07 +0500 Subject: [PATCH 19/27] more removal of unsupported eip-86 code --- ethcore/transaction/src/transaction.rs | 17 ----------------- ethcore/transaction/src/transaction/eip2930.rs | 4 ---- 2 files changed, 21 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index aa016e2db69..82081b645d5 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -195,23 +195,6 @@ impl TransactionWrapper { public: None, } } - - /// Add EIP-86 compatible empty signature. - pub fn null_sign(self, chain_id: u64) -> SignedTransaction { - SignedTransaction { - transaction: UnverifiedTransactionWrapper::new( - self, - U256::zero(), - U256::zero(), - chain_id, - None, - H256::from_low_u64_ne(0), - ) - .compute_hash(), - sender: UNSIGNED_SENDER, - public: None, - } - } } #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs index 840ea88a37c..243d7779638 100644 --- a/ethcore/transaction/src/transaction/eip2930.rs +++ b/ethcore/transaction/src/transaction/eip2930.rs @@ -214,8 +214,4 @@ impl UnverifiedEip2930Transaction { self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns } - // EIP-86 or newer: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. - pub(crate) fn _validate_empty_sig(&self) -> bool { - true // TODO fix for eip2930 - } } From be513ae838fd5b6c3c425478fbe986511bbdebf2 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 29 Mar 2024 20:41:30 +0500 Subject: [PATCH 20/27] add validation of sig v param --- ethcore/transaction/src/transaction.rs | 104 ++++++++---------- .../transaction/src/transaction/eip1559.rs | 49 +++++++-- .../transaction/src/transaction/eip2930.rs | 49 ++++++--- ethcore/transaction/src/transaction/legacy.rs | 42 +++++-- .../src/transaction/tx_builders.rs | 4 +- 5 files changed, 149 insertions(+), 99 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 82081b645d5..2f8fe9a2f1f 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -18,7 +18,7 @@ //! Transaction data structure. -use crate::error; +use crate::{error, Error}; use ethereum_types::{Address, H160, H256, U256}; use ethkey::{self, public_to_address, recover, Public, Secret, Signature}; use hash::keccak; @@ -153,29 +153,29 @@ impl TransactionWrapper { } /// Signs the transaction as coming from `sender`. - pub fn sign(self, secret: &Secret, chain_id: Option) -> SignedTransaction { - let sig = ::ethkey::sign(secret, &self.message_hash(chain_id)) - .expect("data is valid and context has signing capabilities; qed"); - SignedTransaction::new(self.with_signature(sig, chain_id)).expect("secret is valid so it's recoverable") + pub fn sign(self, secret: &Secret, chain_id: Option) -> Result { + let sig = ::ethkey::sign(secret, &self.message_hash(chain_id))?; + Ok(SignedTransaction::new(self.with_signature(sig, chain_id)?)?) } /// Add signature to the transaction. - fn with_signature(self, sig: Signature, chain_id: Option) -> UnverifiedTransactionWrapper { - UnverifiedTransactionWrapper::new( + fn with_signature(self, sig: Signature, chain_id: Option) -> Result { + Ok(UnverifiedTransactionWrapper::new( self, sig.r().into(), sig.s().into(), sig.v() as u64, chain_id, H256::from_low_u64_ne(0), - ) - .compute_hash() + )? + .compute_hash()) } /// Useful for test incorrectly signed transactions. #[cfg(test)] pub fn invalid_sign(self) -> UnverifiedTransactionWrapper { UnverifiedTransactionWrapper::new(self, U256::one(), U256::one(), 0, None, H256::from_low_u64_ne(0)) + .unwrap() .compute_hash() } @@ -190,6 +190,7 @@ impl TransactionWrapper { None, H256::from_low_u64_ne(0), ) + .unwrap() .compute_hash(), sender: from, public: None, @@ -226,33 +227,17 @@ impl rlp::Decodable for UnverifiedTransactionWrapper { } impl UnverifiedTransactionWrapper { - fn new(tx: TransactionWrapper, r: U256, s: U256, v: u64, chain_id: Option, hash: H256) -> Self { + fn new(tx: TransactionWrapper, r: U256, s: U256, v: u64, chain_id: Option, hash: H256) -> Result { match tx { - TransactionWrapper::Legacy(unsigned) => UnverifiedTransactionWrapper::Legacy(UnverifiedLegacyTransaction { - unsigned, - r, - s, - network_v: UnverifiedLegacyTransaction::to_network_v(v, chain_id), - hash, - }), - TransactionWrapper::Eip2930(unsigned) => { - UnverifiedTransactionWrapper::Eip2930(UnverifiedEip2930Transaction { - unsigned, - r, - s, - v, - hash, - }) - }, - TransactionWrapper::Eip1559(unsigned) => { - UnverifiedTransactionWrapper::Eip1559(UnverifiedEip1559Transaction { - unsigned, - r, - s, - v, - hash, - }) - }, + TransactionWrapper::Legacy(unsigned) => Ok(UnverifiedTransactionWrapper::Legacy( + UnverifiedLegacyTransaction::new(unsigned, r, s, v, chain_id, hash)?, + )), + TransactionWrapper::Eip2930(unsigned) => Ok(UnverifiedTransactionWrapper::Eip2930( + UnverifiedEip2930Transaction::new(unsigned, r, s, v, hash)?, + )), + TransactionWrapper::Eip1559(unsigned) => Ok(UnverifiedTransactionWrapper::Eip1559( + UnverifiedEip1559Transaction::new(unsigned, r, s, v, hash)?, + )), } } @@ -275,9 +260,9 @@ impl UnverifiedTransactionWrapper { pub fn unsigned(&self) -> &TransactionSharedRet { match self { - UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Legacy(tx) => tx.deref() as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.deref() as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.deref() as &TransactionSharedRet, } } @@ -320,10 +305,7 @@ impl UnverifiedTransactionWrapper { /// Recovers the public key of the sender. pub fn recover_public(&self) -> Result { - recover( - &self.signature(), - &self.unsigned().message_hash(self.chain_id_from_v()), - ) + recover(&self.signature(), &self.unsigned().message_hash(self.chain_id_from_v())) } /// Do basic validation, checking for valid signature and minimum gas, @@ -386,32 +368,32 @@ impl UnverifiedTransactionWrapper { fn r(&self) -> U256 { match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.r, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.r, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.r, + UnverifiedTransactionWrapper::Legacy(tx) => tx.r(), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.r(), + UnverifiedTransactionWrapper::Eip1559(tx) => tx.r(), } } fn s(&self) -> U256 { match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.s, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.s, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.s, + UnverifiedTransactionWrapper::Legacy(tx) => tx.s(), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.s(), + UnverifiedTransactionWrapper::Eip1559(tx) => tx.s(), } } fn v(&self) -> u64 { match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.network_v, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.v, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.v, + UnverifiedTransactionWrapper::Legacy(tx) => tx.v(), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.v(), + UnverifiedTransactionWrapper::Eip1559(tx) => tx.v(), } } /// Get the hash of this transaction (keccak of the RLP). pub fn tx_hash(&self) -> H256 { match self { - UnverifiedTransactionWrapper::Legacy(tx) => tx.hash, - UnverifiedTransactionWrapper::Eip2930(tx) => tx.hash, - UnverifiedTransactionWrapper::Eip1559(tx) => tx.hash, + UnverifiedTransactionWrapper::Legacy(tx) => tx.hash(), + UnverifiedTransactionWrapper::Eip2930(tx) => tx.hash(), + UnverifiedTransactionWrapper::Eip1559(tx) => tx.hash(), } } } @@ -459,9 +441,9 @@ impl SignedTransaction { pub fn unsigned(&self) -> &TransactionSharedRet { match &self.transaction { - UnverifiedTransactionWrapper::Legacy(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip2930(tx) => &tx.unsigned as &TransactionSharedRet, - UnverifiedTransactionWrapper::Eip1559(tx) => &tx.unsigned as &TransactionSharedRet, + UnverifiedTransactionWrapper::Legacy(tx) => tx.deref() as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip2930(tx) => tx.deref() as &TransactionSharedRet, + UnverifiedTransactionWrapper::Eip1559(tx) => tx.deref() as &TransactionSharedRet, } } @@ -610,7 +592,8 @@ mod tests { value: U256::from(1), data: b"Hello!".to_vec(), }) - .sign(&key.secret(), None); + .sign(&key.secret(), None) + .expect("sign transaction okay"); assert_eq!(Address::from(keccak(key.public())), t.sender()); assert_eq!(t.chain_id_from_v(), None); } @@ -649,7 +632,8 @@ mod tests { value: U256::from(1), data: b"Hello!".to_vec(), }) - .sign(&key.secret(), Some(69)); + .sign(&key.secret(), Some(69)) + .expect("sign transaction okay"); assert_eq!(Address::from(keccak(key.public())), t.sender()); assert_eq!(t.chain_id_from_v(), Some(69)); } @@ -660,7 +644,7 @@ mod tests { let test_vector = |tx_data: &str, address: &'static str| { let bytes: Vec = FromHex::from_hex(tx_data).unwrap(); - let signed = rlp::decode(&bytes).expect("decoding tx data failed"); + let signed = rlp::decode(&bytes).expect("decoding tx data valid"); let signed = SignedTransaction::new(signed).unwrap(); let expected = Address::from_str(address).unwrap(); diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs index d8dd2fb5d81..f687b873492 100644 --- a/ethcore/transaction/src/transaction/eip1559.rs +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -5,6 +5,7 @@ use super::AccessList; use super::SignedTransactionShared; use super::{Action, Bytes, TransactionShared, TxType}; +use crate::Error; use ethereum_types::{H256, U256}; use hash::keccak; use rlp::{self, DecoderError, Rlp, RlpStream}; @@ -35,12 +36,12 @@ pub struct Eip1559Transaction { } impl Eip1559Transaction { - const fn payload_length(&self) -> usize { 9 } + const fn payload_size(&self) -> usize { 9 } /// Append object with a without signature into RLP stream fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { s.append(&(TxType::Type2 as u8)); - s.begin_list(self.payload_length()); + s.begin_list(self.payload_size()); s.append(&self.chain_id); s.append(&self.nonce); s.append(&self.max_priority_fee_per_gas); @@ -94,15 +95,15 @@ impl rlp::Decodable for Eip1559Transaction { #[derive(Debug, Clone, Eq, PartialEq)] pub struct UnverifiedEip1559Transaction { /// Plain Transaction. - pub unsigned: Eip1559Transaction, + unsigned: Eip1559Transaction, /// The V field of the signature - pub v: u64, + v: u64, /// The R field of the signature; helps describe the point on the curve. - pub r: U256, + r: U256, /// The S field of the signature; helps describe the point on the curve. - pub s: U256, + s: U256, /// Hash of the transaction - pub hash: H256, + hash: H256, } impl Deref for UnverifiedEip1559Transaction { @@ -115,14 +116,18 @@ impl rlp::Decodable for UnverifiedEip1559Transaction { fn decode(d: &Rlp) -> Result { let unsigned = Eip1559Transaction::decode(d)?; let hash = keccak(d.as_raw()); - let offset = unsigned.payload_length(); + let offset = unsigned.payload_size(); if d.as_raw().is_empty() { return Err(DecoderError::RlpIsTooShort); } let list = Rlp::new(&d.as_raw()[1..]); + let v = list.val_at(offset)?; + if !Self::validate_v(v) { + return Err(DecoderError::Custom("invalid sig v")); + } Ok(UnverifiedEip1559Transaction { unsigned, - v: list.val_at(offset)?, + v, r: list.val_at(offset + 1)?, s: list.val_at(offset + 2)?, hash, @@ -139,13 +144,28 @@ impl SignedTransactionShared for UnverifiedEip1559Transaction { } impl UnverifiedEip1559Transaction { + pub fn new(unsigned: Eip1559Transaction, r: U256, s: U256, v: u64, hash: H256) -> Result { + if !Self::validate_v(v) { + return Err(Error::InvalidSignature("invalid sig v".into())); + } + Ok(UnverifiedEip1559Transaction { + unsigned, + r, + s, + v, + hash, + }) + } + + fn validate_v(v: u64) -> bool { (0..=1).contains(&v) } + /// tx list item count - fn payload_length(&self) -> usize { self.unsigned.payload_length() + 3 } + fn payload_size(&self) -> usize { self.unsigned.payload_size() + 3 } /// Append object with a signature into RLP stream pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { s.append(&(TxType::Type2 as u8)); - s.begin_list(self.payload_length()); + s.begin_list(self.payload_size()); s.append(&self.chain_id); s.append(&self.nonce); s.append(&self.max_priority_fee_per_gas); @@ -161,6 +181,11 @@ impl UnverifiedEip1559Transaction { } pub fn standard_v(&self) -> u8 { - self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns + self.v.try_into().expect("parity 0 or 1") // ensured that parity is 0 or 1 for tx type 2 } + + pub fn r(&self) -> U256 { self.r } + pub fn s(&self) -> U256 { self.s } + pub fn v(&self) -> u64 { self.v } + pub fn hash(&self) -> H256 { self.hash } } diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs index 243d7779638..ade7e2229c7 100644 --- a/ethcore/transaction/src/transaction/eip2930.rs +++ b/ethcore/transaction/src/transaction/eip2930.rs @@ -3,7 +3,7 @@ //! Eip 2930 transaction encoding/decoding and specific checks use super::{Action, Bytes, TransactionShared, TxType}; -use crate::SignedTransactionShared; +use crate::{Error, SignedTransactionShared}; use ethereum_types::{Address, H256, U256}; use hash::keccak; use rlp::{self, DecoderError, Rlp, RlpStream}; @@ -88,12 +88,12 @@ pub struct Eip2930Transaction { } impl Eip2930Transaction { - const fn payload_length(&self) -> usize { 8 } + const fn payload_size(&self) -> usize { 8 } /// Append object with a without signature into RLP stream fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { s.append(&(TxType::Type1 as u8)); - s.begin_list(self.payload_length()); + s.begin_list(self.payload_size()); s.append(&self.chain_id); s.append(&self.nonce); s.append(&self.gas_price); @@ -145,15 +145,15 @@ impl rlp::Decodable for Eip2930Transaction { #[derive(Debug, Clone, Eq, PartialEq)] pub struct UnverifiedEip2930Transaction { /// Plain Transaction. - pub unsigned: Eip2930Transaction, + unsigned: Eip2930Transaction, /// The V field of the signature - pub v: u64, + v: u64, /// The R field of the signature; helps describe the point on the curve. - pub r: U256, + r: U256, /// The S field of the signature; helps describe the point on the curve. - pub s: U256, + s: U256, /// Hash of the transaction - pub hash: H256, + hash: H256, } impl Deref for UnverifiedEip2930Transaction { @@ -166,14 +166,18 @@ impl rlp::Decodable for UnverifiedEip2930Transaction { fn decode(d: &Rlp) -> Result { let unsigned = Eip2930Transaction::decode(d)?; let hash = keccak(d.as_raw()); - let offset = unsigned.payload_length(); + let offset = unsigned.payload_size(); if d.as_raw().is_empty() { return Err(DecoderError::RlpIsTooShort); } let list = Rlp::new(&d.as_raw()[1..]); + let v = list.val_at(offset)?; + if !Self::validate_v(v) { + return Err(DecoderError::Custom("invalid sig v")); + } Ok(UnverifiedEip2930Transaction { unsigned, - v: list.val_at(offset)?, + v, r: list.val_at(offset + 1)?, s: list.val_at(offset + 2)?, hash, @@ -190,13 +194,28 @@ impl SignedTransactionShared for UnverifiedEip2930Transaction { } impl UnverifiedEip2930Transaction { + pub fn new(unsigned: Eip2930Transaction, r: U256, s: U256, v: u64, hash: H256) -> Result { + if !Self::validate_v(v) { + return Err(Error::InvalidSignature("invalid sig v".into())); + } + Ok(UnverifiedEip2930Transaction { + unsigned, + r, + s, + v, + hash, + }) + } + + fn validate_v(v: u64) -> bool { (0..=1).contains(&v) } + /// tx list item count - fn payload_length(&self) -> usize { self.unsigned.payload_length() + 3 } + fn payload_size(&self) -> usize { self.unsigned.payload_size() + 3 } /// Append object with a signature into RLP stream pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { s.append(&(TxType::Type1 as u8)); - s.begin_list(self.payload_length()); + s.begin_list(self.payload_size()); s.append(&self.chain_id); s.append(&self.nonce); s.append(&self.gas_price); @@ -211,7 +230,11 @@ impl UnverifiedEip2930Transaction { } pub fn standard_v(&self) -> u8 { - self.v.try_into().unwrap_or_default() // we should have parity 0 or 1 for v2 txns + self.v.try_into().expect("parity 0 or 1") // ensured that parity is 0 or 1 for tx type 1 } + pub fn r(&self) -> U256 { self.r } + pub fn s(&self) -> U256 { self.s } + pub fn v(&self) -> u64 { self.v } + pub fn hash(&self) -> H256 { self.hash } } diff --git a/ethcore/transaction/src/transaction/legacy.rs b/ethcore/transaction/src/transaction/legacy.rs index 7cffdce943f..f2ab883cceb 100644 --- a/ethcore/transaction/src/transaction/legacy.rs +++ b/ethcore/transaction/src/transaction/legacy.rs @@ -3,7 +3,7 @@ //! Legacy transaction encoding/decoding and specific checks use super::{Action, Bytes, TransactionShared}; -use crate::SignedTransactionShared; +use crate::{Error, SignedTransactionShared}; use ethereum_types::{H256, U256}; use hash::keccak; use rlp::{self, DecoderError, Rlp, RlpStream}; @@ -29,7 +29,7 @@ pub struct LegacyTransaction { impl LegacyTransaction { /// tx list item count - fn payload_length(chain_id: Option) -> usize { + fn payload_size(chain_id: Option) -> usize { if chain_id.is_none() { 6 } else { @@ -39,7 +39,7 @@ impl LegacyTransaction { /// Append object with a without signature into RLP stream fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, chain_id: Option) { - s.begin_list(Self::payload_length(chain_id)); + s.begin_list(Self::payload_size(chain_id)); s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); @@ -84,17 +84,17 @@ impl rlp::Decodable for LegacyTransaction { #[derive(Debug, Clone, Eq, PartialEq)] pub struct UnverifiedLegacyTransaction { /// Plain Transaction. - pub unsigned: LegacyTransaction, + unsigned: LegacyTransaction, /// The V field of the signature; the LS bit described which half of the curve our point falls /// in. The MS bits describe which chain this transaction is for. If 27/28, its for all chains. /// normally fixed with chain_id for Eip155 - pub network_v: u64, + network_v: u64, /// The R field of the signature; helps describe the point on the curve. - pub r: U256, + r: U256, /// The S field of the signature; helps describe the point on the curve. - pub s: U256, + s: U256, /// Hash of the transaction - pub hash: H256, + hash: H256, } impl Deref for UnverifiedLegacyTransaction { @@ -128,6 +128,23 @@ impl SignedTransactionShared for UnverifiedLegacyTransaction { } impl UnverifiedLegacyTransaction { + pub fn new( + unsigned: LegacyTransaction, + r: U256, + s: U256, + v: u64, + chain_id: Option, + hash: H256, + ) -> Result { + Ok(UnverifiedLegacyTransaction { + unsigned, + r, + s, + network_v: Self::to_network_v(v, chain_id), + hash, + }) + } + /// Append object with a signature into RLP stream pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { s.begin_list(9); @@ -144,9 +161,12 @@ impl UnverifiedLegacyTransaction { pub fn standard_v(&self) -> u8 { eip155_methods::check_replay_protection(self.network_v) } - pub fn to_network_v(v: u64, chain_id: Option) -> u64 { - eip155_methods::add_chain_replay_protection(v, chain_id) - } + fn to_network_v(v: u64, chain_id: Option) -> u64 { eip155_methods::add_chain_replay_protection(v, chain_id) } + + pub fn r(&self) -> U256 { self.r } + pub fn s(&self) -> U256 { self.s } + pub fn v(&self) -> u64 { self.network_v } + pub fn hash(&self) -> H256 { self.hash } } /// Replay protection logic for v part of transaction's signature diff --git a/ethcore/transaction/src/transaction/tx_builders.rs b/ethcore/transaction/src/transaction/tx_builders.rs index 3ebe431157f..dc079f0546c 100644 --- a/ethcore/transaction/src/transaction/tx_builders.rs +++ b/ethcore/transaction/src/transaction/tx_builders.rs @@ -107,9 +107,7 @@ impl TransactionWrapperBuilder { chain_id: self.chain_id.ok_or(TxBuilderError::NoChainIdSet)?, nonce: self.nonce, max_fee_per_gas: self.max_fee_per_gas.ok_or(TxBuilderError::NoFeePerGasSet)?, - max_priority_fee_per_gas: self - .max_priority_fee_per_gas - .ok_or(TxBuilderError::NoFeePerGasSet)?, + max_priority_fee_per_gas: self.max_priority_fee_per_gas.ok_or(TxBuilderError::NoFeePerGasSet)?, gas: self.gas, action: self.action, value: self.value, From 8f1b823dcb60f1d514a622fdcca5067372850600 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 29 Mar 2024 21:56:04 +0500 Subject: [PATCH 21/27] add fn new_with_network_v for legacy txns creation from txns received from network --- ethcore/transaction/src/transaction.rs | 5 ++++- ethcore/transaction/src/transaction/legacy.rs | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 2f8fe9a2f1f..2014125790f 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -227,10 +227,13 @@ impl rlp::Decodable for UnverifiedTransactionWrapper { } impl UnverifiedTransactionWrapper { + /// Creates new UnverifiedTransactionWrapper from TransactionWrapper and signature params. + /// For Legacy transactions param v must be not modified for replay protection with chain_id. + /// Internally used. fn new(tx: TransactionWrapper, r: U256, s: U256, v: u64, chain_id: Option, hash: H256) -> Result { match tx { TransactionWrapper::Legacy(unsigned) => Ok(UnverifiedTransactionWrapper::Legacy( - UnverifiedLegacyTransaction::new(unsigned, r, s, v, chain_id, hash)?, + UnverifiedLegacyTransaction::new_with_chain_id(unsigned, r, s, v, chain_id, hash)?, )), TransactionWrapper::Eip2930(unsigned) => Ok(UnverifiedTransactionWrapper::Eip2930( UnverifiedEip2930Transaction::new(unsigned, r, s, v, hash)?, diff --git a/ethcore/transaction/src/transaction/legacy.rs b/ethcore/transaction/src/transaction/legacy.rs index f2ab883cceb..f0f9a7d0791 100644 --- a/ethcore/transaction/src/transaction/legacy.rs +++ b/ethcore/transaction/src/transaction/legacy.rs @@ -128,7 +128,7 @@ impl SignedTransactionShared for UnverifiedLegacyTransaction { } impl UnverifiedLegacyTransaction { - pub fn new( + pub fn new_with_chain_id( unsigned: LegacyTransaction, r: U256, s: U256, @@ -145,6 +145,22 @@ impl UnverifiedLegacyTransaction { }) } + pub fn new_with_network_v( + unsigned: LegacyTransaction, + r: U256, + s: U256, + network_v: u64, + hash: H256, + ) -> Result { + Ok(UnverifiedLegacyTransaction { + unsigned, + r, + s, + network_v, + hash, + }) + } + /// Append object with a signature into RLP stream pub(crate) fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { s.begin_list(9); From b6064ceec79ebf0ff896889196e2991efee2d58d Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 29 Mar 2024 22:13:16 +0500 Subject: [PATCH 22/27] add sig v check for legacy tx --- ethcore/transaction/src/transaction/legacy.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethcore/transaction/src/transaction/legacy.rs b/ethcore/transaction/src/transaction/legacy.rs index f0f9a7d0791..b962858a394 100644 --- a/ethcore/transaction/src/transaction/legacy.rs +++ b/ethcore/transaction/src/transaction/legacy.rs @@ -136,6 +136,9 @@ impl UnverifiedLegacyTransaction { chain_id: Option, hash: H256, ) -> Result { + if !Self::validate_v(v) { + return Err(Error::InvalidSignature("invalid sig v".into())); + } Ok(UnverifiedLegacyTransaction { unsigned, r, @@ -145,6 +148,8 @@ impl UnverifiedLegacyTransaction { }) } + fn validate_v(v: u64) -> bool { (0..=1).contains(&v) } + pub fn new_with_network_v( unsigned: LegacyTransaction, r: U256, From 7fbfac76c6a2b889ae334aaa770782321d4c6b2b Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 31 Mar 2024 13:22:05 +0500 Subject: [PATCH 23/27] allow unsigned tx creation with builder only --- ethcore/transaction/src/transaction.rs | 4 ++-- ethcore/transaction/src/transaction/eip1559.rs | 18 +++++++++--------- ethcore/transaction/src/transaction/eip2930.rs | 16 ++++++++-------- ethcore/transaction/src/transaction/legacy.rs | 12 ++++++------ 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 2014125790f..da3f627c771 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -37,7 +37,7 @@ pub use self::eip1559::{Eip1559Transaction, UnverifiedEip1559Transaction}; type BlockNumber = u64; type Bytes = Vec; -#[derive(PartialEq)] +#[derive(Clone, PartialEq)] pub enum TxType { Legacy, Type1 = 1, @@ -227,7 +227,7 @@ impl rlp::Decodable for UnverifiedTransactionWrapper { } impl UnverifiedTransactionWrapper { - /// Creates new UnverifiedTransactionWrapper from TransactionWrapper and signature params. + /// Creates new UnverifiedTransactionWrapper from TransactionWrapper and signature params. /// For Legacy transactions param v must be not modified for replay protection with chain_id. /// Internally used. fn new(tx: TransactionWrapper, r: U256, s: U256, v: u64, chain_id: Option, hash: H256) -> Result { diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs index f687b873492..02056a1464b 100644 --- a/ethcore/transaction/src/transaction/eip1559.rs +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -16,23 +16,23 @@ use std::{convert::TryInto, ops::Deref}; #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Eip1559Transaction { /// Simple replay attack protection - pub chain_id: u64, + pub(crate) chain_id: u64, /// Nonce. - pub nonce: U256, + pub(crate) nonce: U256, /// Max fee per gas. - pub max_fee_per_gas: U256, + pub(crate) max_fee_per_gas: U256, /// Max priority fee per gas. - pub max_priority_fee_per_gas: U256, + pub(crate) max_priority_fee_per_gas: U256, /// Gas paid up front for transaction execution. - pub gas: U256, + pub(crate) gas: U256, /// Action, can be either call or contract create. - pub action: Action, + pub(crate) action: Action, /// Transfered value. - pub value: U256, + pub(crate) value: U256, /// Transaction data. - pub data: Bytes, + pub(crate) data: Bytes, /// Access list. - pub access_list: AccessList, + pub(crate) access_list: AccessList, } impl Eip1559Transaction { diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs index ade7e2229c7..1ea3d38ee42 100644 --- a/ethcore/transaction/src/transaction/eip2930.rs +++ b/ethcore/transaction/src/transaction/eip2930.rs @@ -70,21 +70,21 @@ impl rlp::Encodable for AccessList { #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Eip2930Transaction { /// Simple replay attack protection - pub chain_id: u64, + pub(crate) chain_id: u64, /// Nonce. - pub nonce: U256, + pub(crate) nonce: U256, /// Gas price. - pub gas_price: U256, + pub(crate) gas_price: U256, /// Gas paid up front for transaction execution. - pub gas: U256, + pub(crate) gas: U256, /// Action, can be either call or contract create. - pub action: Action, + pub(crate) action: Action, /// Transfered value. - pub value: U256, + pub(crate) value: U256, /// Transaction data. - pub data: Bytes, + pub(crate) data: Bytes, /// Access list. - pub access_list: AccessList, + pub(crate) access_list: AccessList, } impl Eip2930Transaction { diff --git a/ethcore/transaction/src/transaction/legacy.rs b/ethcore/transaction/src/transaction/legacy.rs index b962858a394..e056aa15ae8 100644 --- a/ethcore/transaction/src/transaction/legacy.rs +++ b/ethcore/transaction/src/transaction/legacy.rs @@ -14,17 +14,17 @@ use std::ops::Deref; #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct LegacyTransaction { /// Nonce. - pub nonce: U256, + pub(crate) nonce: U256, /// Gas price. - pub gas_price: U256, + pub(crate) gas_price: U256, /// Gas paid up front for transaction execution. - pub gas: U256, + pub(crate) gas: U256, /// Action, can be either call or contract create. - pub action: Action, + pub(crate) action: Action, /// Transfered value. - pub value: U256, + pub(crate) value: U256, /// Transaction data. - pub data: Bytes, + pub(crate) data: Bytes, } impl LegacyTransaction { From 9ec173470b6970d9c06b93eeca005881fb5600a8 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 1 Apr 2024 15:37:32 +0500 Subject: [PATCH 24/27] fixed clippy errors --- ethcore/transaction/src/transaction.rs | 5 ++--- ethkey/src/error.rs | 6 +++--- ethkey/src/prefix.rs | 4 ++-- ethkey/src/secret.rs | 2 +- ethkey/src/signature.rs | 8 ++++---- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index da3f627c771..7f8a6226adf 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -595,7 +595,7 @@ mod tests { value: U256::from(1), data: b"Hello!".to_vec(), }) - .sign(&key.secret(), None) + .sign(key.secret(), None) .expect("sign transaction okay"); assert_eq!(Address::from(keccak(key.public())), t.sender()); assert_eq!(t.chain_id_from_v(), None); @@ -615,7 +615,6 @@ mod tests { assert_eq!(Address::from_low_u64_ne(0x69), t.sender()); assert_eq!(t.chain_id_from_v(), None); - let t = t.clone(); assert_eq!(Address::from_low_u64_ne(0x69), t.sender()); assert_eq!(t.chain_id_from_v(), None); } @@ -635,7 +634,7 @@ mod tests { value: U256::from(1), data: b"Hello!".to_vec(), }) - .sign(&key.secret(), Some(69)) + .sign(key.secret(), Some(69)) .expect("sign transaction okay"); assert_eq!(Address::from(keccak(key.public())), t.sender()); assert_eq!(t.chain_id_from_v(), Some(69)); diff --git a/ethkey/src/error.rs b/ethkey/src/error.rs index 7cba375d0f2..8da8bd54399 100644 --- a/ethkey/src/error.rs +++ b/ethkey/src/error.rs @@ -57,9 +57,9 @@ impl error::Error for Error { } } -impl Into for Error { - fn into(self) -> String { - format!("{}", self) +impl From for String { + fn from(err: Error) -> String { + format!("{}", err) } } diff --git a/ethkey/src/prefix.rs b/ethkey/src/prefix.rs index d66ae490a41..ea71b40339f 100644 --- a/ethkey/src/prefix.rs +++ b/ethkey/src/prefix.rs @@ -25,8 +25,8 @@ pub struct Prefix { impl Prefix { pub fn new(prefix: Vec, iterations: usize) -> Self { Prefix { - prefix: prefix, - iterations: iterations, + prefix, + iterations, } } } diff --git a/ethkey/src/secret.rs b/ethkey/src/secret.rs index 25adb7441af..1281bbcc91b 100644 --- a/ethkey/src/secret.rs +++ b/ethkey/src/secret.rs @@ -108,7 +108,7 @@ impl From for Secret { impl From<&'static str> for Secret { fn from(s: &'static str) -> Self { - s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s)) + s.parse().unwrap_or_else(|_| panic!("invalid string literal for {}: '{}'", stringify!(Self), s)) } } diff --git a/ethkey/src/signature.rs b/ethkey/src/signature.rs index a71eb08ee39..fe87118c73d 100644 --- a/ethkey/src/signature.rs +++ b/ethkey/src/signature.rs @@ -96,7 +96,7 @@ impl Signature { // remove when integer generics exist impl PartialEq for Signature { fn eq(&self, other: &Self) -> bool { - &self.0[..] == &other.0[..] + self.0[..] == other.0[..] } } @@ -159,9 +159,9 @@ impl From<[u8; 65]> for Signature { } } -impl Into<[u8; 65]> for Signature { - fn into(self) -> [u8; 65] { - self.0 +impl From for [u8; 65] { + fn from(val: Signature) -> Self { + val.0 } } From 40af261070348da03be1e43e5d46a99012c21ad7 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 1 Apr 2024 15:38:08 +0500 Subject: [PATCH 25/27] removed unused test code --- ethcore/transaction/src/transaction.rs | 26 ------------ test.sh | 59 +------------------------- 2 files changed, 2 insertions(+), 83 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 7f8a6226adf..0920112552b 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -311,32 +311,6 @@ impl UnverifiedTransactionWrapper { recover(&self.signature(), &self.unsigned().message_hash(self.chain_id_from_v())) } - /// Do basic validation, checking for valid signature and minimum gas, - // TODO: consider use in block validation. - #[cfg(feature = "json-tests")] - pub fn validate( - self, - schedule: &Schedule, - require_low: bool, - allow_chain_id_of_one: bool, - allow_empty_signature: bool, - ) -> Result { - let chain_id = if allow_chain_id_of_one { Some(1) } else { None }; - self.verify_basic(require_low, chain_id, allow_empty_signature)?; - if !allow_empty_signature || !self.is_unsigned() { - self.recover_public()?; - } - if self.gas < U256::from(self.gas_required(&schedule)) { - return Err(error::Error::InvalidGasLimit(::unexpected::OutOfBounds { - min: Some(U256::from(self.gas_required(&schedule))), - max: None, - found: self.gas, - }) - .into()); - } - Ok(self) - } - /// Verify basic signature params. Does not attempt sender recovery. pub fn verify_basic( &self, diff --git a/test.sh b/test.sh index 82e05d954c5..b8551313c00 100755 --- a/test.sh +++ b/test.sh @@ -1,60 +1,5 @@ #!/bin/sh -# Running Parity Full Test Suite - -FEATURES="json-tests" -OPTIONS="--release" -VALIDATE=1 - -case $1 in - --no-json) - FEATURES="ipc" - shift # past argument=value - ;; - --no-release) - OPTIONS="" - shift - ;; - --no-validate) - VALIDATE=0 - shift - ;; - --no-run) - OPTIONS="--no-run" - shift - ;; - *) - # unknown option - ;; -esac - -set -e - -if [ "$VALIDATE" -eq "1" ]; then -# Validate --no-default-features build -echo "________Validate build________" -cargo check --no-default-features -cargo check --manifest-path util/io/Cargo.toml --no-default-features -cargo check --manifest-path util/io/Cargo.toml --features "mio" - -# Validate chainspecs -echo "________Validate chainspecs________" -./scripts/validate_chainspecs.sh -fi - - -# Running the C++ example -echo "________Running the C++ example________" -cd parity-clib-examples/cpp && \ - mkdir -p build && \ - cd build && \ - cmake .. && \ - make && \ - ./parity-example && \ - cd .. && \ - rm -rf build && \ - cd ../.. # Running tests -echo "________Running Parity Full Test Suite________" -git submodule update --init --recursive -cargo test -j 8 $OPTIONS --features "$FEATURES" --all $1 +echo "Running Parity (fixed for MM2) Tests" +cargo test -p ethcore-transaction -p ethkey From 5dbe94081c38472bd733c15a1b4f614e6dcc54dd Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 5 Apr 2024 12:08:03 +0500 Subject: [PATCH 26/27] removed extra checks added doc comments to tx types --- ethcore/transaction/src/transaction.rs | 4 ++++ ethcore/transaction/src/transaction/eip1559.rs | 3 --- ethcore/transaction/src/transaction/eip2930.rs | 3 --- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 0920112552b..cd075267732 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -39,9 +39,13 @@ type Bytes = Vec; #[derive(Clone, PartialEq)] pub enum TxType { + /// Legacy non-typed transaction Legacy, + /// Transaction with EIP-2718 type field set to 1 according to EIP-2930 Type1 = 1, + /// Transaction with EIP-2718 type field set to 2 according to EIP-1559 Type2 = 2, + /// Indicates we could not parse transaction type correctly Invalid, } diff --git a/ethcore/transaction/src/transaction/eip1559.rs b/ethcore/transaction/src/transaction/eip1559.rs index 02056a1464b..c2567482b8b 100644 --- a/ethcore/transaction/src/transaction/eip1559.rs +++ b/ethcore/transaction/src/transaction/eip1559.rs @@ -117,9 +117,6 @@ impl rlp::Decodable for UnverifiedEip1559Transaction { let unsigned = Eip1559Transaction::decode(d)?; let hash = keccak(d.as_raw()); let offset = unsigned.payload_size(); - if d.as_raw().is_empty() { - return Err(DecoderError::RlpIsTooShort); - } let list = Rlp::new(&d.as_raw()[1..]); let v = list.val_at(offset)?; if !Self::validate_v(v) { diff --git a/ethcore/transaction/src/transaction/eip2930.rs b/ethcore/transaction/src/transaction/eip2930.rs index 1ea3d38ee42..7053a77fb5c 100644 --- a/ethcore/transaction/src/transaction/eip2930.rs +++ b/ethcore/transaction/src/transaction/eip2930.rs @@ -167,9 +167,6 @@ impl rlp::Decodable for UnverifiedEip2930Transaction { let unsigned = Eip2930Transaction::decode(d)?; let hash = keccak(d.as_raw()); let offset = unsigned.payload_size(); - if d.as_raw().is_empty() { - return Err(DecoderError::RlpIsTooShort); - } let list = Rlp::new(&d.as_raw()[1..]); let v = list.val_at(offset)?; if !Self::validate_v(v) { From 729773d1ed81bfc75f00ab79162d2f022b38abe1 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 5 Apr 2024 13:23:08 +0500 Subject: [PATCH 27/27] removed unneeded From for String --- ethkey/src/error.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ethkey/src/error.rs b/ethkey/src/error.rs index 8da8bd54399..4a8d4907e29 100644 --- a/ethkey/src/error.rs +++ b/ethkey/src/error.rs @@ -57,12 +57,6 @@ impl error::Error for Error { } } -impl From for String { - fn from(err: Error) -> String { - format!("{}", err) - } -} - impl From<::secp256k1::Error> for Error { fn from(e: ::secp256k1::Error) -> Error { match e {