From e92c6ee7198db4f55fc0c2ad9cd836953ed65659 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 4 Feb 2016 17:23:53 +0100 Subject: [PATCH 1/4] Signed transaciton split in progress --- ethcore/src/block.rs | 10 +- ethcore/src/blockchain.rs | 2 +- ethcore/src/engine.rs | 2 +- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/transaction.rs | 342 ++++++++++++++++++++++----------- ethcore/src/verification.rs | 2 +- ethcore/src/views.rs | 2 +- 7 files changed, 235 insertions(+), 127 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index a2de89d13..2e6b84d2a 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -14,7 +14,7 @@ pub struct Block { /// The header of this block. pub header: Header, /// The transactions in this block. - pub transactions: Vec, + pub transactions: Vec, /// The uncles of this block. pub uncles: Vec
, } @@ -76,7 +76,7 @@ pub struct BlockRefMut<'a> { /// Block header. pub header: &'a Header, /// Block transactions. - pub transactions: &'a Vec, + pub transactions: &'a Vec, /// Block uncles. pub uncles: &'a Vec
, /// Transaction receipts. @@ -113,7 +113,7 @@ pub trait IsBlock { fn state(&self) -> &State { &self.block().state } /// Get all information on transactions in this block. - fn transactions(&self) -> &Vec { &self.block().base.transactions } + fn transactions(&self) -> &Vec { &self.block().base.transactions } /// Get all information on receipts in this block. fn receipts(&self) -> &Vec { &self.block().receipts } @@ -228,7 +228,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> { /// Push a transaction into the block. /// /// If valid, it will be executed, and archived together with the receipt. - pub fn push_transaction(&mut self, t: Transaction, h: Option) -> Result<&Receipt, Error> { + pub fn push_transaction(&mut self, t: SignedTransaction, h: Option) -> Result<&Receipt, Error> { let env_info = self.env_info(); // info!("env_info says gas_used={}", env_info.gas_used); match self.block.state.apply(&env_info, self.engine, &t) { @@ -316,7 +316,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact<'x, 'y>(header: &Header, transactions: &[Transaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { +pub fn enact<'x, 'y>(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { { let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce()); trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author())); diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index e2ed54c19..cc684df67 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -93,7 +93,7 @@ pub trait BlockProvider { /// Get a list of transactions for a given block. /// Returns None if block deos not exist. - fn transactions(&self, hash: &H256) -> Option> { + fn transactions(&self, hash: &H256) -> Option> { self.block(hash).map(|bytes| BlockView::new(&bytes).transactions()) } diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index 7017989e7..27e50bb84 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -58,7 +58,7 @@ pub trait Engine : Sync + Send { // TODO: consider including State in the params. fn verify_transaction_basic(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) } /// Verify a particular transaction is valid. - fn verify_transaction(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) } + fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } /// Don't forget to call Super::populateFromParent when subclassing & overriding. // TODO: consider including State in the params. diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index e9aedc128..a8cc92484 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -161,7 +161,7 @@ impl Engine for Ethash { Ok(()) } - fn verify_transaction(&self, t: &Transaction, _header: &Header) -> Result<(), Error> { + fn verify_transaction(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> { t.sender().map(|_|()) // Perform EC recovery and cache sender } } diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index a5e70b0d6..0eed2dedd 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -35,19 +35,34 @@ pub struct Transaction { /// Transaction data. pub data: Bytes, - // signature - /// The V field of the signature, either 27 or 28; helps describe the point on the curve. - pub v: u8, - /// 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: RefCell>, - sender: RefCell>, + //// signature + ///// The V field of the signature, either 27 or 28; helps describe the point on the curve. + //pub v: u8, + ///// 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: RefCell>, + //sender: RefCell>, } impl Transaction { + /// Append object with a without signature into RLP stream + pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { + s.begin_list(6); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + match self.action { + Action::Create => s.append_empty_data(), + Action::Call(ref to) => s.append(to) + }; + s.append(&self.value); + s.append(&self.data); + } + /// Create a new transaction. #[cfg(test)] #[cfg(feature = "json-tests")] @@ -59,11 +74,11 @@ impl Transaction { action: Action::Create, value: x!(0), data: vec![], - v: 0, - r: x!(0), - s: x!(0), - hash: RefCell::new(None), - sender: RefCell::new(None), + //v: 0, + //r: x!(0), + //s: x!(0), + //hash: RefCell::new(None), + //sender: RefCell::new(None), } } @@ -77,11 +92,11 @@ impl Transaction { action: Action::Call(to), value: value, data: data, - v: 0, - r: x!(0), - s: x!(0), - hash: RefCell::new(None), - sender: RefCell::new(None), + //v: 0, + //r: x!(0), + //s: x!(0), + //hash: RefCell::new(None), + //sender: RefCell::new(None), } } @@ -95,37 +110,37 @@ impl Transaction { action: Action::Create, value: value, data: data, - v: 0, - r: x!(0), - s: x!(0), - hash: RefCell::new(None), - sender: RefCell::new(None), + //v: 0, + //r: x!(0), + //s: x!(0), + //hash: RefCell::new(None), + //sender: RefCell::new(None), } } - /// Append object into RLP stream, optionally with or without the signature. - pub fn rlp_append_opt(&self, s: &mut RlpStream, with_seal: Seal) { - s.begin_list(6 + match with_seal { Seal::With => 3, _ => 0 }); - s.append(&self.nonce); - s.append(&self.gas_price); - s.append(&self.gas); - match self.action { - Action::Create => s.append_empty_data(), - Action::Call(ref to) => s.append(to), - }; - s.append(&self.value); - s.append(&self.data); - if let Seal::With = with_seal { - s.append(&(self.v as u16)).append(&self.r).append(&self.s); - } - } + ///// Append object into RLP stream, optionally with or without the signature. + //pub fn rlp_append_opt(&self, s: &mut RlpStream, with_seal: Seal) { + //s.begin_list(6 + match with_seal { Seal::With => 3, _ => 0 }); + //s.append(&self.nonce); + //s.append(&self.gas_price); + //s.append(&self.gas); + //match self.action { + //Action::Create => s.append_empty_data(), + //Action::Call(ref to) => s.append(to), + //}; + //s.append(&self.value); + //s.append(&self.data); + //if let Seal::With = with_seal { + //s.append(&(self.v as u16)).append(&self.r).append(&self.s); + //} + //} - /// Get the RLP serialisation of the object, optionally with or without the signature. - pub fn rlp_bytes_opt(&self, with_seal: Seal) -> Bytes { - let mut s = RlpStream::new(); - self.rlp_append_opt(&mut s, with_seal); - s.out() - } + ///// Get the RLP serialisation of the object, optionally with or without the signature. + //pub fn rlp_bytes_opt(&self, with_seal: Seal) -> Bytes { + //let mut s = RlpStream::new(); + //self.rlp_append_opt(&mut s, with_seal); + //s.out() + //} } impl FromJson for Transaction { @@ -140,73 +155,41 @@ impl FromJson for Transaction { }, value: xjson!(&json["value"]), data: xjson!(&json["data"]), - v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, - r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, - s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, - hash: RefCell::new(None), - sender: match json.find("sender") { - Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), - _ => RefCell::new(None), - }, + //v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, + //r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, + //s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, + //hash: RefCell::new(None), + //sender: match json.find("sender") { + //Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), + //_ => RefCell::new(None), + //}, }; - if let Some(&Json::String(ref secret_key)) = json.find("secretKey") { - r.sign(&h256_from_hex(clean(secret_key))); - } + //if let Some(&Json::String(ref secret_key)) = json.find("secretKey") { + //r.sign(&h256_from_hex(clean(secret_key))); + //} r } } -impl Encodable for Transaction { - fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_opt(s, Seal::With) } -} +//impl Encodable for Transaction { + //fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_opt(s, Seal::With) } +//} impl Transaction { - /// Get the hash of this header (sha3 of the RLP). - pub fn hash(&self) -> H256 { - let mut hash = self.hash.borrow_mut(); - match &mut *hash { - &mut Some(ref h) => h.clone(), - hash @ &mut None => { - *hash = Some(self.rlp_sha3()); - hash.as_ref().unwrap().clone() - } - } - } - - /// 0 is `v` is 27, 1 if 28, and 4 otherwise. - pub fn standard_v(&self) -> u8 { match self.v { 27 => 0, 28 => 1, _ => 4 } } - - /// Construct a signature object from the sig. - pub fn signature(&self) -> Signature { Signature::from_rsv(&From::from(&self.r), &From::from(&self.s), self.standard_v()) } - - /// The message hash of the transaction. - pub fn message_hash(&self) -> H256 { self.rlp_bytes_opt(Seal::Without).sha3() } - - /// Returns transaction sender. - pub fn sender(&self) -> Result { - let mut sender = self.sender.borrow_mut(); - match &mut *sender { - &mut Some(ref h) => Ok(h.clone()), - sender @ &mut None => { - *sender = Some(From::from(try!(ec::recover(&self.signature(), &self.message_hash())).sha3())); - Ok(sender.as_ref().unwrap().clone()) - } - } - } /// Signs the transaction as coming from `sender`. - pub fn sign(&mut self, secret: &Secret) { + //pub fn sign(&mut self, secret: &Secret) { // TODO: make always low. - let sig = ec::sign(secret, &self.message_hash()); - let (r, s, v) = sig.unwrap().to_rsv(); - self.r = r; - self.s = s; - self.v = v + 27; - } + //let sig = ec::sign(secret, &self.message_hash()); + //let (r, s, v) = sig.unwrap().to_rsv(); + //self.r = r; + //self.s = s; + //self.v = v + 27; + //} /// Signs the transaction as coming from `sender`. - #[cfg(test)] - pub fn signed(self, secret: &Secret) -> Transaction { let mut r = self; r.sign(secret); r } + //#[cfg(test)] + //pub fn signed(self, secret: &Secret) -> Transaction { let mut r = self; r.sign(secret); r } /// Get the transaction cost in gas for the given params. pub fn gas_required_for(is_create: bool, data: &[u8], schedule: &Schedule) -> u64 { @@ -216,19 +199,32 @@ impl Transaction { ) } + /// The message hash of the transaction. + pub fn message_hash(&self) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream); + stream.out().sha3() + } + + pub fn sign(self, secret: &Secret) -> SignedTransaction { + let sig = ec::sign(secret, &self.message_hash()); + let (r, s, v) = sig.unwrap().to_rsv(); + SignedTransaction { + transaction: self, + r: r, + s: s, + v: v, + hash: RefCell::new(None), + sender: RefCell::new(None) + } + } + /// Get the transaction cost in gas for this transaction. pub fn gas_required(&self, schedule: &Schedule) -> u64 { Self::gas_required_for(match self.action{Action::Create=>true, Action::Call(_)=>false}, &self.data, schedule) } - /// Checks whether the signature has a low 's' value. - pub fn check_low_s(&self) -> Result<(), Error> { - if !ec::is_low_s(&self.s) { - Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))) - } else { - Ok(()) - } - } + /// Do basic validation, checking for valid signature and minimum gas, // TODO: consider use in block validation. @@ -258,19 +254,69 @@ impl Decodable for Action { } } -impl Decodable for Transaction { +//impl Decodable for Transaction { + //fn decode(decoder: &D) -> Result where D: Decoder { + //let d = decoder.as_rlp(); + //if d.item_count() != 9 { + //return Err(DecoderError::RlpIncorrectListLen); + //} + //Ok(Transaction { + //nonce: try!(d.val_at(0)), + //gas_price: try!(d.val_at(1)), + //gas: try!(d.val_at(2)), + //action: try!(d.val_at(3)), + //value: try!(d.val_at(4)), + //data: try!(d.val_at(5)), + //v: try!(d.val_at(6)), + //r: try!(d.val_at(7)), + //s: try!(d.val_at(8)), + //hash: RefCell::new(None), + //sender: RefCell::new(None), + //}) + //} +//} + +#[derive(Debug, Clone)] +pub struct SignedTransaction { + transaction: Transaction, + v: u8, + r: U256, + s: U256, + + hash: RefCell>, + sender: RefCell> +} + +impl Deref for SignedTransaction { + type Target = Transaction; + + fn deref(&self) -> &Self::Target { + &self.transaction + } +} + +impl Decodable for SignedTransaction { fn decode(decoder: &D) -> Result where D: Decoder { let d = decoder.as_rlp(); if d.item_count() != 9 { return Err(DecoderError::RlpIncorrectListLen); } - Ok(Transaction { - nonce: try!(d.val_at(0)), - gas_price: try!(d.val_at(1)), - gas: try!(d.val_at(2)), - action: try!(d.val_at(3)), - value: try!(d.val_at(4)), - data: try!(d.val_at(5)), + Ok(SignedTransaction { + transaction: Transaction { + nonce: try!(d.val_at(0)), + gas_price: try!(d.val_at(1)), + gas: try!(d.val_at(2)), + action: try!(d.val_at(3)), + value: try!(d.val_at(4)), + data: try!(d.val_at(5)), + + // to remove + v: 0, + r: From::from(0), + s: From::from(0), + hash: RefCell::new(None), + sender: RefCell::new(None) + }, v: try!(d.val_at(6)), r: try!(d.val_at(7)), s: try!(d.val_at(8)), @@ -280,6 +326,68 @@ impl Decodable for Transaction { } } +impl Encodable for SignedTransaction { + fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_sealed_transaction(s) } +} + +impl SignedTransaction { + /// Append object with a signature into RLP stream + pub fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + s.begin_list(9); + s.append(&self.nonce); + s.appned(&self.gas_price); + s.append(&self.gas); + match self.action { + Action::Create => s.append_empty_data(), + Action::Call(ref to) => s.append(to) + }; + s.append(&self.value); + s.append(&self.data); + s.append(&self.v); + s.append(&self.r); + s.append(&self.s); + } + + /// Get the hash of this header (sha3 of the RLP). + pub fn hash(&self) -> H256 { + let mut hash = self.hash.borrow_mut(); + match &mut *hash { + &mut Some(ref h) => h.clone(), + hash @ &mut None => { + *hash = Some(self.rlp_sha3()); + hash.as_ref().unwrap().clone() + } + } + } + + /// 0 is `v` is 27, 1 if 28, and 4 otherwise. + pub fn standard_v(&self) -> u8 { match self.v { 27 => 0, 28 => 1, _ => 4 } } + + /// Construct a signature object from the sig. + pub fn signature(&self) -> Signature { Signature::from_rsv(&From::from(&self.r), &From::from(&self.s), self.standard_v()) } + + /// Checks whether the signature has a low 's' value. + pub fn check_low_s(&self) -> Result<(), Error> { + if !ec::is_low_s(&self.s) { + Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))) + } else { + Ok(()) + } + } + + /// Returns transaction sender. + pub fn sender(&self) -> Result { + let mut sender = self.sender.borrow_mut(); + match &mut *sender { + &mut Some(ref h) => Ok(h.clone()), + sender @ &mut None => { + *sender = Some(From::from(try!(ec::recover(&self.signature(), &self.message_hash())).sha3())); + Ok(sender.as_ref().unwrap().clone()) + } + } + } +} + #[test] fn sender_test() { let t: Transaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index efed43b84..db7faa074 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -14,7 +14,7 @@ pub struct PreVerifiedBlock { /// Populated block header pub header: Header, /// Populated block transactions - pub transactions: Vec, + pub transactions: Vec, /// Block bytes pub bytes: Bytes, } diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index e1c704625..334dcef65 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -135,7 +135,7 @@ impl<'a> BlockView<'a> { } /// Return List of transactions in given block. - pub fn transactions(&self) -> Vec { + pub fn transactions(&self) -> Vec { self.rlp.val_at(1) } From eab8410402a1e307d24aa4e13aeb6d447c07c25d Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 4 Feb 2016 23:48:29 +0100 Subject: [PATCH 2/4] finishe signed transactions --- ethcore/src/engine.rs | 2 +- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/executive.rs | 57 +++-- ethcore/src/json_tests/state.rs | 2 +- ethcore/src/json_tests/transaction.rs | 8 +- ethcore/src/state.rs | 2 +- ethcore/src/tests/helpers.rs | 4 +- ethcore/src/transaction.rs | 291 ++++++++------------------ ethcore/src/verification.rs | 25 ++- 9 files changed, 164 insertions(+), 229 deletions(-) diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index 27e50bb84..a5a83c9cf 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -56,7 +56,7 @@ pub trait Engine : Sync + Send { /// Additional verification for transactions in blocks. // TODO: Add flags for which bits of the transaction to check. // TODO: consider including State in the params. - fn verify_transaction_basic(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) } + fn verify_transaction_basic(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } /// Verify a particular transaction is valid. fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index a8cc92484..7645a9458 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -154,7 +154,7 @@ impl Engine for Ethash { Ok(()) } - fn verify_transaction_basic(&self, t: &Transaction, header: &Header) -> result::Result<(), Error> { + fn verify_transaction_basic(&self, t: &SignedTransaction, header: &Header) -> result::Result<(), Error> { if header.number() >= self.u64_param("frontierCompatibilityModeLimit") { try!(t.check_low_s()); } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index b67b71306..3a16ea8c7 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -86,7 +86,7 @@ impl<'a> Executive<'a> { } /// This funtion should be used to execute transaction. - pub fn transact(&'a mut self, t: &Transaction) -> Result { + pub fn transact(&'a mut self, t: &SignedTransaction) -> Result { let sender = try!(t.sender()); let nonce = self.state.nonce(&sender); @@ -268,7 +268,7 @@ impl<'a> Executive<'a> { } /// Finalizes the transaction (does refunds and suicides). - fn finalize(&mut self, t: &Transaction, substate: Substate, result: evm::Result) -> ExecutionResult { + fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result) -> ExecutionResult { let schedule = self.engine.schedule(self.info); // refunds from SSTORE nonzero -> zero @@ -685,9 +685,15 @@ mod tests { // test is incorrect, mk evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int} fn test_transact_simple(factory: Factory) { - let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::zero()); let keypair = KeyPair::create().unwrap(); - t.sign(&keypair.secret()); + let t = Transaction { + action: Action::Create, + value: U256::from(17), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::zero(), + nonce: U256::zero() + }.sign(&keypair.secret()); let sender = t.sender().unwrap(); let contract = contract_address(&sender, &U256::zero()); @@ -717,8 +723,14 @@ mod tests { evm_test!{test_transact_invalid_sender: test_transact_invalid_sender_jit, test_transact_invalid_sender_int} fn test_transact_invalid_sender(factory: Factory) { - let t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::zero()); - + let t = Transaction { + action: Action::Create, + value: U256::from(17), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::zero(), + nonce: U256::zero() + }.fake_sign(); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); let mut info = EnvInfo::default(); @@ -738,11 +750,17 @@ mod tests { evm_test!{test_transact_invalid_nonce: test_transact_invalid_nonce_jit, test_transact_invalid_nonce_int} fn test_transact_invalid_nonce(factory: Factory) { - let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::one()); let keypair = KeyPair::create().unwrap(); - t.sign(&keypair.secret()); + let t = Transaction { + action: Action::Create, + value: U256::from(17), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::zero(), + nonce: U256::one() + }.sign(&keypair.secret()); let sender = t.sender().unwrap(); - + let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(17)); @@ -764,9 +782,15 @@ mod tests { evm_test!{test_transact_gas_limit_reached: test_transact_gas_limit_reached_jit, test_transact_gas_limit_reached_int} fn test_transact_gas_limit_reached(factory: Factory) { - let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(80_001), U256::zero(), U256::zero()); let keypair = KeyPair::create().unwrap(); - t.sign(&keypair.secret()); + let t = Transaction { + action: Action::Create, + value: U256::from(17), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(80_001), + gas_price: U256::zero(), + nonce: U256::zero() + }.sign(&keypair.secret()); let sender = t.sender().unwrap(); let mut state_result = get_temp_state(); @@ -791,9 +815,16 @@ mod tests { evm_test!{test_not_enough_cash: test_not_enough_cash_jit, test_not_enough_cash_int} fn test_not_enough_cash(factory: Factory) { - let mut t = Transaction::new_create(U256::from(18), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::one(), U256::zero()); + let keypair = KeyPair::create().unwrap(); - t.sign(&keypair.secret()); + let t = Transaction { + action: Action::Create, + value: U256::from(18), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::zero() + }.sign(&keypair.secret()); let sender = t.sender().unwrap(); let mut state_result = get_temp_state(); diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index fa8da9329..304d423dd 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -33,7 +33,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { flush!(" - {}...", name); - let t = Transaction::from_json(&test["transaction"]); + let t = SignedTransaction::from_json(&test["transaction"]); let env = EnvInfo::from_json(&test["env"]); let _out = Bytes::from_json(&test["out"]); let post_state_root = xjson!(&test["postStateRoot"]); diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index 91f7d96e5..99e5e07c9 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -6,7 +6,7 @@ fn do_json_test(json_data: &[u8]) -> Vec { let mut failed = Vec::new(); let old_schedule = evm::Schedule::new_frontier(); let new_schedule = evm::Schedule::new_homestead(); - let ot = RefCell::new(Transaction::new()); + let ot = RefCell::new(None); for (name, test) in json.as_object().unwrap() { let mut fail = false; let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.clone()); println!("Transaction: {:?}", ot.borrow()); fail = true }; @@ -15,7 +15,7 @@ fn do_json_test(json_data: &[u8]) -> Vec { .and_then(|s| BlockNumber::from_str(s).ok()) .unwrap_or(0) { x if x < 1_000_000 => &old_schedule, _ => &new_schedule }; let rlp = Bytes::from_json(&test["rlp"]); - let res = UntrustedRlp::new(&rlp).as_val().map_err(From::from).and_then(|t: Transaction| t.validate(schedule, schedule.have_delegate_call)); + let res = UntrustedRlp::new(&rlp).as_val().map_err(From::from).and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call)); fail_unless(test.find("transaction").is_none() == res.is_err()); if let (Some(&Json::Object(ref tx)), Some(&Json::String(ref expect_sender))) = (test.find("transaction"), test.find("sender")) { let t = res.unwrap(); @@ -26,10 +26,10 @@ fn do_json_test(json_data: &[u8]) -> Vec { fail_unless(t.nonce == xjson!(&tx["nonce"])); fail_unless(t.value == xjson!(&tx["value"])); if let Action::Call(ref to) = t.action { - *ot.borrow_mut() = t.clone(); + *ot.borrow_mut() = Some(t.clone()); fail_unless(to == &xjson!(&tx["to"])); } else { - *ot.borrow_mut() = t.clone(); + *ot.borrow_mut() = Some(t.clone()); fail_unless(Bytes::from_json(&tx["to"]).is_empty()); } } diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index ed7d29813..6f723952a 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -139,7 +139,7 @@ impl State { /// Execute a given transaction. /// This will change the state accordingly. - pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult { + pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction) -> ApplyResult { // let old = self.to_pod(); let e = try!(Executive::new(self, env_info, engine).transact(t)); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 04d47cbd3..c69f62617 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -103,12 +103,12 @@ fn create_unverifiable_block(order: u32, parent_hash: H256) -> Bytes { create_test_block(&create_unverifiable_block_header(order, parent_hash)) } -pub fn create_test_block_with_data(header: &Header, transactions: &[&Transaction], uncles: &[Header]) -> Bytes { +pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTransaction], uncles: &[Header]) -> Bytes { let mut rlp = RlpStream::new_list(3); rlp.append(header); rlp.begin_list(transactions.len()); for t in transactions { - rlp.append_raw(&t.rlp_bytes_opt(Seal::With), 1); + rlp.append_raw(&encode::(t).to_vec(), 1); } rlp.append(&uncles); rlp.out() diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 0eed2dedd..355d01e0a 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -1,7 +1,6 @@ //! Transaction data structure. use util::*; -use basic_types::*; use error::*; use evm::Schedule; @@ -18,6 +17,16 @@ impl Default for Action { fn default() -> Action { Action::Create } } +impl Decodable for Action { + fn decode(decoder: &D) -> Result where D: Decoder { + let rlp = decoder.as_rlp(); + match rlp.is_empty() { + true => Ok(Action::Create), + false => Ok(Action::Call(try!(rlp.as_val()))) + } + } +} + /// A set of information describing an externally-originating message call /// or contract creation operation. #[derive(Default, Debug, Clone)] @@ -34,18 +43,6 @@ pub struct Transaction { pub value: U256, /// Transaction data. pub data: Bytes, - - - //// signature - ///// The V field of the signature, either 27 or 28; helps describe the point on the curve. - //pub v: u8, - ///// 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: RefCell>, - //sender: RefCell>, } impl Transaction { @@ -62,90 +59,11 @@ impl Transaction { s.append(&self.value); s.append(&self.data); } - - /// Create a new transaction. - #[cfg(test)] - #[cfg(feature = "json-tests")] - pub fn new() -> Self { - Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(0), - action: Action::Create, - value: x!(0), - data: vec![], - //v: 0, - //r: x!(0), - //s: x!(0), - //hash: RefCell::new(None), - //sender: RefCell::new(None), - } - } - - /// Create a new message-call transaction. - #[allow(dead_code)] - pub fn new_call(to: Address, value: U256, data: Bytes, gas: U256, gas_price: U256, nonce: U256) -> Transaction { - Transaction { - nonce: nonce, - gas_price: gas_price, - gas: gas, - action: Action::Call(to), - value: value, - data: data, - //v: 0, - //r: x!(0), - //s: x!(0), - //hash: RefCell::new(None), - //sender: RefCell::new(None), - } - } - - /// Create a new contract-creation transaction. - #[cfg(test)] - pub fn new_create(value: U256, data: Bytes, gas: U256, gas_price: U256, nonce: U256) -> Transaction { - Transaction { - nonce: nonce, - gas_price: gas_price, - gas: gas, - action: Action::Create, - value: value, - data: data, - //v: 0, - //r: x!(0), - //s: x!(0), - //hash: RefCell::new(None), - //sender: RefCell::new(None), - } - } - - ///// Append object into RLP stream, optionally with or without the signature. - //pub fn rlp_append_opt(&self, s: &mut RlpStream, with_seal: Seal) { - //s.begin_list(6 + match with_seal { Seal::With => 3, _ => 0 }); - //s.append(&self.nonce); - //s.append(&self.gas_price); - //s.append(&self.gas); - //match self.action { - //Action::Create => s.append_empty_data(), - //Action::Call(ref to) => s.append(to), - //}; - //s.append(&self.value); - //s.append(&self.data); - //if let Seal::With = with_seal { - //s.append(&(self.v as u16)).append(&self.r).append(&self.s); - //} - //} - - ///// Get the RLP serialisation of the object, optionally with or without the signature. - //pub fn rlp_bytes_opt(&self, with_seal: Seal) -> Bytes { - //let mut s = RlpStream::new(); - //self.rlp_append_opt(&mut s, with_seal); - //s.out() - //} } -impl FromJson for Transaction { - fn from_json(json: &Json) -> Transaction { - let mut r = Transaction { +impl FromJson for SignedTransaction { + fn from_json(json: &Json) -> SignedTransaction { + let t = Transaction { nonce: xjson!(&json["nonce"]), gas_price: xjson!(&json["gasPrice"]), gas: xjson!(&json["gasLimit"]), @@ -155,41 +73,58 @@ impl FromJson for Transaction { }, value: xjson!(&json["value"]), data: xjson!(&json["data"]), - //v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, - //r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, - //s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, - //hash: RefCell::new(None), - //sender: match json.find("sender") { - //Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), - //_ => RefCell::new(None), - //}, }; - //if let Some(&Json::String(ref secret_key)) = json.find("secretKey") { - //r.sign(&h256_from_hex(clean(secret_key))); - //} - r + match json.find("secretKey") { + Some(&Json::String(ref secret_key)) => t.sign(&h256_from_hex(clean(secret_key))), + _ => SignedTransaction { + transaction: t, + v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, + r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, + s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, + hash: RefCell::new(None), + sender: match json.find("sender") { + Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), + _ => RefCell::new(None), + } + } + } } } -//impl Encodable for Transaction { - //fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_opt(s, Seal::With) } -//} - impl Transaction { + /// The message hash of the transaction. + pub fn message_hash(&self) -> H256 { + let mut stream = RlpStream::new(); + self.rlp_append_unsigned_transaction(&mut stream); + stream.out().sha3() + } /// Signs the transaction as coming from `sender`. - //pub fn sign(&mut self, secret: &Secret) { - // TODO: make always low. - //let sig = ec::sign(secret, &self.message_hash()); - //let (r, s, v) = sig.unwrap().to_rsv(); - //self.r = r; - //self.s = s; - //self.v = v + 27; - //} + pub fn sign(self, secret: &Secret) -> SignedTransaction { + let sig = ec::sign(secret, &self.message_hash()); + let (r, s, v) = sig.unwrap().to_rsv(); + SignedTransaction { + transaction: self, + r: r, + s: s, + v: v + 27, + hash: RefCell::new(None), + sender: RefCell::new(None) + } + } - /// Signs the transaction as coming from `sender`. - //#[cfg(test)] - //pub fn signed(self, secret: &Secret) -> Transaction { let mut r = self; r.sign(secret); r } + /// Useful for test incorrectly signed transactions. + #[cfg(test)] + pub fn fake_sign(self) -> SignedTransaction { + SignedTransaction { + transaction: self, + r: U256::zero(), + s: U256::zero(), + v: 0, + hash: RefCell::new(None), + sender: RefCell::new(None) + } + } /// Get the transaction cost in gas for the given params. pub fn gas_required_for(is_create: bool, data: &[u8], schedule: &Schedule) -> u64 { @@ -199,91 +134,27 @@ impl Transaction { ) } - /// The message hash of the transaction. - pub fn message_hash(&self) -> H256 { - let mut stream = RlpStream::new(); - self.rlp_append_unsigned_transaction(&mut stream); - stream.out().sha3() - } - - pub fn sign(self, secret: &Secret) -> SignedTransaction { - let sig = ec::sign(secret, &self.message_hash()); - let (r, s, v) = sig.unwrap().to_rsv(); - SignedTransaction { - transaction: self, - r: r, - s: s, - v: v, - hash: RefCell::new(None), - sender: RefCell::new(None) - } - } - /// Get the transaction cost in gas for this transaction. pub fn gas_required(&self, schedule: &Schedule) -> u64 { Self::gas_required_for(match self.action{Action::Create=>true, Action::Call(_)=>false}, &self.data, schedule) } - - - - /// Do basic validation, checking for valid signature and minimum gas, - // TODO: consider use in block validation. - #[cfg(test)] - #[cfg(feature = "json-tests")] - pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result { - if require_low && !ec::is_low_s(&self.s) { - return Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))); - } - try!(self.sender()); - if self.gas < U256::from(self.gas_required(&schedule)) { - Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) - } else { - Ok(self) - } - } } -impl Decodable for Action { - fn decode(decoder: &D) -> Result where D: Decoder { - let rlp = decoder.as_rlp(); - if rlp.is_empty() { - Ok(Action::Create) - } else { - Ok(Action::Call(try!(rlp.as_val()))) - } - } -} -//impl Decodable for Transaction { - //fn decode(decoder: &D) -> Result where D: Decoder { - //let d = decoder.as_rlp(); - //if d.item_count() != 9 { - //return Err(DecoderError::RlpIncorrectListLen); - //} - //Ok(Transaction { - //nonce: try!(d.val_at(0)), - //gas_price: try!(d.val_at(1)), - //gas: try!(d.val_at(2)), - //action: try!(d.val_at(3)), - //value: try!(d.val_at(4)), - //data: try!(d.val_at(5)), - //v: try!(d.val_at(6)), - //r: try!(d.val_at(7)), - //s: try!(d.val_at(8)), - //hash: RefCell::new(None), - //sender: RefCell::new(None), - //}) - //} -//} #[derive(Debug, Clone)] pub struct SignedTransaction { + /// Plain Transaction. transaction: Transaction, + /// The V field of the signature, either 27 or 28; helps describe the point on the curve. v: u8, + /// The R field of the signature; helps describe the point on the curve. r: U256, + /// The S field of the signature; helps describe the point on the curve. s: U256, - + /// Cached hash. hash: RefCell>, + /// Cached sender. sender: RefCell> } @@ -309,13 +180,6 @@ impl Decodable for SignedTransaction { action: try!(d.val_at(3)), value: try!(d.val_at(4)), data: try!(d.val_at(5)), - - // to remove - v: 0, - r: From::from(0), - s: From::from(0), - hash: RefCell::new(None), - sender: RefCell::new(None) }, v: try!(d.val_at(6)), r: try!(d.val_at(7)), @@ -335,7 +199,7 @@ impl SignedTransaction { pub fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { s.begin_list(9); s.append(&self.nonce); - s.appned(&self.gas_price); + s.append(&self.gas_price); s.append(&self.gas); match self.action { Action::Create => s.append_empty_data(), @@ -386,11 +250,27 @@ impl SignedTransaction { } } } + + /// Do basic validation, checking for valid signature and minimum gas, + // TODO: consider use in block validation. + #[cfg(test)] + #[cfg(feature = "json-tests")] + pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result { + if require_low && !ec::is_low_s(&self.s) { + return Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))); + } + try!(self.sender()); + if self.gas < U256::from(self.gas_required(&schedule)) { + Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) + } else { + Ok(self) + } + } } #[test] fn sender_test() { - let t: Transaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); + let t: SignedTransaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); assert_eq!(t.data, b""); assert_eq!(t.gas, U256::from(0x5208u64)); assert_eq!(t.gas_price, U256::from(0x01u64)); @@ -405,6 +285,13 @@ fn sender_test() { #[test] fn signing() { let key = KeyPair::create().unwrap(); - let t = Transaction::new_create(U256::from(42u64), b"Hello!".to_vec(), U256::from(3000u64), U256::from(50_000u64), U256::from(1u64)).signed(&key.secret()); + let t = Transaction { + 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()); assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap()); } diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index db7faa074..51f81dd81 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -220,7 +220,6 @@ mod tests { use engine::*; use spec::*; use transaction::*; - use basic_types::*; use tests::helpers::*; fn check_ok(result: Result<(), Error>) { @@ -309,8 +308,26 @@ mod tests { good.timestamp = 40; good.number = 10; - let tr1 = Transaction::new_create(x!(0), Bytes::new(), x!(30000), x!(40000), x!(1)); - let tr2 = Transaction::new_create(x!(0), Bytes::new(), x!(30000), x!(40000), x!(2)); + let keypair = KeyPair::create().unwrap(); + + let tr1 = Transaction { + action: Action::Create, + value: U256::from(0), + data: Bytes::new(), + gas: U256::from(30_000), + gas_price: U256::from(40_000), + nonce: U256::one() + }.sign(&keypair.secret()); + + let tr2 = Transaction { + action: Action::Create, + value: U256::from(0), + data: Bytes::new(), + gas: U256::from(30_000), + gas_price: U256::from(40_000), + nonce: U256::from(2) + }.sign(&keypair.secret()); + let good_transactions = [ &tr1, &tr2 ]; let diff_inc = U256::from(0x40); @@ -346,7 +363,7 @@ mod tests { let mut uncles_rlp = RlpStream::new(); uncles_rlp.append(&good_uncles); let good_uncles_hash = uncles_rlp.as_raw().sha3(); - let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| t.rlp_bytes_opt(Seal::With)).collect()); + let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| encode::(t).to_vec()).collect()); let mut parent = good.clone(); parent.number = 9; From 7db500c38d2b0dfb684b5e39432b2e1acf9565e8 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 5 Feb 2016 13:29:07 +0100 Subject: [PATCH 3/4] rename transactions message_hash -> hash --- ethcore/src/transaction.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 355d01e0a..02f1ae879 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -93,7 +93,7 @@ impl FromJson for SignedTransaction { impl Transaction { /// The message hash of the transaction. - pub fn message_hash(&self) -> H256 { + pub fn hash(&self) -> H256 { let mut stream = RlpStream::new(); self.rlp_append_unsigned_transaction(&mut stream); stream.out().sha3() @@ -101,7 +101,7 @@ impl Transaction { /// Signs the transaction as coming from `sender`. pub fn sign(self, secret: &Secret) -> SignedTransaction { - let sig = ec::sign(secret, &self.message_hash()); + let sig = ec::sign(secret, &self.hash()); let (r, s, v) = sig.unwrap().to_rsv(); SignedTransaction { transaction: self, @@ -245,7 +245,7 @@ impl SignedTransaction { match &mut *sender { &mut Some(ref h) => Ok(h.clone()), sender @ &mut None => { - *sender = Some(From::from(try!(ec::recover(&self.signature(), &self.message_hash())).sha3())); + *sender = Some(From::from(try!(ec::recover(&self.signature(), &self.transaction.hash())).sha3())); Ok(sender.as_ref().unwrap().clone()) } } From 0ddd113429f9252f1e0c007c69b60ca3040550de Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 5 Feb 2016 13:50:35 +0100 Subject: [PATCH 4/4] changed SignedTransaction transaction property name to unsigned --- ethcore/src/transaction.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 02f1ae879..cd686bf7d 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -77,7 +77,7 @@ impl FromJson for SignedTransaction { match json.find("secretKey") { Some(&Json::String(ref secret_key)) => t.sign(&h256_from_hex(clean(secret_key))), _ => SignedTransaction { - transaction: t, + unsigned: t, v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, @@ -104,7 +104,7 @@ impl Transaction { let sig = ec::sign(secret, &self.hash()); let (r, s, v) = sig.unwrap().to_rsv(); SignedTransaction { - transaction: self, + unsigned: self, r: r, s: s, v: v + 27, @@ -117,7 +117,7 @@ impl Transaction { #[cfg(test)] pub fn fake_sign(self) -> SignedTransaction { SignedTransaction { - transaction: self, + unsigned: self, r: U256::zero(), s: U256::zero(), v: 0, @@ -145,7 +145,7 @@ impl Transaction { #[derive(Debug, Clone)] pub struct SignedTransaction { /// Plain Transaction. - transaction: Transaction, + unsigned: Transaction, /// The V field of the signature, either 27 or 28; helps describe the point on the curve. v: u8, /// The R field of the signature; helps describe the point on the curve. @@ -162,7 +162,7 @@ impl Deref for SignedTransaction { type Target = Transaction; fn deref(&self) -> &Self::Target { - &self.transaction + &self.unsigned } } @@ -173,7 +173,7 @@ impl Decodable for SignedTransaction { return Err(DecoderError::RlpIncorrectListLen); } Ok(SignedTransaction { - transaction: Transaction { + unsigned: Transaction { nonce: try!(d.val_at(0)), gas_price: try!(d.val_at(1)), gas: try!(d.val_at(2)), @@ -245,7 +245,7 @@ impl SignedTransaction { match &mut *sender { &mut Some(ref h) => Ok(h.clone()), sender @ &mut None => { - *sender = Some(From::from(try!(ec::recover(&self.signature(), &self.transaction.hash())).sha3())); + *sender = Some(From::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3())); Ok(sender.as_ref().unwrap().clone()) } }