diff --git a/Cargo.lock b/Cargo.lock index 0127cab22..d2f0d4dd7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -737,7 +737,7 @@ dependencies = [ [[package]] name = "hyper" version = "0.9.4" -source = "git+https://github.com/ethcore/hyper#9e346c1d4bc30cd4142dea9d8a0b117d30858ca4" +source = "git+https://github.com/ethcore/hyper#4379a3629abc10e42e6d3fbcb21ecef5c1c86a77" dependencies = [ "cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 5910d0309..6ca2615f3 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -140,7 +140,7 @@ pub trait BlockProvider { fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec; /// Returns logs matching given filter. - fn logs(&self, mut blocks: Vec, matches: F, limit: Option) -> Vec + fn logs(&self, blocks: Vec, matches: F, limit: Option) -> Vec where F: Fn(&LogEntry) -> bool, Self: Sized; } @@ -371,7 +371,8 @@ impl BlockProvider for BlockChain { .enumerate() .flat_map(move |(index, (mut logs, tx_hash))| { let current_log_index = log_index; - log_index -= logs.len(); + let no_of_logs = logs.len(); + log_index -= no_of_logs; logs.reverse(); logs.into_iter() @@ -383,6 +384,7 @@ impl BlockProvider for BlockChain { transaction_hash: tx_hash, // iterating in reverse order transaction_index: receipts_len - index - 1, + transaction_log_index: no_of_logs - i - 1, log_index: current_log_index - i - 1, }) }) @@ -1924,6 +1926,7 @@ mod tests { block_number: block1.header().number(), transaction_hash: tx_hash1.clone(), transaction_index: 0, + transaction_log_index: 0, log_index: 0, }, LocalizedLogEntry { @@ -1932,6 +1935,7 @@ mod tests { block_number: block1.header().number(), transaction_hash: tx_hash1.clone(), transaction_index: 0, + transaction_log_index: 1, log_index: 1, }, LocalizedLogEntry { @@ -1940,6 +1944,7 @@ mod tests { block_number: block1.header().number(), transaction_hash: tx_hash2.clone(), transaction_index: 1, + transaction_log_index: 0, log_index: 2, }, LocalizedLogEntry { @@ -1948,6 +1953,7 @@ mod tests { block_number: block2.header().number(), transaction_hash: tx_hash3.clone(), transaction_index: 0, + transaction_log_index: 0, log_index: 0, } ]); @@ -1958,6 +1964,7 @@ mod tests { block_number: block2.header().number(), transaction_hash: tx_hash3.clone(), transaction_index: 0, + transaction_log_index: 0, log_index: 0, } ]); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index b2aaa64e5..4dc3e6345 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -58,7 +58,7 @@ use client::{ use client::Error as ClientError; use env_info::EnvInfo; use executive::{Executive, Executed, TransactOptions, contract_address}; -use receipt::LocalizedReceipt; +use receipt::{Receipt, LocalizedReceipt}; use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; use trace; use trace::FlatTransactionTraces; @@ -263,7 +263,7 @@ impl Client { } } - /// Register an action to be done if a mode change happens. + /// Register an action to be done if a mode change happens. pub fn on_mode_change(&self, f: F) where F: 'static + FnMut(&Mode) + Send { *self.on_mode_change.lock() = Some(Box::new(f)); } @@ -787,7 +787,6 @@ impl snapshot::DatabaseRestore for Client { } } - impl BlockChainClient for Client { fn call(&self, t: &SignedTransaction, block: BlockID, analytics: CallAnalytics) -> Result { let header = try!(self.block_header(block).ok_or(CallError::StatePruned)); @@ -891,7 +890,7 @@ impl BlockChainClient for Client { trace!(target: "mode", "Making callback..."); f(&*mode) }, - _ => {} + _ => {} } } match new_mode { @@ -1012,53 +1011,23 @@ impl BlockChainClient for Client { let chain = self.chain.read(); self.transaction_address(id) .and_then(|address| chain.block_number(&address.block_hash).and_then(|block_number| { - let t = chain.block_body(&address.block_hash) - .and_then(|block| { - BodyView::new(&block).localized_transaction_at(&address.block_hash, block_number, address.index) - }); + let transaction = chain.block_body(&address.block_hash) + .and_then(|body| BodyView::new(&body).localized_transaction_at(&address.block_hash, block_number, address.index)); - let tx_and_sender = t.and_then(|tx| tx.sender().ok().map(|sender| (tx, sender))); - - match (tx_and_sender, chain.transaction_receipt(&address)) { - (Some((tx, sender)), Some(receipt)) => { - let block_hash = tx.block_hash.clone(); - let block_number = tx.block_number.clone(); - let transaction_hash = tx.hash(); - let transaction_index = tx.transaction_index; - let prior_gas_used = match tx.transaction_index { - 0 => U256::zero(), - i => { - let prior_address = TransactionAddress { block_hash: address.block_hash, index: i - 1 }; - let prior_receipt = chain.transaction_receipt(&prior_address).expect("Transaction receipt at `address` exists; `prior_address` has lower index in same block; qed"); - prior_receipt.gas_used - } - }; - Some(LocalizedReceipt { - transaction_hash: tx.hash(), - transaction_index: tx.transaction_index, - block_hash: tx.block_hash, - block_number: tx.block_number, - cumulative_gas_used: receipt.gas_used, - gas_used: receipt.gas_used - prior_gas_used, - contract_address: match tx.action { - Action::Call(_) => None, - Action::Create => Some(contract_address(&sender, &tx.nonce)) - }, - logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry { - entry: log, - block_hash: block_hash.clone(), - block_number: block_number, - transaction_hash: transaction_hash.clone(), - transaction_index: transaction_index, - log_index: i - }).collect(), - log_bloom: receipt.log_bloom, - state_root: receipt.state_root, + let previous_receipts = (0..address.index + 1) + .map(|index| { + let mut address = address.clone(); + address.index = index; + chain.transaction_receipt(&address) }) - }, - _ => None - } - })) + .collect(); + match (transaction, previous_receipts) { + (Some(transaction), Some(previous_receipts)) => { + Some(transaction_receipt(transaction, previous_receipts)) + }, + _ => None, + } + })) } fn tree_route(&self, from: &H256, to: &H256) -> Option { @@ -1215,7 +1184,7 @@ impl BlockChainClient for Client { self.miner.pending_transactions(self.chain.read().best_block_number()) } - fn signing_network_id(&self) -> Option { + fn signing_network_id(&self) -> Option { self.engine.signing_network_id(&self.latest_env_info()) } @@ -1319,32 +1288,169 @@ impl MayPanic for Client { } } +/// Returns `LocalizedReceipt` given `LocalizedTransaction` +/// and a vector of receipts from given block up to transaction index. +fn transaction_receipt(tx: LocalizedTransaction, mut receipts: Vec) -> LocalizedReceipt { + assert_eq!(receipts.len(), tx.transaction_index + 1, "All previous receipts are provided."); -#[test] -fn should_not_cache_details_before_commit() { - use tests::helpers::*; - use std::thread; - use std::time::Duration; - use std::sync::atomic::{AtomicBool, Ordering}; - - let client = generate_dummy_client(0); - let genesis = client.chain_info().best_block_hash; - let (new_hash, new_block) = get_good_dummy_block_hash(); - - let go = { - // Separate thread uncommited transaction - let go = Arc::new(AtomicBool::new(false)); - let go_thread = go.clone(); - let another_client = client.reference().clone(); - thread::spawn(move || { - let mut batch = DBTransaction::new(&*another_client.chain.read().db().clone()); - another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new()); - go_thread.store(true, Ordering::SeqCst); - }); - go + let sender = tx.sender() + .expect("LocalizedTransaction is part of the blockchain; We have only valid transactions in chain; qed"); + let receipt = receipts.pop().expect("Current receipt is provided; qed"); + let prior_gas_used = match tx.transaction_index { + 0 => 0.into(), + i => receipts.get(i - 1).expect("All previous receipts are provided; qed").gas_used, }; + let no_of_logs = receipts.into_iter().map(|receipt| receipt.logs.len()).sum::(); + let transaction_hash = tx.hash(); + let block_hash = tx.block_hash; + let block_number = tx.block_number; + let transaction_index = tx.transaction_index; - while !go.load(Ordering::SeqCst) { thread::park_timeout(Duration::from_millis(5)); } - - assert!(client.tree_route(&genesis, &new_hash).is_none()); + LocalizedReceipt { + transaction_hash: transaction_hash, + transaction_index: transaction_index, + block_hash: block_hash, + block_number:block_number, + cumulative_gas_used: receipt.gas_used, + gas_used: receipt.gas_used - prior_gas_used, + contract_address: match tx.action { + Action::Call(_) => None, + Action::Create => Some(contract_address(&sender, &tx.nonce)) + }, + logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry { + entry: log, + block_hash: block_hash, + block_number: block_number, + transaction_hash: transaction_hash, + transaction_index: transaction_index, + transaction_log_index: i, + log_index: no_of_logs + i, + }).collect(), + log_bloom: receipt.log_bloom, + state_root: receipt.state_root, + } +} + +#[cfg(test)] +mod tests { + + #[test] + fn should_not_cache_details_before_commit() { + use client::BlockChainClient; + use tests::helpers::*; + + use std::thread; + use std::time::Duration; + use std::sync::Arc; + use std::sync::atomic::{AtomicBool, Ordering}; + use util::kvdb::DBTransaction; + + let client = generate_dummy_client(0); + let genesis = client.chain_info().best_block_hash; + let (new_hash, new_block) = get_good_dummy_block_hash(); + + let go = { + // Separate thread uncommited transaction + let go = Arc::new(AtomicBool::new(false)); + let go_thread = go.clone(); + let another_client = client.reference().clone(); + thread::spawn(move || { + let mut batch = DBTransaction::new(&*another_client.chain.read().db().clone()); + another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new()); + go_thread.store(true, Ordering::SeqCst); + }); + go + }; + + while !go.load(Ordering::SeqCst) { thread::park_timeout(Duration::from_millis(5)); } + + assert!(client.tree_route(&genesis, &new_hash).is_none()); + } + + #[test] + fn should_return_correct_log_index() { + use super::transaction_receipt; + use ethkey::KeyPair; + use log_entry::{LogEntry, LocalizedLogEntry}; + use receipt::{Receipt, LocalizedReceipt}; + use transaction::{Transaction, LocalizedTransaction, Action}; + use util::Hashable; + + // given + let key = KeyPair::from_secret("test".sha3()).unwrap(); + let secret = key.secret(); + + let block_number = 1; + let block_hash = 5.into(); + let state_root = 99.into(); + let gas_used = 10.into(); + let raw_tx = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 21000.into(), + action: Action::Call(10.into()), + value: 0.into(), + data: vec![], + }; + let tx1 = raw_tx.clone().sign(secret, None); + let transaction = LocalizedTransaction { + signed: tx1.clone(), + block_number: block_number, + block_hash: block_hash, + transaction_index: 1, + }; + let logs = vec![LogEntry { + address: 5.into(), + topics: vec![], + data: vec![], + }, LogEntry { + address: 15.into(), + topics: vec![], + data: vec![], + }]; + let receipts = vec![Receipt { + state_root: state_root, + gas_used: 5.into(), + log_bloom: Default::default(), + logs: vec![logs[0].clone()], + }, Receipt { + state_root: state_root, + gas_used: gas_used, + log_bloom: Default::default(), + logs: logs.clone(), + }]; + + // when + let receipt = transaction_receipt(transaction, receipts); + + // then + assert_eq!(receipt, LocalizedReceipt { + transaction_hash: tx1.hash(), + transaction_index: 1, + block_hash: block_hash, + block_number: block_number, + cumulative_gas_used: gas_used, + gas_used: gas_used - 5.into(), + contract_address: None, + logs: vec![LocalizedLogEntry { + entry: logs[0].clone(), + block_hash: block_hash, + block_number: block_number, + transaction_hash: tx1.hash(), + transaction_index: 1, + transaction_log_index: 0, + log_index: 1, + }, LocalizedLogEntry { + entry: logs[1].clone(), + block_hash: block_hash, + block_number: block_number, + transaction_hash: tx1.hash(), + transaction_index: 1, + transaction_log_index: 1, + log_index: 2, + }], + log_bloom: Default::default(), + state_root: state_root, + }); + } } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 3b72a96b3..19626d434 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -654,7 +654,7 @@ impl BlockChainClient for TestBlockChainClient { self.miner.pending_transactions(self.chain_info().best_block_number) } - fn signing_network_id(&self) -> Option { None } + fn signing_network_id(&self) -> Option { None } fn mode(&self) -> Mode { Mode::Active } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 34bb27726..513043cf2 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -229,7 +229,7 @@ pub trait BlockChainClient : Sync + Send { } /// Get the preferred network ID to sign on - fn signing_network_id(&self) -> Option; + fn signing_network_id(&self) -> Option; /// Get the mode. fn mode(&self) -> Mode; diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index b90c08bb8..2573c7e29 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -109,7 +109,7 @@ pub trait Engine : Sync + Send { fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } /// The network ID that transactions should be signed with. - fn signing_network_id(&self, _env_info: &EnvInfo) -> Option { None } + fn signing_network_id(&self, _env_info: &EnvInfo) -> Option { None } /// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods /// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 8a1a497bd..1410d9933 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -157,9 +157,9 @@ impl Engine for Ethash { } } - fn signing_network_id(&self, env_info: &EnvInfo) -> Option { - if env_info.number >= self.ethash_params.eip155_transition && self.params().network_id < 127 { - Some(self.params().network_id as u8) + fn signing_network_id(&self, env_info: &EnvInfo) -> Option { + if env_info.number >= self.ethash_params.eip155_transition { + Some(self.params().network_id) } else { None } @@ -308,7 +308,7 @@ impl Engine for Ethash { } if let Some(n) = t.network_id() { - if header.number() < self.ethash_params.eip155_transition || n as usize != self.params().network_id { + if header.number() < self.ethash_params.eip155_transition || n != self.params().network_id { return Err(TransactionError::InvalidNetworkId.into()) } } diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 2babfb708..ff6d3e2e3 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -38,7 +38,7 @@ pub struct CommonParams { /// Maximum size of extra data. pub maximum_extra_data_size: usize, /// Network id. - pub network_id: usize, + pub network_id: u64, /// Main subprotocol name. pub subprotocol_name: String, /// Minimum gas limit. @@ -160,7 +160,7 @@ impl Spec { pub fn nodes(&self) -> &[String] { &self.nodes } /// Get the configured Network ID. - pub fn network_id(&self) -> usize { self.params.network_id } + pub fn network_id(&self) -> u64 { self.params.network_id } /// Get the configured Network ID. pub fn subprotocol_name(&self) -> String { self.params.subprotocol_name.clone() } diff --git a/ethcore/src/types/log_entry.rs b/ethcore/src/types/log_entry.rs index 0e5f7d531..8e99c27aa 100644 --- a/ethcore/src/types/log_entry.rs +++ b/ethcore/src/types/log_entry.rs @@ -95,6 +95,8 @@ pub struct LocalizedLogEntry { pub transaction_index: usize, /// Log position in the block. pub log_index: usize, + /// Log position in the transaction. + pub transaction_log_index: usize, } impl Deref for LocalizedLogEntry { diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 84c403e0e..29976ce4b 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -72,8 +72,8 @@ pub struct Transaction { impl Transaction { /// Append object with a without signature into RLP stream - pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option) { - s.begin_list(if let None = network_id { 6 } else { 9 }); + pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option) { + s.begin_list(if network_id.is_none() { 6 } else { 9 }); s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); @@ -140,26 +140,26 @@ impl From for SignedTransaction { impl Transaction { /// The message hash of the transaction. - pub fn hash(&self, network_id: Option) -> H256 { + pub fn hash(&self, network_id: Option) -> H256 { let mut stream = RlpStream::new(); self.rlp_append_unsigned_transaction(&mut stream, network_id); stream.out().sha3() } /// Signs the transaction as coming from `sender`. - pub fn sign(self, secret: &Secret, network_id: Option) -> SignedTransaction { + pub fn sign(self, secret: &Secret, network_id: Option) -> SignedTransaction { let sig = ::ethkey::sign(secret, &self.hash(network_id)) .expect("data is valid and context has signing capabilities; qed"); self.with_signature(sig, network_id) } /// Signs the transaction with signature. - pub fn with_signature(self, sig: Signature, network_id: Option) -> SignedTransaction { + pub fn with_signature(self, sig: Signature, network_id: Option) -> SignedTransaction { SignedTransaction { unsigned: self, r: sig.r().into(), s: sig.s().into(), - v: sig.v() + if let Some(n) = network_id { 35 + n * 2 } else { 27 }, + v: sig.v() as u64 + if let Some(n) = network_id { 35 + n * 2 } else { 27 }, hash: Cell::new(None), sender: Cell::new(None), } @@ -210,8 +210,8 @@ pub struct SignedTransaction { /// Plain Transaction. 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 network this transaction is for. If 27/28, its for all networks. - v: u8, + /// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks. + v: u64, /// 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. @@ -302,10 +302,13 @@ impl SignedTransaction { } /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. - pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => (v - 1) % 2, _ => 4 } } + pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => ((v - 1) % 2) as u8, _ => 4 } } - /// The network ID, or `None` if this is a global transaction. - pub fn network_id(&self) -> Option { + /// The `v` value that appears in the RLP. + pub fn original_v(&self) -> u64 { self.v } + + /// The network ID, or `None` if this is a global transaction. + pub fn network_id(&self) -> Option { match self.v { v if v > 36 => Some((v - 35) / 2), _ => None, @@ -367,7 +370,7 @@ impl SignedTransaction { } /// Signed Transaction that is a part of canon blockchain. -#[derive(Debug, PartialEq, Eq, Binary)] +#[derive(Debug, Clone, PartialEq, Eq, Binary)] pub struct LocalizedTransaction { /// Signed part. pub signed: SignedTransaction, @@ -461,7 +464,7 @@ fn should_agree_with_vitalik() { let signed: SignedTransaction = decode(&FromHex::from_hex(tx_data).unwrap()); signed.check_low_s().unwrap(); assert_eq!(signed.sender().unwrap(), address.into()); - flushln!("networkid: {:?}", signed.network_id()); + flushln!("networkid: {:?}", signed.network_id()); }; test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce") diff --git a/parity/params.rs b/parity/params.rs index 1eceb89e0..6ee1e056b 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -27,7 +27,7 @@ use user_defaults::UserDefaults; #[derive(Debug, PartialEq)] pub enum SpecType { Mainnet, - Testnet, + Morden, Ropsten, Olympic, Classic, @@ -48,8 +48,8 @@ impl str::FromStr for SpecType { let spec = match s { "frontier" | "homestead" | "mainnet" => SpecType::Mainnet, "frontier-dogmatic" | "homestead-dogmatic" | "classic" => SpecType::Classic, - "morden" | "testnet" => SpecType::Testnet, - "ropsten" => SpecType::Ropsten, + "morden" => SpecType::Morden, + "ropsten" | "testnet" => SpecType::Ropsten, "olympic" => SpecType::Olympic, "expanse" => SpecType::Expanse, other => SpecType::Custom(other.into()), @@ -62,7 +62,7 @@ impl SpecType { pub fn spec(&self) -> Result { match *self { SpecType::Mainnet => Ok(ethereum::new_frontier()), - SpecType::Testnet => Ok(ethereum::new_morden()), + SpecType::Morden => Ok(ethereum::new_morden()), SpecType::Ropsten => Ok(ethereum::new_ropsten()), SpecType::Olympic => Ok(ethereum::new_olympic()), SpecType::Classic => Ok(ethereum::new_classic()), @@ -283,10 +283,11 @@ mod tests { assert_eq!(SpecType::Mainnet, "frontier".parse().unwrap()); assert_eq!(SpecType::Mainnet, "homestead".parse().unwrap()); assert_eq!(SpecType::Mainnet, "mainnet".parse().unwrap()); - assert_eq!(SpecType::Testnet, "testnet".parse().unwrap()); - assert_eq!(SpecType::Testnet, "morden".parse().unwrap()); + assert_eq!(SpecType::Ropsten, "testnet".parse().unwrap()); + assert_eq!(SpecType::Morden, "morden".parse().unwrap()); assert_eq!(SpecType::Ropsten, "ropsten".parse().unwrap()); assert_eq!(SpecType::Olympic, "olympic".parse().unwrap()); + assert_eq!(SpecType::Classic, "classic".parse().unwrap()); } #[test] diff --git a/parity/run.rs b/parity/run.rs index 56ff92c25..f8f68b0c6 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -177,7 +177,7 @@ pub fn execute(cmd: RunCmd, logger: Arc) -> Result<(), String> { let mut sync_config = SyncConfig::default(); sync_config.network_id = match cmd.network_id { Some(id) => id, - None => spec.network_id(), + None => spec.network_id() as usize, }; if spec.subprotocol_name().len() != 3 { warn!("Your chain specification's subprotocol length is not 3. Ignoring."); diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 9f654e7e0..d7c801e13 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -191,6 +191,7 @@ fn rpc_eth_logs() { data: vec![1,2,3], }, transaction_index: 0, + transaction_log_index: 0, transaction_hash: H256::default(), log_index: 0, }, LocalizedLogEntry { @@ -202,8 +203,9 @@ fn rpc_eth_logs() { data: vec![1,2,3], }, transaction_index: 0, + transaction_log_index: 1, transaction_hash: H256::default(), - log_index: 0, + log_index: 1, }]); @@ -211,8 +213,8 @@ fn rpc_eth_logs() { let request2 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":1}], "id": 1}"#; let request3 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":0}], "id": 1}"#; - let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"id":1}"#; - let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"id":1}"#; + let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; + let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; let response3 = r#"{"jsonrpc":"2.0","result":[],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request1), Some(response1.to_owned())); @@ -233,6 +235,7 @@ fn rpc_logs_filter() { data: vec![1,2,3], }, transaction_index: 0, + transaction_log_index: 0, transaction_hash: H256::default(), log_index: 0, }, LocalizedLogEntry { @@ -244,8 +247,9 @@ fn rpc_logs_filter() { data: vec![1,2,3], }, transaction_index: 0, + transaction_log_index: 1, transaction_hash: H256::default(), - log_index: 0, + log_index: 1, }]); // Register filters first @@ -259,8 +263,8 @@ fn rpc_logs_filter() { let request_changes1 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x0"], "id": 1}"#; let request_changes2 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x1"], "id": 1}"#; - let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"id":1}"#; - let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"id":1}"#; + let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; + let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request_changes1), Some(response1.to_owned())); assert_eq!(tester.io.handle_request_sync(request_changes2), Some(response2.to_owned())); @@ -485,7 +489,7 @@ fn rpc_eth_pending_transaction_by_hash() { tester.miner.pending_transactions.lock().insert(H256::zero(), tx); } - let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":0,"value":"0xa"},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","networkId":null,"nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","standardV":"0x0","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":"0x1b","value":"0xa"},"id":1}"#; let request = r#"{ "jsonrpc": "2.0", "method": "eth_getTransactionByHash", @@ -761,6 +765,7 @@ fn rpc_eth_send_transaction() { assert_eq!(tester.io.handle_request_sync(&request), Some(response)); } + #[test] fn rpc_eth_send_transaction_with_bad_to() { let tester = EthTester::default(); @@ -878,6 +883,7 @@ fn rpc_eth_transaction_receipt() { block_number: 0x4510c, transaction_hash: H256::new(), transaction_index: 0, + transaction_log_index: 0, log_index: 1, }], log_bloom: 0.into(), @@ -894,7 +900,7 @@ fn rpc_eth_transaction_receipt() { "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index f52785e90..5aab6ced8 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -139,7 +139,7 @@ mod tests { fn test_serialize_block_transactions() { let t = BlockTransactions::Full(vec![Transaction::default()]); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"v":0,"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000"}]"#); + assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0"}]"#); let t = BlockTransactions::Hashes(vec![H256::default().into()]); let serialized = serde_json::to_string(&t).unwrap(); diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index fc163c54b..e09c85688 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -124,7 +124,7 @@ impl Serialize for FilterChanges { mod tests { use serde_json; use std::str::FromStr; - use util::hash::*; + use util::hash::H256; use super::*; use v1::types::BlockNumber; use ethcore::filter::Filter as EthFilter; diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index b945de6ea..453242454 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -38,9 +38,12 @@ pub struct Log { /// Transaction Index #[serde(rename="transactionIndex")] pub transaction_index: Option, - /// Log Index + /// Log Index in Block #[serde(rename="logIndex")] pub log_index: Option, + /// Log Index in Transaction + #[serde(rename="transactionLogIndex")] + pub transaction_log_index: Option, /// Log Type #[serde(rename="type")] pub log_type: String, @@ -57,6 +60,7 @@ impl From for Log { transaction_hash: Some(e.transaction_hash.into()), transaction_index: Some(e.transaction_index.into()), log_index: Some(e.log_index.into()), + transaction_log_index: Some(e.transaction_log_index.into()), log_type: "mined".to_owned(), } } @@ -73,6 +77,7 @@ impl From for Log { transaction_hash: None, transaction_index: None, log_index: None, + transaction_log_index: None, log_type: "pending".to_owned(), } } @@ -86,7 +91,7 @@ mod tests { #[test] fn log_serialization() { - let s = r#"{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","type":"mined"}"#; + let s = r#"{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":"0x1","type":"mined"}"#; let log = Log { address: H160::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), @@ -99,6 +104,7 @@ mod tests { block_number: Some(U256::from(0x4510c)), transaction_hash: Some(H256::default()), transaction_index: Some(U256::default()), + transaction_log_index: Some(1.into()), log_index: Some(U256::from(1)), log_type: "mined".to_owned(), }; diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index 24170a14c..511ecccac 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -109,7 +109,7 @@ mod tests { #[test] fn receipt_serialization() { - let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","type":"mined"}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f"}"#; + let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":null,"type":"mined"}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f"}"#; let receipt = Receipt { transaction_hash: Some(0.into()), @@ -130,6 +130,7 @@ mod tests { block_number: Some(0x4510c.into()), transaction_hash: Some(0.into()), transaction_index: Some(0.into()), + transaction_log_index: None, log_index: Some(1.into()), log_type: "mined".into(), }], diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 0982a5ef9..11c8c7ab7 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -54,12 +54,18 @@ pub struct Transaction { /// Public key of the signer. #[serde(rename="publicKey")] pub public_key: Option, - /// The V field of the signature. - pub v: u8, + /// The network id of the transaction, if any. + #[serde(rename="networkId")] + pub network_id: Option, + /// The standardised V field of the signature (0 or 1). + #[serde(rename="standardV")] + pub standard_v: U256, + /// The standardised V field of the signature. + pub v: U256, /// The R field of the signature. - pub r: H256, + pub r: U256, /// The S field of the signature. - pub s: H256, + pub s: U256, } impl From for Transaction { @@ -86,7 +92,9 @@ impl From for Transaction { }, raw: ::rlp::encode(&t.signed).to_vec().into(), public_key: t.public_key().ok().map(Into::into), - v: signature.v(), + network_id: t.network_id(), + standard_v: t.standard_v().into(), + v: t.original_v().into(), r: signature.r().into(), s: signature.s().into(), } @@ -117,7 +125,9 @@ impl From for Transaction { }, raw: ::rlp::encode(&t).to_vec().into(), public_key: t.public_key().ok().map(Into::into), - v: signature.v(), + network_id: t.network_id(), + standard_v: t.standard_v().into(), + v: t.original_v().into(), r: signature.r().into(), s: signature.s().into(), } @@ -133,7 +143,7 @@ mod tests { fn test_transaction_serialize() { let t = Transaction::default(); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"v":0,"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0"}"#); } } diff --git a/signer/src/tests/mod.rs b/signer/src/tests/mod.rs index d442a7e0d..e80b5778d 100644 --- a/signer/src/tests/mod.rs +++ b/signer/src/tests/mod.rs @@ -15,7 +15,6 @@ // along with Parity. If not, see . use std::ops::{Deref, DerefMut}; -use std::thread; use std::time; use std::sync::Arc; use devtools::{http_client, RandomTempPath}; diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index dab00537e..3e409a6df 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -37,12 +37,12 @@ //! implementations for even more speed, hidden behind the `x64_arithmetic` //! feature flag. -use std::{mem, fmt}; +use std::{mem, fmt, cmp}; use std::str::{FromStr}; use std::hash::Hash; use std::ops::{Shr, Shl, BitAnd, BitOr, BitXor, Not, Div, Rem, Mul, Add, Sub}; use std::cmp::Ordering; -use rustc_serialize::hex::{FromHex, FromHexError}; +use rustc_serialize::hex::{ToHex, FromHex, FromHexError}; /// Conversion from decimal string error #[derive(Debug, PartialEq)] @@ -520,8 +520,10 @@ pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Displa fn bit(&self, index: usize) -> bool; /// Return single byte fn byte(&self, index: usize) -> u8; - /// Convert U256 to the sequence of bytes with a big endian + /// Convert to the sequence of bytes with a big endian fn to_big_endian(&self, bytes: &mut[u8]); + /// Convert to a non-zero-prefixed hex representation (not prefixed by `0x`). + fn to_hex(&self) -> String; /// Create `Uint(10**n)` fn exp10(n: usize) -> Self; /// Return eponentation `self**other`. Panic on overflow. @@ -683,6 +685,17 @@ macro_rules! construct_uint { bytes[i] = (arr[pos] >> ((rev % 8) * 8)) as u8; } } + #[inline] + fn to_hex(&self) -> String { + if self.is_zero() { return "0".to_owned(); } // special case. + let mut bytes = [0u8; 8 * $n_words]; + self.to_big_endian(&mut bytes); + let bp7 = self.bits() + 7; + let len = cmp::max(bp7 / 8, 1); + let bytes_hex = bytes[bytes.len() - len..].to_hex(); + (&bytes_hex[1 - bp7 % 8 / 4..]).to_owned() + } + #[inline] fn exp10(n: usize) -> Self { match n { @@ -1636,7 +1649,7 @@ mod tests { } #[test] - fn uint256_pow () { + fn uint256_pow() { assert_eq!(U256::from(10).pow(U256::from(0)), U256::from(1)); assert_eq!(U256::from(10).pow(U256::from(1)), U256::from(10)); assert_eq!(U256::from(10).pow(U256::from(2)), U256::from(100)); @@ -1646,12 +1659,24 @@ mod tests { #[test] #[should_panic] - fn uint256_pow_overflow_panic () { + fn uint256_pow_overflow_panic() { U256::from(2).pow(U256::from(0x100)); } #[test] - fn uint256_overflowing_pow () { + fn should_format_hex_correctly() { + assert_eq!(&U256::from(0).to_hex(), &"0"); + assert_eq!(&U256::from(0x1).to_hex(), &"1"); + assert_eq!(&U256::from(0xf).to_hex(), &"f"); + assert_eq!(&U256::from(0x10).to_hex(), &"10"); + assert_eq!(&U256::from(0xff).to_hex(), &"ff"); + assert_eq!(&U256::from(0x100).to_hex(), &"100"); + assert_eq!(&U256::from(0xfff).to_hex(), &"fff"); + assert_eq!(&U256::from(0x1000).to_hex(), &"1000"); + } + + #[test] + fn uint256_overflowing_pow() { // assert_eq!( // U256::from(2).overflowing_pow(U256::from(0xff)), // (U256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap(), false)